6.IMX6ULL LINUX驱动之基于设备树的LED驱动

481 阅读3分钟

一、编写Led的设备树文件

上一节学习了设备树的语法了解到了设备树就是用来存储一些设备的信息的文件。那么我们现在就来写led的设备树文件。我们在根下创建一个结点,就拿我的名字来命名把。如下代码所示,主要的是reg地址,都是存储的点灯所使用的寄存器地址。

Pintitus{
        #address-cells = <1>;
        #size-cells = <1>;
        status = "okay";
        reg = <
             0x020C406C   0x04 /*GPIO1的CCM1*/
             0x020C4074   0x04 /*GPIO4的CCM3*/
            0x020E006C   0x04 /*红灯的复用寄存器        GPIO1_4*/       
            0x020E02F8   0x04 /*红灯的电气特性寄存器*/
            0x020E01E0   0x04 /*绿灯的复用寄存器        GPIO4_20*/
            0X020E046C   0x04 /*绿灯的电气特性寄存器*/
            0x020E01DC   0x04 /*蓝灯的复用寄存器        GPIO4_19*/
            0X020E0468   0x04 /*蓝灯的电气特性寄存器*/
            0x0209C000   0x04 /*GPIO1_DR*/
            0x0209C004   0x04 /*GPIO1_GDIR*/
            0x020A8000   0x04 /*GPIO4_DR*/
            0x020A8004   0x04 /*GPIO4_GDIR*/
        >;
    };

二、设备树获取信息的驱动程序

思想:

通过获取的设备树属性保存起来进行地址映射,或者使用of_iomap函数映射地址+大小。

    /*  获取设备树结点    */
    led.nd = of_find_node_by_path("/pintitus");
    if(led.nd == NULL){
        ret = -EINVAL;
        printk("ERROR TO GET of_find_node_by_path\r\n");
    }
​
    /*  获取属性reg数组:笔记一定要使用u32的    */
    ret = of_property_read_u32_array(led.nd ,"reg" , regdata , 24);
    if(ret < 0){
        printk("ERROR TO GET of_property_read_u32_array\r\n");
    }else{
        printk("reg data :\r\n");
        for(i = 0;i < 24 ; i++ )
            printk("%#x \r\n",regdata[i]);
    }
/*
    第一种方法
*/
    /*  通过使用设备树的reg信息结点来映射地址    */
    IMX6U_CCM_CCGR1 = ioremap(regdata[0] , regdata[1]);
    IMX6U_CCM_CCGR3 = ioremap(regdata[2] , regdata[3]);
    IOMUXC_GPIO1_IO04_GPIO1_IO04 = ioremap(regdata[4] , regdata[5]);
    IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO04 = ioremap(regdata[6] , regdata[7]);
    IOMUXC_CSI_HSYNC_GPIO4_IO20 = ioremap(regdata[8] , regdata[9]);
    IOMUXC_SW_PAD_CTL_PAD_CSI_HSYNC = ioremap(regdata[10] , regdata[11]);
    IOMUXC_CSI_VSYNC_GPIO4_IO19 = ioremap(regdata[12] , regdata[13]);
    IOMUXC_SW_PAD_CTL_PAD_CSI_VSYNC = ioremap(regdata[14] , regdata[15]);
    GPIO1_DR = ioremap(regdata[16] , regdata[17]);
    GPIO1_GDIR = ioremap(regdata[18] , regdata[19]);
    GPIO4_DR = ioremap(regdata[20] , regdata[21]);
    GPIO4_GDIR = ioremap(regdata[22] , regdata[23]);
/*
    第二种方法
*/
    /*  of类的函数还有一种通过设备结点的索引号直接获取地址  */
    IMX6U_CCM_CCGR1 = of_iomap( led.nd , 0);
    IMX6U_CCM_CCGR3 = of_iomap( led.nd , 1);
......
​

部分程序:

void Led_Init(void){
    u32 tmp = 0;
/*  1.初始化LED地址映射 */
    IMX6U_CCM_CCGR1 = ioremap(regdata[0] , regdata[1]);
    IMX6U_CCM_CCGR3 = ioremap(regdata[2] , regdata[3]);
    IOMUXC_GPIO1_IO04_GPIO1_IO04 = ioremap(regdata[4] , regdata[5]);
    IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO04 = ioremap(regdata[6] , regdata[7]);
    IOMUXC_CSI_HSYNC_GPIO4_IO20 = ioremap(regdata[8] , regdata[9]);
    IOMUXC_SW_PAD_CTL_PAD_CSI_HSYNC = ioremap(regdata[10] , regdata[11]);
    IOMUXC_CSI_VSYNC_GPIO4_IO19 = ioremap(regdata[12] , regdata[13]);
    IOMUXC_SW_PAD_CTL_PAD_CSI_VSYNC = ioremap(regdata[14] , regdata[15]);
    GPIO1_DR = ioremap(regdata[16] , regdata[17]);
    GPIO1_GDIR = ioremap(regdata[18] , regdata[19]);
    GPIO4_DR = ioremap(regdata[20] , regdata[21]);
    GPIO4_GDIR = ioremap(regdata[22] , regdata[23]);
    /*  2.初始化时钟    */
    /*  3.电气特性设置    */
    /*  4.寄存器设置    */
}
/*
    注册与注销设备
*/
static int __init led_init(void){  
    int     ret = 0;
    const   char *name;
    u8      i = 0;
    /*  获取设备树结点    */
    led.nd = of_find_node_by_path("/pintitus");
    if(led.nd == NULL){
        ret = -EINVAL;
        printk("ERROR TO GET of_find_node_by_path\r\n");
    }
​
    /*  获取属性状态字符串    */
    ret = of_property_read_string(led.nd, "status", &name);
    if(ret < 0){
        printk("ERROR TO GET of_property_read_string\r\n");
    }else{
        printk("status = %s\r\n" , name);
    }
    /*  获取属性reg数组:笔记一定要使用u32的    */
    ret = of_property_read_u32_array(led.nd ,"reg" , regdata , 24);
    if(ret < 0){
        printk("ERROR TO GET of_property_read_u32_array\r\n");
    }else{
        printk("reg data :\r\n");
        for(i = 0;i < 24 ; i++ )
            printk("%#x \r\n",regdata[i]);
    }
    
    /*  1.注册字符设备  */
    led.major = 0;
    if(led.major){
        led.devid = MKDEV(led.major , 0);
        ret = register_chrdev_region(led.devid , LED_CNT , LED_NAME);
    }else{
        ret = alloc_chrdev_region(&led.devid , 0 , LED_CNT , LED_NAME);
        led.major = MAJOR(led.devid);
        led.minor = MINOR(led.devid);
    }
    if(ret < 0){
        goto failed_devid;
    }
    printk("led major = %d , minor = %d\r\n" ,led.major , led.minor );
​
​
    /*  2.添加字符设备  */
    led.cdev.owner = THIS_MODULE;
    cdev_init(&led.cdev , &led_fops);
    ret = cdev_add(&led.cdev , led.devid , LED_CNT);
    if(ret < 0)
        goto failed_cdev;
​
    /*  3.自动创建设备结点  */
    led.class = class_create(THIS_MODULE , LED_NAME);
    if(IS_ERR(led.class)){
        ret = PTR_ERR(led.class);
        goto failed_class;
    }
​
    led.device = device_create(led.class , NULL , led.devid , NULL ,LED_NAME);
    if(IS_ERR(led.device)){
        ret = PTR_ERR(led.device);
        goto failed_device;
    }
​
    Led_Init();
    return 0;
​
failed_device:
    class_destroy(led.class);
    printk("failed_device\r\n");
failed_class:
    cdev_del(&led.cdev);
    printk("failed_class\r\n");
failed_cdev:
    unregister_chrdev_region(led.devid , LED_CNT);
    printk("failed_cdev\r\n");
failed_devid:
    return ret;
}
static void __exit led_exit(void){
    printk("-----Led_exit-----\n");
    
    /*取消LED地址映射*/
    iounmap(IMX6U_CCM_CCGR1);
    iounmap(IMX6U_CCM_CCGR3);
    iounmap(IOMUXC_GPIO1_IO04_GPIO1_IO04);
    iounmap(IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO04);
    iounmap(IOMUXC_CSI_HSYNC_GPIO4_IO20);
    iounmap(IOMUXC_SW_PAD_CTL_PAD_CSI_HSYNC);
    iounmap(IOMUXC_CSI_VSYNC_GPIO4_IO19);
    iounmap(IOMUXC_SW_PAD_CTL_PAD_CSI_VSYNC);
    iounmap(GPIO1_DR);
    iounmap(GPIO1_GDIR);
    iounmap(GPIO4_DR);
    iounmap(GPIO4_GDIR);
​
    /*删除字符设备*/
    cdev_del(&led.cdev);
    /*释放设备号*/
    unregister_chrdev_region(led.devid , LED_CNT);
    /*摧毁设备*/
    device_destroy(led.class , led.devid);
    /*摧毁类*/
    class_destroy(led.class);
}
module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");

\