迅为i.MX6ULL终结者设备树下的Platform驱动实验程序编写

发布时间:2020-12-31 11:17    发布者:就是塔塔
文章目录
  • 1 修改设备树文件
  • 2 platform驱动程序
  • 3 应用测试程序

1 修改设备树文件

设备树文件可以直接使用第三十五章中添加的gpioled子节点即可,不用重复添加。

2 platform驱动程序

本实验例程路径:i.MX6UL终结者光盘资料/06_Linux驱动例程/15_gpioled_dts
创建led_driver.c文件,具体内容如下:

  1.   1 #include
  2.   2 #include
  3.   3 #include
  4.   4 #include
  5.   5 #include
  6.   6 #include
  7.   7 #include
  8.   8 #include
  9.   9 #include
  10. 10 #include
  11. 11 #include
  12. 12 #include
  13. 13 #include
  14. 14 #include
  15. 15 #include
  16. 16 #include
  17. 17 #include
  18. 18 #include
  19. 19 #include
  20. 20 #include
  21. 21 #include
  22. 22 #include
  23. 23
  24. 24 #define LEDDEV_CNT              1                    /* 设备号长度   */
  25. 25 #define LEDDEV_NAME             "dtsplatled"    /* 设备名字     */
  26. 26 #define LEDOFF                  0
  27. 27 #define LEDON                   1
  28. 28
  29. 29 /* leddev设备结构体 */
  30. 30 struct leddev_dev{
  31. 31         dev_t devid;                            /* 设备号       */
  32. 32         struct cdev cdev;                       /* cdev         */
  33. 33         struct class *class;            /* 类           */
  34. 34         struct device *device;          /* 设备 */
  35. 35         int major;                     /* 主设备号     */
  36. 36         struct device_node *node;       /* LED设备节点 */
  37. 37         int led0;                      /* LED灯GPIO标号 */
  38. 38 };
  39. 39
  40. 40 struct leddev_dev leddev;               /* led设备 */
  41. 41
  42. 42 /*
  43. 43  * @description         : LED打开/关闭
  44. 44  * @param - sta         : LEDON(0) 打开LED,LEDOFF(1) 关闭LED
  45. 45  * @return                      : 无
  46. 46  */
  47. 47 void led0_switch(u8 sta)
  48. 48 {
  49. 49         if (sta == LEDON )
  50. 50                 gpio_set_value(leddev.led0, 0);
  51. 51         else if (sta == LEDOFF)
  52. 52                 gpio_set_value(leddev.led0, 1);
  53. 53 }
  54. 54
  55. 55 /*
  56. 56  * @description         : 打开设备
  57. 57  * @param - inode       : 传递给驱动的inode
  58. 58  * @param - filp        : 设备文件,file结构体有个叫做private_data的成员变量
  59. 59  * 一般在open的时候将private_data指向设备结构体。
  60. 60  * @return                      : 0 成功;其他 失败
  61. 61  */
  62. 62 static int led_open(struct inode *inode, struct file *filp)
  63. 63 {
  64. 64         filp->private_data = &leddev; /* 设置私有数据  */
  65. 65         return 0;
  66. 66 }
  67. 67
  68. 68 /*
  69. 69  * @description         : 向设备写数据
  70. 70  * @param - filp        : 设备文件,表示打开的文件描述符
  71. 71  * @param - buf         : 要写给设备写入的数据
  72. 72  * @param - cnt         : 要写入的数据长度
  73. 73  * @param - offt        : 相对于文件首地址的偏移
  74. 74  * @return                      : 写入的字节数,如果为负值,表示写入失败
  75. 75  */
  76. 76 static ssize_t led_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
  77. 77 {
  78. 78         int retvalue;
  79. 79         unsigned char databuf[2];
  80. 80         unsigned char ledstat;
  81. 81
  82. 82         retvalue = copy_from_user(databuf, buf, cnt);
  83. 83         if(retvalue < 0) {
  84. 84
  85. 85                 printk("kernel write failed!\r\n");
  86. 86                 return -EFAULT;
  87. 87         }
  88. 88
  89. 89         ledstat = databuf[0];
  90. 90         if (ledstat == LEDON) {
  91. 91                 led0_switch(LEDON);
  92. 92         } else if (ledstat == LEDOFF) {
  93. 93                 led0_switch(LEDOFF);
  94. 94         }
  95. 95         return 0;
  96. 96 }
  97. 97
  98. 98 /* 设备操作函数 */
  99. 99 static struct file_operations led_fops = {
  100. 100         .owner = THIS_MODULE,
  101. 101         .open = led_open,
  102. 102         .write = led_write,
  103. 103 };
  104. 104
  105. 105 /*
  106. 106  * @description         : flatform驱动的probe函数,当驱动与
  107. 107  *                                        设备匹配以后此函数就会执行
  108. 108  * @param - dev         : platform设备
  109. 109  * @return                      : 0,成功;其他负值,失败
  110. 110  */
  111. 111 static int led_probe(struct platform_device *dev)
  112. 112 {
  113. 113         printk("led driver and device was matched!\r\n");
  114. 114         /* 1、设置设备号 */
  115. 115         if (leddev.major) {
  116. 116                 leddev.devid = MKDEV(leddev.major, 0);
  117. 117               register_chrdev_region(leddev.devid, LEDDEV_CNT, LEDDEV_NAME);
  118. 118         } else {
  119. 119              alloc_chrdev_region(&leddev.devid, 0, LEDDEV_CNT, LEDDEV_NAME);
  120. 120                 leddev.major = MAJOR(leddev.devid);
  121. 121         }
  122. 122
  123. 123         /* 2、注册设备      */
  124. 124         cdev_init(&leddev.cdev, &led_fops);
  125. 125         cdev_add(&leddev.cdev, leddev.devid, LEDDEV_CNT);
  126. 126
  127. 127         /* 3、创建类      */
  128. 128         leddev.class = class_create(THIS_MODULE, LEDDEV_NAME);
  129. 129         if (IS_ERR(leddev.class)) {
  130. 130                 return PTR_ERR(leddev.class);
  131. 131         }
  132. 132
  133. 133         /* 4、创建设备 */
  134. 134         leddev.device = device_create(leddev.class, NULL, leddev.devid,
  135. NULL, LEDDEV_NAME);
  136. 135         if (IS_ERR(leddev.device)) {
  137. 136                 return PTR_ERR(leddev.device);
  138. 137         }
  139. 138
  140. 139         /* 5、初始化IO */
  141. 140         leddev.node = of_find_node_by_path("/gpioled");
  142. 141         if (leddev.node == NULL){
  143. 142                 printk("gpioled node nost find!\r\n");
  144. 143                 return -EINVAL;
  145. 144         }
  146. 145
  147. 146         leddev.led0 = of_get_named_gpio(leddev.node, "led-gpio", 0);
  148. 147         if (leddev.led0 < 0) {
  149. 148                 printk("can't get led-gpio\r\n");
  150. 149                 return -EINVAL;
  151. 150         }
  152. 151
  153. 152         gpio_request(leddev.led0, "led0");
  154. 153     gpio_direction_output(leddev.led0, 1); /* led0 IO设置为输出,默认高电平 */
  155. 154         return 0;
  156. 155 }
  157. 156
  158. 157 /*
  159. 158  * @description : platform驱动的remove函数,移除platform
  160. 驱动的时候此函数会执行
  161. 159  * @param - dev         : platform设备
  162. 160  * @return         : 0,成功;其他负值,失败
  163. 161  */
  164. 162 static int led_remove(struct platform_device *dev)
  165. 163 {
  166. 164         gpio_set_value(leddev.led0, 1);         /* 卸载驱动的时候关闭LED */
  167. 165
  168. 166         cdev_del(&leddev.cdev);                         /*  删除cdev */
  169. 167         unregister_chrdev_region(leddev.devid, LEDDEV_CNT); /* 注销设备号 */
  170. 168         device_destroy(leddev.class, leddev.devid);
  171. 169         class_destroy(leddev.class);
  172. 170         return 0;
  173. 171 }
  174. 172
  175. 173 /* 匹配列表 */
  176. 174 static const struct of_device_id led_of_match[] = {
  177. 175         { .compatible = "gpioled" },
  178. 176         { /* Sentinel */ }
  179. 177 };
  180. 178
  181. 179 /* platform驱动结构体 */
  182. 180 static struct platform_driver led_driver = {
  183. 181         .driver         = {
  184. 182                 .name   = "imx6ul-led",     /* 驱动名字,用于和设备匹配 */
  185. 183                 .of_match_table = led_of_match, /* 设备树匹配表 */
  186. 184         },
  187. 185         .probe          = led_probe,
  188. 186         .remove         = led_remove,
  189. 187 };
  190. 188
  191. 189 /*
  192. 190  * @description : 驱动模块加载函数
  193. 191  * @param               : 无
  194. 192  * @return              : 无
  195. 193  */
  196. 194 static int __init leddriver_init(void)
  197. 195 {
  198. 196         return platform_driver_register(&led_driver);
  199. 197 }
  200. 198
  201. 199 /*
  202. 200  * @description : 驱动模块卸载函数
  203. 201  * @param               : 无
  204. 202  * @return              : 无
  205. 203  */
  206. 204 static void __exit leddriver_exit(void)
  207. 205 {
  208. 206         platform_driver_unregister(&led_driver);
  209. 207 }
  210. 208
  211. 209 module_init(leddriver_init);
  212. 210 module_exit(leddriver_exit);
  213. 211 MODULE_LICENSE("GPL");
  214. 212 MODULE_AUTHOR("topeet");
