节点追加数据方法
设备树下的 LED 驱动实验
cd kernel/arch/arm64/boot/dts/rockchip/
vim rk3568-atk-evb1-ddr4-v10.dtsi
SDK根目录下
./build.sh kernel
烧录内核文件
应用程序代码
static int __init led_init(void)
{
u32 val = 0;
int ret;
u32 regdata[16];
const char *str;
struct property *proper;
/* 获取设备树中的属性数据 */
/* 1、获取设备节点:rk3568_led */
dtsled.nd = of_find_node_by_path("/rk3568_led");
if(dtsled.nd == NULL) {
printk("rk3568_led node not find!\r\n");
goto fail_find_node;
} else {
printk("rk3568_led node find!\r\n");
}
/* 2、获取compatible属性内容 */
proper = of_find_property(dtsled.nd, "compatible", NULL);
if(proper == NULL) {
printk("compatible property find failed\r\n");
} else {
printk("compatible = %s\r\n", (char*)proper->value);
}
/* 3、获取status属性内容 */
ret = of_property_read_string(dtsled.nd, "status", &str);
if(ret < 0){
printk("status read failed!\r\n");
} else {
printk("status = %s\r\n",str);
}
/* 4、获取reg属性内容 */
ret = of_property_read_u32_array(dtsled.nd, "reg", regdata, 16);
if(ret < 0) {
printk("reg property read failed!\r\n");
} else {
u8 i = 0;
printk("reg data:\r\n");
for(i = 0; i < 16; i++)
printk("%#X ", regdata[i]);
printk("\r\n");
}
/* 初始化LED */
/* 1、寄存器地址映射 */
PMU_GRF_GPIO0C_IOMUX_L_PI = of_iomap(dtsled.nd, 0);
PMU_GRF_GPIO0C_DS_0_PI = of_iomap(dtsled.nd, 1);
GPIO0_SWPORT_DR_H_PI = of_iomap(dtsled.nd, 2);
GPIO0_SWPORT_DDR_H_PI = of_iomap(dtsled.nd, 3);
/* 2、设置GPIO0_C0为GPIO功能。*/
val = readl(PMU_GRF_GPIO0C_IOMUX_L_PI);
val &= ~(0X7 << 0); /* bit2:0,清零 */
val |= ((0X7 << 16) | (0X0 << 0)); /* bit18:16 置1,允许写bit2:0,
bit2:0:0,用作GPIO0_C0 */
writel(val, PMU_GRF_GPIO0C_IOMUX_L_PI);
/* 3、设置GPIO0_C0驱动能力为level5 */
val = readl(PMU_GRF_GPIO0C_DS_0_PI);
val &= ~(0X3F << 0); /* bit5:0清零*/
val |= ((0X3F << 16) | (0X3F << 0)); /* bit21:16 置1,允许写bit5:0,
bit5:0:0,用作GPIO0_C0 */
writel(val, PMU_GRF_GPIO0C_DS_0_PI);
/* 4、设置GPIO0_C0为输出 */
val = readl(GPIO0_SWPORT_DDR_H_PI);
val &= ~(0X1 << 0); /* bit0 清零*/
val |= ((0X1 << 16) | (0X1 << 0)); /* bit16 置1,允许写bit0,
bit0,高电平 */
writel(val, GPIO0_SWPORT_DDR_H_PI);
/* 5、设置GPIO0_C0为低电平,关闭LED灯。*/
val = readl(GPIO0_SWPORT_DR_H_PI);
val &= ~(0X1 << 0); /* bit0 清零*/
val |= ((0X1 << 16) | (0X0 << 0)); /* bit16 置1,允许写bit0,
bit0,低电平 */
writel(val, GPIO0_SWPORT_DR_H_PI);
/* 注册字符设备驱动 */
/* 1、创建设备号 */
if (dtsled.major) { /* 定义了设备号 */
dtsled.devid = MKDEV(dtsled.major, 0);
ret = register_chrdev_region(dtsled.devid, DTSLED_CNT, DTSLED_NAME);
if(ret < 0) {
pr_err("cannot register %s char driver [ret=%d]\n",DTSLED_NAME, DTSLED_CNT);
goto fail_devid;
}
} else { /* 没有定义设备号 */
ret = alloc_chrdev_region(&dtsled.devid, 0, DTSLED_CNT, DTSLED_NAME); /* 申请设备号 */
if(ret < 0) {
pr_err("%s Couldn't alloc_chrdev_region, ret=%d\r\n", DTSLED_NAME, ret);
goto fail_devid;
}
dtsled.major = MAJOR(dtsled.devid); /* 获取分配号的主设备号 */
dtsled.minor = MINOR(dtsled.devid); /* 获取分配号的次设备号 */
}
printk("dtsled major=%d,minor=%d\r\n",dtsled.major, dtsled.minor);
/* 2、初始化cdev */
dtsled.cdev.owner = THIS_MODULE;
cdev_init(&dtsled.cdev, &dtsled_fops);
/* 3、添加一个cdev */
ret = cdev_add(&dtsled.cdev, dtsled.devid, DTSLED_CNT);
if(ret < 0)
goto del_unregister;
/* 4、创建类 */
dtsled.class = class_create(THIS_MODULE, DTSLED_NAME);
if (IS_ERR(dtsled.class)) {
goto del_cdev;
}
/* 5、创建设备 */
dtsled.device = device_create(dtsled.class, NULL, dtsled.devid, NULL, DTSLED_NAME);
if (IS_ERR(dtsled.device)) {
goto destroy_class;
}
return 0;
destroy_class:
class_destroy(dtsled.class);
del_cdev:
cdev_del(&dtsled.cdev);
del_unregister:
unregister_chrdev_region(dtsled.devid, DTSLED_CNT);
fail_devid:
led_unmap();
fail_find_node:
return -EIO;
}