日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux GPIO驱动详解

發(fā)布時(shí)間:2024/9/3 linux 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux GPIO驱动详解 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

注意:在/arch/arm/mach-s3c2410/include/mach/gpio-fns.h源代碼中有如下說明:

?16/* These functions are in the to-be-removed category and it is strongly
17 * encouraged not to use these in new code. They will be marked deprecated
18 * very soon.
19 *
20 * Most of the functionality can be either replaced by the gpiocfg calls
21 * for the s3c platform or by the generic GPIOlib API.
22 *
23 * As of 2.6.35-rc, these will be removed, with the few drivers using them
24 * either replaced or given a wrapper until the calls can be removed.
25*/

?

該頭文件包括:

static inline void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int cfg)

該函數(shù)直接使用

linux/arch/arm/plat-s3c/gpio-config.c中的

int s3c_gpio_cfgpin(unsigned int pin, unsigned int config)

即可?

?

***************************************************************************?

?

首先看一下設(shè)備初始化程序:

85 /*
86 * 設(shè)備初始化
87 */

88 static int __init dev_init(void)
89 {
90 int ret;
91 int i;
92 for (i = 0; i < 4; i++) {
93?//設(shè)置 LED 對(duì)應(yīng)的端口寄存器為輸出(OUTPUT)
94 ? ? ? ??
if (s3c_gpio_cfgpin(led_table[i], led_cfg_table[i])<0)

? ? ? ? ? ? ? ? ? ???? printk(KERN_INFO "config pin %d failed", i);


95 printk(KERN_INFO "config pin %d failed", i);

95?//設(shè)置 LED 對(duì)應(yīng)的端口寄存器為低電平輸出,在模塊加載> 結(jié)束后,四個(gè) LED 應(yīng)該是全部都是發(fā)光
96?狀態(tài)
?97 ? ? ? ??s3c2410_gpio_setpin(led_table[i], 0);
98 }
?99 ?ret = misc_register(&misc);?//注冊(cè)設(shè)備
100 printk (DEVICE_NAME"/tinitialized/n");?//打印初始化信息
101 return ret;
102 }

?

可以看到,這里涉及到兩個(gè)函數(shù),分別是s3c2410_gpio_cfgpin,s3c2410_gpio_setpin,這兩個(gè)函數(shù)分別對(duì)四個(gè)LED進(jìn)行配置,從函數(shù)名來看,cfgpin對(duì)引腳寄存器狀態(tài)進(jìn)行配置,而setpin應(yīng)該是對(duì)寄存器數(shù)據(jù)值進(jìn)行配置,我們?cè)诜治龊瘮?shù)之前先弄清楚傳入的參數(shù)到底是什么。

led_table[i]
28?//LED 對(duì)應(yīng)的 GPIO 端口列表
29 static unsigned long led_table [] = {
?30 ? ? S3C2410_GPB(5),
?31 ? ? S3C2410_GPB(6),
?32 ? ? S3C2410_GPB(7),
?33 ? ? S3C2410_GPB(8),
34 };

這里S3C2410_GPB宏定義在mach/gpio-nrs.h中?
/* GPIO bank sizes */
#define S3C2410_GPIO_A_NR (32)
#define S3C2410_GPIO_B_NR (32)
#define S3C2410_GPIO_C_NR (32)
#define S3C2410_GPIO_D_NR (32)
#define S3C2410_GPIO_E_NR (32)
#define S3C2410_GPIO_F_NR (32)
#define S3C2410_GPIO_G_NR (32)
#define S3C2410_GPIO_H_NR (32)
#define S3C2410_GPIO_J_NR (32) /* technically 16. */
#define S3C2410_GPIO_K_NR (32) /* technically 16. */
#define S3C2410_GPIO_L_NR (32) /* technically 15. */
#define S3C2410_GPIO_M_NR (32) /* technically 2. */

?

#if CONFIG_S3C_GPIO_SPACE != 0
#error CONFIG_S3C_GPIO_SPACE cannot be zero at the moment
#endif
?

?

#define S3C2410_GPIO_NEXT(__gpio) /
((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 0)

?

//這里的CONFIG_S3C_GPIO_SPAC是內(nèi)核配置選項(xiàng),在.config中可以找到,我的配置為:

CONFIG_S3C_GPIO_SPACE = 0?

?

enum s3c_gpio_number {
S3C2410_GPIO_A_START?= 0,
S3C2410_GPIO_B_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_A),
S3C2410_GPIO_C_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_B),
S3C2410_GPIO_D_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_C),
S3C2410_GPIO_E_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_D),
S3C2410_GPIO_F_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_E),
S3C2410_GPIO_G_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_F),
S3C2410_GPIO_H_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_G),
S3C2410_GPIO_J_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_H),
S3C2410_GPIO_K_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_J),
S3C2410_GPIO_L_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_K),
S3C2410_GPIO_M_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_L),
};

#define S3C2410_GPB(_nr) ? ?(S3C2410_GPIO_B_START + (_nr))??

因此,以S3C2410_GPB(5)為例,其宏展開為:

S3C2410_GPIO_NEXT(S3C2410_GPIO_A) +5?=>?

(S3C2410_GPIO_A_START?+?S3C2410_GPIO_A_NR?+ ?CONFIG_S3C_GPIO_SPACE + 0) +?5?=>

很顯然,?S3C2410_GPB(5)就是從GPA的首地址+GPA個(gè)數(shù)+GPB的offset就是當(dāng)前GPB的IO偏移量,即

0+32+5=37, 同理

? ? ? ? ??S3C2410_GPB(0) 相當(dāng)于 32

?30 ? ? S3C2410_GPB(5) 相當(dāng)于 37
?31 ? ? S3C2410_GPB(6) 相當(dāng)于 38
?32 ? ? S3C2410_GPB(7) 相當(dāng)于 39
?33 ? ? S3C2410_GPB(8) 相當(dāng)于 40

***************************************************************************?

?led_cfg_table[i]

