参考博文:http://blog.chinaunix.net/uid-27717694-id-3624294.html
分析GPIO的初始化过程,GPIO是与硬件体系密切相关的,Linux提供一个模型来让驱动统一处理GPIO, 即各个板卡都有实现自己的gpio_chip控制模块:request,free,input,output,set,get,irq…然后把控制模块注册到内核中,这时会改变全局GPIO数组:gpio_desc[],由驱动传入对应gpio的全局序号去request,data out, data in, free。这时会调用gpio_chip中的具体实现。
static int __init davinci_gpio_setup(void)
{
int i, base;
unsigned ngpio;
struct davinci_soc_info *soc_info = &davinci_soc_info;
struct davinci_gpio_regs *regs;
if (soc_info->gpio_type != GPIO_TYPE_DAVINCI)
return 0;
/*
* The gpio banks conceptually expose a segmented bitmap,
* and "ngpio" is one more than the largest zero-based
* bit index that's valid.
*/
ngpio = soc_info->gpio_num;
if (ngpio == 0) {
pr_err("GPIO setup: how many GPIOs?\n");
return -EINVAL;
}
if (WARN_ON(DAVINCI_N_GPIO < ngpio))
ngpio = DAVINCI_N_GPIO;//gpio引脚的最大数目为144
/*内核空间只能访问虚拟地址空间的3-4G的地址空间,通常3-4G的空间一部分是映射物理内存,
通常默认不会映射寄存器,如果想访问某个寄存器,需要把寄存器的物理地址映射到高端内存
上,这样内核空间才能直接访问,在Gpio-davinci.h (arch\arm\mach-davinci\include\mach) 中定
定义了这个基地址:#define DAVINCI_GPIO_BASE 0x01C67000。推测是将这个地址开始的4K
大小的空间映射到高端内存,然后进行操作。
*/
gpio_base = ioremap(soc_info->gpio_base, SZ_4K);
if (WARN_ON(!gpio_base))
return -ENOMEM;
/*chips在上面有定义:static struct davinci_gpio_controller chips[4],就相当于分别给
每个davinci_gpio_controller指定相应的配置函数*/
for (i = 0, base = 0; base < ngpio; i++, base += 32) {
chips[i].chip.label = "DaVinci";
chips[i].chip.direction_input = davinci_direction_in;
chips[i].chip.get = davinci_gpio_get;
chips[i].chip.direction_output = davinci_direction_out;
chips[i].chip.set = davinci_gpio_set;
chips[i].chip.base = base;
chips[i].chip.ngpio = ngpio - base;
if (chips[i].chip.ngpio > 32)
chips[i].chip.ngpio = 32;
spin_lock_init(&chips[i].lock);
/*根据base的值,确定寄存器对应的偏移地址,便于后续对寄存器进行操作,一共有5个
chip,144个base*/
regs = gpio2regs(base);
chips[i].regs = regs;
chips[i].set_data = ®s->set_data;
chips[i].clr_data = ®s->clr_data;
chips[i].in_data = ®s->in_data;
gpiochip_add(&chips[i].chip);//gpio chip的注册,并插入到框架gpio的管理中
}
//chips数组添加到板级资源中
soc_info->gpio_ctlrs = chips;
soc_info->gpio_ctlrs_num = DIV_ROUND_UP(ngpio, 32);
davinci_gpio_irq_setup();
return 0;
}
davinci_soc_info的结构如下:
struct davinci_gpio_controller;
/*
* SoC info passed into common davinci modules.
*
* Base addresses in this structure should be physical and not virtual.
* Modules that take such base addresses, should internally ioremap() them to
* use.
*/
struct davinci_soc_info {
struct map_desc *io_desc;
unsigned long io_desc_num;
u32 cpu_id;
u32 jtag_id;
u32 jtag_id_reg;
struct davinci_id *ids;
unsigned long ids_num;
struct clk_lookup *cpu_clks;
u32 *psc_bases;
unsigned long psc_bases_num;
u32 pinmux_base;
const struct mux_config *pinmux_pins;
unsigned long pinmux_pins_num;
u32 intc_base;
int intc_type;
u8 *intc_irq_prios;
unsigned long intc_irq_num;
u32 *intc_host_map;
struct davinci_timer_info *timer_info;
int gpio_type;
u32 gpio_base;
unsigned gpio_num;
unsigned gpio_irq;
unsigned gpio_unbanked;
struct davinci_gpio_controller *gpio_ctlrs;
int gpio_ctlrs_num;
struct platform_device *serial_dev;
struct emac_platform_data *emac_pdata;
phys_addr_t sram_phys;
unsigned sram_len;
};
向内核注册gpiochip的函数:gpiochip_add(&chips[i].chip):
/**
* gpiochip_add() - register a gpio_chip
* @chip: the chip to register, with chip->base initialized
* Context: potentially before irqs or kmalloc will work
*
* Returns a negative errno if the chip can't be registered, such as
* because the chip->base is invalid or already associated with a
* different chip. Otherwise it returns zero as a success code.
*
* When gpiochip_add() is called very early during boot, so that GPIOs
* can be freely used, the chip->dev device must be registered before
* the gpio framework's arch_initcall(). Otherwise sysfs initialization
* for GPIOs will fail rudely.
*
* If chip->base is negative, this requests dynamic assignment of
* a range of valid GPIOs.
*/
int gpiochip_add(struct gpio_chip *chip)
{
unsigned long flags;
int status = 0;
unsigned id;
int base = chip->base;
/*确定GPIO号的有效性,只有有效的GPIO号才能传递给GPIO的建立函数:
gpio_request等用来请求和使用,否则进行失败处理*/
if ((!gpio_is_valid(base) || !gpio_is_valid(base + chip->ngpio - 1))
&& base >= 0) {
status = -EINVAL;
goto fail;
}
spin_lock_irqsave(&gpio_lock, flags);
/*如果这组GPIO的起始号小于0,表示是热插拔的设备,动态的分配gpiod的开始索引*/
if (base < 0) {
/*在gpio_desc[]中分配chip->ngpio个空间(从最后往前分配),返回第一个index*/
base = gpiochip_find_base(chip->ngpio);
if (base < 0) {
status = base;
goto unlock;
}
chip->base = base;
}
/* 被分配的GPIO号不准与其他chip冲突 */
for (id = base; id < base + chip->ngpio; id++) {
if (gpio_desc[id].chip != NULL) {
status = -EBUSY;
break;
}
}
/*将该组的控制结构chip填充GPIO的标准框架gpio_desc结构中*/
if (status == 0) {
for (id = base; id < base + chip->ngpio; id++) {
gpio_desc[id].chip = 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;
/*将注册好之后的GPIO进行打印,也就是如下的几条打印语句
[ 0.086234] gpiochip_add: registered GPIOs 0 to 31 on device: DaVinci
[ 0.086283] gpiochip_add: registered GPIOs 32 to 63 on device: DaVinci
[ 0.086319] gpiochip_add: registered GPIOs 64 to 95 on device: DaVinci
[ 0.086355] gpiochip_add: registered GPIOs 96 to 127 on device: DaVinci
[ 0.086389] gpiochip_add: registered GPIOs 128 to 143 on device: DaVinci
*/
pr_info("gpiochip_add: registered GPIOs %d to %d on device: %s\n",
chip->base, chip->base + chip->ngpio - 1,
chip->label ? : "generic");
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;
}
gpio描述符的结构如下:
struct gpio_desc {
struct gpio_chip *chip;
unsigned long flags;
/* flag symbols are bit numbers */
#define FLAG_REQUESTED 0
#define FLAG_IS_OUT 1
#define FLAG_RESERVED 2
#define FLAG_EXPORT 3 /* protected by sysfs_lock */
#define FLAG_SYSFS 4 /* exported via /sys/class/gpio/control */
#define FLAG_TRIG_FALL 5 /* trigger on falling edge */
#define FLAG_TRIG_RISE 6 /* trigger on rising edge */
#define FLAG_ACTIVE_LOW 7 /* sysfs value has active low */
#define ID_SHIFT 16 /* add new flags before this one */
#define GPIO_FLAGS_MASK ((1 << ID_SHIFT) - 1)
#define GPIO_TRIGGER_MASK (BIT(FLAG_TRIG_FALL) | BIT(FLAG_TRIG_RISE))
#ifdef CONFIG_DEBUG_FS
const char *label;
#endif
};