Linux下GPIO驱动详解文章(二)

2014-11-24 11:39:33 来源: 作者: 浏览: 8
5 =>


(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 _

-->

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: