有了设备树以后,我们可以将寄存器信息保存到设备树,即便是更换了一个设备,我们也无需修改驱动文件,只需要修改设备树文件并重新编译。
下面介绍两种通过设备树驱动 LED 的最简单的方式,这两种方式的主要是设备树中 reg 属性的写法不同,这也就影响到调用的API也会有所不同。
一、方法1
1、添加设备树节点
下面是在设备树的根节点下添加节点,节点路径为 /alientek-led。
alientek-led {compatible = "alientek-led";#address-cells = <1>;#size-cells = <1>;status = "okay";reg = <0x20C406C 0x04 /* CCM_CCGR1_BASE */0x20E0068 0x04 /* IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03_BASE */0x20E02F4 0x04 /* IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03_BASE */0x209C004 0x04 /* GPIO1_GDIR_BASE */0x209C000 0x04 /* GPIO1_DR_BASE */>;
};
2、驱动获取设备树节点
在读取设备树属性之前需要先获取到设备树节点,在上一节中已经介绍了获取设备树节点的API,详情可参考: 操作设备树节点 API
struct chrdev_led_t{// ...struct device_node* dtsNode; /* 设备树节点 */
};
static struct chrdev_led_t chrdev_led;// 获取设备树节点
chrdev_led.dtsNode = of_find_node_by_path("/alientek-led");
if(chrdev_led.dtsNode == NULL)
{ printk("node cannot be found!\n");return -1;
}
3、驱动读取设备树 reg 属性
如果 reg 属性采用的是当前写法,需要搭配 ioremap 函数使用。详情可参考: 操作设备树节点 API
ret = of_property_read_u32_array(chrdev_led.dtsNode, "reg", regData, 10);
if (ret < 0)
{printk("reg property read failed!\n");return -1;
}
/* 建立物理地址和虚拟地址的映射 */
CCM_CCGR1 = ioremap(regData[0], regData[1]);
IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03 = ioremap(regData[2], regData[3]);
IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03 = ioremap(regData[4], regData[5]);
GPIO1_GDIR = ioremap(regData[6], regData[7]);
GPIO1_DR = ioremap(regData[8], regData[9]);
后续外设初始化内容可以参考: 寄存器驱动 LED
二、方法2
1、添加设备树节点
下面是在设备树的根节点下添加节点,节点路径为 /alientek-led。
alientek-led {compatible = "alientek-led";#address-cells = <1>;#size-cells = <1>;status = "okay";reg = <0x20C406C 0x04>,<0x20E0068 0x04>,<0x20E02F4 0x04>,<0x209C004 0x04>,<0x209C000 0x04>;
};
2、驱动获取设备树节点
获取设备树节点的方式同方法一。
3、驱动读取设备树 reg 属性
如果 reg 属性采用的是当前写法,需要搭配 of_iomap 函数使用。 详情可参考: 操作设备树节点 API
/* 建立物理地址和虚拟地址的映射 */
CCM_CCGR1 = of_iomap(chrdev_led.dtsNode, 0);
IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03 = of_iomap(chrdev_led.dtsNode, 1);
IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03 = of_iomap(chrdev_led.dtsNode, 2);
GPIO1_GDIR = of_iomap(chrdev_led.dtsNode, 3);
GPIO1_DR = of_iomap(chrdev_led.dtsNode, 4);
后续外设初始化内容可以参考: 寄存器驱动 LED