gpio框架及處理流程分析


----------------------------------------------------------------------------------------------
gpio作為一種通用的IO接口,使用方法主要如下:
----------------------------------------------------------------------------------------------
Gpio:每個 GPIO 都代表一個連接到特定引腳或球柵陣列(BGA)封裝中“球珠”的一個位
標准頭文件  <linux/gpio.h> [對外接口]
其中根據是否定義CONFIG_GENERIC_GPIO判斷系統是否支持gpio
頭文件為 <asm/gpio.h>;實現文件為 <driver/gpio/gpiolib.c>

步驟
1. gpio_request(gpio_num, "xx gpio");  申請GPIO, 返回0為申請成功,否則失敗。
2. 設置gpio方向:
int gpio_direction_input(unsigned gpio);                      //設置為輸入
int gpio_direction_output(unsigned gpio, int value);          //設置為輸出,並初始化值為value.
3. 獲取/設置gpio值:    int gpio_cansleep(unsigned gpio);
a.不可睡眠:
gpio_get_value(unsigned gpio);                              //返回value
gpio_set_value(unsigned gpio, int value);                    //設置值
b.可睡眠:(對於有些掛載在I2C,SPI總線上的擴展GPIO,讀寫操作可能會導致睡眠,因此不能在中斷函數中使用。使用下面的函數以區別於正常的GPIO)
int gpio_get_value_cansleep(unsigned gpio);                  //輸入端口:返回零或非零,可能睡眠
void gpio_set_value_cansleep(unsigned gpio, int value);       //輸出端口:可能睡眠
4. void gpio_free(unsigned gpio);                             //釋放GPIO
5. int gpio_is_valid(int number);                             //檢測此gpio口是否有效
批量初始化方法:
申請:
err = gpio_request_array(leds_gpios, ARRAY_SIZE(leds_gpios));
釋放:
gpio_free_array(leds_gpios, ARRAY_SIZE(leds_gpios));

導出gpio到用戶空間:int gpio_export(unsigned gpio, bool direction_may_change);
創建一個sysfs連接到已導出的GPIO節點:
int gpio_export_link(struct device *dev, const char *name, unsigned gpio)
取消導出:void gpio_unexport();

Gpio設置中斷:
    gpio  --->  irq        int gpio_to_irq(unsigned gpio);
    首先應該設置此gpio為輸入狀態,然后獲取對應的中斷號(或錯誤嗎)。返回編號調用:
request_irq()和free_irq()。
    Irq ---> gpio        int irq_to_gpio(unsigned irq);
    返回gpio編號,再調用gpio_get_value()獲取相應的值。(避免使用反向映射,不支持)
    
-----------------------------------------------------------------------------------------    
gpiolib.c (gpio框架)   drivers/gpio/gpiolib.c + include/asm-generic/gpio.h [對gpio chip接口]
-----------------------------------------------------------------------------------------
gpio_chip作為一個接口負責框架層與控制器層的通訊,主要關注點有:
其申請/釋放/方向/獲取輸入/設置輸出/轉irq/base+ngpio[見第三部分控制器驅動]

在框架層的主要關注點在:
1. 如何分配不同chip的gpio域
2. 如何管理隸屬與不同chip的gpio,並反向追溯到chip以調用控制器的具體寄存器操作
3. 統一提前管理了哪些gpio狀態以及是否有必要

在gpiochip_add()中是對gpio chip的注冊,並插入到框架gpio的管理中,

全局變量 static struct gpio_desc gpio_desc[ARCH_NR_GPIOS];
gpio_desc作為整個系統的gpio的管理者,主要包含兩個成員:chip 與 flags.
flags為框架層對gpio的整體管理標識,起MASK的作用。[有:是否已申請/是否是輸出/是否保留等]

插入的規則實現在:gpiochip_find_base(int ngpio)
從后往前遍歷全局gpio desc, 只要是非保留gpio且無宿主chip的連續gpio的空間起址作為base, ngpio則依次向下擴展。
簡單的初始化:掛上對應的chip,檢查是否有設置輸入函數,沒有則設置 IS_OUT位到flags.
[其中關於gpio的設備樹管理暫時不予關注]

request流程: 檢查對應gpio的flags是否FLAG_REQUESTED,如果未被request則調用chip的request接口實現芯片級別的調用。
free流程: 確認已經被REQUESTED, 后啟用芯片級的free.

