zoukankan      html  css  js  c++  java
  • RK:GPIO的基操、中断使用(一)

    只是一些暗恋而已 https://blog.csdn.net/qq_30624591/article/details/87834629

    http://wiki.t-firefly.com/zh_CN/AIO-3288C/driver_gpio.html

    GPIO的使用场景
    作为输入设备 :
    光感设备、红外设备、GPIO 按键设备、等等为输入设备,高低电平变化由这些
    设备来控制;
    作为输出设备:
    继电器、开关、需要由高低电平变化控制的设备均为输出设备;

    一、RK3288 GPIO
    1.1、查看gpio信息 cat /sys/kernel/debug/gpio
    1.2、RK3288有9组GPIO bank:GPIO0~GPIO8,每组又以 A0~A7, B0~B7, C0~C7, D0~D7 作为编号区分(不是所有 bank 都有全部编号,例如 GPIO0 就只有A0~C7)。 所有的GPIO在上电后的初始状态都是输入模式,可以通过软件设为上拉或下拉,也可以设置为中断脚,驱动强度都是可编程的。 每个 GPIO 口除了通用输入输出功能外,还可能有其它复用功能。
    1.3、PIN

        'A0': 0,    'A1': 1,    'A2': 2,    'A3': 3,    'A4': 4,    'A5': 5,    'A6': 6,    'A7': 7,
        'B0': 8,    'B1': 9,    'B2':10,    'B3':11,    'B4':12,    'B5':13,    'B6':14,    'B7':15,
        'C0':16,    'C1':17,    'C2':18,    'C3':19,    'C4':20,    'C5':21,    'C6':22,    'C7':23,
        'D0':24,    'D1':25,    'D2':26,    'D3':27,    'D4':28,    'D5':29,    'D6':30,    'D7':31,

    1.4、RK323 GPIO

         
    rk3288-tb_zk_r323.dts

    gpio_0 = <&gpio8 6 GPIO_ACTIVE_HIGH>;
    gpio_1 = <&gpio8 7 GPIO_ACTIVE_HIGH>;
    gpio_2 = <&gpio8 8 GPIO_ACTIVE_HIGH>;
    gpio_3 = <&gpio8 9 GPIO_ACTIVE_HIGH>;

     二、GPIO的基操

    2.1、下面是常用的 GPIO API 定义:

    #include <linux/gpio.h>
    #include <linux/of_gpio.h> 
    enum of_gpio_flags {
        OF_GPIO_ACTIVE_LOW = 0x1,
    }; 
    int of_get_named_gpio_flags(struct device_node *np, const char *propname,
                   int index, enum of_gpio_flags *flags); 
    int gpio_is_valid(int gpio); 
    int gpio_request(unsigned gpio, const char *label); 
    void gpio_free(unsigned gpio); 
    int gpio_direction_input(int gpio); 
    int gpio_direction_output(int gpio, int v);

     2.2、操作普通GPIO说明

    2.2.1、在dts添加gpio的引用描述:在dts文件上添加,通常在设备树中 gpio的配置使用,
    这里定义了一个pin脚作为一般的输出输入口

    crush{
    status = "okay";
    compatible = "rockchip,crush";    
    blue_led_gpio = <&gpio8 1 GPIO_ACTIVE_HIGH>;
    };

    2.2.2、解析dts并且获取gpio口:函数返回值就得到gpio号

    int of_get_named_gpio_flags(struct device_node *np, const char *propname,
    int index, enum of_gpio_flags *flags);

    2.2.3、判断gpio口是否合法能用

    int gpio_is_valid(int number)

    2.2.4、申请gpio口:gpio_request的第一个参数是需要申请的gpio号。第二个参数是我们给该gpio起个名字,
    申请成功后,可以通过/sys/kernel/debug/gpio文件查看到该GPIO的状态

    int gpio_request(unsigned gpio, const char *label)

    2.2.5、设置gpio口的方向,如果是设置方向为输出的话同时设置电平拉高或拉低

    int gpio_direction_input(unsigned gpio); //设置gpio为输入
    
    int gpio_direction_output(unsigned gpio, int value); //设置gpio为输出,且设置电平

    2.2.6、操作gpio口(拉高或者拉低gpio的电平,value为1是拉高,0是拉低)

    void gpio_set_value(unsigned int gpio, int value);

    2.2.7、获取gpio口的状态:get到1为高电平,得到0为低电平

    ret = gpio_get_value(unsigned gpio);

    2.2.8、释放gpio口:在remove函数中添加对应的释放操作

    gpio_free(int number)

    三、RK3288 Android7.1 GPIO驱动控制LED灯亮灭

    3.1、目的:a、/sys/class/crush/crush_gpio/device

                       b、对红蓝灯的read、write

    3.2、crush.c

    #include <linux/module.h>
    #include <linux/device.h>
    #include <linux/err.h>
    #include <linux/kdev_t.h>
    #include <linux/idr.h>
    #include <linux/gfp.h>
    #include <linux/gpio.h>
    #include <linux/of_gpio.h>
    #include <linux/of_device.h>
    #include <linux/of_address.h>
    #include <linux/platform_device.h>
    #include <linux/delay.h>
    
    static struct class *crush_class;//定义设备类
    
    struct crush_data
    {
                    struct device *classdev;
                    int blue;
                    int red;
                    int gpio0;//default input
                    int gpio2;//default output 0        
    };
    
    static struct crush_data *ch_data;
    
    static ssize_t show_name(struct device *dev,struct device_attribute *attr, char *buf)
    {
            return sprintf(buf, "crush gatsby
    ");
    }
    
    //执行cat 会调用到此函数  show对应的是read
    static ssize_t show_blue(struct device *dev,struct device_attribute *attr, char *buf)
    {
            return sprintf(buf, "%d
    ", gpio_get_value(ch_data->blue));
    }
    
    //执行echo 会调用到此函数 store对应的是write
    static ssize_t store_blue(struct device *dev,struct device_attribute *attr, const char *buf, size_t count)
    {
            unsigned long blue;
            int rc;
        
            rc = kstrtoul(buf, 0, &blue);
            if (rc)
                return rc;
                
            if(blue == 0000)
            {
                gpio_direction_output(ch_data->blue,0);
            }
            else if(blue == 0001)
            {
                gpio_direction_output(ch_data->blue,1);
            }        
            rc = count;    
        
            return rc;
    }
    
    //          设备属性文件名   mode(权限) read                write
    //0660 -rw-rw----  Linux4.4只能给 0660 
    static DEVICE_ATTR(name,                     0660, show_name,                     NULL);
    static DEVICE_ATTR(blue,                     0660, show_blue,                     store_blue);
    
    static struct attribute *crush_attributes[] = {
            &dev_attr_name.attr,
            &dev_attr_blue.attr,
            NULL
    };
    
    static const struct attribute_group crush_attr_group = 
    {
            .attrs    = crush_attributes,
    };
    
    //probe初始化函数   cdev 分配设备对象空间
    static int crush_driver_probe(struct platform_device *pdev)
    {
              struct device_node *np = pdev->dev.of_node;
              int gpio, err;
                        
              
              ch_data = devm_kzalloc(&pdev->dev, sizeof(struct crush_data),GFP_KERNEL);
              if (!ch_data)
                  return -ENOMEM;
              
              err = sysfs_create_group(&pdev->dev.kobj, &crush_attr_group);
              if (err)
                  return err;
              
              //在 /sys/class/ 目录下生成 crush_gpio
              ch_data->classdev=device_create(crush_class, &pdev->dev, MKDEV(0, 0), NULL,"crush_gpio", 0);
              
              gpio = of_get_named_gpio(np, "blue_led_gpio", 0);
              ch_data->blue=gpio;
              
              //判断GPIO是否合法能用
              if (!gpio_is_valid(gpio)) 
              {
                    dev_err(&pdev->dev, "invalid blue_led_gpio %d
    ", gpio);
              } 
                 
              return 0;
                
    }
    
    static int crush_driver_remove(struct platform_device *pdev)
    {
            device_unregister(ch_data->classdev);
            sysfs_remove_group(&pdev->dev.kobj, &crush_attr_group);
            return 0;
    }
    
    static const struct of_device_id crush_match[] = {
        { .compatible = "rockchip,crush" },
        {},
    };
    static struct platform_driver crush_driver = {
            .probe = crush_driver_probe,
            .remove = crush_driver_remove,
            .driver = {
                .name = "crush",
                .owner = THIS_MODULE,
                .of_match_table = of_match_ptr(crush_match),
            },
    };
    
    static int __init crush_init(void)
    {
            printk("crush_init
    ");
            //在/sys/class目录下生成 crush目录
            crush_class = class_create(THIS_MODULE, "crush");
            if (IS_ERR(crush_class)) 
            {
                printk("couldn't create sysfs crush class
    ");
                return PTR_ERR(crush_class);
            }
            
            return platform_driver_register(&crush_driver);
    }
    
    static void __exit crush_exit(void)
    {
            class_destroy(crush_class);
            platform_driver_unregister(&crush_driver);
    }
    
    module_init(crush_init);
    module_exit(crush_exit);
    
    MODULE_AUTHOR("Gatsby");
    MODULE_DESCRIPTION("hardware monitoring sysfs/class support");
    MODULE_LICENSE("GPL");

    3.3、DEVICE_ATTR Linux4.4 用不了0777

     在 device ockchipcommoninit.rk30board.rc 

    chmod 0777 /sys/class/xh_custom/xh_custom_gpio/device/blue

    四、gpio 做中断脚使用,xh_key 驱动解析
    4.1、中断服务函数

    irq_handler_t irq16_handler(int irq,void *dev_id)

    4.2、从dts中转换gpio编号到对应irq号,把GPIO的PIN值转换为相应的IRQ值

    static inline int gpio_to_irq(unsigned int gpio)
    {
        return __gpio_to_irq(gpio);
    }

    4.3、中断注册函数

    request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
    const char *name, void *dev_id)

    a、irq中断号(和平台架构相关,结合datasheet以及平台文件) IRQ_EINT(x)
    b、中断处理函数: 中断发生时,系统调用这个函数,dev_id参数将被传递给它
    c、中断标记:上升或下降中断触发
    d、中断名字:
    e、dev_id:一般使用设备的设备结构体或者NULL
    f、返回值:request_irq()返回0表示成功,返回-EINVAL表示中断号无效或处理函数指针为NULL,返回-EBUSY表示中断已经被占用,且不能被共享。

    4.4、中断卸载函数:

    void free_irq(unsigned int irq, void *dev_id)

    4.5、xh_key.c

    //中断服务函数
    static irqreturn_t gpio_key_irq(int irq, void *dev_id)
    {
    
        mod_timer(&key_timer, jiffies + (HZ /200));  //5ms
         
        return IRQ_HANDLED;
    }
            
    if (!gpio_is_valid(gpio)) 
    {
            dev_err(&pdev->dev, "invalid gpio_0 %d
    ", gpio);
    } 
    else 
    {       //转换gpio编号到对应irq号
            xh_data->irq = gpio_to_irq(xh_data->gpio0);
                                                  //默认值  指定中断触发类型:上升沿有效  下降沿有效
            request_irq(xh_data->irq, gpio_key_irq, IRQF_SHARED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,"gpio_key_irq", xh_data);
    }    
  • 相关阅读:
    Installing Oracle Database 12c Release 2(12.2) RAC on RHEL7.3 in Silent Mode
    周四测试
    假期生活
    《人月神话》阅读笔记三
    《人月神话》阅读笔记二
    《人月神话》阅读笔记一
    软件进度7
    软件进度6
    软件进度5
    软件进度4
  • 原文地址:https://www.cnblogs.com/crushgirl/p/13306123.html
Copyright © 2011-2022 走看看