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