Linux啟動過程初始化步驟(八)----davinci_gpio_irq_setup函式
阿新 • • 發佈:2018-12-01
/* * NOTE: for suspend/resume, probably best to make a platform_device with * suspend_late/resume_resume calls hooking into results of the set_wake() * calls ... so if no gpios are wakeup events the clock can be disabled, * with outputs left at previously set levels, and so that VDD3P3V.IOPWDN0 * (dm6446) can be set appropriately for GPIOV33 pins. */ static int __init davinci_gpio_irq_setup(void) { unsigned gpio, irq, bank; struct clk *clk; u32 binten = 0; unsigned ngpio, bank_irq; struct davinci_soc_info *soc_info = &davinci_soc_info; struct davinci_gpio_regs __iomem *g; ngpio = soc_info->gpio_num; bank_irq = soc_info->gpio_irq; if (bank_irq == 0) { printk(KERN_ERR "Don't know first GPIO bank IRQ.\n"); return -EINVAL; } clk = clk_get(NULL, "gpio");//獲取時鐘 if (IS_ERR(clk)) { printk(KERN_ERR "Error %ld getting gpio clock?\n", PTR_ERR(clk)); return PTR_ERR(clk); } /*使能GPIO時鐘並呼叫arch\arm\mach-davinci\psc.c中的davinci_psc_config函式來開啟該模組電源*/ clk_enable(clk); /* Arrange gpio_to_irq() support, handling either direct IRQs or * banked IRQs. Having GPIOs in the first GPIO bank use direct * IRQs, while the others use banked IRQs, would need some setup * tweaks to recognize hardware which can do that. */ for (gpio = 0, bank = 0; gpio < ngpio; bank++, gpio += 32) { chips[bank].chip.to_irq = gpio_to_irq_banked; chips[bank].irq_base = soc_info->gpio_unbanked ? -EINVAL : (soc_info->intc_irq_num + gpio); } /* * AINTC can handle direct/unbanked IRQs for GPIOs, with the GPIO * controller only handling trigger modes. We currently assume no * IRQ mux conflicts; gpio_irq_type_unbanked() is only for GPIOs. */ if (soc_info->gpio_unbanked) { static struct irq_chip_type gpio_unbanked; /* pass "bank 0" GPIO IRQs to AINTC, 我們假設只有第一個gpio_chip能夠提供直接對映的IRQ給AINTC(最多32個GPIO) */ chips[0].chip.to_irq = gpio_to_irq_unbanked; binten = BIT(0); /* AINTC handles mask/unmask; GPIO handles triggering */ irq = bank_irq; gpio_unbanked = *container_of(irq_get_chip(irq), struct irq_chip_type, chip); gpio_unbanked.chip.name = "GPIO-AINTC"; gpio_unbanked.chip.irq_set_type = gpio_irq_type_unbanked; /* default trigger: both edges */ g = gpio2regs(0); __raw_writel(~0, &g->set_falling); __raw_writel(~0, &g->set_rising); /* set the direct IRQs up to use that irqchip */ for (gpio = 0; gpio < soc_info->gpio_unbanked; gpio++, irq++) { irq_set_chip(irq, &gpio_unbanked.chip);//註冊用於GPIO中斷禁止,使能和型別選擇的回撥例程 irq_set_handler_data(irq, &chips[gpio / 32]);//為GPIO設定不同的中斷例程 irq_set_status_flags(irq, IRQ_TYPE_EDGE_BOTH);//中斷模式為雙邊沿觸發 } goto done; } /* * Or, AINTC can handle IRQs for banks of 16 GPIO IRQs, which we * then chain through our own handler. */ for (gpio = 0, irq = gpio_to_irq(0), bank = 0; gpio < ngpio; bank++, bank_irq++) { unsigned i; /* disabled by default, enabled only as needed */ g = gpio2regs(gpio); __raw_writel(~0, &g->clr_falling); __raw_writel(~0, &g->clr_rising); /* set up all irqs in this bank */ irq_set_chained_handler(bank_irq, gpio_irq_handler); /* * Each chip handles 32 gpios, and each irq bank consists of 16 * gpio irqs. Pass the irq bank's corresponding controller to * the chained irq handler. */ irq_set_handler_data(bank_irq, &chips[gpio / 32]); for (i = 0; i < 16 && gpio < ngpio; i++, irq++, gpio++) { irq_set_chip(irq, &gpio_irqchip);//註冊用於GPIO中斷禁止、使能和型別選擇的回撥例程 irq_set_chip_data(irq, (__force void *)g);//儲存控制體即暫存器的地址 irq_set_handler_data(irq, (void *)__gpio_mask(gpio)); irq_set_handler(irq, handle_simple_irq);//為每個GPIO中斷設定同一個hand_simple_irq中斷例程 set_irq_flags(irq, IRQF_VALID);//fiq中斷有效 } binten |= BIT(bank); } done: /* BINTEN -- per-bank interrupt enable. genirq would also let these * bits be set/cleared dynamically. */ __raw_writel(binten, gpio_base + 0x08); /*輸出註冊了的中斷號,對應開發板列印輸出的如下語句: printk(KERN_INFO "DaVinci: %d gpio irqs\n", irq - gpio_to_irq(0)); return 0; }