这一章使用第五章的设备树知识来写led驱动
1.修改设备树在根节点下面添加子节点
alphaled {
#address-cells = <1>;
#size-cells = <1>;
compatible = "atkalpha-led";
status = "okay";
reg = < 0x020C406C 0x04
0x020E0068 0x04
0x020E02F4 0x04
0x0209C000 0x04
0x0209C004 0x04 >;
};
- alphaled是节点名字
- #address和#size都是1,表示reg属性起始地址占用一个字节,地址长度也占用一个字节
- compatbile设置节点兼容性为"atkalpha-led"。
- status状态属性设置为okey
- reg属性,设置了所要使用的寄存器物理地址。
添加完保存后使用命令
make dtbs
编译得到deb文件。
2.驱动程序摘取正点原子/04_dtsled部分代码,代码在第五节新字符驱动上修改。
#define DTSLED_CNT 1
#define DTSLED_NAME "dtsled"
struct dtsled_dev{
dev_t devid;
struct cdev cdev;
struct class *class;
struct device *device;
int major;
int minor;
struct device_node *nd;
};
struct dtsled_dev dtsled;
static int led_open(struct inode *inode, struct file *filp)
{
filp->private_data = &dtsled;
return 0;
}
static struct file_operations dtsled_fops = {
.owner = THIS_MODULE,
.open = led_open,
.read = led_read,
.write = led_write,
.release = led_release,
};
static int __init led_init(void)
{
u32 val = 0;
int ret;
u32 regdata[14];
const char *str;
struct property *proper;
dtsled.nd = of_find_node_by_path("/alphaled");
if(dtsled.nd == NULL) {
printk("alphaled node nost find!rn");
return -EINVAL;
} else {
printk("alphaled node find!rn");
}
proper = of_find_property(dtsled.nd, "compatible", NULL);
if(proper == NULL) {
printk("compatible property find failedrn");
} else {
printk("compatible = %srn", (char*)proper->value);
}
ret = of_property_read_string(dtsled.nd, "status", &str);
if(ret < 0){
printk("status read failed!rn");
} else {
printk("status = %srn",str);
}
ret = of_property_read_u32_array(dtsled.nd, "reg", regdata, 10);
if(ret < 0) {
printk("reg property read failed!rn");
} else {
u8 i = 0;
printk("reg data:rn");
for(i = 0; i < 10; i++)
printk("%#X ", regdata[i]);
printk("rn");
}
#if 0
IMX6U_CCM_CCGR1 = ioremap(regdata[0], regdata[1]);
SW_MUX_GPIO1_IO03 = ioremap(regdata[2], regdata[3]);
SW_PAD_GPIO1_IO03 = ioremap(regdata[4], regdata[5]);
GPIO1_DR = ioremap(regdata[6], regdata[7]);
GPIO1_GDIR = ioremap(regdata[8], regdata[9]);
#else
IMX6U_CCM_CCGR1 = of_iomap(dtsled.nd, 0);
SW_MUX_GPIO1_IO03 = of_iomap(dtsled.nd, 1);
SW_PAD_GPIO1_IO03 = of_iomap(dtsled.nd, 2);
GPIO1_DR = of_iomap(dtsled.nd, 3);
GPIO1_GDIR = of_iomap(dtsled.nd, 4);
#endif
if (dtsled.major) {
dtsled.devid = MKDEV(dtsled.major, 0);
register_chrdev_region(dtsled.devid, DTSLED_CNT, DTSLED_NAME);
} else {
alloc_chrdev_region(&dtsled.devid, 0, DTSLED_CNT, DTSLED_NAME);
dtsled.major = MAJOR(dtsled.devid);
dtsled.minor = MINOR(dtsled.devid);
}
printk("dtsled major=%d,minor=%drn",dtsled.major, dtsled.minor);
dtsled.cdev.owner = THIS_MODULE;
cdev_init(&dtsled.cdev, &dtsled_fops);
cdev_add(&dtsled.cdev, dtsled.devid, DTSLED_CNT);
dtsled.class = class_create(THIS_MODULE, DTSLED_NAME);
if (IS_ERR(dtsled.class)) {
return PTR_ERR(dtsled.class);
}
dtsled.device = device_create(dtsled.class, NULL, dtsled.devid, NULL, DTSLED_NAME);
if (IS_ERR(dtsled.device)) {
return PTR_ERR(dtsled.device);
}
return 0;
}
static void __exit led_exit(void)
{
iounmap(IMX6U_CCM_CCGR1);
iounmap(SW_MUX_GPIO1_IO03);
iounmap(SW_PAD_GPIO1_IO03);
iounmap(GPIO1_DR);
iounmap(GPIO1_GDIR);
cdev_del(&dtsled.cdev);
unregister_chrdev_region(dtsled.devid, DTSLED_CNT);
device_destroy(dtsled.class, dtsled.devid);
class_destroy(dtsled.class);
}
代码关键在获取设备树中的属性数据:因为知道设备树的地址,可以直接通过地址查找"/alphaled",得到设备节点(在创建设备结构体,多加一个成员:struct device_node),得到节点后就要获取属性值,compatible、status、reg等。这里获取reg采用_read_u32_array(),因为我们的reg是一组32位数组。获取reg数组后,可以用ioremap()得到物理地址对应的虚拟地址,也可以通过of_iomap()直接获取虚拟地址。使用设备树推荐第二种。
其余部分和第五章一样。
3.测试与前面一样。
4.设备树的编译更换运行学习资料是用正点,但是开发板用的东山,设备树描述板级信息,所以我们用了东山的设备树文件。
东山用的是4.9.88版本源码,正点是4.1.15,都是4版本问题不大。板子到我手里时用的应该是正点的4.1.15版本,因为我下载正点的.ko驱动没有报错。因为要使用东山的设备树,设备树和源码的版本要一致,因此我把东山的4.9.88版本源码重新烧录安装。
进入东山资料下载的4.1.15源码archarmbootdts,找到100ask_imx6ull-14x14.dts,可自行添加节点,完成后返回源码,执行make debs,产生100ask_imx6ull-14x14.dtb文件。此dtb就是要更换的设备树文件。
编译的设备树由两种更换方法:
第一,通过nfs从pc传文件至开发板,把dtb文件替换/boot里的dtb文件,开发板/boot里面应该有两个文件zImage和*.dtb,开发板启动要用的,缺少或者不匹配内核无法启动。Starting Kernel ...之后板子再无其他输出,启动失败!替换成功后可以reboot重新启动开发板,如果正常开机就可以使用新的设备树。
第二,通过东山的缮写工具,100ask_imx6ull_flashing_tool.exe,把Ubuntu的设备树通过FileZila传输到pc上,然后替换/files文件里的.dtb文件。打开.exe,开发板设置为USB启动方式,显示设备已连接,点击更新设备树,怎软件会把dtb文件替换开发板/boot目录下的dtb文件。换成emmc模式,重新启动,可以用新的设备树。
第二种比较麻烦,推荐第一种。
安装时遇到一系列问题,以下作为记录。在使用100ASK ToolV3.0工具烧写emmc.img后,emmc启动开发板,发现/boot目录下有三个dtb文件。
当我分别把100ask_imx6ull-14x14.dtb和100ask_myir_imx6ull_mini.dtb删除后,板子可以正常启动,但我把100ask_imx6ull_mini.dtb删除后,板子就启动不了,可以判断他用的是mini设备树。怪不得我修改14x14.dtb的时候重启板子节点没有改变。可我板子是全功能的pro板啊!然后我把14x14.dtb文件重命名为mini.dtb,启动不了。
r然后我使用mfgtool 烧写整个系统到 EMMC 上,启动发现是正常的,/boot里面有一个dtb文件,就是14x14的,之后替换也正常。
更新系统后,安装驱动文件显示版本不匹配,但我确实都是4.1.15,不过驱动仍然正常使用,此报错先搁置,遇到不能用的时候再探讨。
之后需要重点学学习系统移植篇,对内核系统还是不熟悉。捣腾两周才算解决。



