設備樹下的LED驅動

1、修改設備樹文件
在根節點/創建一個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);
}

更多精彩文章請關注嵌入式機器人公衆號平臺
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章