/************************************************************** gpio_to_irq(S5PV210_GPH2(0)) **************************************************************/ 4 #define gpio_to_irq __gpio_to_irq 5 6 int __gpio_to_irq(unsigned gpio) 7 { 8 struct gpio_chip *chip; 9 chip = gpio_to_chip(S5PV210_GPH2(0));
static inline struct gpio_chip *gpio_to_chip(unsigned gpio) { return gpio_desc[S5PV210_GPH2(0)].chip; //参考gpio-s5pv210.c中 //samsung_gpiolib_add_4bit_chips(s5pv210_gpio_4bit, nr_chips)函数 //gpio_desc[id].chip = chip; }
10 return chip->to_irq ? chip->to_irq(chip, gpio - chip->base) : -ENXIO; 11 //s5pv210_gpio_4bit 12 }
int samsung_gpiolib_to_irq(struct gpio_chip *chip, unsigned int offset) { //获得gpio_chip结构体所在的父结构体s3c_gpio_chip的指针
struct s3c_gpio_chip *s3c_chip = container_of(chip,struct s3c_gpio_chip, chip);
//获取虚拟映射机制中定义的终端号 return s3c_chip->irq_base + offset;
#define IRQ_EINT(x) ((x) < 16 ? ((x) + S5P_EINT_BASE1) \ : ((x) - 16 + S5P_EINT_BASE2)) #define S5P_EINT_BASE2 (IRQ_VIC_END + 1) #define IRQ_VIC_END S5P_IRQ_VIC3(31) #define S5P_IRQ_VIC3(x) (S5P_VIC3_BASE + (x)) #define S5P_VIC3_BASE S5P_IRQ(96) #define S5P_IRQ(x) ((x) + S5P_IRQ_OFFSET) #define S5P_IRQ_OFFSET (32) #define S5P_EINT_BASE1 (S5P_IRQ_VIC0(0)) #define S5P_IRQ_VIC0(x) (S5P_VIC0_BASE + (x)) #define S5P_VIC0_BASE S5P_IRQ(0)
}
static struct s3c_gpio_chip s5pv210_gpio_4bit[] = { { .chip = { .base = S5PV210_GPA0(0), .ngpio = S5PV210_GPIO_A0_NR, .label = "GPA0", }, }, ............... ............... { .base = (S5P_VA_GPIO + 0xC40), .config = &gpio_cfg_noint, .irq_base = IRQ_EINT(16), .chip = { .base = S5PV210_GPH2(0), .ngpio = S5PV210_GPIO_H2_NR, .label = "GPH2", .to_irq = samsung_gpiolib_to_irq, }, }, { .base = (S5P_VA_GPIO + 0xC60), .config = &gpio_cfg_noint, .irq_base = IRQ_EINT(24), .chip = { .base = S5PV210_GPH3(0), .ngpio = S5PV210_GPIO_H3_NR, .label = "GPH3", .to_irq = samsung_gpiolib_to_irq, }, }, };
1 static __init int s5pv210_gpiolib_init(void) 2 { 3 struct s3c_gpio_chip *chip = s5pv210_gpio_4bit; 4 int nr_chips = ARRAY_SIZE(s5pv210_gpio_4bit);
for (i = 0; i < nr_chips; i++, chip++) { if (chip->config == NULL) { chip->config = &gpio_cfg; chip->group = gpioint_group++; } if (chip->base == NULL) chip->base = S5PV210_BANK_BASE(i); }
6 samsung_gpiolib_add_4bit_chips(s5pv210_gpio_4bit, nr_chips);
void __init samsung_gpiolib_add_4bit_chips(struct s3c_gpio_chip *chip, int nr_chips) { for (; nr_chips > 0; nr_chips--, chip++) { samsung_gpiolib_add_4bit(chip);
void __init samsung_gpiolib_add_4bit(struct s3c_gpio_chip *chip) { chip->chip.direction_input = samsung_gpiolib_4bit_input; chip->chip.direction_output = samsung_gpiolib_4bit_output; chip->pm = __gpio_pm(&s3c_gpio_pm_4bit); }
s3c_gpiolib_add(chip);
__init void s3c_gpiolib_add(struct s3c_gpio_chip *chip) {
//将s3c_gpio_chip 结构体变量s5pv210_gpio_4bit数组中的每一个数组变量 ".chip"传递给gpio_chip结构体指针gc
struct gpio_chip *gc = &chip->chip;
//gc = { // .base = S5PV210_GPH2(0), // .ngpio = S5PV210_GPIO_H2_NR, // .label = "GPH2", // .to_irq = samsung_gpiolib_to_irq, // }, int ret; spin_lock_init(&chip->lock);
//给gc结构体指针其他结构体成员赋值 if (!gc->direction_input) gc->direction_input = s3c_gpiolib_input; if (!gc->direction_output) gc->direction_output = s3c_gpiolib_output; if (!gc->set) gc->set = s3c_gpiolib_set; if (!gc->get) gc->get = s3c_gpiolib_get; #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);
int gpiochip_add(struct gpio_chip *chip){
unsigned long flags; int status = 0; unsigned id;
int base = chip->base; //base = S5PV210_GPH2(0) //查看获得的gpio_chip结构体指针基址和范围是否在有效范围之内 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); if (base < 0) { status = base; goto unlock; } chip->base = base; } //these GPIO numbers must not be managed by another gpio_chip
//遍历某个GPIO端口组的所有IO,如:S5PV210_GPH2端口组的8个IO口S5PV210_GPH2(0)~(7)
for (id = base; id < base + chip->ngpio; id++)
{
//正常状态gpio_desc[base].chip未被初始化,所以各个成员为NULL
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[S5PV210_GPH2(0)].chip的赋值,作为返回值在gpio_to_chip()中返回 // 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; } } 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; }
if (ret >= 0) s3c_gpiolib_track(chip)
}
}
}
7 s5p_register_gpioint_bank(IRQ_GPIOINT, 0, S5P_GPIOINT_GROUP_MAXNR); 8 9 return 0; 10 }