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

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

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x
文章目录
. P9 f7 ?7 z* ?, u( L# `  u
  • 1 修改设备树文件
  • 2 platform驱动程序
  • 3 应用测试程序
    9 e: e7 i7 D! Q7 g  K7 K
$ Q1 Q/ p; h/ W2 c& r: ?! W: x
1 修改设备树文件

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

2 platform驱动程序

本实验例程路径:i.MX6UL终结者光盘资料/06_Linux驱动例程/15_gpioled_dts
+ B- e! n- u  p' x3 C: Y创建led_driver.c文件,具体内容如下:

  1. 1 #include <linux/types.h>
    . D: f/ `; |# M) Z% V
  2.   2 #include <linux/kernel.h>
    6 p& V& J: S+ W, d+ u+ W, L" L  C
  3.   3 #include <linux/delay.h>0 |1 h1 v) \' j* `& u  `
  4.   4 #include <linux/ide.h>, g: ~5 O7 |  d
  5.   5 #include <linux/init.h>7 K0 C$ }1 Y: n& M
  6.   6 #include <linux/module.h>+ e$ f- p* x. t* z0 T
  7.   7 #include <linux/errno.h>
    * d1 [* k# r: ~, I# g) k; O  d& F
  8.   8 #include <linux/gpio.h>* ]' b# V1 f+ {- j- M; U
  9.   9 #include <linux/cdev.h>9 k2 t* F! P. y! I* Z1 c: E  o
  10. 10 #include <linux/device.h># {" o7 a, J# P; n
  11. 11 #include <linux/of_gpio.h>
    " i. o& \: t' G
  12. 12 #include <linux/semaphore.h>
    ' P8 q- ~3 j8 p* [! c* p* m" M
  13. 13 #include <linux/timer.h>
    ' J- t! u, d" P( l$ ~2 _
  14. 14 #include <linux/irq.h>
    7 f7 e* W5 |: x! L' m6 F4 Z
  15. 15 #include <linux/wait.h>
    + r" p, [; G' g# g  g
  16. 16 #include <linux/poll.h>. U( Q# V; D8 s- t9 A* C& W/ U; p
  17. 17 #include <linux/fs.h>
    # X4 J% F7 c/ [" g- w
  18. 18 #include <linux/fcntl.h>- ?5 ]* g( ]# [2 \) \
  19. 19 #include <linux/platform_device.h>/ u+ |6 ?! A' \9 I4 F; j
  20. 20 #include <asm/mach/map.h>3 ~6 ^( K4 r9 u# l9 L4 I4 r- E1 V( }4 h
  21. 21 #include <asm/uaccess.h>7 E9 ^" H' \7 [/ p! O8 L8 e0 H3 V
  22. 22 #include <asm/io.h>0 N2 Q  z6 Q1 ^2 @) `, u
  23. 23 * G! r# l* N- b& z
  24. 24 #define LEDDEV_CNT              1                    /* 设备号长度   */
    % C0 ]( J; B, M. Z& H) e/ h: N" Y
  25. 25 #define LEDDEV_NAME             "dtsplatled"    /* 设备名字     */
    ' ]% h9 b5 p3 }% S' y) I
  26. 26 #define LEDOFF                  0
    - L1 O6 f6 d* L# p- O2 l" d% j
  27. 27 #define LEDON                   1
    + z9 I' S) S  x& U, G5 m4 C: g) ~
  28. 28
    ! A' j5 |2 k4 w9 F# E
  29. 29 /* leddev设备结构体 */
    5 e% j3 u  S- M6 J) a9 V, y7 i
  30. 30 struct leddev_dev{
    " ~. q# c* j1 Q$ V# \/ E3 H- P" r! r
  31. 31         dev_t devid;                            /* 设备号       */
    + r7 D4 Z- f3 I& a: y
  32. 32         struct cdev cdev;                       /* cdev         */- P* W! {. [9 @( k8 K
  33. 33         struct class *class;            /* 类           */
    * H, @5 C* i* Z/ @1 T0 O9 a4 q: a
  34. 34         struct device *device;          /* 设备 */
    % s+ h8 r3 q9 y( E/ z% c2 e
  35. 35         int major;                     /* 主设备号     */
    + i) i- A0 v+ k! [7 ~. @5 V
  36. 36         struct device_node *node;       /* LED设备节点 */
    ! ~% k2 R5 c+ @8 a' z* X4 q) q
  37. 37         int led0;                      /* LED灯GPIO标号 */: |/ `! @3 N2 I, U, u+ T
  38. 38 };
    / x) J! ]1 ]5 [. Y- }/ t. o6 K
  39. 39
    4 v; v0 |+ i" k% y( M: c9 D
  40. 40 struct leddev_dev leddev;               /* led设备 */0 `5 K; W, w0 l. u
  41. 41 - O4 \/ m3 m3 x
  42. 42 /*
    / A7 u9 s5 n  w4 H
  43. 43  * @description         : LED打开/关闭- q  j9 T+ N2 s. z
  44. 44  * @param - sta         : LEDON(0) 打开LED,LEDOFF(1) 关闭LED9 D6 M! N* G' t% E* U3 L$ A/ {
  45. 45  * @return                      : 无. ]0 ?& E1 U- E' p  w
  46. 46  */. `% Z0 C! @5 b( k, c
  47. 47 void led0_switch(u8 sta)
    - a/ R4 R4 ^+ k$ M# `
  48. 48 {
    1 \) B- s( p' |. P7 U# A
  49. 49         if (sta == LEDON )
    - a' W& p3 E, t/ L4 L3 F
  50. 50                 gpio_set_value(leddev.led0, 0);# V5 N1 e0 z$ B0 r% ^
  51. 51         else if (sta == LEDOFF)
    - V+ f& X9 ^4 |1 }) f4 I6 r
  52. 52                 gpio_set_value(leddev.led0, 1);0 d" H' o4 E1 M3 D
  53. 53 }
    9 A: ^7 d, T" }5 E3 z8 G8 i# ^
  54. 54 0 p. @% i2 o7 r9 Q2 c1 a4 Q
  55. 55 /*5 t* o  Z: T0 T, A: ?) }$ I0 q4 W3 m; Q) V
  56. 56  * @description         : 打开设备' O* n1 \  a7 b$ }4 g8 z2 B
  57. 57  * @param - inode       : 传递给驱动的inode+ U3 c" O# r6 l2 d- ~4 j
  58. 58  * @param - filp        : 设备文件,file结构体有个叫做private_data的成员变量
    9 ^2 V% L: d' R  D: }& ^' |. D* J
  59. 59  * 一般在open的时候将private_data指向设备结构体。* R5 K; R* @5 ~2 C4 p6 I* e
  60. 60  * @return                      : 0 成功;其他 失败
    * v. p# U3 r- H' c& G+ r  ^
  61. 61  */5 t: r$ L- u- Q) i
  62. 62 static int led_open(struct inode *inode, struct file *filp)) t* a, y" s" @* E+ D2 o
  63. 63 {
    ( b+ a: U& X* n& B6 N6 X
  64. 64         filp->private_data = &leddev; /* 设置私有数据  */1 ?! Y$ z7 B6 \3 l' u5 o/ T
  65. 65         return 0;
    " R- e# [7 R( [8 U% g  u5 o+ g6 O2 \
  66. 66 }: y9 b1 r! f0 @  _  [8 F/ z
  67. 67 3 ~( O; a8 v  i) ]
  68. 68 /*  C! G; n- X# Q+ h3 b9 D1 h
  69. 69  * @description         : 向设备写数据
    # U' y. Y' ^* ~; r: P
  70. 70  * @param - filp        : 设备文件,表示打开的文件描述符( U) l. z. E8 c2 I
  71. 71  * @param - buf         : 要写给设备写入的数据
    2 O6 u3 ?8 X2 z' N  |/ ?9 Y) |4 @. D
  72. 72  * @param - cnt         : 要写入的数据长度
    : \  W% z$ k  N2 }+ p1 S0 `. t
  73. 73  * @param - offt        : 相对于文件首地址的偏移
    0 t" k9 Q! {1 L; f3 H
  74. 74  * @return                      : 写入的字节数,如果为负值,表示写入失败* i8 [% }. i) U/ R* }: h& ?3 c
  75. 75  */; R! I5 v+ Y( d, u: K+ B
  76. 76 static ssize_t led_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
    . B; L7 V  s. g- I
  77. 77 {
    $ {0 d* s7 i- u- a  y3 }" a: q
  78. 78         int retvalue;
    * {: u( M9 ^& }2 U" ?0 v- K2 K
  79. 79         unsigned char databuf[2];" \. J! B. r4 S7 u" R1 s- |
  80. 80         unsigned char ledstat;
    8 e0 l% n0 [( S
  81. 81
    " P. H( W# h/ q( Y+ `+ y
  82. 82         retvalue = copy_from_user(databuf, buf, cnt);8 L$ r" A' z- O" W
  83. 83         if(retvalue < 0) {- Y* t0 \; `8 S. e
  84. 84
    0 M) r: T( \3 U7 e7 n4 ?# G
  85. 85                 printk("kernel write failed!\r\n");
    1 V# L5 ^. p0 w
  86. 86                 return -EFAULT;$ r" z( {9 f2 X- Q/ O# A
  87. 87         }- Q& I) q4 @* [
  88. 88 ; y+ x6 M; ]3 \3 @
  89. 89         ledstat = databuf[0];
    / S7 F: t( d4 p) N
  90. 90         if (ledstat == LEDON) {6 [' }/ G- s. K1 R7 B; x
  91. 91                 led0_switch(LEDON);6 C; b9 z2 t4 e- }2 [
  92. 92         } else if (ledstat == LEDOFF) {
    ' |9 h3 F, O* R: j4 J" u
  93. 93                 led0_switch(LEDOFF);1 p( P% h/ k4 Y  R0 F$ j
  94. 94         }
    , _5 E0 R1 w- x3 x0 v
  95. 95         return 0;- }$ H  e5 e& P& B: W( k8 k# `
  96. 96 }
      b/ L5 Z0 A4 H' O( _
  97. 97
    7 H( c6 |5 L; l0 d
  98. 98 /* 设备操作函数 */
    $ Y' a6 d0 h) o5 i2 F+ [3 w; h
  99. 99 static struct file_operations led_fops = {  R! w( X8 Z- Y2 K; Y. e
  100. 100         .owner = THIS_MODULE,
    8 B- Y7 |/ x7 ^5 M2 p" C$ J7 Z
  101. 101         .open = led_open,! j+ B$ V9 C) T+ i6 i
  102. 102         .write = led_write,
    * m6 ?0 A; Q1 @3 x2 D
  103. 103 };
    / A* J8 y0 K/ ], I% `3 M
  104. 104
      d( M+ \/ U3 q& D9 q3 h3 I  M
  105. 105 /*# }, p6 G) ?+ x, I4 {% w
  106. 106  * @description         : flatform驱动的probe函数,当驱动与
    ) R9 j9 q9 y& `% z
  107. 107  *                                        设备匹配以后此函数就会执行
    1 v; J8 q& }) {0 [0 [% W1 R0 s
  108. 108  * @param - dev         : platform设备' T; {3 ]! p/ K. A9 g5 I
  109. 109  * @return                      : 0,成功;其他负值,失败
      B0 c! K7 q% Y% Q8 ^- V
  110. 110  */. I: Z+ }2 [7 \7 G& T
  111. 111 static int led_probe(struct platform_device *dev)- s+ v* c% C0 y4 m
  112. 112 {3 Q' t5 t6 d) o, \" I6 q
  113. 113         printk("led driver and device was matched!\r\n");
    8 N* a8 \- C  Q+ W. r- Q# e7 v
  114. 114         /* 1、设置设备号 */. z+ U- c: Z5 W# o* j8 {% C6 |3 Z
  115. 115         if (leddev.major) {
    : {' V' }0 @# C) n' n& H- S
  116. 116                 leddev.devid = MKDEV(leddev.major, 0);
    % q2 X, {6 R  @; W$ _3 |9 d( J# x
  117. 117               register_chrdev_region(leddev.devid, LEDDEV_CNT, LEDDEV_NAME);2 A' S+ @, k& g6 x7 {1 N
  118. 118         } else {6 h. G6 a0 B0 p! \1 A' K& D# S7 {
  119. 119              alloc_chrdev_region(&leddev.devid, 0, LEDDEV_CNT, LEDDEV_NAME);
    1 ]% V, m$ l& t( u, C/ l& `4 e
  120. 120                 leddev.major = MAJOR(leddev.devid);- h& L# H% X6 ?! K) o% C
  121. 121         }
    % I, d* W# b: ?! I2 Q8 k9 K# e
  122. 122 4 z. a& ^3 _: g6 N
  123. 123         /* 2、注册设备      */# t, p4 i8 e& s* H2 N" W
  124. 124         cdev_init(&leddev.cdev, &led_fops);
    / C/ o+ q+ i4 g5 K) @+ [0 L" @
  125. 125         cdev_add(&leddev.cdev, leddev.devid, LEDDEV_CNT);1 a5 H3 o/ Q. L$ x5 G
  126. 126
    1 M7 _) e& x# F# [. a4 x; ~* _
  127. 127         /* 3、创建类      */' m* p% m) _# s2 f& U
  128. 128         leddev.class = class_create(THIS_MODULE, LEDDEV_NAME);( N' q% t( I2 ]3 m* {- b0 I3 ^
  129. 129         if (IS_ERR(leddev.class)) {
    " `6 n) }3 r& N6 z1 s% i$ P0 o0 e
  130. 130                 return PTR_ERR(leddev.class);" P$ z# `% V4 ?7 W6 {
  131. 131         }- ]# O% n2 I# R5 j; j+ F9 b. S: ~
  132. 132
    . r" [$ O$ j8 d
  133. 133         /* 4、创建设备 */
    6 M5 i2 v4 L( r& ?
  134. 134         leddev.device = device_create(leddev.class, NULL, leddev.devid,
    " D1 T$ @3 A- i, ~2 }1 L' ~) ^- X
  135. NULL, LEDDEV_NAME);
    7 o3 ]  d" V: f' b
  136. 135         if (IS_ERR(leddev.device)) {3 z2 h% P- E& ]  \0 @2 _8 z7 _) u
  137. 136                 return PTR_ERR(leddev.device);( \9 |  t: E- J5 j, y, m2 H
  138. 137         }8 P, K7 P, |2 f
  139. 138 3 f! ?% Y  k+ d, M
  140. 139         /* 5、初始化IO */4 X" J% l: n5 g7 t6 [) a' _; z
  141. 140         leddev.node = of_find_node_by_path("/gpioled");4 n3 @( R# c6 K) G! a. z$ M1 }0 x4 r
  142. 141         if (leddev.node == NULL){5 d; A3 t8 a7 T6 V( J( u
  143. 142                 printk("gpioled node nost find!\r\n");
    1 G" K# m% w- f6 f; p
  144. 143                 return -EINVAL;
    : }6 @+ `8 ~! ~: K* x
  145. 144         }
    + M: ~% A3 ]2 w7 R
  146. 145
    - r" K: K7 z1 E  {
  147. 146         leddev.led0 = of_get_named_gpio(leddev.node, "led-gpio", 0);
    ( m: f- M2 o( F* u2 B
  148. 147         if (leddev.led0 < 0) {6 f" G' c( J' }0 _% H, t/ m2 Q
  149. 148                 printk("can't get led-gpio\r\n");, T# C; U  X# |2 k7 M
  150. 149                 return -EINVAL;3 X  \: H  Z" Z. n3 A8 W! d! ~! u
  151. 150         }% [7 h; l. o0 H! ~1 P! \
  152. 151
    3 `9 l, I: e3 b
  153. 152         gpio_request(leddev.led0, "led0");6 t0 g  a: l2 z" h- s
  154. 153     gpio_direction_output(leddev.led0, 1); /* led0 IO设置为输出,默认高电平 */7 |0 q+ }* M3 V% K' e8 w
  155. 154         return 0;6 |( \- {5 o3 L5 q: h
  156. 155 }0 Y: K/ h8 G9 @: ^$ e  \; O
  157. 156
    + g! O' F) |7 Y3 ^% \
  158. 157 /*
    / p8 g, B1 |& y; f! x. J7 e
  159. 158  * @description : platform驱动的remove函数,移除platform
    ) X: U% h) x4 T1 L3 ]* n" z3 x
  160. 驱动的时候此函数会执行: i. ]# Q7 i0 V: N, h# S1 B! M
  161. 159  * @param - dev         : platform设备
    5 _2 G* L" i0 t+ |
  162. 160  * @return         : 0,成功;其他负值,失败! N$ u* @' N5 Y8 \; B
  163. 161  */
    * X" P( ^9 b0 ]. ]3 i& L
  164. 162 static int led_remove(struct platform_device *dev)
    7 |3 R6 ?  _  h
  165. 163 {
    9 {' P( S9 H2 H& F' U5 \& ~# `
  166. 164         gpio_set_value(leddev.led0, 1);         /* 卸载驱动的时候关闭LED */
    & g7 T1 Z9 t! f3 g) H) |
  167. 165
    , K' W/ Y( b6 i. c; h3 G
  168. 166         cdev_del(&leddev.cdev);                         /*  删除cdev */
    - V8 e( i9 a& T7 ~) u8 i
  169. 167         unregister_chrdev_region(leddev.devid, LEDDEV_CNT); /* 注销设备号 */
    ) V- F4 n0 X2 a# h
  170. 168         device_destroy(leddev.class, leddev.devid);
    ( b8 G3 r8 k7 w! Y) ?
  171. 169         class_destroy(leddev.class);& T, o4 O& C1 E% a
  172. 170         return 0;
    8 g: J" z3 i4 I: \
  173. 171 }
    , E- c9 m& s$ ^7 ?
  174. 172
    & h$ P/ E: n7 C0 f# m9 A0 n
  175. 173 /* 匹配列表 */( E; e  l3 ?) G- W7 X7 P" ]
  176. 174 static const struct of_device_id led_of_match[] = {
    ) A! [7 A2 y- h* \4 [
  177. 175         { .compatible = "gpioled" },
    , f& _: {- B2 b% l0 |' A& M
  178. 176         { /* Sentinel */ }$ O2 G% ?0 g! m+ `
  179. 177 };
    ! D7 n8 Q( Y- x$ f- y0 K
  180. 178
    & O# Y6 R- t* ?
  181. 179 /* platform驱动结构体 */8 f# ~; l4 }6 k# ~: l
  182. 180 static struct platform_driver led_driver = {) j: r! U& \% |7 P+ P4 N/ f  ^
  183. 181         .driver         = {
    6 @5 V# h% k- Z/ R
  184. 182                 .name   = "imx6ul-led",     /* 驱动名字,用于和设备匹配 */. p1 ?1 R, l4 I# o3 t$ I! v) k, {
  185. 183                 .of_match_table = led_of_match, /* 设备树匹配表 */
    $ |: ]1 l, b/ N$ k$ p0 X1 F
  186. 184         },
    6 o) F, q, H! |/ l: _
  187. 185         .probe          = led_probe,  o( o7 G1 P" a$ C, g
  188. 186         .remove         = led_remove,$ C2 L! x3 t" I+ v% s* h
  189. 187 };
    , j9 r: }% n. O8 X( l1 d6 M
  190. 188 : J. N5 U0 l- D! y9 t+ x+ O
  191. 189 /*
      z9 j7 i( h1 S" ^4 m) R
  192. 190  * @description : 驱动模块加载函数' i+ O+ h- w9 j1 v
  193. 191  * @param               : 无* r9 t1 Q, e9 ]$ X! M
  194. 192  * @return              : 无. _$ ?1 f! j9 B( F4 `. F  `% X& m
  195. 193  */
    ( w1 v9 H# u) `8 `% }& y
  196. 194 static int __init leddriver_init(void)& o7 x2 F. t8 h7 x, |5 N
  197. 195 {
    ) q* @$ H  J2 Y2 G
  198. 196         return platform_driver_register(&led_driver);8 T4 `5 h, c, ~$ S7 J
  199. 197 }
    4 @6 o% U) F+ C0 }& H8 R' D6 X( `% ~
  200. 198
    4 T! h: K4 l1 I: t% p0 K7 r
  201. 199 /*5 ~/ n6 E- B2 H. J$ M; J
  202. 200  * @description : 驱动模块卸载函数
    2 X( T, H6 P* v0 A  \
  203. 201  * @param               : 无7 C9 q' i2 w. l1 r) U0 I; I  o
  204. 202  * @return              : 无! w2 p2 j4 z& j; L/ J( {2 n
  205. 203  */, D9 _/ _) n$ |: v0 L" S2 S  m* E
  206. 204 static void __exit leddriver_exit(void)$ x6 Q9 n/ j9 I" n. Q
  207. 205 {
    " q$ v, G1 M7 D2 l1 c
  208. 206         platform_driver_unregister(&led_driver);( y2 {) F, y3 i. N
  209. 207 }
    $ T1 S) ~8 S/ h; M& D, ?& R9 m
  210. 208
    5 ~& \4 n4 U$ @5 u0 }8 r$ Z9 M
  211. 209 module_init(leddriver_init);
    % S! V2 k% q8 U' Q) Y/ ?8 ~$ D  C
  212. 210 module_exit(leddriver_exit);- ]0 C+ a6 F- C% t! ~9 Q* Q7 a9 S
  213. 211 MODULE_LICENSE("GPL");0 q) w9 A+ _3 {/ p! \
  214. 212 MODULE_AUTHOR("topeet");
    5 A7 v: ]1 X( q9 u$ b/ E5 m" `- m
复制代码

5 ^% H9 }; t" _; i! y

第 174~177 行,匹配表,描述了此驱动都和什么样的设备匹配,第 175 行添加了一条值为"gpioled"的 compatible 属性值,当设备树中某个设备节点的 compatible 属性值也为 “gpioled”的时候就会与此驱动匹配。8 ^/ r# h2 r( t  Z2 E! D# S( M
第 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即可。

$ m4 R# E( t. J8 P( |
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

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

EDA365公众号

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

GMT+8, 2025-7-21 04:06 , Processed in 0.109375 second(s), 24 queries , Gzip On.

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

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

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