從系統gpio接口傳遞下來的gpio均是以base為基址,而傳遞到芯片上都是回歸到原始gpio號
------------------------------------------------------------------------------------------
SC8810 gpio控制器驅動
-------------------------------------------------------------------------------------------
這里是整個gpio系統的核心,初步總結需要關注以下幾點:
chip支持的gpio section如何划分
gpio如何配置使能即芯片如何管理眾多gpio口的多個標識位的功能選項
申請/釋放/方向/獲取輸入/設置輸出/轉irq/base+ngpio的處理流程及原理
gpio對應irq號的分配及映射規則
配置一個系統gpio需要的必要步驟

section:(GPIO_BASE:0xE0031000/SPRD_MISC_BASE:0xE0037000)
     {   (GPIO_BASE + 0*0x80),    0x10,    GPIO_SECTION_GPIO    },
     {   (GPIO_BASE + 1*0x80),    0x10,    GPIO_SECTION_GPIO    },
    {   (GPIO_BASE + 2*0x80),    0x10,    GPIO_SECTION_GPIO    },
    {   (GPIO_BASE + 3*0x80),    0x10,    GPIO_SECTION_GPIO    },
    {   (GPIO_BASE + 4*0x80),    0x10,    GPIO_SECTION_GPIO    },
    {   (GPIO_BASE + 5*0x80),    0x10,    GPIO_SECTION_GPIO    },
    {   (GPIO_BASE + 6*0x80),    0x10,    GPIO_SECTION_GPIO    },
    {   (GPIO_BASE + 7*0x80),    0x10,    GPIO_SECTION_GPIO    },
    {   (GPIO_BASE + 8*0x80),    0x10,    GPIO_SECTION_GPIO    },

    {   (SPRD_MISC_BASE + 0x480),   0x10, GPIO_SECTION_GPIO    },
    {   (SPRD_MISC_BASE + 0x4c0),   0xe,  GPIO_SECTION_GPIO    },

當獲取一個gpio號后,需要獲取的基本信息為:在哪個section/偏移量是多大/是何種芯片gpio
獲取方法:
a.((gpio_id>>4) -1) * 0x80 + (u32) GPIO_BASE;
b.gpio_id & 0xF
c.gpio是在數字芯片上還是模擬芯片上:
#define NR_D_DIE_GPIOS 147
即:芯片上的gpio號小於147即位於數字芯片,否則位於模擬芯片

在一個芯片的整個寄存器內存中,采取以section + 功能的管理方式,也就是說對於同一個gpio的不同功能配置需要通過三個步驟,第一首先
需要找到段寄存器(section的基址);第二步是功能偏移的管理寄存器(功能偏移),第三步是根據段內偏移定位到某一位(bit)來配置。

注:
根據不同類型的gpio類型:
enum gpio_section_type {
    GPIO_SECTION_GPI = 0x0,
    GPIO_SECTION_GPO,
    GPIO_SECTION_GPIO,
    GPIO_SECTION_INVALID
};
其相應的功能偏移頁不同。

申請:設置其功能寄存器的GPIO_DMSK功能偏移,在對應段內偏移處置位。
釋放:清除對應MASK位
輸出方向:三個步驟,1.設置GPIO_DIR對應位為1;2.清除GPIO_INEN對應位;3.設置GPIO_DATA對應位為需要輸出的值。
輸入方向:第一二步相反,無第三步。
設置及獲取值:直接設置/讀取GPIO_DATA功能寄存器[需要檢查一些相關的方向等信息]

to irq
全局的映射數組來管理所有的gpio與irq的映射
static struct gpio_irq_map gpio_irq_table[NR_GPIO_IRQS];
映射規則是:從0-10[僅限映射10個中斷號],遍歷映射表找到第一個gpio offset相同的表項,返回其對應的irq值。
方向 to gpio 一般kernel不支持使用,但實現原理與上相同。

在gpio芯片管理中,最重要的一塊就是irq的管理,包括irq的所有屬性管理,如:irq屏蔽使能/觸發條件等等。
下一篇筆記將詳細描述 kernel irq的管理框架以及gpio的irq分配規則及觸發原理。


免責聲明!

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



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