(S3C2410_GPIO_A_START + S3C2410_GPIO_A_NR + CONFIG_S3C_GPIO_SPACE + 0) + 5 =>
很显然, S3C2410_GPB(5)就是从GPA的首地址+GPA个数+GPB的offset就是当前GPB的IO偏移量,即
0+32+5=37, 同理
S3C2410_GPB(0) 相当于 32
30 S3C2410_GPB(5) 相当于 37
31 S3C2410_GPB(6) 相当于 38
32 S3C2410_GPB(7) 相当于 39
33 S3C2410_GPB(8) 相当于 40
***************************************************************************
led_cfg_table[i]
36 //LED 对应端口将要输出的状态列表
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) // 最后两位是设置,11表示RESERVE
#define S3C2410_GPIO_INPUT (0xFFFFFFF0) /* not available on A */ // 最后两位是设置,00表示INPUT
#define S3C2410_GPIO_OUTPUT (0xFFFFFFF1) // 最后两位是设置,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 */
***************************************************************************
根据前面的分析,s3c2410传入了当前GPIO的偏移地址,以及OUTPUT状态
现在我们深入前面的两个函数:
定义在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;
if (!chip)
return -EINVAL; // 没找到的话,返回invalid
offset = pin - chip->chip.base; // 否则offset等于该GPIO引脚相对于GPX(0)的偏移量,每个偏移1
s3c_gpio_lock(chip, flags); // 自旋锁锁住该GPIO,通过chip指针指向lock,看下面的define和图
ret = s3c_gpio_do_setcfg(chip, offset, config); //设置该GPIO状态寄存器的数值为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是一个函数指针,由后面的分析知道,如果针对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 _