36?//LED 對(duì)應(yīng)端口將要輸出的狀態(tài)列表
37 static unsigned int led_cfg_table [] = {
38 S3C2410_GPIO_OUTPUT,
39 S3C2410_GPIO_OUTPUT,
40 S3C2410_GPIO_OUTPUT,
41 S3C2410_GPIO_OUTPUT,
42 };

S3C2410_GPIO_OUTPUT定義在mach/regs-gpio.h

#define S3C2410_GPIO_LEAVE (0xFFFFFFFF) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??// 最后兩位是設(shè)置,11表示RESERVE
#define S3C2410_GPIO_INPUT (0xFFFFFFF0) /* not available on A */ ? ? ? ?
// 最后兩位是設(shè)置,00表示INPUT

#define S3C2410_GPIO_OUTPUT (0xFFFFFFF1) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? // 最后兩位是設(shè)置,01表示OUTPUT
#define S3C2410_GPIO_IRQ (0xFFFFFFF2) /* not available for all */
#define S3C2410_GPIO_SFN2 (0xFFFFFFF2) /* bank A => addr/cs/nand */
#define S3C2410_GPIO_SFN3 (0xFFFFFFF3) /* not available on A */

***************************************************************************?

根據(jù)前面的分析,s3c2410傳入了當(dāng)前GPIO的偏移地址,以及OUTPUT狀態(tài)

現(xiàn)在我們深入前面的兩個(gè)函數(shù):

定義在linux/arch/arm/plat-s3c/gpio-config.c
int?s3c_gpio_cfgpin(unsigned int pin, unsigned int config)
{
struct s3c_gpio_chip *chip =?s3c_gpiolib_getchip(pin); ??//得到對(duì)應(yīng)GPIO結(jié)構(gòu)體首指針,里面包含了該GPIO的各種參數(shù)
unsigned long flags;
int offset;
int ret;

if (!chip)
? ? ?return -EINVAL; ??// 沒找到的話,返回invalid

?offset = pin - chip->chip.base; ? ?// 否則offset等于該GPIO引腳相對(duì)于GPX(0)的偏移量,每個(gè)偏移1

s3c_gpio_lock(chip, flags); ? ?// 自旋鎖鎖住該GPIO,通過chip指針指向lock,看下面的define和圖
ret =?s3c_gpio_do_setcfg(chip, offset, config); ???//設(shè)置該GPIO狀態(tài)寄存器的數(shù)值為config
s3c_gpio_unlock(chip, flags);??// 解鎖

?

// 自旋鎖操作
/* locking wrappers to deal with multiple access to the same gpio bank */
//#define?s3c_gpio_lock(_oc, _fl) spin_lock_irqsave(&(_oc)->lock, _fl)

//#define?s3c_gpio_unlock(_oc, _fl) spin_unlock_irqrestore(&(_oc)->lock, _fl)


//s3c_gpio_do_setcfg操作

static inline int?s3c_gpio_do_setcfg(struct s3c_gpio_chip *chip,
unsigned int off, unsigned int config)
{
? ? ?return (chip->config->set_config)(chip, off, config);
}

//這里的set_config是一個(gè)函數(shù)指針,由后面的分析知道,如果針對(duì)GPA,該函數(shù)指針指向s3c_gpio_setcfg_s3c24xx_a?,?如果針對(duì)GPX應(yīng)該是指向s3c_gpio_setcfg_s3c24xx——但發(fā)現(xiàn),如果是其他GPX,根本沒有定義set_config!!!?(這個(gè)問題已經(jīng)解決,見后文s3c24xx_gpiolib_init函數(shù),事實(shí)上,其余的config的確指向s3c_gpio_do_setcfg函數(shù))

struct?s3c_gpio_cfg?s3c24xx_gpiocfg_default = {
? ? ? ? ? ?.set_config = s3c_gpio_setcfg_s3c24xx,
? ? ? ? ? ?.get_config = s3c_gpio_getcfg_s3c24xx,
};

?

int?s3c_gpio_setcfg_s3c24xx_a(struct s3c_gpio_chip *chip, unsigned int off, unsigned int cfg)
{
void __iomem *reg = chip->base; ??// GPXCON的物理基地址
unsigned int shift = off; ? ?// 每個(gè)GPA對(duì)應(yīng)一位
u32 con;

?if (s3c_gpio_is_cfg_special(cfg)) { ? ??//OUTPUT狀態(tài)是否為(0xfffffffX),是,返回1
? ? ? ? ?cfg &= 0xf; ?// cfg = 0xX

? /* Map output to 0, and SFN2 to 1 */?本實(shí)驗(yàn)不會(huì)運(yùn)行到這
cfg -= 1;
if (cfg > 1)
? ? ? ? return -EINVAL;

cfg <<= shift;
}

con = __raw_readl(reg); ? ??// 先讀出該GPXCON的值,32位
con &= ~(0x1 << shift); ? ? //?
con |= cfg; ? ? ? ? ? ? ? ? ? ?? ? ?//
?__raw_writel(con, reg); ? ?// 將新值寫入GPXCON

?

PS:? ?

#define __raw_writeb(v,a) (__chk_io_ptr(a), *(volatile unsigned char __force *)(a) = (v))
#define __raw_writew(v,a) (__chk_io_ptr(a), *(volatile unsigned short __force *)(a) = (v))
#define __raw_writel(v,a) (__chk_io_ptr(a), *(volatile unsigned int __force *)(a) = (v))

#define __raw_readb(a) (__chk_io_ptr(a), *(volatile unsigned char __force *)(a))
#define __raw_readw(a) (__chk_io_ptr(a), *(volatile unsigned short __force *)(a))
#define __raw_readl(a) (__chk_io_ptr(a), *(volatile unsigned int __force *)(a))


return 0;
}

如果針對(duì)GPX情況

int?s3c_gpio_setcfg_s3c24xx(struct s3c_gpio_chip *chip,
unsigned int off, unsigned int cfg)
{
void __iomem *reg = chip->base;
?unsigned int shift = off * 2; ? ?// 每個(gè)GPX對(duì)應(yīng)2位
u32 con;

if (s3c_gpio_is_cfg_special(cfg)) {
? ? ? ? ? cfg &= 0xf;
if (cfg > 3)
? ? ? ? ? return -EINVAL;

? cfg <<= shift; ? ? ? ?// 將cfg的0,1兩位左移offset
}

?con = __raw_readl(reg); ? ? ? ??// 讀對(duì)應(yīng)的GPXCON值
?con &= ~(0x3 << shift); ? ? ??? ?// 將GPXCON(pin)的兩bits請(qǐng)0
?con |= cfg; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??// 設(shè)置config值
?__raw_writel(con, reg); ? ? ? ? ??// 寫入新的GPXCON

return 0;
}

?


return ret;
} ? ? ? ? ? ? ? ?
// end?s3c_gpio_cfgpin

