Linux内核初始化步骤(八)---GPIO相关的初始化工作

参考博文: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
};

你可能感兴趣的:(Linux内核)