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

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

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x
文章目录
) X, J, P4 M+ m5 P# n
  • 1 修改设备树文件
  • 2 platform驱动程序
  • 3 应用测试程序( }* U. `5 I! A  f
5 _8 s) n3 d* b* h+ M
1 修改设备树文件

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

2 platform驱动程序

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

  1. 1 #include <linux/types.h>
    . X2 v* U' ?0 c" w
  2.   2 #include <linux/kernel.h>" [: r4 `5 t8 E
  3.   3 #include <linux/delay.h>* w  P2 D" t/ N  G
  4.   4 #include <linux/ide.h>
    8 k8 j9 B) |% L9 y* u7 O5 P. c
  5.   5 #include <linux/init.h>
      ~. @- V, Z' G; ?
  6.   6 #include <linux/module.h>4 J. v. ?  G$ b0 g) L2 z
  7.   7 #include <linux/errno.h>
    - u3 A: l6 c6 _
  8.   8 #include <linux/gpio.h>% t) _, A4 }% l& N
  9.   9 #include <linux/cdev.h>
    . [7 k: j; D: H
  10. 10 #include <linux/device.h>
    / l# B$ u: O# c0 L4 D
  11. 11 #include <linux/of_gpio.h>
    , |5 k, L* N$ b. b
  12. 12 #include <linux/semaphore.h>
    - O4 j/ C: \) v: A1 a) E; |
  13. 13 #include <linux/timer.h># U; x) B: q( Q2 d. W2 B. u& n
  14. 14 #include <linux/irq.h>+ ^9 ]9 D! ?4 j- ?- n) |& D6 g* O
  15. 15 #include <linux/wait.h>4 f4 h% m1 Y- J" L. U+ u
  16. 16 #include <linux/poll.h>
    8 z* k2 Z' {% h* ]" m# ~
  17. 17 #include <linux/fs.h>
    2 h$ G; N9 @, h1 A2 _! {& P, B9 J- ]0 D6 a
  18. 18 #include <linux/fcntl.h>* n1 j  y7 O/ Z7 P
  19. 19 #include <linux/platform_device.h>
    & b% i2 N; r0 T6 Y1 {$ a/ M  y
  20. 20 #include <asm/mach/map.h>
      ]8 ^+ a4 u0 C0 L
  21. 21 #include <asm/uaccess.h>6 `: _% s& a: u' S* m
  22. 22 #include <asm/io.h>2 G+ b. D7 q% Q5 k" m+ ~# _" J: q
  23. 23 ' P, e; A5 w; Q- J8 V5 j
  24. 24 #define LEDDEV_CNT              1                    /* 设备号长度   */
    / j2 B# p0 I  |2 ]
  25. 25 #define LEDDEV_NAME             "dtsplatled"    /* 设备名字     */' S5 P, z# R& q. p$ u8 ?
  26. 26 #define LEDOFF                  0
    - [& \1 F) x5 V; G* ]1 m5 [
  27. 27 #define LEDON                   1
    - j* _1 C9 `/ x5 K* B/ G$ V2 J
  28. 28 1 ^: ^2 ]# X. k9 v
  29. 29 /* leddev设备结构体 */
    0 s: m3 Q4 X4 g" F) L
  30. 30 struct leddev_dev{  e) p$ r. d& h7 Y) K6 L
  31. 31         dev_t devid;                            /* 设备号       */: T4 @* ?4 i/ J( ~' s
  32. 32         struct cdev cdev;                       /* cdev         */
    * v; e0 y) D6 d% g6 f( q  K. d- O
  33. 33         struct class *class;            /* 类           */
    " z& U: N" N3 F5 S! j0 y; S/ C
  34. 34         struct device *device;          /* 设备 *// D% |2 b) ?8 l9 {3 w$ K. C
  35. 35         int major;                     /* 主设备号     */
    7 q8 u" K: L( Z) U6 R
  36. 36         struct device_node *node;       /* LED设备节点 */+ ?/ k9 @; v" h$ l8 B- h) Q
  37. 37         int led0;                      /* LED灯GPIO标号 */
    ) M% {  ?  x- O. t* F
  38. 38 };+ S7 h3 ]% R3 R, t: D( O
  39. 39
    + N1 N' L$ Z* g% b" @$ t
  40. 40 struct leddev_dev leddev;               /* led设备 */
    8 W7 }( ]( J2 U! A5 H1 }# I) w
  41. 41
    & H2 Z3 C; }& I5 G) `
  42. 42 /*
    & H' F5 f2 U4 ]. F* r  y# F4 ~5 N
  43. 43  * @description         : LED打开/关闭0 Z8 H, K$ X- K, c0 P- G
  44. 44  * @param - sta         : LEDON(0) 打开LED,LEDOFF(1) 关闭LED/ y" ]4 t5 S$ F5 E
  45. 45  * @return                      : 无  O7 g/ E& d+ i5 e4 ~
  46. 46  */2 o' n! e+ p* w0 {9 W
  47. 47 void led0_switch(u8 sta)
    : p9 u6 n% }6 I8 Y9 [; j  k
  48. 48 {
    ( @$ k( X6 Z% z. b# ]
  49. 49         if (sta == LEDON )/ N' x* }3 i* C+ `6 H5 |2 F
  50. 50                 gpio_set_value(leddev.led0, 0);
    " o+ v, O' a+ I4 G8 U, ^
  51. 51         else if (sta == LEDOFF)
    " M  h  s# Y; B4 n6 F6 v
  52. 52                 gpio_set_value(leddev.led0, 1);
    : O8 M) H6 O6 |9 v3 Q* y, p' G, R
  53. 53 }; J8 p+ g$ J9 Y% z5 N" y" H/ o! M
  54. 54
    ) `  J) w$ v6 c3 k; G1 O
  55. 55 /** f3 i- o& R( ^
  56. 56  * @description         : 打开设备* i1 p9 N3 r- n, u
  57. 57  * @param - inode       : 传递给驱动的inode
      r4 b7 \3 \6 h3 n! e, [2 U  p
  58. 58  * @param - filp        : 设备文件,file结构体有个叫做private_data的成员变量
    & p7 p. j! j# E+ P, |! @
  59. 59  * 一般在open的时候将private_data指向设备结构体。
    1 T* Q! M' t  A. L5 U" _
  60. 60  * @return                      : 0 成功;其他 失败! y2 e7 O4 C$ O, ~; e3 p
  61. 61  */  g0 R: g# W2 @
  62. 62 static int led_open(struct inode *inode, struct file *filp)3 A9 K. S) s* Z' i3 e5 n$ @
  63. 63 {5 H4 W& Z3 |) R- `* p4 F! U) A3 H+ s
  64. 64         filp->private_data = &leddev; /* 设置私有数据  *// E6 ~& |8 i" N7 q* W
  65. 65         return 0;$ }' [( E$ q/ `
  66. 66 }
    " c0 u6 q2 E( Z* E' r
  67. 67
    5 ?. I! w  I( b: z0 w3 q$ k
  68. 68 /*/ y- j8 ~7 A9 T7 I$ H& o2 H
  69. 69  * @description         : 向设备写数据 & L8 p& n/ x! K3 `! _
  70. 70  * @param - filp        : 设备文件,表示打开的文件描述符
      ?" K+ D' D+ w- f9 f5 J
  71. 71  * @param - buf         : 要写给设备写入的数据! @  Y% j7 x7 a9 c  X
  72. 72  * @param - cnt         : 要写入的数据长度3 ~4 q' D& j" Y# a2 y
  73. 73  * @param - offt        : 相对于文件首地址的偏移7 P  @/ m  e+ h  n2 k" q- v# L
  74. 74  * @return                      : 写入的字节数,如果为负值,表示写入失败) s; g$ w0 f; k7 r! d
  75. 75  */( P+ Q' y% ~! i
  76. 76 static ssize_t led_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)$ `, Z- k- k; j! t2 }
  77. 77 {
    4 m9 G8 H4 g. b% F0 d
  78. 78         int retvalue;) N9 |! p* t. k4 j. X7 d
  79. 79         unsigned char databuf[2];
    ! b, e' B' h# a! `' r' ^8 r
  80. 80         unsigned char ledstat;
    ) ~9 ~1 w5 \% W- p
  81. 81
    ; B! x! ?4 h/ O# V( U
  82. 82         retvalue = copy_from_user(databuf, buf, cnt);4 p) a3 T% e7 o" i5 C; P
  83. 83         if(retvalue < 0) {+ v! S& {( ^/ x1 F  P$ g6 \/ C8 |  C
  84. 84 0 H0 U% t5 K9 j1 Y7 N
  85. 85                 printk("kernel write failed!\r\n");% v$ J6 {; i5 t
  86. 86                 return -EFAULT;
    " A, j- C. p& |
  87. 87         }. {) }1 ]) b9 I8 o& B
  88. 88 8 |. }% O# B3 l7 I5 R- X. t( [
  89. 89         ledstat = databuf[0];2 E5 q8 y/ g' P1 A* N5 R
  90. 90         if (ledstat == LEDON) {9 a) H0 R1 u6 \) q8 F- Y; l& }( u+ v
  91. 91                 led0_switch(LEDON);! G3 |& q4 c. c' [
  92. 92         } else if (ledstat == LEDOFF) {' b2 Q# A5 n. i
  93. 93                 led0_switch(LEDOFF);
    & _4 b. m+ h% a' s
  94. 94         }0 U9 ]) r' B& Y1 y
  95. 95         return 0;
    8 p2 j4 _# [1 v7 I' f
  96. 96 }8 G( w- R5 E) h3 d4 K$ ~& r
  97. 97
    ; D( Z' P% I- _# P4 w8 C
  98. 98 /* 设备操作函数 */
      @4 `) b5 m8 ~1 B4 G. K
  99. 99 static struct file_operations led_fops = {
    + }% S$ M% O; I9 U/ H
  100. 100         .owner = THIS_MODULE,0 l/ A& ]3 S; {* f
  101. 101         .open = led_open,4 R) v3 u, i1 y& S+ j6 U! K
  102. 102         .write = led_write,
    : h! Z: v& r3 A
  103. 103 };
    6 R0 m3 e% o7 U
  104. 104
    % y7 T0 c5 j, F; ]/ X5 m
  105. 105 /*
    & B, V+ a4 ?. R& ~7 D+ L
  106. 106  * @description         : flatform驱动的probe函数,当驱动与
    ! a5 A$ K9 }9 Y. ?) ~+ \: t
  107. 107  *                                        设备匹配以后此函数就会执行1 e3 b. J% {  l
  108. 108  * @param - dev         : platform设备3 p9 P9 k5 R) D8 f! g8 s( ^
  109. 109  * @return                      : 0,成功;其他负值,失败( E% ?; I" z9 O% X1 d6 S
  110. 110  */
    # c& J4 g" g' l1 Y/ x# V- g
  111. 111 static int led_probe(struct platform_device *dev)
    . R8 a5 Y6 x, b' N
  112. 112 {
    & n  @" Q8 E6 D8 e8 f
  113. 113         printk("led driver and device was matched!\r\n");
    8 u& k8 [! X6 o. P+ W, b
  114. 114         /* 1、设置设备号 */
    % _' M1 y; r* q4 o6 z
  115. 115         if (leddev.major) {
    / I, H/ x0 I' J/ \  h5 L9 C8 @
  116. 116                 leddev.devid = MKDEV(leddev.major, 0);+ f( @& H+ G! x
  117. 117               register_chrdev_region(leddev.devid, LEDDEV_CNT, LEDDEV_NAME);2 W! G4 ^  {2 c3 a( {' Z
  118. 118         } else {
    $ S, i2 q% _/ N4 u% ?  r' M1 V
  119. 119              alloc_chrdev_region(&leddev.devid, 0, LEDDEV_CNT, LEDDEV_NAME);
    : g: {$ T* Y5 c2 f
  120. 120                 leddev.major = MAJOR(leddev.devid);
    $ `! M( L! Q* r2 S' `7 D9 v: }8 G% z
  121. 121         }
    / |1 H+ T+ @# ?6 @
  122. 122 ; j. s% k7 p+ Y) V- P
  123. 123         /* 2、注册设备      */; [$ }; C7 e! v5 O9 b
  124. 124         cdev_init(&leddev.cdev, &led_fops);8 N3 R- n3 k$ }6 N3 G
  125. 125         cdev_add(&leddev.cdev, leddev.devid, LEDDEV_CNT);1 o" F' L: e8 T# F" N! j
  126. 126 0 K- E0 p) e+ I% Q" [2 Q& ~6 Z- E  F
  127. 127         /* 3、创建类      */8 Z) B6 m) k3 X- J8 y
  128. 128         leddev.class = class_create(THIS_MODULE, LEDDEV_NAME);0 |* Q6 d3 o" g- o
  129. 129         if (IS_ERR(leddev.class)) {
    ! {; @& P9 r/ h7 f
  130. 130                 return PTR_ERR(leddev.class);
    - Q9 ]. n1 H/ }. `/ l* v; N, [3 q- n
  131. 131         }
    . X9 D, s$ L( g" k. B- [( l
  132. 132
    " k/ q# p) _: {. Z% r$ v1 I
  133. 133         /* 4、创建设备 */
    / q$ P# H4 p9 m
  134. 134         leddev.device = device_create(leddev.class, NULL, leddev.devid,
    6 p; P; y  ^9 p  A7 L. m
  135. NULL, LEDDEV_NAME);
    " M6 r  Q# U4 E- f0 @; n
  136. 135         if (IS_ERR(leddev.device)) {
    & a& t- f# }. P3 Y- c+ l0 _3 ?0 M
  137. 136                 return PTR_ERR(leddev.device);
    3 [& H- h. M6 [3 J
  138. 137         }3 {0 f$ X) Q( _  j
  139. 138 $ U, h1 ^( U+ ^
  140. 139         /* 5、初始化IO */
    1 Z3 R- N$ c3 [
  141. 140         leddev.node = of_find_node_by_path("/gpioled");
    : u& b  m, w) R, J) i) m: y0 X" F/ k
  142. 141         if (leddev.node == NULL){$ R* v5 N( Y, d/ w# O5 U
  143. 142                 printk("gpioled node nost find!\r\n");* {. I0 \1 t. W) `, j
  144. 143                 return -EINVAL;' T8 S# w6 b. q% C$ g/ M, @
  145. 144         }: O1 M3 U* u6 ^! T9 M; J
  146. 145 7 ~; {+ Y- @8 I/ U) y3 _0 D) N" U
  147. 146         leddev.led0 = of_get_named_gpio(leddev.node, "led-gpio", 0);7 e" v# G7 M6 ]( p
  148. 147         if (leddev.led0 < 0) {- n% }9 l4 C0 j/ k
  149. 148                 printk("can't get led-gpio\r\n");
    4 P$ \6 L# i0 \1 f* y1 L3 j; Q8 ~+ q
  150. 149                 return -EINVAL;
    3 e) I2 G% R# W* l! F5 p* P! k
  151. 150         }
    8 `, F. N  R$ O* L
  152. 151 : t( {' M4 l, y( {
  153. 152         gpio_request(leddev.led0, "led0");/ Y# C0 M8 [# g* v. N& u5 H0 R4 G
  154. 153     gpio_direction_output(leddev.led0, 1); /* led0 IO设置为输出,默认高电平 */
    1 j: S7 j: F/ c9 D# M- \" ^' L
  155. 154         return 0;6 C$ K1 e( F- V) ?0 e( ], c
  156. 155 }
    4 q' z, a! B, _  e9 K& G/ V' d
  157. 156
    ' O; e. K7 t3 n  U
  158. 157 /*9 p8 P' q7 ^# E' r0 |( V: M. m
  159. 158  * @description : platform驱动的remove函数,移除platform
    + r2 J; B! P2 x9 P
  160. 驱动的时候此函数会执行
    & V& F% T1 `/ I2 [5 l  Q
  161. 159  * @param - dev         : platform设备
    , b$ A! U) d% q% V$ O
  162. 160  * @return         : 0,成功;其他负值,失败- u4 e# u- }8 `2 S* ?
  163. 161  */
    + o+ T- U2 _6 M$ g0 T% G4 Z. d5 h
  164. 162 static int led_remove(struct platform_device *dev)
    9 i9 [" c6 [% q9 h; ~" z
  165. 163 {, o* `% y" t3 O
  166. 164         gpio_set_value(leddev.led0, 1);         /* 卸载驱动的时候关闭LED */
    8 V) N# m9 ~/ S
  167. 165 8 ~2 I% r5 Z8 @
  168. 166         cdev_del(&leddev.cdev);                         /*  删除cdev */
    ; `% t3 Q% w# F
  169. 167         unregister_chrdev_region(leddev.devid, LEDDEV_CNT); /* 注销设备号 */
    $ h- w, f; @9 G4 M; v# K% s
  170. 168         device_destroy(leddev.class, leddev.devid);
    + s- T- t& t: S5 G. `! R/ h
  171. 169         class_destroy(leddev.class);
    8 Z. g  r7 ]2 C- U
  172. 170         return 0;
    $ @4 b% T8 h9 q4 c6 k, k
  173. 171 }& \/ |) z0 p$ W$ ~! c6 ?
  174. 172
    & f9 b; Q7 d; Q1 Y, a
  175. 173 /* 匹配列表 */
    & ?4 H4 a4 m" n* Z1 u  `, E$ W) D' Q3 z
  176. 174 static const struct of_device_id led_of_match[] = {6 I/ C- q- U$ T
  177. 175         { .compatible = "gpioled" }," k8 s# ]! M" W% J' I
  178. 176         { /* Sentinel */ }
    4 O7 x# R( g. C# E' w, ~+ V: i
  179. 177 };! w  A7 m2 P' u' h  T$ T6 G4 n8 i
  180. 178 : p9 W$ }) Z5 w0 ?* D1 o5 K, f
  181. 179 /* platform驱动结构体 */1 Q$ {/ A$ Z1 d/ j& \
  182. 180 static struct platform_driver led_driver = {/ b. I7 `% o9 F+ I. y4 A6 \2 Q5 F
  183. 181         .driver         = {& g# ]( S+ [/ [) e8 Z, X" h
  184. 182                 .name   = "imx6ul-led",     /* 驱动名字,用于和设备匹配 */
      \: E4 q/ b) P- i& a( K
  185. 183                 .of_match_table = led_of_match, /* 设备树匹配表 */; m0 h, s4 o. P3 T/ Y1 A8 S% m3 O
  186. 184         },; P; f  o- t& v
  187. 185         .probe          = led_probe,
    8 C5 f3 Q: g& l( o( D  y
  188. 186         .remove         = led_remove,
    # M' Z! K8 G. h6 I/ r" x# G
  189. 187 };. F, s1 X  O: O, S# V
  190. 188 - ]9 _2 O! Y; e% p: ?4 U
  191. 189 /*
    # L. T9 Z0 Z7 {1 @2 ^8 u! {% t+ O
  192. 190  * @description : 驱动模块加载函数# h0 n- M  E  o2 _  D6 J9 l
  193. 191  * @param               : 无7 Z3 @+ M7 {5 J, {
  194. 192  * @return              : 无5 p, f" {9 D' P, p
  195. 193  */
    4 x* ~% A! j+ `9 B
  196. 194 static int __init leddriver_init(void)
    9 f( x  `$ ^$ |) q2 Y  [0 T6 F3 i
  197. 195 {  m; ^9 V8 w8 t8 T, |8 w2 C9 O
  198. 196         return platform_driver_register(&led_driver);
    9 @. w. s' e1 l/ b
  199. 197 }* |* D  v/ I, }3 q- k. L
  200. 198 ( x) X( t8 f+ ?# i" D
  201. 199 /*' s2 ]; C3 u) M
  202. 200  * @description : 驱动模块卸载函数
    4 l0 a& |9 B6 [
  203. 201  * @param               : 无
    * r* X$ h$ W0 }5 b" j% s! b. Y/ @' u
  204. 202  * @return              : 无0 X( h* H/ M" L( s4 N7 M8 y7 K
  205. 203  */' R- T+ z/ x3 ?# Q: r, ?8 p
  206. 204 static void __exit leddriver_exit(void)
    * K1 W' o/ w" h8 q6 H1 t0 j
  207. 205 {6 F* G# p- q+ Y0 p6 b& n! n
  208. 206         platform_driver_unregister(&led_driver);8 C1 A! `1 c2 V4 ~
  209. 207 }
    1 _/ n0 o. N- w3 i+ I
  210. 208
    / O  D- c/ t8 [2 f! n. t
  211. 209 module_init(leddriver_init);/ H4 y6 r( @& m* t
  212. 210 module_exit(leddriver_exit);" h5 l% ?$ d) U# ?& i& D# u
  213. 211 MODULE_LICENSE("GPL");
    ; g5 b3 I! q+ }3 B; q
  214. 212 MODULE_AUTHOR("topeet");3 z: P% T; `  I" U4 F) N  r
复制代码
  {0 g* `9 N7 ?9 t" e- G: u/ h

第 174~177 行,匹配表,描述了此驱动都和什么样的设备匹配,第 175 行添加了一条值为"gpioled"的 compatible 属性值,当设备树中某个设备节点的 compatible 属性值也为 “gpioled”的时候就会与此驱动匹配。* A* H, y. j, O$ @1 v# Z! Z
第 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即可。

+ f' T0 E# z: x# g) C: F9 O
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

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

EDA365公众号

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

GMT+8, 2025-10-11 09:19 , Processed in 0.140625 second(s), 24 queries , Gzip On.

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

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

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