?

?

這里涉及到了一個(gè)重要的數(shù)據(jù)結(jié)構(gòu),s3c_gpio_chip,此數(shù)據(jù)結(jié)構(gòu)比較復(fù)雜,我貼出這個(gè)數(shù)據(jù)結(jié)構(gòu)的結(jié)構(gòu)圖:

這個(gè)重要的數(shù)據(jù)結(jié)構(gòu)中可以記錄每個(gè)GPIO所需要的所有數(shù)據(jù),后面會(huì)遇到的s3c24xx_gpios[]結(jié)構(gòu)體就是該結(jié)構(gòu)體的集合,描述了芯片中所有的GPIO端口,之后我們需要時(shí)時(shí)回頭看看這個(gè)結(jié)構(gòu)。

我們先來看s3c_gpiolib_getchip?,它實(shí)現(xiàn)了返回對(duì)應(yīng)pin值的GPIO結(jié)構(gòu)體首指針的功能

#include<mach/gpio-core.h>?

?static inline struct s3c_gpio_chip *s3c_gpiolib_getchip(unsigned int pin)
{
struct s3c_gpio_chip *chip;

?if (pin > S3C_GPIO_END) ??
?//如果超過GPJ(32)就return NULL

? ? ?return NULL;

chip = &s3c24xx_gpios[pin/32]; ? ??//根據(jù)偏移,計(jì)算出對(duì)應(yīng)pin的GPIO結(jié)構(gòu)體指針
? ? ?return ((pin - chip->chip.base) < chip->chip.ngpio) ? chip : NULL;

? ? ?// ?這里驗(yàn)證,如果pin偏移超過了GPIO的個(gè)數(shù),說明出錯(cuò)了,否則就返回該GPIO的結(jié)構(gòu)體指針
}

回想以下之前s3c2410_gpio_cfgpin中,我們傳入的參數(shù)是led_table[i]?led_cfg_table[i],

/* GPIO sizes for various SoCs:
*
?* ? ? ? ? ? ? ? ? ?2442
* 2410 2412 2440 2443 2416
* ---- ---- ---- ---- ----
* A 23 ? ? 22 ? ? 25 ?? ? 16 ? ? ?25
?* B 11 ? ?11 ? ? 11 ? ?? 11 ? ? ?? 9
?* C 16 ? ?15 ? ? 16 ? ?? 16 ? ?? 16
?* D 16 ? 16 ? ?? 16 ? ?? 16 ? ?? 16
?* E 16 ? ?16 ? ? 16 ? ? ? 16 ? ? ?16
?* F 8 ? ? ? ?8 ? ? ? 8 ? ? ? ? 8 ? ? ? 8
?* G16 ? ?16 ? ? 16 ? ? ? 16 ? ? ? 8
?* H 11 ? ?11 ? ? ?9 ? ? ? 15 ? ? ?15
?* J -- ? ? ?-- ? ? 13 ? ? ? 16 ? ? ? --
?* K -- ? ? -- ? ? ?-- ? ? ?? -- ? ? ? 16
?* L -- ? ? ?-- ? ? ?-- ? ? ? 15 ? ? ? ?7
?* M -- ? ? -- ? ? ?-- ? ? ? ? 2 ? ? ? ?2
*/
?

struct s3c_gpio_chip?s3c24xx_gpios[] = {
[0] = {
.base?= S3C2410_GPACON, ?// datasheet上地址為0x56000000

//#define S3C2410_GPACON ? ? S3C2410_GPIOREG(0x00)

#define S3C2410_GPIOREG(x) ((x) + S3C24XX_VA_GPIO)?

#define S3C24XX_VA_GPIO ? ? ((S3C24XX_PA_GPIO - S3C24XX_PA_UART) + S3C24XX_VA_UART)

S3C24XX_PA_GPIO相當(dāng)于(0x15600000)?

S3C24XX_PA_UART相當(dāng)于(0x15000000)?

#define S3C_VA_UART ? ?S3C_ADDR(0x01000000) ? ?/* UART */?

#define S3C_ADDR_BASE 0xF6000000


#ifndef __ASSEMBLY__
#define S3C_ADDR(x) ((void __iomem __force *)S3C_ADDR_BASE + (x))
#else
#define S3C_ADDR(x) (S3C_ADDR_BASE + (x))
#endif

0x15600000-15000000+F7000000?這里的S3C2410_GPACON應(yīng)該怎么算?

?

.pm = __gpio_pm(&s3c_gpio_pm_1bit),
.config = &s3c24xx_gpiocfg_banka, ? // 設(shè)置GPIO的函數(shù)指針

? ? ? ? ? ? ? ? ? ? ?static struct s3c_gpio_cfg s3c24xx_gpiocfg_banka = {
? ? ? ? ? ? ? ? ? ? ? ? ?.set_config =?s3c_gpio_setcfg_s3c24xx_a,
? ? ? ? ? ? ? ? ? ? ? ? ?.get_config = s3c_gpio_getcfg_s3c24xx_a,
? ? ? ? ? ? ? ? ? ? ? };

.chip = {
.base = S3C2410_GPA(0), ??//基地址,也是偏移量
.owner = THIS_MODULE,
.label = "GPIOA",
.ngpio = 24,
.direction_input = s3c24xx_gpiolib_banka_input,
.direction_output = s3c24xx_gpiolib_banka_output,
},
},
[1] = {
.base = S3C2410_GPBCON,
.pm = __gpio_pm(&s3c_gpio_pm_2bit),
.chip = {
.base = S3C2410_GPB(0),
.owner = THIS_MODULE,
.label = "GPIOB",
.ngpio = 16,

},
},
[2] = {
.base = S3C2410_GPCCON,
.pm = __gpio_pm(&s3c_gpio_pm_2bit),
.chip = {
.base = S3C2410_GPC(0),
.owner = THIS_MODULE,
.label = "GPIOC",
.ngpio = 16,
},
},
[3] = {
.base = S3C2410_GPDCON,
.pm = __gpio_pm(&s3c_gpio_pm_2bit),
.chip = {
.base = S3C2410_GPD(0),
.owner = THIS_MODULE,
.label = "GPIOD",
.ngpio = 16,
},
},
[4] = {
.base = S3C2410_GPECON,
.pm = __gpio_pm(&s3c_gpio_pm_2bit),
.chip = {
.base = S3C2410_GPE(0),
.label = "GPIOE",
.owner = THIS_MODULE,
.ngpio = 16,
},
},
[5] = {
.base = S3C2410_GPFCON,
.pm = __gpio_pm(&s3c_gpio_pm_2bit),
.chip = {
.base = S3C2410_GPF(0),
.owner = THIS_MODULE,
.label = "GPIOF",
.ngpio = 8,
.to_irq = s3c24xx_gpiolib_bankf_toirq,
},
},
[6] = {
.base = S3C2410_GPGCON,
.pm = __gpio_pm(&s3c_gpio_pm_2bit),
.irq_base = IRQ_EINT8,
.chip = {
.base = S3C2410_GPG(0),
.owner = THIS_MODULE,
.label = "GPIOG",
.ngpio = 16,
.to_irq = samsung_gpiolib_to_irq,
},
}, {
.base = S3C2410_GPHCON,
.pm = __gpio_pm(&s3c_gpio_pm_2bit),
.chip = {
.base = S3C2410_GPH(0),
.owner = THIS_MODULE,
.label = "GPIOH",
.ngpio = 11,
},
},
/* GPIOS for the S3C2443 and later devices. */2440用不到
{
.base = S3C2440_GPJCON,
.pm = __gpio_pm(&s3c_gpio_pm_2bit),
.chip = {
.base = S3C2410_GPJ(0),
.owner = THIS_MODULE,
.label = "GPIOJ",
.ngpio = 16,
},
}, {
.base = S3C2443_GPKCON,
.pm = __gpio_pm(&s3c_gpio_pm_2bit),
.chip = {
.base = S3C2410_GPK(0),
.owner = THIS_MODULE,
.label = "GPIOK",
.ngpio = 16,
},
}, {
.base = S3C2443_GPLCON,
.pm = __gpio_pm(&s3c_gpio_pm_2bit),
.chip = {
.base = S3C2410_GPL(0),
.owner = THIS_MODULE,
.label = "GPIOL",
.ngpio = 15,
},
}, {
.base = S3C2443_GPMCON,
.pm = __gpio_pm(&s3c_gpio_pm_2bit),
.chip = {
.base = S3C2410_GPM(0),
.owner = THIS_MODULE,
.label = "GPIOM",
.ngpio = 2,
},
},
};

***************************************************************************?


下面分析第二個(gè)函數(shù),先看一下相關(guān)結(jié)構(gòu)體

?

gpio_desc和gpio_chip結(jié)構(gòu)圖

?

?

?

void?s3c2410_gpio_setpin(unsigned int pin, unsigned int to)
{
/* do this via gpiolib until all users removed */

? ? ??gpio_request(pin, "temporary");
? ? ??gpio_set_value(pin, to);
? ? ??gpio_free(pin);
}

又出現(xiàn)了三個(gè)函數(shù),我們一一說明:

1169/* These "optional" allocation calls help prevent drivers from stomping
1170 * on each other, and help provide better diagnostics in debugfs.
1171 * They're called even less than the "set direction" calls.
1172 */

PS:static struct gpio_desc gpio_desc[ARCH_NR_GPIOS];

其中ARCH_NR_GPIOS在arch/arm/mach-s3c2410/include/mach/gpio.h中定義

#define ARCH_NR_GPIOS (32 * 9 + CONFIG_S3C24XX_GPIO_EXTRA)

