设备树学习之(二)点灯

来源:互联网 发布:gta5淘宝怎么搜 编辑:程序博客网 时间:2024/06/04 20:03

转载自:http://blog.csdn.net/lizuobin2/article/details/54563829

开发板:tiny4412SDK + S702 + 4GB Flash
要移植的内核版本:Linux-4.4.0 (支持device tree)
u-boot版本:友善之臂自带的 U-Boot 2010.12
busybox版本:busybox 1.25

目标:
学习设备树中GPIO控制器的使用,实现配置引脚为输出功能,写简单的字符设备驱动程序,实现点亮LED。

原理图:
这里写图片描述
tiny4412 核心板上有6颗LED,这里我们只控制其中4颗,它们分别接在GPM4_0、GPM4_1、GPM4_2、GPM4_3 引脚。想要点亮LED,首先得配置引脚为输出功能,输出低电平时LED点亮,高电平时,LED熄灭。重点在于设备树中GPIO控制器资源的使用。

设备树参考:

参考:Samsung GPIO and Pin Mux/Config controllerExample 1: A pin-controller node with pin groups.    pinctrl_0: pinctrl@11400000 {         compatible = "samsung,exynos4210-pinctrl";        reg = <0x11400000 0x1000>;        interrupts = <0 47 0>;        /* ... */        uart0_data: uart0-data {             samsung,pins = "gpa0-0", "gpa0-1";            samsung,pin-function = <2>;            samsung,pin-pud = <0>;            samsung,pin-drv = <0>;         };Example 3: A uart client node that supports 'default' and 'flow-control' states.    uart@13800000 {         compatible = "samsung,exynos4210-uart";        reg = <0x13800000 0x100>;        interrupts = <0 52 0>;        pinctrl-names = "default", "flow-control;        pinctrl-0 = <&uart0_data>;        pinctrl-1 = <&uart0_data &uart0_fctl>;     };  "samsung,pins" property of the child node. The following pin configuration properties are supported.  - samsung,pin-val: Initial value of pin output buffer.  - samsung,pin-pud: Pull up/down configuration.  - samsung,pin-drv: Drive strength configuration.  - samsung,pin-pud-pdn: Pull up/down configuration in power down mode.  - samsung,pin-drv-pdn: Drive strength configuration in power down mode.
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

设备树:

&pinctrl@11000000 {        led_demo: led{                samsung,pins = "gpm4-0", "gpm4-1" ,"gpm4-2", "gpm4-3";                samsung,pin-function = <0x1>;   //1为输出                samsung,pin-pud = <0x0>;        //没有上拉                samsung,pin-drv = <0x0>;        //驱动强度?        };}; led_pin {    compatible         = "tiny4412,led_demo";    pinctrl-names = "led_demo";    pinctrl-0 = <&led_demo>;    tiny4412,int_gpio1 = <&gpm4 0 GPIO_ACTIVE_HIGH>;    tiny4412,int_gpio2 = <&gpm4 1 GPIO_ACTIVE_HIGH>;    tiny4412,int_gpio3 = <&gpm4 2 GPIO_ACTIVE_HIGH>;    tiny4412,int_gpio4 = <&gpm4 3 GPIO_ACTIVE_HIGH>;};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

我们在 pinctrl 中增加了 led 节点,它代表了一种引脚功能,比如这里设置的 gpm4_0、gpm4_1、gpm4_2、gpm4_3,引脚功能为 0x01 输出,无上拉等等。在其它地方,我们可以引用它,来表示引脚支持的功能。
下面我们增加了 led_pin 节点,它有一个属性 pinctrl-names = “led_demo”,这是我们给引脚功能状态起的名字,如果支持多种功能,可以是字符串列表的形式。字符串的个数要和下面 pinctrl-n 的个数对应,pinctrl-0 引用了我们前面定义的那个将引脚设置为输出功能的属性。
在代码中,我们可以用过 pinctrl-names 来获得特定的引脚功能,并设置它。如果 pinctrl-names 为 “default”,那么这种功能状态将设置为默认的引脚状态,代码中无需处理。

代码片段:

static int led_probe(struct platform_device *pdev) {    struct device *dev = &pdev->dev;    dev_t devid;    struct pinctrl *pctrl;    struct pinctrl_state *pstate;    pctrl = devm_pinctrl_get(dev);    if(pctrl == NULL)    {        printk("devm_pinctrl_get error\n");    }    pstate = pinctrl_lookup_state(pctrl, "led_demo");    if(pstate == NULL)    {        printk("pinctrl_lookup_state error\n");    }    pinctrl_select_state(pctrl, pstate);//设置为输出模式     printk("enter %s\n",__func__);    led1 = of_get_named_gpio(dev->of_node, "tiny4412,int_gpio1", 0);;    led2 = of_get_named_gpio(dev->of_node, "tiny4412,int_gpio2", 0);;    led3 = of_get_named_gpio(dev->of_node, "tiny4412,int_gpio3", 0);;    led4 = of_get_named_gpio(dev->of_node, "tiny4412,int_gpio4", 0);;    if(led1 <= 0)    {        printk("%s error\n",__func__);        return -EINVAL;    }    else    {        printk("led1 %d\n",led1);        printk("led2 %d\n",led2);        printk("led3 %d\n",led3);        printk("led4 %d\n",led4);        devm_gpio_request_one(dev, led1, GPIOF_OUT_INIT_HIGH, "LED1");        devm_gpio_request_one(dev, led2, GPIOF_OUT_INIT_HIGH, "LED2");        devm_gpio_request_one(dev, led3, GPIOF_OUT_INIT_HIGH, "LED3");        devm_gpio_request_one(dev, led4, GPIOF_OUT_INIT_HIGH, "LED4");    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

完整代码:

#include <linux/module.h>#include <linux/kernel.h>#include <linux/cdev.h>#include <linux/device.h>#include <linux/platform_device.h>#include <linux/gpio.h>#include <linux/of.h>#include <linux/of_gpio.h>#include <linux/fs.h>#include <asm/uaccess.h>#define LED_CNT   4static int  major;static struct cdev  led_cdev;   //内核中用cdev描述一个字符设备static struct class *cls;static int led1,led2,led3,led4;static ssize_t led_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos){    char buf;    int minor = iminor(file->f_inode);    printk("minor is %d\n",minor);    printk("%s\n",__func__);    if(count != 1){        printk("count != 1\n");         return 1;    }    if (copy_from_user(&buf, user_buf, count))        return -EFAULT;    printk("rcv %d\n",buf);    if(buf == 0x01)    {        switch(minor){        case 0:            gpio_set_value(led1, 0);            break;        case 1:            gpio_set_value(led2, 0);            break;        case 2:            gpio_set_value(led3, 0);            break;        case 3:            gpio_set_value(led4, 0);            break;        default:            printk("%s rcv minor error\n",__func__);        }                           }    else if(buf == 0x0)    {        switch(minor){        case 0:            gpio_set_value(led1, 1);            break;        case 1:            gpio_set_value(led2, 1);            break;        case 2:            gpio_set_value(led3, 1);            break;        case 3:            gpio_set_value(led4, 1);            break;        default:            printk("%s rcv minor error\n",__func__);        }           }}static int led_open(struct inode *inode, struct file *file){    printk("led_open\n");    return 0;}static struct file_operations led_fops = {    .owner = THIS_MODULE,    .open  = led_open,    .write = led_write,};static int led_probe(struct platform_device *pdev) {    struct device *dev = &pdev->dev;    dev_t devid;    struct pinctrl *pctrl;    struct pinctrl_state *pstate;    pctrl = devm_pinctrl_get(dev);    if(pctrl == NULL)    {        printk("devm_pinctrl_get error\n");    }    pstate = pinctrl_lookup_state(pctrl, "led_demo");    if(pstate == NULL)    {        printk("pinctrl_lookup_state error\n");    }    pinctrl_select_state(pctrl, pstate);//设置为输出模式     printk("enter %s\n",__func__);    led1 = of_get_named_gpio(dev->of_node, "tiny4412,int_gpio1", 0);;    led2 = of_get_named_gpio(dev->of_node, "tiny4412,int_gpio2", 0);;    led3 = of_get_named_gpio(dev->of_node, "tiny4412,int_gpio3", 0);;    led4 = of_get_named_gpio(dev->of_node, "tiny4412,int_gpio4", 0);;    if(led1 <= 0)    {        printk("%s error\n",__func__);        return -EINVAL;    }    else    {        printk("led1 %d\n",led1);        printk("led2 %d\n",led2);        printk("led3 %d\n",led3);        printk("led4 %d\n",led4);        devm_gpio_request_one(dev, led1, GPIOF_OUT_INIT_HIGH, "LED1");        devm_gpio_request_one(dev, led2, GPIOF_OUT_INIT_HIGH, "LED2");        devm_gpio_request_one(dev, led3, GPIOF_OUT_INIT_HIGH, "LED3");        devm_gpio_request_one(dev, led4, GPIOF_OUT_INIT_HIGH, "LED4");    }    if(alloc_chrdev_region(&devid, 0, LED_CNT, "led") < 0)/* (major,0~1) 对应 hello_fops, (major, 2~255)都不对应hello_fops */    {        printk("%s ERROR\n",__func__);        goto error;    }    major = MAJOR(devid);                         cdev_init(&led_cdev, &led_fops);        //绑定文件操作函数    cdev_add(&led_cdev, devid, LED_CNT);    //注册到内核    cls = class_create(THIS_MODULE, "led"); //创建led类,向类中添加设备,mdev会帮我们创建设备节点    device_create(cls, NULL, MKDEV(major, 0), NULL, "led0");     device_create(cls, NULL, MKDEV(major, 1), NULL, "led1");     device_create(cls, NULL, MKDEV(major, 2), NULL, "led2");     device_create(cls, NULL, MKDEV(major, 3), NULL, "led3"); error:    unregister_chrdev_region(MKDEV(major, 0), LED_CNT);    return 0;}static int led_remove(struct platform_device *pdev) {    printk("enter %s\n",__func__);    device_destroy(cls, MKDEV(major, 0));    device_destroy(cls, MKDEV(major, 1));    device_destroy(cls, MKDEV(major, 2));    device_destroy(cls, MKDEV(major, 3));    class_destroy(cls);    cdev_del(&led_cdev);    unregister_chrdev_region(MKDEV(major, 0), LED_CNT);    printk("%s enter.\n", __func__);    return 0;}static const struct of_device_id led_dt_ids[] = {    { .compatible = "tiny4412,led_demo", },    {},};MODULE_DEVICE_TABLE(of, led_dt_ids);static struct platform_driver led_driver = {    .driver        = {        .name      = "led_demo",        .of_match_table    = of_match_ptr(led_dt_ids),    },    .probe         = led_probe,    .remove        = led_remove,};static int led_init(void){    int ret;    printk("enter %s\n",__func__);    ret = platform_driver_register(&led_driver);    if (ret)        printk(KERN_ERR "led demo: probe failed: %d\n", ret);    return ret; }static void led_exit(void){    printk("enter %s\n",__func__);    platform_driver_unregister(&led_driver);}module_init(led_init);module_exit(led_exit);MODULE_LICENSE("GPL");
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
0 0
原创粉丝点击