Article Directory
In this experiment, use the misc device driver to write the driver of the buzzer, and use the platform to implement the bus, device and driver. Misc is mainly responsible for the creation of character devices.
1 Modify the device tree file
The beep device node in the device tree can directly use the beep device node created in 36.3.2.
2 Write the driver
The path of the experiment routine: i.MX6UL Terminator CD-ROM information/06_Linux driver routine/16_beep_misc to
create beep_misc.c file, the specific content is as follows:
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 <linux/of.h>
12 #include <linux/of_address.h>
13 #include <linux/of_gpio.h>
14 #include <linux/platform_device.h>
15 #include <linux/miscdevice.h>
16 #include <asm/mach/map.h>
17 #include <asm/uaccess.h>
18 #include <asm/io.h>
19
20 #define MISCBEEP_NAME "miscbeep" /* 名字 */
21 #define MISCBEEP_MINOR 144 /* 子设备号 */
22 #define BEEPOFF 0 /* 关蜂鸣器 */
23 #define BEEPON 1 /* 开蜂鸣器 */
24
25 /* miscbeep设备结构体 */
26 struct miscbeep_dev{
27 dev_t devid; /* 设备号*/
28 struct cdev cdev; /* cdev */
29 struct class *class; /* 类 */
30 struct device *device; /* 设备*/
31 struct device_node *nd; /* 设备节点 */
32 int beep_gpio; /* beep所使用的GPIO编号 */
33 };
34
35 struct miscbeep_dev miscbeep; /* beep设备 */
36
37 /*
38 * @description : 打开设备
39 * @param - inode : 传递给驱动的inode
40 * @param - filp : 设备文件,file结构体有个叫做private_data的成员变量
41 * 一般在open的时候将private_data指向设备结构体。
42 * @return : 0 成功;其他 失败
43 */
44 static int miscbeep_open(struct inode *inode, struct file *filp)
45 {
46 filp->private_data = &miscbeep; /* 设置私有数据 */
47 return 0;
48 }
49
50 /*
51 * @description : 向设备写数据
52 * @param - filp : 设备文件,表示打开的文件描述符
53 * @param - buf : 要写给设备写入的数据
54 * @param - cnt : 要写入的数据长度
55 * @param - offt : 相对于文件首地址的偏移
56 * @return : 写入的字节数,如果为负值,表示写入失败
57 */
58 static ssize_t miscbeep_write(struct file *filp, const char __user *buf,
size_t cnt, loff_t *offt)
59 {
60 int retvalue;
61 unsigned char databuf[1];
62 unsigned char beepstat;
63 struct miscbeep_dev *dev = filp->private_data;
64
65 retvalue = copy_from_user(databuf, buf, cnt);
66 if(retvalue < 0) {
67 printk("kernel write failed!\r\n");
68 return -EFAULT;
69 }
70
71 beepstat = databuf[0]; /* 获取状态值 */
72 if(beepstat == BEEPON) {
73 gpio_set_value(dev->beep_gpio, 1); /* 打开蜂鸣器 */
74 } else if(beepstat == BEEPOFF) {
75 gpio_set_value(dev->beep_gpio, 0); /* 关闭蜂鸣器 */
76 }
77 return 0;
78 }
79
80 /* 设备操作函数 */
81 static struct file_operations miscbeep_fops = {
82 .owner = THIS_MODULE,
83 .open = miscbeep_open,
84 .write = miscbeep_write,
85 };
86
87 /* MISC设备结构体 */
88 static struct miscdevice beep_miscdev = {
89 .minor = MISCBEEP_MINOR,
90 .name = MISCBEEP_NAME,
91 .fops = &miscbeep_fops,
92 };
93
94 /*
95 * @description : flatform驱动的probe函数,当驱动与
96 * 设备匹配以后此函数就会执行
97 * @param - dev : platform设备
98 * @return : 0,成功;其他负值,失败
99 */
100 static int miscbeep_probe(struct platform_device *dev)
101 {
102 int ret = 0;
103
104 printk("beep driver and device was matched!\r\n");
105 /* 设置BEEP所使用的GPIO */
106 /* 1、获取设备节点:beep */
107 miscbeep.nd = of_find_node_by_path("/beep");
108 if(miscbeep.nd == NULL) {
109 printk("beep node not find!\r\n");
110 return -EINVAL;
111 }
112
113 /* 2、 获取设备树中的gpio属性,得到BEEP所使用的BEEP编号 */
114 miscbeep.beep_gpio = of_get_named_gpio(miscbeep.nd, "beep-gpio", 0);
115 if(miscbeep.beep_gpio < 0) {
116 printk("can't get beep-gpio");
117 return -EINVAL;
118 }
119
120 /* 3、设置GPIO5_IO01为输出,并且输出低电平,默认关闭BEEP */
121 ret = gpio_direction_output(miscbeep.beep_gpio, 0);
122 if(ret < 0) {
123 printk("can't set gpio!\r\n");
124 }
125
126 /* 一般情况下会注册对应的字符设备,但是这里我们使用MISC设备
127 * 所以我们不需要自己注册字符设备驱动,只需要注册misc设备驱动即可
128 */
129 ret = misc_register(&beep_miscdev);
130 if(ret < 0){
131 printk("misc device register failed!\r\n");
132 return -EFAULT;
133 }
134
135 return 0;
136 }
137
138 /*
139 * @description : platform驱动的remove函数,移除platform驱动
的时候此函数会执行
140 * @param - dev : platform设备
141 * @return : 0,成功;其他负值,失败
142 */
143 static int miscbeep_remove(struct platform_device *dev)
144 {
145 /* 注销设备的时候关闭LED灯 */
146 gpio_set_value(miscbeep.beep_gpio, 1);
147
148 /* 注销misc设备 */
149 misc_deregister(&beep_miscdev);
150 return 0;
151 }
152
153 /* 匹配列表 */
154 static const struct of_device_id beep_of_match[] = {
155 {
.compatible = "beep" },
156 {
/* Sentinel */ }
157 };
158
159 /* platform驱动结构体 */
160 static struct platform_driver beep_driver = {
161 .driver = {
162 .name = "imx6ul-beep", /* 驱动名字,用于和设备匹配 */
163 .of_match_table = beep_of_match, /* 设备树匹配表*/
164 },
165 .probe = miscbeep_probe,
166 .remove = miscbeep_remove,
167 };
168
169 /*
170 * @description : 驱动出口函数
171 * @param : 无
172 * @return : 无
173 */
174 static int __init miscbeep_init(void)
175 {
176 return platform_driver_register(&beep_driver);
177 }
178
179 /*
180 * @description : 驱动出口函数
181 * @param : 无
182 * @return : 无
183 */
184 static void __exit miscbeep_exit(void)
185 {
186 platform_driver_unregister(&beep_driver);
187 }
188
189 module_init(miscbeep_init);
190 module_exit(miscbeep_exit);
191 MODULE_LICENSE("GPL");
192 MODULE_AUTHOR("topeet");
Lines 88~92, misc device structure beep_miscdev, line 89 sets the sub-device number to 144, and line 90 sets the device name to "miscbeep", so that when the system starts, there will be a file named "miscbeep" in the /dev/ directory. "Miscbeep" device file. Line 91, set the operation function set of the misc device, which is of type file_operations.
Line 100~136, the probe function of the platform framework. This function will be executed when the driver matches the device. First, initialize the IO used by BEEP in this function. Finally, register the misc device to the Linux kernel through the misc_register function on line 129, which is the beep_miscdev defined earlier.
Lines 143~151, remove function of platform framework, call misc_deregister function in this function to deregister misc device.