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

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM