1. gpiolib庫簡介
linux中從2.6.35以后就開始有gpiolib庫了,gpiolib的作用是對所有的gpio實行統一管理,因為驅動在工作的時候,會出現好幾個驅動共同使用同一個gpio的情況;這會造成混亂。所以內核提供了一些方法來管理gpio資源。
2. gpiolib庫的建立
gpiolib庫建立的目標函數:
//所在文件:/kernel/arch/arm/mach-s5pv210/mach-smdkc110.c
static void __init smdkc110_map_io(void)
{
......
s5pv210_gpiolib_init();
......
}
//所在文件:/kernel/arch/arm/mach-s5pv210/gpiolib.c
__init int s5pv210_gpiolib_init(void)
{
struct s3c_gpio_chip *chip = s5pv210_gpio_4bit;
int nr_chips = ARRAY_SIZE(s5pv210_gpio_4bit);
int i = 0;
for (i = 0; i < nr_chips; i++, chip++)
{
if (chip->config == NULL)
chip->config = &gpio_cfg;
if (chip->base == NULL)
chip->base = S5PV210_BANK_BASE(i);
}
samsung_gpiolib_add_4bit_chips(s5pv210_gpio_4bit, nr_chips);
return 0;
}
s5pv210_gpiolib_init()函數分析:
(1)gpiolib庫的初始化實質就是對s3c_gpio_chip結構體數組進行賦值;struct s3c_gpio_chip用以描述一個GPIO端口。
struct s3c_gpio_chip
{
struct gpio_chip chip;
struct s3c_gpio_cfg *config;
struct s3c_gpio_pm *pm;
void __iomem *base; //存放GPIO的虛擬地址
int eint_offset;
spinlock_t lock;
#ifdef CONFIG_PM
u32 pm_save[7];
#endif
};
struct gpio_chip
{
......
const char *label; //GPIO端口名稱
int base; //GPIO端口號
......
}
(2)內核中建立了static struct s3c_gpio_chip s5pv210_gpio_4bit[] 這個數組,將所有的gpio的.chip結構體中的一些元素初始化,這個數組的所有元素是與數據手冊中的所有gpio是一一對應的。
static struct s3c_gpio_chip s5pv210_gpio_4bit[] = {
{
.chip = {
.base = S5PV210_GPA0(0),
.ngpio = S5PV210_GPIO_A0_NR,
.label = 'GPA0',
.to_irq = s5p_gpiolib_gpioint_to_irq,
},
}, {
.chip = {
.base = S5PV210_GPA1(0),
.ngpio = S5PV210_GPIO_A1_NR,
.label = 'GPA1',
.to_irq = s5p_gpiolib_gpioint_to_irq,
},
}, {
.chip = {
.base = S5PV210_GPB(0),
.ngpio = S5PV210_GPIO_B_NR,
.label = 'GPB',
.to_irq = s5p_gpiolib_gpioint_to_irq,
},
},
......
}
.chip.base是GPIO的編號,用宏定義表示。S5PV210_GPA0(0)宏解析如下,即S5PV210_GPA0(0) = 0,S5PV210_GPA0(1) = 1。
#define S5PV210_GPA0(_nr) (S5PV210_GPIO_A0_START + (_nr))
#define S5PV210_GPA1(_nr) (S5PV210_GPIO_A1_START + (_nr))
S5PV210_GPIO_A0_START = 0,
S5PV210_GPIO_A1_START = S5PV210_GPIO_NEXT(S5PV210_GPIO_A0),
#define S5PV210_GPIO_NEXT(__gpio)
((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 1)
#define S5PV210_GPIO_A0_NR (8)
#define S5PV210_GPIO_A1_NR (4)
#define S5PV210_GPIO_B_NR (8)
#define S5PV210_GPIO_C0_NR (5)
(3)chip->base = S5PV210_BANK_BASE(i),將GPIO的虛擬地址寫入。
//每個gpio的地址差0x20
#define S5PV210_BANK_BASE(bank_nr) (S5P_VA_GPIO + ((bank_nr) * 0x20)
(4)samsung_gpiolib_add_4bit_chips()函數的作用是將所有GPIO向內核注冊。注冊的實質是:在linux內核中有一個gpio_desc結構體數組,注冊就是把我們封裝的gpio的所有信息的結構體放到數組的格子中。
void __init samsung_gpiolib_add_4bit_chips(struct s3c_gpio_chip *chip, int nr_chips)
{
for (; nr_chips > 0; nr_chips--, chip++)
{
samsung_gpiolib_add_4bit(chip);
s3c_gpiolib_add(chip);
}
}
回到頂部
3. gpiolib庫的使用
(1)申請GPIO
/*
*參數:
* unsigned gpio:GPIO編號
* const char *label:GPIO名稱
*返回值:
* 返回值為0,GPIO申請成功;否則,GPIO申請失敗
*/
int gpio_request(unsigned gpio, const char *label);
(2)設置GPIO方向
1)設置為輸入
/*
*參數:
* unsigned gpio:GPIO編號
*返回值:
* 返回值為<0,設置失敗
*/
int gpio_direction_input(unsigned gpio);
2)設置為輸出
/*
*參數:
* unsigned gpio:GPIO編號
* int value:GPIO輸出值
*返回值:
* 返回值為<0,設置失敗
*/
int gpio_direction_output(unsigned gpio, int value);
(3)獲取/設置GPIO的值
a. 可睡眠
對于有些掛載在I2C,SPI總線上的擴展GPIO,讀寫操作可能會導致睡眠,因此不能在中斷函數中使用可睡眠操作。使用下面的函數以區別于正常的GPIO:
1)獲取GPIO的值
/*
*參數:
* unsigned gpio:GPIO編號
*返回值:
* 返回GPIO的值,0或1
*/
int gpio_get_value_cansleep(unsigned gpio);
2)設置GPIO的值
/*
*參數:
* unsigned gpio:GPIO編號
* int value:GPIO設置值
*返回值:
* 無
*/
void gpio_set_value_cansleep(unsigned gpio, int value);
b. 不可睡眠
1)獲取GPIO的值
/*
*參數:
* unsigned gpio:GPIO編號
*返回值:
* 返回GPIO的值,0或1
*/
int gpio_get_value(unsigned gpio);
2)設置GPIO的值
/*
*參數:
* unsigned gpio:GPIO編號
* int value:GPIO設置值
*返回值:
* 無
*/
void gpio_set_value(unsigned gpio, int value);
(4)釋放GPIO
/*
*參數:
* unsigned gpio:GPIO編號
*返回值:
* 無
*/
void gpio_free(unsigned gpio);
(5)批量初始化/釋放GPIO
1)批量初始化GPIO
/*
*參數:
* unsigned gpio *array:GPIO數組(多個GPIO編號)
* size_t num:GPIO數組大小,GPIO即的個數
*返回值:
* 返回0,初始化成功;否則,初始化失敗
*/
int gpio_request_array(struct gpio *array, size_t num);
2)批量釋放GPIO
/*
*參數:
* unsigned gpio *array:GPIO數組(多個GPIO編號)
* size_t num:GPIO數組大小,GPIO即的個數
*返回值:
* 無
*/
void gpio_free_array(struct gpio *array, size_t num);
回到頂部
4. S3C平臺的GPIO操作接口
kernel/arch/arm/plat-s3c/include/plat/gpio-cfg.h文件中提供了S3C平臺的GPIO操作接口,以下列舉一些常用的GPIO操作接口。
(1)GPIO的工作模式設置
Linux內核中GPIO的工作模式的定義。
/*
*GPIO的工作模式定義
*/
#define S3C_GPIO_INPUT (S3C_GPIO_SPECIAL(0)) //輸出模式
#define S3C_GPIO_OUTPUT (S3C_GPIO_SPECIAL(1)) //輸入模式
#define S3C_GPIO_SFN(x) (S3C_GPIO_SPECIAL(x)) //其他模式,根據參數x決定
S3C_GPIO_SFN(x)中x的值對應的功能可通過數據手冊來查閱。譬如,根據D5PV210的數據手冊可知:
/*
*x = 0,GPH0_0為輸入模式
*x = 1,GPH0_0為輸出模式
*x = 0x0f,GPH0_0為外部中斷模式
*/
S3C_GPIO_SFN(0) //輸入模式
S3C_GPIO_SFN(1) //輸出模式
S3C_GPIO_SFN(0x0f)//外部中斷模式
1)s3c_gpio_cfgpin()設置指定引腳的工作模式
/*
*功能:設置指定引腳的工作模式
*參數:
* unsigned int pin:需要設置的引腳號
* unsigned int to:需要設置的工作模式
*/
int s3c_gpio_cfgpin(unsigned int pin, unsigned int to);
s3c_gpio_cfgpin(S5PV210_GPA0(0), S3C_GPIO_SFN(0)); //設置GPH0_0為輸入模式
s3c_gpio_cfgpin(S5PV210_GPA0(0), S3C_GPIO_SFN(1)); //設置GPH0_0為輸出模式
s3c_gpio_cfgpin(S5PV210_GPA0(0), S3C_GPIO_SFN(0x0f));//設置GPH0_0為外部中斷模式
2)s3c_gpio_getcfg()讀取指定引腳的設置值
/*
*功能:讀取指定引腳的設置值
*參數:
* unsigned int pin:需要獲取的引腳號
*返回值:獲取G引腳工作模式的值
*/
unsigned s3c_gpio_getcfg(unsigned int pin);
3)s3c_gpio_cfgin_range()批量設置多個引腳的工作模式
/*
*功能:批量設置多個引腳的工作模式
*參數:
* unsigned int start:起始引腳號
* unsigned int nr: 需要設置的引腳個數
* unsigned int cfg: 需要設置的工作模式
*/
int s3c_gpio_cfgpin_range(unsigned int start, unsigned int nr, unsigned int cfg);
(2)GPIO的上下拉設置
Linux內核中,上下拉的狀態值的定義。
#define S3C_GPIO_PULL_NONE ((__force s3c_gpio_pull_t)0x00) //關閉,上拉下拉都關閉
#define S3C_GPIO_PULL_DOWN ((__force s3c_gpio_pull_t)0x01) //下拉
#define S3C_GPIO_PULL_UP ((__force s3c_gpio_pull_t)0x02) //上拉
1)s3c_gpio_setpull()設置GPIO引腳的上下拉使能
/*
*功能:設置單個引腳的上下拉模式
*參數:
* unsigned int pin:需要設置的引腳
* s3c_gpio_pull_t pull:上下拉的狀態值
*/
int s3c_gpio_setpull(unsigned int pin, s3c_gpio_pull_t pull);
2)s3c_gpio_getpull()讀取指定引腳的上下拉狀態
/*
*功能:讀取指定引腳的上下拉狀態
*參數:
* unsigned int pin:需要讀取的引腳
*返回值:
* s3c_gpio_pull_t :上下拉的狀態值
*/
s3c_gpio_pull_t s3c_gpio_getpull(unsigned int pin);
3) s3c_gpio_cfgall()批量設置多個引腳的工作模式和上下拉狀態
/*
*功能:批量設置多個引腳的工作模式和上下拉狀態
*參數:
* unsigned int start: 起始引腳號
* unsigned int nr: 需要設置的引腳個數
* unsigned int cfg: 需要設置的引腳工作模式
* s3c_gpio_pull_t pull:需要設置的引腳的上下拉狀態
*/
int s3c_gpio_cfgall_range(unsigned int start, unsigned int nr, unsigned int cfg, s3c_gpio_pull_t pull);
上一篇:make: Warning: File `led.c' has modification time 15 s in the future
下一篇:喜羊羊系列【設備 - 驅動器 編譯進內核】
推薦閱讀最新更新時間:2025-04-16 02:19




設計資源 培訓 開發板 精華推薦
- 2025上海車展即將啟幕,高通攜手汽車生態伙伴帶來駕駛輔助和艙駕創新成果
- 2025Medtec預登記全面啟動 全鏈創新技術引爆國產替代及出海浪潮
- MEMS傳感器振動檢測技術:現狀、挑戰與解決方案
- MEMS傳感器振動應用技術綜述:原理、方法與發展趨勢
- 從零入門:工業信號調節器的類型(模擬數字)與隔離器(光耦磁耦)對比
- 高精度工業信號調節器:低噪聲放大器與校準電路的實現
- 工業4.0下的信號調節器,物聯網、邊緣計算與遠程監控的融合
- 伊士曼中間膜“黑科技”玩轉舒適智駕
- 逐點半導體與PerfDog達成合作,為游戲性能測評提供多維度數據支撐
- 破解汽車與工業等應用新挑戰,TDK展示多傳感器融合與AI+發展趨勢