设备树学习之(二)点灯
来源:互联网 发布: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
- 设备树学习之(二)点灯
- 设备树学习之(二)点灯
- 设备树学习之(二)点灯
- tiny4412学习(四)之移植linux-设备树(2)设备树之LED点灯
- 字符设备驱动学习笔记--点灯
- arduino学习之:LED点灯
- s5pv210驱动学习之点灯程序
- 字符设备驱动点灯
- Arduino学习笔记二:修改LED点灯程序
- 基于stm32f103zet6之UC/OS_II的学习1(初步移植OS--点灯大法)
- 基于stm32f103zet6之UC/OS_II的学习2(初步分析OS--点灯大法)
- tiny4412 设备树之i2c设备(二)
- TQ210裸机编程——按键点灯 (二)
- Linux设备驱动程序学习之设备模型二
- 学习《Linux设备模型浅析之设备篇》笔记(二)
- S5PV210 之点灯
- 6410之点灯驱动
- 6410之点灯
- 第一章 Oracle关系数据库
- 素数筛算法
- hdu 2955 Robberies
- Biorhythms
- java socket客户端发信息,服务器接收并反馈。
- 设备树学习之(二)点灯
- MyEclipse配置自定义class类模板
- Java学习笔记1
- POJ.1611 The Suspects (并查集)
- python学习
- 最长上升序列/非递减序列
- A
- Recyclerview刷新机制
- Lake Counting -poj2386-深搜或者广搜