1. 程式人生 > >Linux核心初始化步驟(八)---GPIO相關的初始化工作

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 = &regs->set_data;
		chips[i].clr_data = &regs->clr_data;
		chips[i].in_data = &regs->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
};