跟着正点原子学习Linux-LED驱动

/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”);



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值