1、修改设备树文件
在根节点/创建一个LED的子节点
设备树下的LED驱动_驱动程序2、驱动编写
(1)入口函数

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

	/* 获取设备树中的属性数据 */
	
	//1、获取根节点下的设备节点 muggle_led
	dtsled.nd = of_find_node_by_path("/muggle_led");

	//判断获得的节点是否正确
	if(dtsled.nd == NULL)
	{
		printk("muggle-led node  can not found!\r\n");
		return -EINVAL;
	}
	else
	{
		printk("muggle-led node has been found!\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 read success: %s\r\n", str);
	}

	//4、获取reg属性内容
	ret = of_property_read_u32_array(dtsled.nd, "reg", regdata,  10);
	if(ret < 0 )
	{
		printk("reg 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");
	}


	/* 初始化LED */
#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);	//映射reg的数据
	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

	//使能GPIO1时钟
	val = readl(IMX6U_CCM_CCGR1);				//读取数值
	val &= ~(3<<26);							//引脚清0
	val |= (3<<26);								//设置新值
	writel(val, IMX6U_CCM_CCGR1);				//写入数值

	//设置GPIO_IO03的复用功能,将其复用为GPIO_IO03最后设置IO属性
	writel(5, SW_MUX_GPIO1_IO03);
	writel(5, SW_PAD_GPIO1_IO03);

	//4、设置GPIO_GDIR输出功能
	val = readl(GPIO1_GDIR);
	val &= (1<<3);
	val |= (1<<3);
	writel(val, GPIO1_GDIR);


	//5、默认关闭LED
	val = readl(GPIO1_DR);
	val |= (1<<3);
	writel(val, GPIO1_DR);


	/* 注册字符设备驱动 */
	//1 创建设备号
	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=%d\r\n", dtsled.major, dtsled.minor);

	//2 初始化 cdev
	dtsled.cdev.owner = THIS_MODULE;
	cdev_init(&dtsled.cdev, &dtsled_fops);

	//3 添加一个cdev
	cdev_add(&dtsled.cdev, dtsled.devid, DTSLED_CNT);

	//4 创建一个类
	dtsled.class = class_create(THIS_MODULE, DTSLED_NAME);
	if(IS_ERR(dtsled.class))
	{
		return PTR_ERR(dtsled.class);
	}

	//5 创建设备
	dtsled.device = device_create(dtsled.class, NULL, dtsled.devid, NULL, DTSLED_NAME);
	if(IS_ERR(dtsled.device))
	{
		return PTR_ERR(dtsled.class);
	}
	return 0;
		
}

(1.1)是遍历设备树的根节点,获取compatiblestatusreg属性,获取到reg中引脚的地址数据,然后of_iomap映射备用。
(1.2)使能GPIO引脚,写入数据。
(1.3)注册字符设备驱动:创建设备号、初始化cdev、添加cdev时加入dtsled_fops结构体、创建一个类最后创建设备
(1.4)编写dtsled_fopsopenreadwriterelease函数
(1.4.1)open函数主要实现私有数据的设置
(1.4.2)write函数从用户空间获取数据,操作LED关停

(2)出口函数

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);/* 删除 cdev */
	unregister_chrdev_region(dtsled.devid, DTSLED_CNT);/*注销设备号*/

	device_destroy(dtsled.class, dtsled.devid);
	class_destroy(dtsled.class);
}

更多精彩文章请关注嵌入式机器人公众号平台
设备树下的LED驱动_设备号_02