标签:中断控制 属性 nod 用户手册 级联 stat 硬件 需要 property
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (res) drvdata->irq = res->start;
ret = devm_request_irq(dev, d->irq, exynos_eint_gpio_irq, 0, dev_name(dev), d);
也就是当GIC上的SPI-47这个中断被触发后,中断处理函数exynos_eint_gpio_irq会被调用。
1 bank = d->pin_banks; 2 for (i = 0; i < d->nr_banks; ++i, ++bank) { 3 if (bank->eint_type != EINT_TYPE_GPIO) 4 continue; 5 6 bank->irq_domain = irq_domain_add_linear(bank->of_node, 7 bank->nr_pins, &exynos_eint_irqd_ops, bank); 8 9 bank->irq_chip = &exynos_gpio_irq_chip; 10 }
也就是图3中的每一组GPIO都可以是一个中断控制器,bank->nr_pins是该组GPIO有几个引脚,每一个引脚对应一个中断,所以也就表示该irq_domain可以最大支持的中断个数。第9行设置了irq_chip,用户控制每一个引脚中断的打开、关闭、清除等。
1 static irqreturn_t exynos_eint_gpio_irq(int irq, void *data) 2 { 3 struct samsung_pinctrl_drv_data *d = data; 4 struct samsung_pin_bank *bank = d->pin_banks; 5 unsigned int svc, group, pin, virq; 6 7 svc = readl(d->virt_base + EXYNOS_SVC_OFFSET); 8 group = EXYNOS_SVC_GROUP(svc); 9 pin = svc & EXYNOS_SVC_NUM_MASK; 10 11 if (!group) 12 return IRQ_HANDLED; 13 bank += (group - 1); 14 15 virq = irq_linear_revmap(bank->irq_domain, pin); 16 if (!virq) 17 return IRQ_NONE; 18 generic_handle_irq(virq); 19 return IRQ_HANDLED; 20 }
第7行的宏EXYNOS_SVC_OFFSET是0xB08,这个需要结合Exynos4412的用户手册看:
1 for (i = 0; i < d->nr_banks; ++i, ++bank) { 2 if (bank->eint_type != EINT_TYPE_WKUP) 3 continue; 4 5 bank->irq_domain = irq_domain_add_linear(bank->of_node, 6 bank->nr_pins, &exynos_eint_irqd_ops, bank); 7 8 bank->irq_chip = irq_chip; 9 10 if (!of_find_property(bank->of_node, "interrupts", NULL)) { 11 bank->eint_type = EINT_TYPE_WKUP_MUX; 12 ++muxed_banks; 13 continue; 14 } 15 16 weint_data = devm_kzalloc(dev, bank->nr_pins 17 * sizeof(*weint_data), GFP_KERNEL); 18 19 for (idx = 0; idx < bank->nr_pins; ++idx) { 20 irq = irq_of_parse_and_map(bank->of_node, idx); 21 22 weint_data[idx].irq = idx; 23 weint_data[idx].bank = bank; 24 irq_set_chained_handler_and_data(irq, 25 exynos_irq_eint0_15, 26 &weint_data[idx]); 27 } 28 }
在设备树中GPX0和GPX1设置interupts属性,而GPX2和GPX3没有。所以执行完上面的逻辑,muxed_banks为2,就是GPX2和GPX3,而其bank->eint_type被设置为了EINT_TYPE_WKUP_MUX。
1 static void exynos_irq_eint0_15(struct irq_desc *desc) 2 { 3 struct exynos_weint_data *eintd = irq_desc_get_handler_data(desc); 4 struct samsung_pin_bank *bank = eintd->bank; 5 struct irq_chip *chip = irq_desc_get_chip(desc); 6 int eint_irq; 7 8 chained_irq_enter(chip, desc); 9 10 eint_irq = irq_linear_revmap(bank->irq_domain, eintd->irq); 11 generic_handle_irq(eint_irq); 12 13 chained_irq_exit(chip, desc); 14 }
1 irq = irq_of_parse_and_map(wkup_np, 0); 2 3 muxed_data = devm_kzalloc(dev, sizeof(*muxed_data) 4 + muxed_banks*sizeof(struct samsung_pin_bank *), GFP_KERNEL); 5 6 irq_set_chained_handler_and_data(irq, exynos_irq_demux_eint16_31, 7 muxed_data); 8 9 bank = d->pin_banks; 10 idx = 0; 11 for (i = 0; i < d->nr_banks; ++i, ++bank) { 12 if (bank->eint_type != EINT_TYPE_WKUP_MUX) 13 continue; 14 15 muxed_data->banks[idx++] = bank; 16 } 17 muxed_data->nr_banks = muxed_banks;
第1行解析设备树里"wakeup-interrupt-controller"节点的interrupts属性,映射获得对应的virq
第6行设置级联
1 static void exynos_irq_demux_eint16_31(struct irq_desc *desc) 2 { 3 struct irq_chip *chip = irq_desc_get_chip(desc); 4 struct exynos_muxed_weint_data *eintd = irq_desc_get_handler_data(desc); 5 struct samsung_pinctrl_drv_data *d = eintd->banks[0]->drvdata; 6 unsigned long pend; 7 unsigned long mask; 8 int i; 9 10 chained_irq_enter(chip, desc); 11 12 for (i = 0; i < eintd->nr_banks; ++i) { 13 struct samsung_pin_bank *b = eintd->banks[i]; 14 pend = readl(d->virt_base + b->irq_chip->eint_pend 15 + b->eint_offset); 16 mask = readl(d->virt_base + b->irq_chip->eint_mask 17 + b->eint_offset); 18 exynos_irq_demux_eint(pend & ~mask, b->irq_domain); 19 } 20 21 chained_irq_exit(chip, desc); 22 }
第12行的for循环依次处理GPX2和GPX3,主要就是看是不是有那个引脚的中断处于pengding中,如果有的话,函数exynos_irq_demux_eint会进行处理。
1 static inline void exynos_irq_demux_eint(unsigned long pend, 2 struct irq_domain *domain) 3 { 4 unsigned int irq; 5 6 while (pend) { 7 irq = fls(pend) - 1; 8 generic_handle_irq(irq_find_mapping(domain, irq)); 9 pend &= ~(1 << irq); 10 } 11 }
1 static void __init combiner_init(void __iomem *combiner_base, 2 struct device_node *np) 3 { 4 int i, irq; 5 unsigned int nr_irq; 6 7 nr_irq = max_nr * IRQ_IN_COMBINER; 8 9 combiner_data = kcalloc(max_nr, sizeof (*combiner_data), GFP_KERNEL); 10 11 combiner_irq_domain = irq_domain_add_linear(np, nr_irq, 12 &combiner_irq_domain_ops, combiner_data); 13 14 for (i = 0; i < max_nr; i++) { 15 irq = irq_of_parse_and_map(np, i); 16 17 combiner_init_one(&combiner_data[i], i, 18 combiner_base + (i >> 2) * 0x10, irq); 19 combiner_cascade_irq(&combiner_data[i], irq); 20 } 21 }
第15行解析interrupt combiner节点的interrupts属性,获得对应的virq
第19行设置级联
标签:中断控制 属性 nod 用户手册 级联 stat 硬件 需要 property
原文地址:http://www.cnblogs.com/pengdonglin137/p/7466342.html