因此,每個(gè)引腳都分配了一個(gè)gpio_desc數(shù)據(jù)結(jié)構(gòu)
1173int?gpio_request(unsigned gpio, const char *label) ? ? ? ??// 這個(gè)函數(shù)還不是很明白
1174{
1175 struct gpio_desc *desc;
1176 struct gpio_chip *chip;
1177 int status = -EINVAL;
1178 unsigned long flags;
1179
1180 spin_lock_irqsave(&gpio_lock, flags); ? ?// gpio_lock是自旋鎖,上鎖,保存FLAG在flags變量中
1181
1182 if (!gpio_is_valid(gpio)) ? ??// 不符合要求,跳轉(zhuǎn)到done
1183 ? ? goto done;
1184 desc = &gpio_desc[gpio]; ? ?// desc = &gpio_desc[pin]
1185 chip = desc->chip;
1186 if (chip == NULL) ? ? ? ? ? ???// gpio_desc.chip指向NULL,跳轉(zhuǎn)到done
1187 ? ? goto done;
1188
1189 if (!try_module_get(chip->owner)) ??// 該函數(shù)用于增加模塊使用計(jì)數(shù);若返回為0,表示調(diào)用失敗,希望使用的模塊沒有被加載或正在被卸載中
1190 ? ? goto done;
1191
1192 /* NOTE: gpio_request() can be called in early boot,
1193 * before IRQs are enabled, for non-sleeping (SOC) GPIOs.
1194 */

1195
1196 if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) { ? ?// 原子操作,將flags的第FLAG_REQUESTED位置1,并返回其原值
1197 ? ??desc_set_label(desc, label ? : "?");?? ?// 如果原來的值是0, 執(zhí)行desc_set_label, 對(duì)desc->chip.label賦值,如果label有定義,直接用定義,比如上面的“
temporary”,否則用“?”


static inline void desc_set_label(struct gpio_desc *d, const char *label)
{
#ifdef CONFIG_DEBUG_FS
?d->label = label; ? ? ? ? ? ? ??// 為什么不是d->chip.label = label; ?
#endif
}

1198?status = 0;
1199 } else { ? ? ? ? ? ? ? ? ? ? ?
// 如果flags的第FLAG_REQUESTED位原來的值是1
1200 status = -EBUSY;
1201 module_put(chip->owner); ???// 該函數(shù)用于減少模塊使用計(jì)數(shù)
1202 ? ? goto done;
1203 }
1204
1205 if (chip->request) { ? ?// chip->request在linux初始化時(shí)是沒有指向的,可以見后面
s3c_gpiolib_add
1206 /* chip->request may sleep */
1207 ? ? ? ? ? ? ? ? ? ?spin_unlock_irqrestore(&gpio_lock, flags); ? ? ? ? ??
?// 如果chip->request不為0, 解鎖,因?yàn)楹竺嬲{(diào)用的chip->request有可能睡眠
1208 ? ? ? ? ? ? ? ? ? ?status = chip->request(chip, gpio - chip->base);
1209 ? ? ? ? ? ? ? ? ?? spin_lock_irqsave(&gpio_lock, flags); ? ? ? ? ? ??? ? ? ?// 執(zhí)行完后,繼續(xù)上鎖
1210
1211 ? ? ? ? ? ? ? ? ? ?if (status < 0) { ? ? ? ?// status返回負(fù)數(shù),說明出錯(cuò)
1212 ? ? ? ? ? ? ? ? ? ? ? ? ? ?? desc_set_label(desc, NULL);
1213 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?module_put(chip->owner);
1214 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?clear_bit(FLAG_REQUESTED, &desc->flags);
1215 ? ? ? ? ? ? ? ? ? ? }
1216 }
1217
1218done:
1219 if (status)
1220 ? ? pr_debug("gpio_request: gpio-%d (%s) status %d/n", ?gpio, label ? : "?", status);

1221 ???// 如果狀態(tài)不為0, 打印gpio-pin"****"的狀態(tài)
1222 spin_unlock_irqrestore(&gpio_lock, flags); ??? // 解鎖
1223 return status; ???// 返回狀態(tài)
1224}

***************************************************************************

下面先分析gpio_free函數(shù)
void?gpio_free(unsigned gpio) ? ? ? ? ???// 待分析
{
unsigned long flags;
struct gpio_desc *desc;
struct gpio_chip *chip;

might_sleep();

if (!gpio_is_valid(gpio)) {
? ? ? ? WARN_ON(extra_checks);
? ? ? ? return;
}

gpio_unexport(gpio);

spin_lock_irqsave(&gpio_lock, flags);

desc = &gpio_desc[gpio];
chip = desc->chip;
if (chip && test_bit(FLAG_REQUESTED, &desc->flags)) {
? ? ?if (chip->free) {
? ? ? ? ? spin_unlock_irqrestore(&gpio_lock, flags);
? ? ? ? ? might_sleep_if(chip->can_sleep);
? ? ? ? ? chip->free(chip, gpio - chip->base);
? ? ? ? ? spin_lock_irqsave(&gpio_lock, flags);
? ? ? }
desc_set_label(desc, NULL);
module_put(desc->chip->owner);
clear_bit(FLAG_ACTIVE_LOW, &desc->flags);
clear_bit(FLAG_REQUESTED, &desc->flags);
} else
WARN_ON(extra_checks);

spin_unlock_irqrestore(&gpio_lock, flags);
}
EXPORT_SYMBOL_GPL(gpio_free);

***************************************************************************?

arch/arm/mach-s3c2410/include/mach/gpio.h?

#define gpio_set_value __gpio_set_value?

void?__gpio_set_value(unsigned gpio, int value)
{
struct gpio_chip *chip;

chip =?gpio_to_chip(gpio); ? ? ???// 返回對(duì)應(yīng)于pin的gpio_desc[pin].chip指針
WARN_ON(chip->can_sleep);
chip->set(chip, gpio - chip->base, value); ? ? ? /
/ 這里調(diào)用的是s3c_gpiolib_set函數(shù)!!!
}

/* caller holds gpio_lock *OR* gpio is marked as requested */
static inline struct gpio_chip *gpio_to_chip(unsigned gpio)
{
? ? ? return gpio_desc[gpio].chip;
}

看到這里,一直有個(gè)問題讓我百思不得其解,這里的chip按理說應(yīng)該是s3c_gpio_chip中的chip成員,但是之前都沒有代碼交代他們是如何聯(lián)系到一起的,s3c_gpio_chip與gpio_desc結(jié)構(gòu)體如何聯(lián)系在一起,也沒有函數(shù)交代,并且這里的chip->set函數(shù)指針也沒有實(shí)現(xiàn)的代碼,但是,經(jīng)實(shí)驗(yàn)確認(rèn)沒有問題后,我開始查找plat-s3c24xx/gpiolib.c中的函數(shù)希望能有些線索,果然,找到了這么一個(gè)函數(shù):

static __init int?s3c24xx_gpiolib_init(void)
{
struct s3c_gpio_chip *chip =?s3c24xx_gpios;
int gpn;

for (gpn = 0; gpn < ARRAY_SIZE(s3c24xx_gpios); gpn++, chip++) {
? ? ? ? if (!chip->config)
? ? ? ? ? ? ? ? ? chip->config = &s3c24xx_gpiocfg_default; ? ? ? ? ?// 原來chip->config默認(rèn)函數(shù)也是在這里!!!

? ? ? ? s3c_gpiolib_add(chip); ? ? ? ? ??// 之前的疑惑都在這里實(shí)現(xiàn)!!!
}

return 0;
}

core_initcall(s3c24xx_gpiolib_init);

但是,這個(gè)s3c24xx_gpiolib_init函數(shù)又是在什么時(shí)候執(zhí)行的呢?可以看到,在該函數(shù)的下面,有一句:core_initcall(s3c24xx_gpiolib_init);?查閱相關(guān)資料發(fā)現(xiàn), 在linux初始化的過程中,內(nèi)核采用了一種initcall的機(jī)制,它利用gcc的擴(kuò)展功能以及l(fā)d的連接控制腳本實(shí)現(xiàn)了在內(nèi)核初始化的過程中通過簡(jiǎn)單的循環(huán)就實(shí)現(xiàn)了相關(guān)驅(qū)動(dòng)的初始化

也就是說,在linux初始化期間,就已經(jīng)執(zhí)行了s3c24xx_gpiolib_init,現(xiàn)在我們可以分析下s3c_gpiolib_add(chip);?這個(gè)函數(shù)了,

__init void?s3c_gpiolib_add(struct s3c_gpio_chip *chip)
{
struct gpio_chip *gc =?&chip->chip;
int ret;

BUG_ON(!chip->base);
BUG_ON(!gc->label);
BUG_ON(!gc->ngpio);

?spin_lock_init(&chip->lock); ? ??
// 初始化s3c_gpio_chip的自旋鎖

if (!gc->direction_input)
? ? ? ? ? ?gc->direction_input = s3c_gpiolib_input; ? ? ? ??// direction_input 函數(shù)指針
if (!gc->direction_output)
? ? ? ? ? ?gc->direction_output = s3c_gpiolib_output; ? ?
?// direction_output 函數(shù)指針
if (!gc->set)
? ? ? ? ? ?gc->set = s3c_gpiolib_set; ? ? ??
?// set函數(shù)指針
if (!gc->get)
? ? ? ? ? ?gc->get = s3c_gpiolib_get; ? ? ??
?// get函數(shù)指針

#ifdef CONFIG_PM
if (chip->pm != NULL) {
? ? ? ? ? if (!chip->pm->save || !chip->pm->resume)
? ? ? ? ? ? ? ? ? ? printk(KERN_ERR "gpio: %s has missing PM functions/n", gc->label);
? ? ? ? ? } else
? ? ? ? ? printk(KERN_ERR "gpio: %s has no PM function/n", gc->label);
#endif

/* gpiochip_add() prints own failure message on error. */
ret =?gpiochip_add(gc);
if (ret >= 0)
? ? ? ? ??s3c_gpiolib_track(chip);
}

gpiochip_add函數(shù)分析:

/**
* gpiochip_add() - register a gpio_chip
* @chip: the chip to register, with chip->base initialized
* Context: potentially before irqs or kmalloc will work
*
* Returns a negative errno if the chip can't be registered, such as
* because the chip->base is invalid or already associated with a
* different chip. Otherwise it returns zero as a success code.
*
* When gpiochip_add() is called very early during boot, so that GPIOs
* can be freely used, the chip->dev device must be registered before
* the gpio framework's arch_initcall(). Otherwise sysfs initialization
* for GPIOs will fail rudely.
*
* If chip->base is negative, this requests dynamic assignment of
* a range of valid GPIOs.
*/

int?gpiochip_add(struct gpio_chip *chip) ? ???// 在gpio_desc[]中分配空間,并鏈接chip結(jié)構(gòu)
{
unsigned long flags;
int status = 0;
unsigned id;
int base = chip->base;

if ((!gpio_is_valid(base) || !gpio_is_valid(base + chip->ngpio - 1))
&& base >= 0) {
? ? ? ? status = -EINVAL;
? ? ? ? goto fail;
}

?spin_lock_irqsave(&gpio_lock, flags); ? ? ??// 上鎖

if (base < 0) {
? ? ? ? ?base =?gpiochip_find_base(chip->ngpio); ??// 這個(gè)函數(shù)在gpiolib.c中,在gpio_desc[]中分配chip->ngpio個(gè)空間(從最后往前分配),返回第一個(gè)index
? ? ? ? ?if (base < 0) { ? ? ? ? ?// 分配不到
? ? ? ? ? ? ? ? status = base;
? ? ? ? ? ? ? ? goto unlock; ? ???// 解鎖退出
? ? ? ? ?}
? ? ? ? ?chip->base = base; ? ?// gpio_chip *chip->base = i (i是gpio_desc[i]中的index)

}

/* these GPIO numbers must not be managed by another gpio_chip */
for (id = base; id < base + chip->ngpio; id++) {
? ? ? ?if (gpio_desc[id].chip != NULL) {
? ? ? ? ? ? status = -EBUSY;
? ? ? ? ? ? break;
? ? ? ?}
}


if (status == 0) { ? ? ? ? // 分配到空間,正常情況下
? ? ? ? ?for (id = base; id < base + chip->ngpio; id++) {
? ? ? ? ? ? ??gpio_desc[id].chip = chip; ???// 這里將gpio_desc與s3c_gpio_chip聯(lián)系起來,他們的chip成員指向的是同一個(gè)數(shù)據(jù)結(jié)構(gòu)

/* REVISIT: most hardware initializes GPIOs as
* inputs (often with pullups enabled) so power
* usage is minimized. Linux code should set the
* gpio direction first thing; but until it does,
* we may expose the wrong direction in sysfs.
*/

? ? ? ? ? ? ? gpio_desc[id].flags = !chip->direction_input ? (1 << FLAG_IS_OUT) : 0; ??// 設(shè)置flags
? ? ? ? ? }
?}?// end if

of_gpiochip_add(chip); ???// 沒操作

unlock:
?spin_unlock_irqrestore(&gpio_lock, flags); ? ? ? ??// 解鎖

if (status)
? ? ? goto fail;

status =?gpiochip_export(chip); ? ? ? ?//×××××××××××××××待分析
if (status)
? ? ? goto fail;

return 0;
fail:
/* failures here can mean systems won't boot... */
pr_err("gpiochip_add: gpios %d..%d (%s) failed to register/n",
chip->base, chip->base + chip->ngpio - 1,
chip->label ? : "generic");
?return status; ? ? ??// 返回狀態(tài)
}


下面是s3c_gpiolib_track函數(shù)

