定义在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); //得到对应GPIO结构体首指针,里面包含了该GPIO的各种参数
unsigned long flags;
int offset;
int ret;
offset = pin - chip->chip.base; // 否则offset等于该GPIO引脚相对于GPX(0)的偏移量,每个偏移1
ret = s3c_gpio_do_setcfg(chip, offset, config); //设置该GPIO状态寄存器的数值为config
//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是一个函数指针,由后面的分析知道,如果针对GPA,该函数指针指向s3c_gpio_setcfg_s3c24xx_a ,如果针对GPX应该是指向s3c_gpio_setcfg_s3c24xx——但发现,如果是其他GPX,根本没有定义set_config!!!(这个问题已经解决,见后文s3c24xx_gpiolib_init函数,事实上,其余的config的确指向s3c_gpio_do_setcfg函数)
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; // 每个GPA对应一位
u32 con;
if (s3c_gpio_is_cfg_special(cfg)) { //OUTPUT状态是否为(0xfffffffX),是,返回1
cfg &= 0xf; // cfg = 0xX
/* Map output to 0, and SFN2 to 1 */ 本实验不会运行到这
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;
}
如果针对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; // 每个GPX对应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); // 读对应的GPXCON值
con &= ~(0x3 << shift); // 将GPXCON(pin)的两bits请0
con |= cfg; // 设置config值
__raw_writel(con, reg); // 写入新的GPXCON
return 0;
}
return ret;
}
我们先来看s3c_gpiolib_getchip,它实现了返回对应pin值的GPIO结构体首指针的功能
#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]; //根据偏移,计算出对应pin的GPIO结构体指针
return ((pin - chip->chip.base) < chip->chip.ngpio) ? chip : NULL;
// 这里验证,如果pin偏移超过了GPIO的个数,说明出错了,否则就返回该GPIO的结构体指针
}
回想以下之前s3c2410_gpio_cfgpin中,我们传入的参数是led_table[i]和 led_cfg_table[i],
struct s3c_gpio_chip s3c24xx_gpios[] = {
[0] = {
.base = S3C2410_GPACON, // datasheet上地址为0x56000000
#define S3C2410_GPIOREG(x) ((x) + S3C24XX_VA_GPIO)
#define S3C24XX_VA_GPIO ((S3C24XX_PA_GPIO - S3C24XX_PA_UART) + S3C24XX_VA_UART)
S3C24XX_PA_GPIO相当于(0x15600000)
S3C24XX_PA_UART相当于(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应该怎么算?
.pm = __gpio_pm(&s3c_gpio_pm_1bit),
.config = &s3c24xx_gpiocfg_banka, // 设置GPIO的函数指针
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,
},
},
};
***************************************************************************
下面分析第二个函数,先看一下相关结构体
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);
}
又出现了三个函数,我们一一说明:
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)
因此,每个引脚都分配了一个gpio_desc数据结构
1173int gpio_request(unsigned gpio, const char *label) // 这个函数还不是很明白
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)) // 不符合要求,跳转到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,跳转到done
1187 goto done;
1188
1189 if (!try_module_get(chip->owner)) // 该函数用于增加模块使用计数;若返回为0,表示调用失败,希望使用的模块没有被加载或正在被卸载中
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, 执行desc_set_label, 对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); // 该函数用于减少模块使用计数
1202 goto done;
1203 }
1204
1205 if (chip->request) { // chip->request在linux初始化时是没有指向的,可以见后面s3c_gpiolib_add
1206 /* chip->request may sleep */
1207 spin_unlock_irqrestore(&gpio_lock, flags); // 如果chip->request不为0, 解锁,因为后面调用的chip->request有可能睡眠
12