复制代码

第 174~177 行,匹配表,描述了此驱动都和什么样的设备匹配,第 175 行添加了一条值为"gpioled"的 compatible 属性值,当设备树中某个设备节点的 compatible 属性值也为 “gpioled”的时候就会与此驱动匹配。
第 180~187 行,platform_driver 驱动结构体,182 行设置这个 platform 驱动的名字为“imx6ul-led”,因此,当驱动加载成功以后就会在/sys/bus/platform/drivers/目录下存在一个名为“imx6u-led”的文件。 第 183 行设置 of_match_table 为上面的 led_of_match。

3 应用测试程序

应用测试程序直接使用上一章44.3.2的led_test.c即可。


本文地址:https://www.eechina.com/thread-752673-1-1.html     【打印本页】

本站部分文章为转载或网友发布,目的在于传递和分享信息,并不代表本网赞同其观点和对其真实性负责;文章版权归原作者及原出处所有,如涉及作品内容、版权和其它问题,我们将根据著作权人的要求,第一时间更正或删除。
您需要登录后才可以发表评论 登录 | 立即注册

厂商推荐

  • Microchip视频专区
  • 你仿真过吗?使用免费的MPLAB Mindi模拟仿真器降低设计风险
  • 想要避免发生灾难,就用MPLAB SiC电源仿真器!
  • 更佳设计的解决方案——Microchip模拟开发生态系统
  • 深度体验Microchip自动辅助驾驶应用方案——2025巡展开启报名!
  • 贸泽电子(Mouser)专区
关于我们  -  服务条款  -  使用指南  -  站点地图  -  友情链接  -  联系我们
电子工程网 © 版权所有   京ICP备16069177号 | 京公网安备11010502021702
快速回复 返回顶部 返回列表