#ifdef CONFIG_S3C_GPIO_TRACK
struct s3c_gpio_chip *s3c_gpios[S3C_GPIO_END];

static __init void?s3c_gpiolib_track(struct s3c_gpio_chip *chip) ? ? ???// 沒完全理解,待分析
{
unsigned int gpn;
int i;

gpn = chip->chip.base;
for (i = 0; i < chip->chip.ngpio; i++, gpn++) {
? ? ? ? ? ?BUG_ON(gpn >= ARRAY_SIZE(s3c_gpios));
? ? ? ? ? ?s3c_gpios[gpn] = chip;
}
}
#endif /* CONFIG_S3C_GPIO_TRACK */

***************************************************************************?


好,現(xiàn)在我們開始分析設(shè)備注冊(cè)與卸載函數(shù),在初始化程序中,有如下語句:

?ret = misc_register(&misc);?//注冊(cè)設(shè)備

?其中的misc_register就是雜項(xiàng)設(shè)備的注冊(cè)函數(shù),首先關(guān)注下這里的參數(shù)misc數(shù)據(jù)結(jié)構(gòu)

75 /*
76 * 把 LED 驅(qū)動(dòng)注冊(cè)為 MISC 設(shè)備
77 */

78 static struct miscdevice misc = {
79 ? ? ? ? ? .minor = MISC_DYNAMIC_MINOR,?//動(dòng)態(tài)設(shè)備號(hào)
80 ? ? ? ? ? .name = DEVICE_NAME,
81 ? ? ? ? ? .fops = &dev_fops,
82 };
miscdevice的數(shù)據(jù)結(jié)構(gòu)如圖所示:

/**
* misc_register - register a miscellaneous device
* @misc: device structure
*?
* Register a miscellaneous device with the kernel. If the minor
* number is set to %MISC_DYNAMIC_MINOR a minor number is assigned
* and placed in the minor field of the structure. For other cases
* the minor number requested is used.
*
* The structure passed is linked into the kernel and may not be
* destroyed until it has been unregistered.
*
* A zero is returned on success and a negative errno code for
* failure.
*/
int

misc_register(struct miscdevice * misc)
{
struct miscdevice *c;
dev_t dev;
int err = 0;

?INIT_LIST_HEAD(&misc->list); ? ???// 初始化鏈表頭,將misc->list的next和pre都指向自己

?mutex_lock(&misc_mtx); ? ? ? ? ??// 獲取互斥鎖, or睡眠
?list_for_each_entry(c, &misc_list, list) { ???// 遍歷整個(gè)misc_list鏈表,所有的雜項(xiàng)驅(qū)動(dòng)設(shè)備都有一個(gè)miscdevice數(shù)據(jù)結(jié)構(gòu),這些雜項(xiàng)驅(qū)動(dòng)設(shè)備通過一個(gè)全局的misc_list鏈表連在一起, 相當(dāng)一個(gè)記錄
? ? ? ? if (c->minor == misc->minor) { ? ??// 如果misc_list中已經(jīng)有了這個(gè)設(shè)備(minor相同),則解鎖返回,這里c是遍歷時(shí)的tmp miscdevice,指向當(dāng)前遍歷節(jié)點(diǎn)
? ? ? ? ? ? ? ? ?mutex_unlock(&misc_mtx);
? ? ? ? ? ? ? ? ?return -EBUSY;
? ? ? ? ?}
}

?if (misc->minor == MISC_DYNAMIC_MINOR) { ? ? ? ?// 如果misc_list中沒有該設(shè)備,判斷minor是否準(zhǔn)備動(dòng)態(tài)分配,實(shí)驗(yàn)中如此設(shè)置
? ? ? ? int i = find_first_zero_bit(misc_minors, DYNAMIC_MINORS); ??// misc_minors是雜項(xiàng)設(shè)備位圖,總共有64個(gè)位DYNAMIC_MINORS=64,表示可以注冊(cè)64個(gè)雜項(xiàng)設(shè)備,這句代碼找到位圖中的空閑位置(表示還能加新設(shè)備)
? ? ? ? if (i >= DYNAMIC_MINORS) { ? ?// 如果超過總設(shè)備數(shù),則解鎖返回
? ? ? ? ? ? ? ? ?mutex_unlock(&misc_mtx);
? ? ? ? ? ? ? ? ?return -EBUSY;
? ? ? ? }
? ? ? ? misc->minor = DYNAMIC_MINORS - i - 1; ? ? ??// 計(jì)算子設(shè)備號(hào),賦值到misc->minor
? ? ? ? set_bit(i, misc_minors); ? ? ? ?// 對(duì)應(yīng)的位圖也置位
}

?dev = MKDEV(MISC_MAJOR, misc->minor); ? ???// 生成設(shè)備號(hào)


// 在sysfs中創(chuàng)建并注冊(cè)一個(gè)設(shè)備,可以在/dev下面看到misc->name

misc->this_device =?device_create(misc_class, misc->parent, dev, misc, "%s", misc->name);

1480/**
1481 *?device_create - creates a device and registers it with sysfs
1482 * @class: pointer to the struct class that this device should be registered to
1483 * @parent: pointer to the parent struct device of this new device, if any
1484 * @devt: the dev_t for the char device to be added
1485 * @drvdata: the data to be added to the device for callbacks
1486 * @fmt: string for the device's name
1487 *
1488 * This function can be used by char device classes. A struct device
1489 * will be created in sysfs, registered to the specified class.
1490 *
1491 * A "dev" file will be created, showing the dev_t for the device, if
1492 * the dev_t is not 0,0.
1493 * If a pointer to a parent struct device is passed in, the newly created
1494 * struct device will be a child of that device in sysfs.
1495 * The pointer to the struct device will be returned from the call.
1496 * Any further sysfs files that might be required can be created using this
1497 * pointer.
1498 *
1499 * Returns &struct device pointer on success, or ERR_PTR() on error.
1500 *
1501 * Note: the struct class passed to this function must have previously
1502 * been created with a call to class_create().
1503 */
1504struct device *device_create(struct class *class, struct device *parent, ? ? ? ? ?
?// 這個(gè)函數(shù)以后會(huì)詳細(xì)看
1505 dev_t devt, void *drvdata, const char *fmt, ...)
1506{
1507 va_list vargs;
1508 struct device *dev;
1509
1510 va_start(vargs, fmt);
1511 dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs);
1512 va_end(vargs);
1513 return dev;
1514}
?

