/*
* 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;
}
Linux启动过程初始化步骤(八)----davinci_gpio_irq_setup函数
猜你喜欢
转载自blog.csdn.net/qq_40788950/article/details/84593528
今日推荐
周排行