• 设备树学习之(二)点灯【转】


    本文转载自:http://blog.csdn.net/lizuobin2/article/details/54563829

    开发板:tiny4412SDK + S702 + 4GB Flash 
    要移植的内核版本:Linux-4.4.0 (支持device tree) 
    u-boot版本:友善之臂自带的 U-Boot 2010.12 
    busybox版本:busybox 1.25

    目标: 
    学习设备树中GPIO控制器的使用,实现配置引脚为输出功能,写简单的字符设备驱动程序,实现点亮LED。

    原理图: 
    这里写图片描述 
    tiny4412 核心板上有6颗LED,这里我们只控制其中4颗,它们分别接在GPM4_0、GPM4_1、GPM4_2、GPM4_3 引脚。想要点亮LED,首先得配置引脚为输出功能,输出低电平时LED点亮,高电平时,LED熄灭。重点在于设备树中GPIO控制器资源的使用。

    设备树参考:

    参考:Samsung GPIO and Pin Mux/Config controller
    Example 1: A pin-controller node with pin groups.
        pinctrl_0: pinctrl@11400000 { 
            compatible = "samsung,exynos4210-pinctrl";
            reg = <0x11400000 0x1000>;
            interrupts = <0 47 0>;
            /* ... */
            uart0_data: uart0-data { 
                samsung,pins = "gpa0-0", "gpa0-1";
                samsung,pin-function = <2>;
                samsung,pin-pud = <0>;
                samsung,pin-drv = <0>; 
            };
    Example 3: A uart client node that supports 'default' and 'flow-control' states.
        uart@13800000 { 
            compatible = "samsung,exynos4210-uart";
            reg = <0x13800000 0x100>;
            interrupts = <0 52 0>;
            pinctrl-names = "default", "flow-control;
            pinctrl-0 = <&uart0_data>;
            pinctrl-1 = <&uart0_data &uart0_fctl>; 
        };
      "samsung,pins" property of the child node. The following pin configuration properties are supported.
      - samsung,pin-val: Initial value of pin output buffer.
      - samsung,pin-pud: Pull up/down configuration.
      - samsung,pin-drv: Drive strength configuration.
      - samsung,pin-pud-pdn: Pull up/down configuration in power down mode.
      - samsung,pin-drv-pdn: Drive strength configuration in power down mode.
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    设备树:

    &pinctrl@11000000 {
            led_demo: led{
                    samsung,pins = "gpm4-0", "gpm4-1" ,"gpm4-2", "gpm4-3";
                    samsung,pin-function = <0x1>;   //1为输出
                    samsung,pin-pud = <0x0>;        //没有上拉
                    samsung,pin-drv = <0x0>;        //驱动强度?
            };
    }; 
    
    led_pin {
        compatible         = "tiny4412,led_demo";
        pinctrl-names = "led_demo";
        pinctrl-0 = <&led_demo>;
        tiny4412,int_gpio1 = <&gpm4 0 GPIO_ACTIVE_HIGH>;
        tiny4412,int_gpio2 = <&gpm4 1 GPIO_ACTIVE_HIGH>;
        tiny4412,int_gpio3 = <&gpm4 2 GPIO_ACTIVE_HIGH>;
        tiny4412,int_gpio4 = <&gpm4 3 GPIO_ACTIVE_HIGH>;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    我们在 pinctrl 中增加了 led 节点,它代表了一种引脚功能,比如这里设置的 gpm4_0、gpm4_1、gpm4_2、gpm4_3,引脚功能为 0x01 输出,无上拉等等。在其它地方,我们可以引用它,来表示引脚支持的功能。 
    下面我们增加了 led_pin 节点,它有一个属性 pinctrl-names = “led_demo”,这是我们给引脚功能状态起的名字,如果支持多种功能,可以是字符串列表的形式。字符串的个数要和下面 pinctrl-n 的个数对应,pinctrl-0 引用了我们前面定义的那个将引脚设置为输出功能的属性。 
    在代码中,我们可以用过 pinctrl-names 来获得特定的引脚功能,并设置它。如果 pinctrl-names 为 “default”,那么这种功能状态将设置为默认的引脚状态,代码中无需处理。

    代码片段:

    static int led_probe(struct platform_device *pdev) {
    
        struct device *dev = &pdev->dev;
        dev_t devid;
        struct pinctrl *pctrl;
        struct pinctrl_state *pstate;
        pctrl = devm_pinctrl_get(dev);
        if(pctrl == NULL)
        {
            printk("devm_pinctrl_get error
    ");
        }
        pstate = pinctrl_lookup_state(pctrl, "led_demo");
        if(pstate == NULL)
        {
            printk("pinctrl_lookup_state error
    ");
        }
        pinctrl_select_state(pctrl, pstate);//设置为输出模式 
        printk("enter %s
    ",__func__);
        led1 = of_get_named_gpio(dev->of_node, "tiny4412,int_gpio1", 0);;
        led2 = of_get_named_gpio(dev->of_node, "tiny4412,int_gpio2", 0);;
        led3 = of_get_named_gpio(dev->of_node, "tiny4412,int_gpio3", 0);;
        led4 = of_get_named_gpio(dev->of_node, "tiny4412,int_gpio4", 0);;
        if(led1 <= 0)
        {
            printk("%s error
    ",__func__);
            return -EINVAL;
        }
        else
        {
            printk("led1 %d
    ",led1);
            printk("led2 %d
    ",led2);
            printk("led3 %d
    ",led3);
            printk("led4 %d
    ",led4);
            devm_gpio_request_one(dev, led1, GPIOF_OUT_INIT_HIGH, "LED1");
            devm_gpio_request_one(dev, led2, GPIOF_OUT_INIT_HIGH, "LED2");
            devm_gpio_request_one(dev, led3, GPIOF_OUT_INIT_HIGH, "LED3");
            devm_gpio_request_one(dev, led4, GPIOF_OUT_INIT_HIGH, "LED4");
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    完整代码:

    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/cdev.h>
    #include <linux/device.h>
    #include <linux/platform_device.h>
    #include <linux/gpio.h>
    #include <linux/of.h>
    #include <linux/of_gpio.h>
    #include <linux/fs.h>
    #include <asm/uaccess.h>
    
    #define LED_CNT   4
    
    static int  major;
    static struct cdev  led_cdev;   //内核中用cdev描述一个字符设备
    static struct class *cls;
    static int led1,led2,led3,led4;
    
    static ssize_t led_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos)
    {
        char buf;
        int minor = iminor(file->f_inode);
    
        printk("minor is %d
    ",minor);
        printk("%s
    ",__func__);
        if(count != 1){
            printk("count != 1
    "); 
            return 1;
        }
        if (copy_from_user(&buf, user_buf, count))
            return -EFAULT;
    
        printk("rcv %d
    ",buf);
        if(buf == 0x01)
        {
            switch(minor){
            case 0:
                gpio_set_value(led1, 0);
                break;
            case 1:
                gpio_set_value(led2, 0);
                break;
            case 2:
                gpio_set_value(led3, 0);
                break;
            case 3:
                gpio_set_value(led4, 0);
                break;
            default:
                printk("%s rcv minor error
    ",__func__);
            }                       
        }
        else if(buf == 0x0)
        {
            switch(minor){
            case 0:
                gpio_set_value(led1, 1);
                break;
            case 1:
                gpio_set_value(led2, 1);
                break;
            case 2:
                gpio_set_value(led3, 1);
                break;
            case 3:
                gpio_set_value(led4, 1);
                break;
            default:
                printk("%s rcv minor error
    ",__func__);
            }       
        }
    }
    static int led_open(struct inode *inode, struct file *file)
    {
        printk("led_open
    ");
        return 0;
    }
    
    static struct file_operations led_fops = {
        .owner = THIS_MODULE,
        .open  = led_open,
        .write = led_write,
    };
    
    static int led_probe(struct platform_device *pdev) {
    
        struct device *dev = &pdev->dev;
        dev_t devid;
        struct pinctrl *pctrl;
        struct pinctrl_state *pstate;
        pctrl = devm_pinctrl_get(dev);
        if(pctrl == NULL)
        {
            printk("devm_pinctrl_get error
    ");
        }
        pstate = pinctrl_lookup_state(pctrl, "led_demo");
        if(pstate == NULL)
        {
            printk("pinctrl_lookup_state error
    ");
        }
        pinctrl_select_state(pctrl, pstate);//设置为输出模式 
        printk("enter %s
    ",__func__);
        led1 = of_get_named_gpio(dev->of_node, "tiny4412,int_gpio1", 0);;
        led2 = of_get_named_gpio(dev->of_node, "tiny4412,int_gpio2", 0);;
        led3 = of_get_named_gpio(dev->of_node, "tiny4412,int_gpio3", 0);;
        led4 = of_get_named_gpio(dev->of_node, "tiny4412,int_gpio4", 0);;
        if(led1 <= 0)
        {
            printk("%s error
    ",__func__);
            return -EINVAL;
        }
        else
        {
            printk("led1 %d
    ",led1);
            printk("led2 %d
    ",led2);
            printk("led3 %d
    ",led3);
            printk("led4 %d
    ",led4);
            devm_gpio_request_one(dev, led1, GPIOF_OUT_INIT_HIGH, "LED1");
            devm_gpio_request_one(dev, led2, GPIOF_OUT_INIT_HIGH, "LED2");
            devm_gpio_request_one(dev, led3, GPIOF_OUT_INIT_HIGH, "LED3");
            devm_gpio_request_one(dev, led4, GPIOF_OUT_INIT_HIGH, "LED4");
        }
    
        if(alloc_chrdev_region(&devid, 0, LED_CNT, "led") < 0)/* (major,0~1) 对应 hello_fops, (major, 2~255)都不对应hello_fops */
        {
            printk("%s ERROR
    ",__func__);
            goto error;
        }
        major = MAJOR(devid);                     
    
        cdev_init(&led_cdev, &led_fops);        //绑定文件操作函数
        cdev_add(&led_cdev, devid, LED_CNT);    //注册到内核
    
        cls = class_create(THIS_MODULE, "led"); //创建led类,向类中添加设备,mdev会帮我们创建设备节点
        device_create(cls, NULL, MKDEV(major, 0), NULL, "led0"); 
        device_create(cls, NULL, MKDEV(major, 1), NULL, "led1"); 
        device_create(cls, NULL, MKDEV(major, 2), NULL, "led2"); 
        device_create(cls, NULL, MKDEV(major, 3), NULL, "led3"); 
    
    error:
        unregister_chrdev_region(MKDEV(major, 0), LED_CNT);
        return 0;
    }
    
    static int led_remove(struct platform_device *pdev) {
    
        printk("enter %s
    ",__func__);
        device_destroy(cls, MKDEV(major, 0));
        device_destroy(cls, MKDEV(major, 1));
        device_destroy(cls, MKDEV(major, 2));
        device_destroy(cls, MKDEV(major, 3));
        class_destroy(cls);
    
        cdev_del(&led_cdev);
        unregister_chrdev_region(MKDEV(major, 0), LED_CNT);
    
        printk("%s enter.
    ", __func__);
        return 0;
    }
    
    static const struct of_device_id led_dt_ids[] = {
        { .compatible = "tiny4412,led_demo", },
        {},
    };
    
    MODULE_DEVICE_TABLE(of, led_dt_ids);
    
    static struct platform_driver led_driver = {
        .driver        = {
            .name      = "led_demo",
            .of_match_table    = of_match_ptr(led_dt_ids),
        },
        .probe         = led_probe,
        .remove        = led_remove,
    };
    
    static int led_init(void){
        int ret;
        printk("enter %s
    ",__func__);
        ret = platform_driver_register(&led_driver);
        if (ret)
            printk(KERN_ERR "led demo: probe failed: %d
    ", ret);
    
        return ret; 
    }
    
    static void led_exit(void)
    {
        printk("enter %s
    ",__func__);
        platform_driver_unregister(&led_driver);
    }
    
    module_init(led_init);
    module_exit(led_exit);
    
    MODULE_LICENSE("GPL");
  • 相关阅读:
    uni-app开发的应用(小程序,app,web等),使用Node+Koa2开发的后端程序接收上传文件的方法
    ES6学习笔记之数组的扩展
    ES6学习笔记之字符串的扩展
    UnhandledPromiseRejectionWarning: SequelizeConnectionError: Client does not support authentication protocol requested by server; consider upgrading MySQL client
    java之内存分布图
    java的构造方法
    java的局部变量和成员变量以及区别
    java类型转换详解(自动转换和强制转换)
    webpack入门宝典
    js函数之四大调用模式
  • 原文地址:https://www.cnblogs.com/zzb-Dream-90Time/p/7550614.html
Copyright © 2020-2023  润新知