/led driver**/
1 #include <linux/types.h>
2 #include <linux/kernel.h>
3 #include <linux/delay.h>
4 #include <linux/ide.h>
5 #include <linux/init.h>
6 #include <linux/module.h>
7 #include <linux/errno.h>
8 #include <linux/gpio.h>
9 #include <asm/mach/map.h>
10 #include <asm/uaccess.h>
11 #include <asm/io.h>
12 /***************************************************************
13 Copyright © ALIENTEK Co., Ltd. 1998-2029. All rights reserved.
14 文件名 : led.c
15 作者 : 左忠凯
16 版本 : V1.0
17 描述 : LED 驱动文件。
18 其他 : 无
19 论坛 : www.openedv.com
20 日志 : 初版 V1.0 2019/1/30 左忠凯创建
21 **************************************************************/
22 #define LED_MAJOR 200 / 主设备号 /
23 #define LED_NAME “led” / 设备名字 /
24
25 #define LEDOFF 0 / 关灯 /
26 #define LEDON 1 / 开灯 /
27
28 / 寄存器物理地址 /
29 #define CCM_CCGR1_BASE (0X020C406C)
30 #define SW_MUX_GPIO1_IO03_BASE (0X020E0068)
31 #define SW_PAD_GPIO1_IO03_BASE (0X020E02F4)
32 #define GPIO1_DR_BASE (0X0209C000)
33 #define GPIO1_GDIR_BASE (0X0209C004)
34
35 / 映射后的寄存器虚拟地址指针 */
36 static void __iomem *IMX6U_CCM_CCGR1;
37 static void __iomem *SW_MUX_GPIO1_IO03;
38 static void __iomem *SW_PAD_GPIO1_IO03;
39 static void __iomem *GPIO1_DR;
40 static void __iomem GPIO1_GDIR;
41
42 /
43 * @description : LED 打开/关闭
- @param - sta : LEDON(0) 打开 LED, LEDOFF(1) 关闭 LED
45 * @return : 无
46 /
47 void led_switch(u8 sta)
48 {
49 u32 val = 0;
50 if(sta == LEDON) {
51 val = readl(GPIO1_DR);//读取原来的值readl是读取32位地址,readb读取8位地址,readw读取16位地址,防止原来的配置被改变
52 val &= ~(1 << 3);
53 writel(val, GPIO1_DR);
54 }else if(sta == LEDOFF) {
55 val = readl(GPIO1_DR);
56 val|= (1 << 3);
57 writel(val, GPIO1_DR);
58 }
59 }
60
61 /
62 * @description : 打开设备
63 * @param – inode : 传递给驱动的 inode
64 * @param - filp : 设备文件, file 结构体有个叫做 private_data 的成员变量
65 * 一般在 open 的时候将 private_data 指向设备结构体。
66 * @return : 0 成功;其他 失败
67 */
68 static int led_open(struct inode *inode, struct file filp)
69 {
70 return 0;
71 }
72
73 /
74 * @description : 从设备读取数据
75 * @param - filp : 要打开的设备文件(文件描述符)
76 * @param - buf : 返回给用户空间的数据缓冲区
77 * @param - cnt : 要读取的数据长度
78 * @param - offt : 相对于文件首地址的偏移
79 * @return : 读取的字节数,如果为负值,表示读取失败
80 */
81 static ssize_t led_read(struct file *filp, char __user *buf,
size_t cnt, loff_t offt)
82 {
83 return 0;
84 }
8586 /
87 * @description : 向设备写数据
88 * @param - filp : 设备文件,表示打开的文件描述符
89 * @param - buf : 要写给设备写入的数据
90 * @param - cnt : 要写入的数据长度
91 * @param - offt : 相对于文件首地址的偏移
92 * @return : 写入的字节数,如果为负值,表示写入失败
93 */
94 static ssize_t led_write(struct file *filp, const char __user *buf,
size_t cnt, loff_t offt)
95 {
96 int retvalue;
97 unsigned char databuf[1];
98 unsigned char ledstat;
99
100 retvalue = copy_from_user(databuf, buf, cnt);
101 if(retvalue < 0) {
102 printk(“kernel write failed!\r\n”);
103 return -EFAULT;
104 }
105
106 ledstat = databuf[0]; / 获取状态值 /
107
108 if(ledstat == LEDON) {
109 led_switch(LEDON); / 打开 LED 灯 /
110 } else if(ledstat == LEDOFF) {
111 led_switch(LEDOFF); / 关闭 LED 灯 /
112 }
113 return 0;
114 }
115
116 /
117 * @description : 关闭/释放设备
118 * @param – filp : 要关闭的设备文件(文件描述符)
119 * @return : 0 成功;其他 失败
120 */
121 static int led_release(struct inode *inode, struct file filp)
122 {
123 return 0;
124 }
125
126 / 设备操作函数 /
127 static struct file_operations led_fops = {
128 .owner = THIS_MODULE,
129 .open = led_open,
130 .read = led_read,
131 .write = led_write,
132 .release = led_release,
133 };
134
135 /
136 * @description : 驱动出口函数
137 * @param : 无
138 * @return : 无
139 /
140 static int __init led_init(void)
141 {
142 int retvalue = 0;
143 u32 val = 0;
144
145 / 初始化 LED /
146 / 1、寄存器地址映射 /
147 IMX6U_CCM_CCGR1 = ioremap(CCM_CCGR1_BASE, 4);
148 SW_MUX_GPIO1_IO03 = ioremap(SW_MUX_GPIO1_IO03_BASE, 4);
149 SW_PAD_GPIO1_IO03 = ioremap(SW_PAD_GPIO1_IO03_BASE, 4);
150 GPIO1_DR = ioremap(GPIO1_DR_BASE, 4);
151 GPIO1_GDIR = ioremap(GPIO1_GDIR_BASE, 4);
152
153 / 2、使能 GPIO1 时钟 /
154 val = readl(IMX6U_CCM_CCGR1);
155 val &= ~(3 << 26); / 清除以前的设置 /
156 val |= (3 << 26); / 设置新值 /
157 writel(val, IMX6U_CCM_CCGR1);
158
159 / 3、设置 GPIO1_IO03 的复用功能,将其复用为
160 * GPIO1_IO03,最后设置 IO 属性。
161 /
162 writel(5, SW_MUX_GPIO1_IO03);
163
164 / 寄存器 SW_PAD_GPIO1_IO03 设置 IO 属性 /
165 writel(0x10B0, SW_PAD_GPIO1_IO03);
166
167 / 4、设置 GPIO1_IO03 为输出功能 /
168 val = readl(GPIO1_GDIR);
169 val &= ~(1 << 3); / 清除以前的设置 /
170 val |= (1 << 3); / 设置为输出 /
171 writel(val, GPIO1_GDIR);
172
173 / 5、默认关闭 LED /
174 val = readl(GPIO1_DR);
175 val |= (1 << 3);
176 writel(val, GPIO1_DR);
177
178 / 6、注册字符设备驱动 /
179 retvalue = register_chrdev(LED_MAJOR, LED_NAME, &led_fops);
180 if(retvalue < 0){
181 printk(“register chrdev failed!\r\n”);
182 return -EIO;
183 }
184 return 0;
185 }
186
187 /
188 * @description : 驱动出口函数
189 * @param : 无
190 * @return : 无
191 /
192 static void __exit led_exit(void)
193 {
194 / 取消映射 /
195 iounmap(IMX6U_CCM_CCGR1);
196 iounmap(SW_MUX_GPIO1_IO03);
197 iounmap(SW_PAD_GPIO1_IO03);
198 iounmap(GPIO1_DR);
199 iounmap(GPIO1_GDIR);
200
201 / 注销字符设备驱动 */
202 unregister_chrdev(LED_MAJOR, LED_NAME);
203 }
204
205 module_init(led_init);
206 module_exit(led_exit);
207 MODULE_LICENSE(“GPL”);
208 MODULE_AUTHOR(“zuozhongkai”);
/led new driver/
1 #include <linux/types.h>
2 #include <linux/kernel.h>
3 #include <linux/delay.h>
4 #include <linux/ide.h>
5 #include <linux/init.h>
6 #include <linux/module.h>
7 #include <linux/errno.h>
8 #include <linux/gpio.h>
9 #include <linux/cdev.h>
10 #include <linux/device.h>
11 #include <asm/mach/map.h>
12 #include <asm/uaccess.h>
13 #include <asm/io.h>
/***************************************************************
16 Copyright © ALIENTEK Co., Ltd. 1998-2029. All rights reserved.
17 文件名 : newchrled.c
18 作者 : 左忠凯
19 版本 : V1.0
20 描述 : LED 驱动文件。
21 其他 : 无
22 论坛 : www.openedv.com
23 日志 : 初版 V1.0 2019/6/27 左忠凯创建
24 **************************************************************/
25 #define NEWCHRLED_CNT 1 / 设备号个数 /
26 #define NEWCHRLED_NAME “newchrled” / 名字 /
27 #define LEDOFF 0 / 关灯 /
28 #define LEDON 1 / 开灯 /
29
30 / 寄存器物理地址 /
31 #define CCM_CCGR1_BASE (0X020C406C)
32 #define SW_MUX_GPIO1_IO03_BASE (0X020E0068)
33 #define SW_PAD_GPIO1_IO03_BASE (0X020E02F4)
34 #define GPIO1_DR_BASE (0X0209C000)
35 #define GPIO1_GDIR_BASE (0X0209C004)
36
37 / 映射后的寄存器虚拟地址指针 */
38 static void __iomem *IMX6U_CCM_CCGR1;
39 static void __iomem *SW_MUX_GPIO1_IO03;
40 static void __iomem *SW_PAD_GPIO1_IO03;
41 static void __iomem *GPIO1_DR;
42 static void __iomem GPIO1_GDIR;
43
44 / newchrled 设备结构体 /
45 struct newchrled_dev{
46 dev_t devid; / 设备号 /
47 struct cdev cdev; / cdev */
48 struct class class; / 类 */
49 struct device device; / 设备 /
50 int major; / 主设备号 /
51 int minor; / 次设备号 /
52 };
53
54 struct newchrled_dev newchrled; / led 设备 /
55
56 /
57 * @description : LED 打开/关闭
58 * @param - sta : LEDON(0) 打开 LED, LEDOFF(1) 关闭 LED
59 * @return : 无
60 /
61 void led_switch(u8 sta)
62 {
63 u32 val = 0;
64 if(sta == LEDON) {
65 val = readl(GPIO1_DR);
66 val &= ~(1 << 3);
67 writel(val, GPIO1_DR);
68 }else if(sta == LEDOFF) {
69 val = readl(GPIO1_DR);
70 val|= (1 << 3);
71 writel(val, GPIO1_DR);
72 }
73 }
74
75 /
76 * @description : 打开设备
77 * @param – inode : 传递给驱动的 inode
78 * @param - filp : 设备文件, file 结构体有个叫做 private_data 的成员变量
79 * 一般在 open 的时候将 private_data 指向设备结构体。
80 * @return : 0 成功;其他 失败
81 */
82 static int led_open(struct inode *inode, struct file filp)
83 {
84 filp->private_data = &newchrled; / 设置私有数据 /
85 return 0;
86 }
87
88 /
89 * @description : 从设备读取数据
90 * @param - filp : 要打开的设备文件(文件描述符)
91 * @param - buf : 返回给用户空间的数据缓冲区
92 * @param - cnt : 要读取的数据长度
93 * @param – offt : 相对于文件首地址的偏移
94 * @return : 读取的字节数,如果为负值,表示读取失败
95 */
96 static ssize_t led_read(struct file *filp, char __user *buf, size_t cnt, loff_t offt)
97 {
98 return 0;
99 }
100
101 /
102 * @description : 向设备写数据
103 * @param – filp : 设备文件,表示打开的文件描述符
104 * @param - buf : 要写给设备写入的数据
105 * @param - cnt : 要写入的数据长度
106 * @param – offt : 相对于文件首地址的偏移
107 * @return : 写入的字节数,如果为负值,表示写入失败
108 */
109 static ssize_t led_write(struct file *filp, const char __user *buf,
size_t cnt, loff_t offt)
110 {
111 int retvalue;
112 unsigned char databuf[1];
113 unsigned char ledstat;
114
115 retvalue = copy_from_user(databuf, buf, cnt);
116 if(retvalue < 0) {
117 printk(“kernel write failed!\r\n”);
118 return -EFAULT;
119 }
120
121 ledstat = databuf[0]; / 获取状态值 /
122
123 if(ledstat == LEDON) {
124 led_switch(LEDON); / 打开 LED 灯 /
125 } else if(ledstat == LEDOFF) {
126 led_switch(LEDOFF); / 关闭 LED 灯 /
127 }
128 return 0;
129 }
130
131 /
132 * @description : 关闭/释放设备
133 * @param – filp : 要关闭的设备文件(文件描述符)
134 * @return : 0 成功;其他 失败
135 */
136 static int led_release(struct inode *inode, struct file filp)
137 {
138 return 0;
139 }
140
141 / 设备操作函数 /
142 static struct file_operations newchrled_fops = {
143 .owner = THIS_MODULE,
144 .open = led_open,
145 .read = led_read,
146 .write = led_write,
147 .release = led_release,
148 };
149
150 /
151 * @description : 驱动出口函数
152 * @param : 无
153 * @return : 无
154 /
155 static int __init led_init(void)
156 {
157 u32 val = 0;
158
159 / 初始化 LED /
160 / 1、寄存器地址映射 /
161 IMX6U_CCM_CCGR1 = ioremap(CCM_CCGR1_BASE, 4);
162 SW_MUX_GPIO1_IO03 = ioremap(SW_MUX_GPIO1_IO03_BASE, 4);
163 SW_PAD_GPIO1_IO03 = ioremap(SW_PAD_GPIO1_IO03_BASE, 4);
164 GPIO1_DR = ioremap(GPIO1_DR_BASE, 4);
165 GPIO1_GDIR = ioremap(GPIO1_GDIR_BASE, 4);
166
167 / 2、使能 GPIO1 时钟 /
168 val = readl(IMX6U_CCM_CCGR1);
169 val &= ~(3 << 26); / 清楚以前的设置 /
170 val |= (3 << 26); / 设置新值 /
171 writel(val, IMX6U_CCM_CCGR1);
172
173 / 3、设置 GPIO1_IO03 的复用功能,将其复用为
174 * GPIO1_IO03,最后设置 IO 属性。
175 /
176 writel(5, SW_MUX_GPIO1_IO03);
177
178 / 寄存器 SW_PAD_GPIO1_IO03 设置 IO 属性 /
179 writel(0x10B0, SW_PAD_GPIO1_IO03);
180
181 / 4、设置 GPIO1_IO03 为输出功能 /
182 val = readl(GPIO1_GDIR);
183 val &= ~(1 << 3); / 清除以前的设置 /
184 val |= (1 << 3); / 设置为输出 /
185 writel(val, GPIO1_GDIR);
186
187 / 5、默认关闭 LED /
188 val = readl(GPIO1_DR);
189 val |= (1 << 3);
190 writel(val, GPIO1_DR);
191
192 / 注册字符设备驱动 /
193 / 1、创建设备号 /
194 if (newchrled.major) { / 定义了设备号 /
195 newchrled.devid = MKDEV(newchrled.major, 0);
196 register_chrdev_region(newchrled.devid, NEWCHRLED_CNT,
NEWCHRLED_NAME);
197 } else { / 没有定义设备号 /
198 alloc_chrdev_region(&newchrled.devid, 0, NEWCHRLED_CNT,
NEWCHRLED_NAME); / 申请设备号 /
199 newchrled.major = MAJOR(newchrled.devid); / 获取主设备号 /
200 newchrled.minor = MINOR(newchrled.devid); / 获取次设备号 /
201 }
202 printk(“newcheled major=%d,minor=%d\r\n”,newchrled.major,
newchrled.minor);
203
204 / 2、初始化 cdev /
205 newchrled.cdev.owner = THIS_MODULE;
206 cdev_init(&newchrled.cdev, &newchrled_fops);
207
208 / 3、添加一个 cdev /
209 cdev_add(&newchrled.cdev, newchrled.devid, NEWCHRLED_CNT);
210
211 / 4、创建类 /
212 newchrled.class = class_create(THIS_MODULE, NEWCHRLED_NAME);
213 if (IS_ERR(newchrled.class)) {
214 return PTR_ERR(newchrled.class);
215 }
216
217 / 5、创建设备 /
218 newchrled.device = device_create(newchrled.class, NULL,
newchrled.devid, NULL, NEWCHRLED_NAME);
219 if (IS_ERR(newchrled.device)) {
220 return PTR_ERR(newchrled.device);
221 }
222
223 return 0;
224 }
225
226 /
227 * @description : 驱动出口函数
228 * @param : 无
229 * @return : 无
230 /
231 static void __exit led_exit(void)
232 {
233 / 取消映射 /
234 iounmap(IMX6U_CCM_CCGR1);
235 iounmap(SW_MUX_GPIO1_IO03);
236 iounmap(SW_PAD_GPIO1_IO03);
237 iounmap(GPIO1_DR);
238 iounmap(GPIO1_GDIR);
239
240 / 注销字符设备 /
241 cdev_del(&newchrled.cdev);/ 删除 cdev */
242 unregister_chrdev_region(newchrled.devid, NEWCHRLED_CNT);
243
244 device_destroy(newchrled.class, newchrled.devid);
245 class_destroy(newchrled.class);
246 }
247
248 module_init(led_init);
249 module_exit(led_exit);
250 MODULE_LICENSE(“GPL”);
251 MODULE_AUTHOR(“zuozhongkai”);