staticint pic32_set_ext_polarity(int bit, u32 type)
{ /* * External interrupts can be either edge rising or edge falling, * but not both.
*/ switch (type) { case IRQ_TYPE_EDGE_RISING:
writel(BIT(bit), evic_base + PIC32_SET(REG_INTCON)); break; case IRQ_TYPE_EDGE_FALLING:
writel(BIT(bit), evic_base + PIC32_CLR(REG_INTCON)); break; default: return -EINVAL;
}
return 0;
}
staticint pic32_set_type_edge(struct irq_data *data, unsignedint flow_type)
{ struct evic_chip_data *priv = irqd_to_priv(data); int ret; int i;
if (!(flow_type & IRQ_TYPE_EDGE_BOTH)) return -EBADR;
/* set polarity for external interrupts only */ for (i = 0; i < ARRAY_SIZE(priv->ext_irqs); i++) { if (priv->ext_irqs[i] == data->hwirq) {
ret = pic32_set_ext_polarity(i, flow_type); if (ret) return ret;
}
}
ret = irq_map_generic_chip(d, virq, hw); if (ret) return ret;
/* * Piggyback on xlate function to move to an alternate chip as necessary * at time of mapping instead of allowing the flow handler/chip to be * changed later. This requires all interrupts to be configured through * DT.
*/ if (priv->irq_types[hw] & IRQ_TYPE_SENSE_MASK) {
data = irq_domain_get_irq_data(d, virq);
irqd_set_trigger_type(data, priv->irq_types[hw]);
irq_setup_alt_chip(data, priv->irq_types[hw]);
}
evic_base = of_iomap(node, 0); if (!evic_base) return -ENOMEM;
priv = kcalloc(nchips, sizeof(*priv), GFP_KERNEL); if (!priv) {
ret = -ENOMEM; goto err_iounmap;
}
evic_irq_domain = irq_domain_create_linear(of_fwnode_handle(node), nchips * 32,
&pic32_irq_domain_ops,
priv); if (!evic_irq_domain) {
ret = -ENOMEM; goto err_free_priv;
}
/* * The PIC32 EVIC has a linear list of irqs and the type of each * irq is determined by the hardware peripheral the EVIC is arbitrating. * These irq types are defined in the datasheet as "persistent" and * "non-persistent" which are mapped here to level and edge * respectively. To manage the different flow handler requirements of * each irq type, different chip_types are used.
*/
ret = irq_alloc_domain_generic_chips(evic_irq_domain, 32, 2, "evic-level", handle_level_irq,
clr, 0, 0); if (ret) goto err_domain_remove;
for (i = 0; i < nchips; i++) {
u32 ifsclr = PIC32_CLR(REG_IFS_OFFSET + (i * 0x10));
u32 iec = REG_IEC_OFFSET + (i * 0x10);
gc = irq_get_domain_generic_chip(evic_irq_domain, i * 32);
gc->reg_base = evic_base;
gc->unused = 0;
/* * Level/persistent interrupts have a special requirement that * the condition generating the interrupt be cleared before the * interrupt flag (ifs) can be cleared. chip.irq_eoi is used to * complete the interrupt with an ack.
*/
gc->chip_types[0].type = IRQ_TYPE_LEVEL_MASK;
gc->chip_types[0].handler = handle_fasteoi_irq;
gc->chip_types[0].regs.ack = ifsclr;
gc->chip_types[0].regs.mask = iec;
gc->chip_types[0].chip.name = "evic-level";
gc->chip_types[0].chip.irq_eoi = irq_gc_ack_set_bit;
gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit;
gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit;
gc->chip_types[0].chip.flags = IRQCHIP_SKIP_SET_WAKE;
/* * External interrupts have software configurable edge polarity. These * interrupts are defined in DT allowing polarity to be configured only * for these interrupts when requested.
*/
pic32_ext_irq_of_init(evic_irq_domain);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.