?

// this_device是在創(chuàng)建設(shè)備節(jié)點(diǎn)時(shí)指向函數(shù)device_create()返回的設(shè)備結(jié)構(gòu)
?if (IS_ERR(misc->this_device)) { ? ? ? ? ? ? ?// 如果創(chuàng)建節(jié)點(diǎn)出錯(cuò),并且
? ? ? ?int i = DYNAMIC_MINORS - misc->minor - 1; ? ? ???// 計(jì)算子設(shè)備號(hào)之前misc->minor的值
? ? ? ?if (i < DYNAMIC_MINORS && i >= 0) ??// 計(jì)算位圖位i,如果在0-64之間,說明在set_bit中置位了,則清楚位圖,處理錯(cuò)誤,準(zhǔn)備返回
? ? ? ? ? ? ?clear_bit(i, misc_minors);
? ? ? ? ? ? ?err = PTR_ERR(misc->this_device);
? ? ? ?goto out;
}

/*
* Add it to the front, so that later devices can "override"
* earlier defaults
*/

?list_add(&misc->list, &misc_list); ? ? ? ? ? ??? // 以上操作都沒有問題后,將新設(shè)備加入misc_list鏈表,解鎖返回
out:
mutex_unlock(&misc_mtx);
return err;
}

***************************************************************************

同樣,對(duì)應(yīng)misc_register函數(shù),在exit中會(huì)調(diào)用misc_deregister函數(shù)
/**
* misc_deregister - unregister a miscellaneous device
* @misc: device to unregister
*
* Unregister a miscellaneous device that was previously
* successfully registered with misc_register(). Success
* is indicated by a zero return, a negative errno code
* indicates an error.
*/


int?misc_deregister(struct miscdevice *misc)
{
int i = DYNAMIC_MINORS - misc->minor - 1;

?if (WARN_ON(list_empty(&misc->list))) ? ?// 如果該misc->list的next指向自己,則出錯(cuò)返回
? ? ?return -EINVAL;

?mutex_lock(&misc_mtx); ? ? ??// 上鎖
?list_del(&misc->list); ? ? ? ? ???// 將misc從misc_list鏈表中刪除
device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor)); ? ? ? ??// 對(duì)應(yīng)device_create!

1524/**
1525 * device_destroy - removes a device that was created with device_create()
1526 * @class: pointer to the struct class that this device was registered with
1527 * @devt: the dev_t of the device that was previously registered
1528 *
1529 * This call unregisters and cleans up a device that was created with a
1530 * call to device_create().
1531 */
1532void?device_destroy(struct class *class, dev_t devt)
1533{
1534 struct device *dev;
1535
1536 dev = class_find_device(class, NULL, &devt, __match_devt);
1537 if (dev) {
1538 put_device(dev);
1539 device_unregister(dev);
1540 }
1541}
1542EXPORT_SYMBOL_GPL(device_destroy);
?


if (i < DYNAMIC_MINORS && i >= 0)
? ? ?clear_bit(i, misc_minors); ? ? ??
// 計(jì)算位圖位i,如果在0-64之間,說明在set_bit中置位了,清楚位圖
mutex_unlock(&misc_mtx);?? ? ? ? // 解鎖返回
return 0;
}

***************************************************************************?

總結(jié)雜項(xiàng)設(shè)備驅(qū)動(dòng)的注冊(cè)與卸載流程:

misc_register:找到空閑設(shè)備位圖位置 -> 計(jì)算子設(shè)備號(hào)(如果動(dòng)態(tài)的話),位圖位置位 - > ?device_creat() -> miscdevice結(jié)構(gòu)體加入misc_list鏈表中

misc_deregister: ?將miscdevice結(jié)構(gòu)體從misc_list鏈表中刪除 -> device_destory() -> 位圖位清零

***************************************************************************?

s3c24xx_gpiolib_init函數(shù)一樣,misc也有一個(gè)初始化函數(shù)會(huì)在linux初始化時(shí)運(yùn)行,下面來分析這個(gè)函數(shù)
static int __init?misc_init(void)
{
int err;

#ifdef CONFIG_PROC_FS ???//在proc文件系統(tǒng)下創(chuàng)建一個(gè)"misc"目錄。 misc_proc_fops是該文件系統(tǒng)下文件的操作函數(shù)集
? ? ? ? ? ?proc_create("misc", 0, NULL, &misc_proc_fops);
#endif
?misc_class = class_create(THIS_MODULE, "misc"); ??// 前面device_create()中的misc_class就是在這里初始化的
?err = PTR_ERR(misc_class);
?if (IS_ERR(misc_class)) ? ? ???// 出錯(cuò)處理
? ? ?goto fail_remove;

err = -EIO;
if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) ??//注冊(cè)一個(gè)主設(shè)備號(hào)為MISC_MAJOR(10)的字符設(shè)備,設(shè)備操作函數(shù)集為misc_fops
goto fail_printk;
misc_class->devnode = misc_devnode;
return 0;

fail_printk: ? ? ??// 錯(cuò)誤處理
printk("unable to get major %d for misc devices/n", MISC_MAJOR);
class_destroy(misc_class);
fail_remove:
remove_proc_entry("misc", NULL);
return err;
}
subsys_initcall(misc_init);

***************************************************************************?

好,到這里基本把一些GPIO相關(guān)的基本函數(shù)和結(jié)構(gòu)體都簡(jiǎn)單說明了,雖然還有不少不清楚的地方,但還是有些幫助,文中還有些不清楚的地方還有待以后能一一解決,我會(huì)不斷補(bǔ)充!


與50位技術(shù)專家面對(duì)面20年技術(shù)見證,附贈(zèng)技術(shù)全景圖

總結(jié)

以上是生活随笔為你收集整理的linux GPIO驱动详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。