设备树驱动编写框架

编写设备树节点

首先是将节点编写在使用的开发板的dts文件中,比如编写led的节点。首先将节点编写在根节点下:

1
2
3
4
5
6
7
8
9
10
11
12
13
alphaled//节点名字{
#address-cells = <1>;
#size-cells = <1>;
compatible = "atkalpha-led";
status = "okay";
reg = {
0X020C406C 0X04 //CCM_CCGR1_BASE
0X020E0068 0X04 //SW_MUX_GPIO103_BASE
0X020E02F4 0X04 //SW_PAD_GPIO103_BASE
0X0209C000 0X04 //GPIO1_DR_BASE
0X0209C004 0X04 //GPIO1_GDIR_BASE
};
};

在节点中已经写入物理地址,所以驱动程序进行获取就行不用写了,设备树修改完重新编译

1
make dtbs

编写程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/ide.h>
#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of_address.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/errno.h>

#define on 1
#define off 0

static void __iomem *CCM_CCGR1;
static void __iomem *SW_MUX_GPIO1_IO03;
static void __iomem *SW_PAD_GPIO1_IO03;
static void __iomem *GPIO1_DR;
static void __iomem *GPIO1_GDIR;

int led_switch(u8 state)
{
u32 val;
val = readl(GPIO1_DR);
if(state == on)
{
val |= (0<<3);
}else if(state == off)
{
val |= (1<<3);
}
writel(val, GPIO1_DR);

return 0;
}

struct devtree {
dev_t devid;
struct cdev cdev;
struct class *class;
struct device *device;
int major;
int minor;
struct device_node *nd;

};
struct devtree chrled;

static int led_open(struct inode *inode , struct file *filp)
{
filp->private_data = &chrled;//设置私有数据
return 0;
}
static int led_release(struct inode *inode, struct file *filp)
{
return 0;
}
static ssize_t led_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{
return 0;
}
static ssize_t led_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{
int val;
unsigned char databuf[1];
unsigned char state;

val = copy_from_user(databuf, buf, cnt);
state = databuf[0];
if(state == on)
{
led_switch(on);
}else if(state == off)
{
led_switch(off);
}

return 0;
}

static struct file_operations chrops = {
.owner = THIS_MODULE,
.open = led_open,
.read = led_read,
.write = led_write,
.release = led_release,
};

static int __init chrled_init(void)
{
int val;
struct property *proper;
int ret;
const char *str;
u32 regdata[14];

chrled.nd = of_find_node_by_path("/alphaled");
if(chrled.nd == NULL)
{
printk("error: node don't find \r\n");
return -EINVAL;
}
proper = of_find_property(chrled.nd, "compatible", NULL);
if(proper == NULL)
{
printk("compatible property find failed\r\n");
}
ret = of_property_read_string(chrled.nd, "status", &str);
if(ret < 0)
{
printk("status read failed\r\n");
}else{
printk("status = %s\r\n",str);
}
ret = of_property_read_u32_array(chrled.nd , "reg", regdata, 10);
if(ret < 0)
{
printk("reg property read failed!\r\n");
}else{
u8 i = 0;
printk("reg data: \r\n");
for(i = 0;i < 10; i++)
printk("%#X ", regdata[i]);
printk("\r\n");
}
CCM_CCGR1 = of_iomap(chrled.nd, 0);
SW_MUX_GPIO1_IO03 = of_iomap(chrled.nd, 1);
SW_PAD_GPIO1_IO03 = of_iomap(chrled.nd, 2);
GPIO1_DR = of_iomap(chrled.nd, 3);
GPIO1_GDIR = of_iomap(chrled.nd, 4);
/*设备驱动*/
val = readl(CCM_CCGR1);
val &= ~(3 << 26);
val |= (3<<26);
writel(val, CCM_CCGR1);
writel(5, SW_MUX_GPIO1_IO03);
writel(0x10B0, SW_PAD_GPIO1_IO03);
val = readl(GPIO1_GDIR);
val &= ~(1<<3);
val |= (1<<3);
writel(val, GPIO1_GDIR);
val = readl(GPIO1_DR);
val |= (1<<3);
writel(val, GPIO1_DR);

if(chrled.major)
{
chrled.devid = MKDEV(chrled.major, 0);
register_chrdev_region(chrled.devid, 1, "led");
}else{
alloc_chrdev_region(&chrled.devid, 0, 1,"led");
chrled.major = MAJOR(chrled.devid);
chrled.minor = MINOR(chrled.devid);
}
cdev_init(&chrled.cdev, &chrops);
chrled.cdev.owner = THIS_MODULE;
cdev_add(&chrled.cdev, chrled.devid, 1);
chrled.class = class_create(THIS_MODULE, "led");
if(IS_ERR(chrled.class))
{
return PTR_ERR(chrled.class);
}
chrled.device = device_create(chrled.class, NULL,chrled.devid, NULL,"led");
if(IS_ERR(chrled.device))
{
return PTR_ERR(chrled.device);
}

return 0;
}
static void __exit chrled_exit(void)
{
iounmap(CCM_CCGR1);
iounmap(SW_MUX_GPIO1_IO03);
iounmap(SW_PAD_GPIO1_IO03);
iounmap(GPIO1_GDIR);
iounmap(GPIO1_DR);

cdev_del(&chrled.cdev);
unregister_chrdev_region(chrled.devid, 1);
device_destroy(chrled.class, chrled.devid);
class_destroy(chrled.class);

}
module_init(chrled_init);
module_exit(chrled_exit);
MODULE_LICENSE("GPL");