Linux核心初始化步驟(八)---GPIO相關的初始化工作
阿新 • • 發佈:2018-12-01
參考博文: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
};