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\n");
}

//执行cat 会调用到此函数  show对应的是read
static ssize_t show_blue(struct device *dev,struct device_attribute *attr, char *buf)
{
        return sprintf(buf, "%d\n", 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\n", 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\n");
        //在/sys/class目录下生成 crush目录
        crush_class = class_create(THIS_MODULE, "crush");
        if (IS_ERR(crush_class)) 
        {
            printk("couldn't create sysfs crush class\n");
            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\rockchip\common\init.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\n", 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);
}    

 

五.查看gpio 输入输出状态

cat /sys/kernel/debug/gpio

  

posted @ 2020-07-15 16:11  CrushGirl  阅读(5082)  评论(0编辑  收藏  举报