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)是遍歷設備樹的根節點,獲取compatible
、status
、reg
屬性,獲取到reg
中引腳的地址數據,然後of_iomap
映射備用。
(1.2)使能GPIO引腳,寫入數據。
(1.3)註冊字符設備驅動:創建設備號、初始化cdev
、添加cdev
時加入dtsled_fops
結構體、創建一個類最後創建設備
(1.4)編寫dtsled_fops
中open
、read
、write
和release
函數
(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);
}
更多精彩文章請關注嵌入式機器人公衆號平臺