找回密码
 注册
关于网站域名变更的通知
查看: 481|回复: 0
打印 上一主题 下一主题

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

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2020-12-31 11:19 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

EDA365欢迎您登录!

您需要 登录 才可以下载或查看,没有帐号?注册

x
文章目录( k4 @% B6 C2 @) h- G0 s
  • 1 修改设备树文件
  • 2 platform驱动程序
  • 3 应用测试程序
    0 `: h, H& o7 @" c

8 h  Y- s9 C9 j: f5 ]1 修改设备树文件

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

2 platform驱动程序

本实验例程路径:i.MX6UL终结者光盘资料/06_Linux驱动例程/15_gpioled_dts- y6 \/ y: U: Q! C& }7 ?2 H
创建led_driver.c文件,具体内容如下:

  1. 1 #include <linux/types.h>8 z. L1 P! m# p1 |# k8 q
  2.   2 #include <linux/kernel.h>% F8 Q% U% B( r+ W3 {7 ?9 E. T
  3.   3 #include <linux/delay.h>
    2 r# L0 O# z* |- x- ~$ y% I0 `
  4.   4 #include <linux/ide.h>
    9 r+ S" i5 i, W, w9 C0 G
  5.   5 #include <linux/init.h>8 P4 m, n% f7 t& O! {7 c
  6.   6 #include <linux/module.h>
    - N- ~( p) B9 [7 \
  7.   7 #include <linux/errno.h>
    $ d1 v# y/ ?! v; U! L9 a7 P$ G
  8.   8 #include <linux/gpio.h>) K* o' L' ~8 [! I4 ~$ O; O! Q
  9.   9 #include <linux/cdev.h>" O3 G+ ^8 @' b" m" a  c( }0 h
  10. 10 #include <linux/device.h>
    8 e/ ?. I5 O3 j
  11. 11 #include <linux/of_gpio.h>+ d7 R2 a- \+ u: S
  12. 12 #include <linux/semaphore.h>
    6 B7 R* w. H4 t/ d# _
  13. 13 #include <linux/timer.h>
    ( y# o' ?# W; Q1 u3 w
  14. 14 #include <linux/irq.h>
    + c' v0 ]- p5 Z
  15. 15 #include <linux/wait.h>
    7 z$ U+ w7 M: H" P! @$ j7 d
  16. 16 #include <linux/poll.h>
    ) Q; B: p' S  p. f
  17. 17 #include <linux/fs.h>
    ! B: a( @& S, @. i2 }- U
  18. 18 #include <linux/fcntl.h>+ q3 H& x9 |, u/ X9 I
  19. 19 #include <linux/platform_device.h>
    ; |3 e' [" {4 k1 q' l# N+ a9 @
  20. 20 #include <asm/mach/map.h>3 u0 P0 o% D" H: Y1 y
  21. 21 #include <asm/uaccess.h>
      L0 p! N5 a0 N4 h* U! M2 N+ T) j
  22. 22 #include <asm/io.h>
    $ P6 v" D0 E" R8 S- Z
  23. 23 3 k+ Y  J/ Y$ X0 t
  24. 24 #define LEDDEV_CNT              1                    /* 设备号长度   */
    ' w. m; ^- w8 j
  25. 25 #define LEDDEV_NAME             "dtsplatled"    /* 设备名字     */
    : l: V) ^& S% X! k( ]( ^
  26. 26 #define LEDOFF                  0
    / l0 O, y: Q/ I  N9 C
  27. 27 #define LEDON                   1
    : b8 S+ A, K/ A6 R0 P. v
  28. 28
    / M# c5 i6 p% ?' h% i* e0 D
  29. 29 /* leddev设备结构体 */
    . i/ j& B* ^. \& p% C: z
  30. 30 struct leddev_dev{
    / b; R( M2 I2 @0 w: Q& _
  31. 31         dev_t devid;                            /* 设备号       */( D/ D2 g8 `0 v
  32. 32         struct cdev cdev;                       /* cdev         */
    2 i* r0 N0 h. j; t6 Y1 i
  33. 33         struct class *class;            /* 类           */% C5 S$ I/ a/ g8 W! N# \6 Z
  34. 34         struct device *device;          /* 设备 */
    ) {3 t% \# |) h' u" N* G
  35. 35         int major;                     /* 主设备号     */
    + d$ ?. e7 M1 t
  36. 36         struct device_node *node;       /* LED设备节点 */* |8 s( {7 I2 O# h1 }0 J, t
  37. 37         int led0;                      /* LED灯GPIO标号 */
    , {- [$ ~2 j  c/ w  f) v7 {
  38. 38 };$ H8 U: s" P' n# H* c6 L3 g/ [
  39. 39 8 j- M* t" y, ^+ d4 s+ @  \
  40. 40 struct leddev_dev leddev;               /* led设备 */; e; t' T; E+ p, k5 r
  41. 41
    0 ~" ?  Y" F4 i  E3 k1 ]- r
  42. 42 /*
    7 X1 |! f' A( y, o" o1 {
  43. 43  * @description         : LED打开/关闭" r6 V9 Z# r7 }3 u. X
  44. 44  * @param - sta         : LEDON(0) 打开LED,LEDOFF(1) 关闭LED
    ; s4 x. \" l3 e' f3 p; i6 ]0 i
  45. 45  * @return                      : 无
    ) W- K* W! h4 Q& _4 ?( C9 y" d
  46. 46  */$ Y0 o5 `, I( z& \
  47. 47 void led0_switch(u8 sta)' Y* B2 Y/ U: I, K3 W
  48. 48 {6 n% j: [& ~' x9 H& r1 ~
  49. 49         if (sta == LEDON )7 [$ G0 `  b4 B  J7 s, q# z
  50. 50                 gpio_set_value(leddev.led0, 0);
    ' ~$ w7 P4 c4 m" R5 d/ C9 H, n' c
  51. 51         else if (sta == LEDOFF)
    . n) n  F7 ], a6 z5 R
  52. 52                 gpio_set_value(leddev.led0, 1);
    * K1 M/ q1 @0 N5 A
  53. 53 }
    # T9 N0 |5 T! y3 L7 V3 s5 d
  54. 54
    % ]/ G( b, E9 @9 ^4 M9 \
  55. 55 /*
    4 ?2 ^) K( ]5 F/ r& P
  56. 56  * @description         : 打开设备
    & |/ e& ?6 Q" i
  57. 57  * @param - inode       : 传递给驱动的inode" L9 G- K* Y; J% d, Q% P4 k
  58. 58  * @param - filp        : 设备文件,file结构体有个叫做private_data的成员变量- P8 {2 X6 J7 m% [4 W6 b
  59. 59  * 一般在open的时候将private_data指向设备结构体。9 [" V) t' F: u1 i' C
  60. 60  * @return                      : 0 成功;其他 失败9 L. n6 |+ u% E5 Z1 c
  61. 61  */
    7 Q/ G3 y: ^) X2 f
  62. 62 static int led_open(struct inode *inode, struct file *filp)( ~' ^  B/ ~4 ~- i* R; i3 y& g
  63. 63 {
    % M5 C; ]4 D2 Y# B3 L
  64. 64         filp->private_data = &leddev; /* 设置私有数据  */* P5 p  ^. x* P, F
  65. 65         return 0;
    $ @$ T! }0 E7 g( o
  66. 66 }
    . L! n& }3 h# W% j) M" ~% K* d
  67. 67
    # l/ e" V4 }4 A( [( l
  68. 68 /*+ L: N& ^/ v9 m- G# |6 k% ~+ r
  69. 69  * @description         : 向设备写数据 - }2 R9 |- s% K$ `1 c$ r2 ~4 j
  70. 70  * @param - filp        : 设备文件,表示打开的文件描述符% p' S+ K$ p- Z6 v
  71. 71  * @param - buf         : 要写给设备写入的数据! X1 x( N: z0 s. T2 |
  72. 72  * @param - cnt         : 要写入的数据长度
    1 m% k: B/ T4 Q
  73. 73  * @param - offt        : 相对于文件首地址的偏移1 M5 Z+ N% l+ P" U/ o; K3 D6 u/ w1 H. y
  74. 74  * @return                      : 写入的字节数,如果为负值,表示写入失败% I+ A9 s% I4 ]
  75. 75  */5 R. O9 N1 m2 p9 Q0 k/ s
  76. 76 static ssize_t led_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)$ J; D" d2 D5 H" C
  77. 77 {
    ( o( o3 G8 g2 p/ ^- j% N
  78. 78         int retvalue;
    8 g% w. u! C7 ~5 i
  79. 79         unsigned char databuf[2];
    " x/ {$ j8 h! d+ L
  80. 80         unsigned char ledstat;3 W( e- @  y7 H" \
  81. 81 $ T. d5 F4 E! T2 M
  82. 82         retvalue = copy_from_user(databuf, buf, cnt);: S$ A) m- H/ q$ T/ H( H5 c
  83. 83         if(retvalue < 0) {8 Y( O) o6 p% ~! s; {; D# m4 M
  84. 84 # V- Q* N. e2 G4 D1 W% r* A2 s8 V
  85. 85                 printk("kernel write failed!\r\n");, N- K7 p  z/ o' e: s. L4 }/ J
  86. 86                 return -EFAULT;+ C9 d4 Q7 r0 U9 M5 ~$ Q. C5 I8 N
  87. 87         }! e- f/ |1 g/ U2 w5 P
  88. 88
    : r7 D- Z4 V+ R
  89. 89         ledstat = databuf[0];& @1 z! I% B  z" ?% H% q5 R6 _0 W8 M
  90. 90         if (ledstat == LEDON) {7 d+ L/ o- B6 F- v( J% ^' C4 l
  91. 91                 led0_switch(LEDON);
    ! I8 M! F! s% r& K/ p. N4 q
  92. 92         } else if (ledstat == LEDOFF) {
    / o5 E% I5 w: u: a! E: Q' h
  93. 93                 led0_switch(LEDOFF);
    - \) W$ H: u4 D
  94. 94         }( t1 ?$ d2 \* V2 c& Q7 B% E6 X! Z2 U
  95. 95         return 0;
    ) c! F# L0 ^" T! i
  96. 96 }
    # @5 k9 F! F$ B( |
  97. 97 1 _, V# [; ~) E/ u2 F
  98. 98 /* 设备操作函数 */
    ( m# V* A; v' t3 _
  99. 99 static struct file_operations led_fops = {* x1 W9 n) M2 J3 b! s3 U
  100. 100         .owner = THIS_MODULE,# I) Q2 G3 s; a) x) ^. B
  101. 101         .open = led_open,6 Z! D5 H1 a; @, E& L$ o
  102. 102         .write = led_write,6 y0 q- N& y4 V2 U$ ]3 ~" x
  103. 103 };. z6 x' u! Q# L9 Z
  104. 104
    0 ^: j7 U3 D7 H, E7 d6 i
  105. 105 /*
    $ n/ G! q' {. |! n# r0 Z* Z
  106. 106  * @description         : flatform驱动的probe函数,当驱动与
    + @$ I8 i/ h' N0 z& t8 @0 |. l% I
  107. 107  *                                        设备匹配以后此函数就会执行, H  n0 l9 V9 Y& [5 |, e
  108. 108  * @param - dev         : platform设备
    2 p$ l" ?# }% L' i
  109. 109  * @return                      : 0,成功;其他负值,失败2 L* S. M6 ?/ Z
  110. 110  */5 h) k: H* s8 j3 ^8 m3 U6 w' @! J
  111. 111 static int led_probe(struct platform_device *dev)' Z+ @5 u' Q. Q& C2 l( l
  112. 112 {
    ) b' s, I4 ^7 d  h( [
  113. 113         printk("led driver and device was matched!\r\n");" a4 j6 @$ |, G) F( P2 u$ i( D
  114. 114         /* 1、设置设备号 */9 v: {! s* ~- l" W0 G. |
  115. 115         if (leddev.major) {/ O* p' }2 E1 [6 }  z! _
  116. 116                 leddev.devid = MKDEV(leddev.major, 0);
    3 K1 Z# G7 @+ Z& H- c8 s
  117. 117               register_chrdev_region(leddev.devid, LEDDEV_CNT, LEDDEV_NAME);
    $ J, S1 ?" ~: V, V. Q
  118. 118         } else {
    * f! s# Q" s/ C% a
  119. 119              alloc_chrdev_region(&leddev.devid, 0, LEDDEV_CNT, LEDDEV_NAME);# S) }+ y" ~2 S
  120. 120                 leddev.major = MAJOR(leddev.devid);
    2 D3 \; ]. ^% s5 P% {) D+ J0 w
  121. 121         }. P* h7 N1 b6 z% h
  122. 122 , H+ F% }( w) y& J, \& ]/ K/ `: a
  123. 123         /* 2、注册设备      */
    # m+ ~; N/ m8 b9 a/ v$ O- ?7 W, w- s
  124. 124         cdev_init(&leddev.cdev, &led_fops);
    - N% j% m3 v3 W0 \; a# }
  125. 125         cdev_add(&leddev.cdev, leddev.devid, LEDDEV_CNT);5 i% l% J! S0 d3 u) u) [6 r0 k
  126. 126
    : c# [4 }3 ?; o$ _: V8 ?6 F6 q
  127. 127         /* 3、创建类      */
    + G$ w2 ]2 _" [) C% H- ]0 r. b
  128. 128         leddev.class = class_create(THIS_MODULE, LEDDEV_NAME);/ }1 C) |9 Q1 L7 k  L' y% x  _# s# V9 `
  129. 129         if (IS_ERR(leddev.class)) {8 x: J& j' M  Q7 [0 C' R
  130. 130                 return PTR_ERR(leddev.class);9 R" S- b2 l/ h
  131. 131         }
    4 o1 |! I5 ^: q
  132. 132 / W" G! Q7 w7 M8 b, s9 s5 [  z
  133. 133         /* 4、创建设备 */' N  S! f: l: `8 n5 F
  134. 134         leddev.device = device_create(leddev.class, NULL, leddev.devid,
    & {; N* ^3 ]* V: D0 Y
  135. NULL, LEDDEV_NAME);, ~6 D% J& c5 s; J; L" f* T
  136. 135         if (IS_ERR(leddev.device)) {+ d7 K8 R; Y. \, |
  137. 136                 return PTR_ERR(leddev.device);
    4 \0 a1 ^. U4 f
  138. 137         }
    , P+ L( K. D7 p9 ?* y# ?
  139. 138
    # g! ~3 D" i' |) M. _
  140. 139         /* 5、初始化IO */3 U/ b! P3 J2 s) h
  141. 140         leddev.node = of_find_node_by_path("/gpioled");
    : ~% K9 m( l) ~3 v2 h) q
  142. 141         if (leddev.node == NULL){
    # A; u) ^( ^1 p% i  K$ c
  143. 142                 printk("gpioled node nost find!\r\n");. e3 C7 k4 ]' F- Y. ]# d8 z) f+ V
  144. 143                 return -EINVAL;9 j3 Q. {# r* k2 g7 R5 ], m3 F6 x
  145. 144         }
    : R3 ]8 n! W. D, p9 d* @" Y$ R
  146. 145
    7 L. R* N# T* Q; m3 U( z& l, l$ s
  147. 146         leddev.led0 = of_get_named_gpio(leddev.node, "led-gpio", 0);
    5 C: \5 f2 L7 z. H
  148. 147         if (leddev.led0 < 0) {
    : t) F5 g# ?" d% Z
  149. 148                 printk("can't get led-gpio\r\n");1 G, ?. B! W. U
  150. 149                 return -EINVAL;0 K. G* q& Y" f1 ^9 ?3 x
  151. 150         }7 X8 o( `! @9 \) X) O+ O
  152. 151
    3 j0 T  `# C/ I, ]. o! e9 r
  153. 152         gpio_request(leddev.led0, "led0");
    # L& P9 H, Q0 Q# p
  154. 153     gpio_direction_output(leddev.led0, 1); /* led0 IO设置为输出,默认高电平 */. W; @- C2 U3 q
  155. 154         return 0;
    + h3 C# v, O7 O% T8 H) Y7 G3 b) z
  156. 155 }
    - `1 `( P) m8 g# e5 s1 P
  157. 156 * |% k( Z% _4 h9 ~2 z8 n% ~6 x8 U
  158. 157 /*
    , _+ F# H. T3 P* e% v; P/ h9 V
  159. 158  * @description : platform驱动的remove函数,移除platform
    ! R" \9 f0 {+ y- S/ }/ U3 h, }
  160. 驱动的时候此函数会执行; E* y6 O" }& T: i
  161. 159  * @param - dev         : platform设备
    ' @4 V& k+ \' a. \
  162. 160  * @return         : 0,成功;其他负值,失败' r( w1 Z( V3 F) L/ ^6 }& Z
  163. 161  */- h5 g. Y3 q5 }9 F% x" e
  164. 162 static int led_remove(struct platform_device *dev)
    . q+ K7 t% U! H4 i
  165. 163 {2 I  R$ h1 g, l% t
  166. 164         gpio_set_value(leddev.led0, 1);         /* 卸载驱动的时候关闭LED */
    $ r5 |9 Y& B0 J
  167. 165
    ' v9 B' R& @' ], m* y
  168. 166         cdev_del(&leddev.cdev);                         /*  删除cdev */
    2 o) [/ y9 _. F7 x
  169. 167         unregister_chrdev_region(leddev.devid, LEDDEV_CNT); /* 注销设备号 */  Y5 L6 t& N* E: o
  170. 168         device_destroy(leddev.class, leddev.devid);
    1 g) B1 A* @( S: z; H" r
  171. 169         class_destroy(leddev.class);; I7 D# K, P  ^- {
  172. 170         return 0;
    ' m0 R7 g" \: k. @
  173. 171 }
    5 }5 D" g7 `( I
  174. 172
    / z+ x, |# F3 z& {
  175. 173 /* 匹配列表 */
    % y; v4 U( J) T" y' c$ k, b
  176. 174 static const struct of_device_id led_of_match[] = {
    8 D7 f4 e/ x9 i6 n8 Z0 Z+ Y
  177. 175         { .compatible = "gpioled" },2 L+ H) C8 h+ ^2 {$ L
  178. 176         { /* Sentinel */ }
    6 B' {3 E# s7 M* V6 P: v
  179. 177 };
    $ {2 b& b* I# X5 e9 ?
  180. 178 0 `7 I" g0 M* F4 a4 ~6 y
  181. 179 /* platform驱动结构体 */
    , d5 G9 r3 {7 D2 K5 U5 w* n9 U* J
  182. 180 static struct platform_driver led_driver = {
    ( z2 e  q4 Q0 ^; g
  183. 181         .driver         = {( k6 N5 w: t8 X/ w
  184. 182                 .name   = "imx6ul-led",     /* 驱动名字,用于和设备匹配 */* o# Y7 U; z+ H! Y' ?& b8 C- E
  185. 183                 .of_match_table = led_of_match, /* 设备树匹配表 */5 i. C* K* J: v# _$ |8 X5 D6 x
  186. 184         },
    ; y, f$ U! V* n' D, {& ~+ n
  187. 185         .probe          = led_probe,
      [  }5 Y% Z2 F: s
  188. 186         .remove         = led_remove,% P3 ?& b7 l3 `: c, e
  189. 187 };1 p1 y5 W2 o# P
  190. 188
    8 f* C! l, j; L. ?4 M
  191. 189 /*
    ; C+ n6 v' E7 l* w( s% S
  192. 190  * @description : 驱动模块加载函数* O6 f' a8 \- ?* f3 e! w
  193. 191  * @param               : 无. M1 f. T4 ~& o) R
  194. 192  * @return              : 无
    + N% F/ e" o. X
  195. 193  */
    9 n0 N6 X4 W0 L' B" L1 T
  196. 194 static int __init leddriver_init(void)( p, b* X+ n* I
  197. 195 {
    0 l0 v# A/ s" v0 r2 S
  198. 196         return platform_driver_register(&led_driver);
      {5 ~/ ?  v" d5 N0 r5 I
  199. 197 }
    0 m* i1 f2 f$ g6 |9 j
  200. 198 ( n* Z# T( D7 E" c/ s
  201. 199 /*
    . I2 j4 n. M6 w$ K
  202. 200  * @description : 驱动模块卸载函数
    ) F2 v" Q( s% A) a4 K
  203. 201  * @param               : 无; F3 S9 v) ~  n6 `) B2 W$ ~
  204. 202  * @return              : 无$ A) i$ `& a% ~* [
  205. 203  */2 d! j0 V. k/ S% b0 J
  206. 204 static void __exit leddriver_exit(void)
    & R% F; }% j/ P
  207. 205 {
    1 a' @0 C- h  z+ \0 B
  208. 206         platform_driver_unregister(&led_driver);
    9 s. g$ w1 {& n% ?9 P2 p1 |% r+ ^
  209. 207 }
    0 x0 k( r4 q$ f$ j/ w
  210. 208 8 A2 n, Z% f. f6 r7 g- x) s
  211. 209 module_init(leddriver_init);
    2 u3 m! n( M) w) Z: s: T: q
  212. 210 module_exit(leddriver_exit);
    2 ~. C" L+ b9 W, }7 P2 p8 h. B7 y) D
  213. 211 MODULE_LICENSE("GPL");8 O$ L. ]1 N3 w. G: ~& U$ C: m
  214. 212 MODULE_AUTHOR("topeet");
    1 r; n' f! z: |, |8 i( }* X( b, \9 z8 ~
复制代码

) D8 \( H: J" Z' D8 e* y8 f

第 174~177 行,匹配表,描述了此驱动都和什么样的设备匹配,第 175 行添加了一条值为"gpioled"的 compatible 属性值,当设备树中某个设备节点的 compatible 属性值也为 “gpioled”的时候就会与此驱动匹配。
: T5 ~/ t+ n1 V: t$ i第 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即可。

4 h5 ?8 f1 V# l' V3 [
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

推荐内容上一条 /1 下一条

EDA365公众号

关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

GMT+8, 2025-11-4 13:47 , Processed in 0.171875 second(s), 24 queries , Gzip On.

深圳市墨知创新科技有限公司

地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

快速回复 返回顶部 返回列表