1、接着上一篇
上一篇说到s3c64xx_gpiolib_add函数中的s3c_gpiolib_add(chips)这个函数了,并对这个函数进行了分析,但还没分析完,这篇接着分析,
/* gpiochip_add() prints own failure message on error. */
ret = gpiochip_add(gc);这个函数是上一篇中分析的重点
if (ret >= 0)
s3c_gpiolib_track(chip);这次要分析的函数,先列出源码,如下所示:
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++) { 循环,其中ngpio在下面被初始化,即各段GPIO的IO数目
.base = S3C24XX_GPIO_BASE(S3C2410_GPG0),
.chip = {
.base = S3C2410_GPG0,
.owner = THIS_MODULE,
.label = "GPIOG",
.ngpio= 10,
BUG_ON(gpn >= ARRAY_SIZE(s3c_gpios));
s3c_gpios[gpn] = chip;这个是什么?
看下这个struct s3c_gpio_chip *s3c_gpios[S3C_GPIO_END]是个struct s3c_gpio_chip结构的数组。
在s3c6410中有如下定义
/* the end of the S3C64XX specific gpios */
#define S3C64XX_GPIO_END (S3C64XX_GPQ(S3C64XX_GPIO_Q_NR) + 1)
#define S3C_GPIO_END S3C64XX_GPIO_END
}
}
这样我们可以通过GPIO的编号找到对应的struct s3c_gpio_chip数据结构。
到此为止,s3c_gpiolib_add函数说完了,同样也意味着arch_initcall(s3c64xx_gpiolib_init)函数也讲述完了。
2、
static struct s3c_gpio_cfg gpio_4bit_cfg_eint0011 = {
.cfg_eint = 3,
.set_config = s3c_gpio_setcfg_s3c64xx_4bit,
.set_pull = s3c_gpio_setpull_updown,
.get_pull = s3c_gpio_getpull_updown,
}这些结构体中的函数都在那里呢?
经过追踪,原来它们都在linux/arch/arm/plat-s3c/gpio-config.c文件中,举例如下;
#ifdef CONFIG_S3C_GPIO_PULL_UPDOWN
int s3c_gpio_setpull_updown(struct s3c_gpio_chip *chip,
unsigned int off, s3c_gpio_pull_t pull)
{
void __iomem *reg = chip->base + 0x08;寄存器基地址+0x08就是控制上拉和下拉寄存器的地址,看下图的:
int shift = off * 2;
u32 pup;
pup = __raw_readl(reg); 先读寄存器
pup &= ~(3 << shift); 把要更改的两位清零,其它位不变
pup |= pull << shift;
pull的类型为
typedef unsigned int __bitwise__ s3c_gpio_pull_t;
我们可以直接用
/* Define values for the pull-{up,down} available for each gpio pin.
*
* These values control the state of the weak pull-{up,down} resistors
* available on most pins on the S3C series. Not all chips support both
* up or down settings, and it may be dependant on the chip that is being
* used to whether the particular mode is available.
*/
#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)
__raw_writel(pup, reg);写寄存器
return 0;
}
加入现在是对GPIOA进行此操作,那么有如下定义:
.base= S3C64XX_GPA_BASE,此为GPIOA的寄存器基地址,虚拟的
.config = &gpio_4bit_cfg_eint0111,
.chip = {
.base = S3C64XX_GPA(0),
.ngpio = S3C64XX_GPIO_A_NR,
.label = "GPA",
}
#define S3C64XX_GPA_BASE (S3C64XX_VA_GPIO + 0x0000)
#define S3C64XX_VA_GPIO S3C_ADDR(0x00500000)
#define S3C_ADDR(x) (S3C_ADDR_BASE + (x))
#define S3C_ADDR_BASE (0xF4000000)
(1)、这个函数中有个__iomem,定义如下:
#ifdef __CHECKER__
# define __user __attribute__((noderef, address_space(1)))
# define __kernel /* default address space */
# define __safe __attribute__((safe))
# define __force __attribute__((force))
# define __nocast __attribute__((nocast))
# define __iomem __attribute__((noderef, address_space(2)))
# define __acquires(x) __attribute__((context(x,0,1)))
# define __releases(x) __attribute__((context(x,1,0)))
# define __acquire(x) __context__(x,1)
# define __release(x) __context__(x,-1)
# define __cond_lock(x,c) ((c) ? ({ __acquire(x); 1; }) : 0)
extern void __chk_user_ptr(const volatile void __user *);
extern void __chk_io_ptr(const volatile void __iomem *);
#else
# define __user
# define __kernel
# define __safe
# define __force
# define __nocast
# define __iomem
# define __chk_user_ptr(x) (void)0
# define __chk_io_ptr(x) (void)0
# define __builtin_warning(x, y...) (1)
# define __acquires(x)
# define __releases(x)
# define __acquire(x) (void)0
# define __release(x) (void)0
# define __cond_lock(x,c) (c)
#endif
(2)、这个函数中__raw_readl和__raw_writel等定义如下:
#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))
s3c_gpio_pull_t s3c_gpio_getpull_updown(struct s3c_gpio_chip *chip,和上面的一样
unsigned int off)
{
void __iomem *reg = chip->base + 0x08;
int shift = off * 2;
u32 pup = __raw_readl(reg);
pup >>= shift;
pup &= 0x3;
return (__force s3c_gpio_pull_t)pup;
}
#endif
还有这个
#ifdef CONFIG_S3C_GPIO_CFG_S3C64XX
int s3c_gpio_setcfg_s3c64xx_4bit(struct s3c_gpio_chip *chip,
unsigned int off, unsigned int cfg)
{
void __iomem *reg = chip->base;
unsigned int shift = (off & 7) * 4;
u32 con;
if (off < 8 && chip->chip.ngpio > 8)
reg -= 4;
if (s3c_gpio_is_cfg_special(cfg)) {
cfg &= 0xf;
cfg <<= shift;
}
con = __raw_readl(reg);
con &= ~(0xf << shift);
con |= cfg;
__raw_writel(con, reg);
return 0;
}
#endif /* CONFIG_S3C_GPIO_CFG_S3C64XX */
Linux下s3c6410的GPIO操作(1)的链接
Linux下s3c6410的GPIO操作(2)的链接