diff options
| -rw-r--r-- | drivers/soc/fsl/qe/Kconfig | 1 | ||||
| -rw-r--r-- | drivers/soc/fsl/qe/qe_ports_ic.c | 116 |
2 files changed, 76 insertions, 41 deletions
diff --git a/drivers/soc/fsl/qe/Kconfig b/drivers/soc/fsl/qe/Kconfig index b35a8fd30ebf..87cd1662e168 100644 --- a/drivers/soc/fsl/qe/Kconfig +++ b/drivers/soc/fsl/qe/Kconfig @@ -71,6 +71,7 @@ config QE_USB config QE_GPIO bool "QE GPIO support" depends on QUICC_ENGINE + select GENERIC_IRQ_CHIP select GPIOLIB help Say Y here if you're going to use hardware that connects to the diff --git a/drivers/soc/fsl/qe/qe_ports_ic.c b/drivers/soc/fsl/qe/qe_ports_ic.c index 29f4334db5a0..4f6b75439f9f 100644 --- a/drivers/soc/fsl/qe/qe_ports_ic.c +++ b/drivers/soc/fsl/qe/qe_ports_ic.c @@ -18,107 +18,144 @@ struct qepic_data { void __iomem *reg; - struct irq_domain *host; int irq; }; static void qepic_mask(struct irq_data *d) { - struct qepic_data *data = irq_data_get_irq_chip_data(d); - u32 val = ioread32be(data->reg + CEPIMR); + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + u32 val; - iowrite32be(val & ~(1 << (31 - irqd_to_hwirq(d))), data->reg + CEPIMR); + guard(raw_spinlock)(&gc->lock); + + val = ioread32be(gc->reg_base + CEPIMR); + iowrite32be(val & ~d->mask, gc->reg_base + CEPIMR); } static void qepic_unmask(struct irq_data *d) { - struct qepic_data *data = irq_data_get_irq_chip_data(d); - u32 val = ioread32be(data->reg + CEPIMR); + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + u32 val; + + guard(raw_spinlock)(&gc->lock); - iowrite32be(val | 1 << (31 - irqd_to_hwirq(d)), data->reg + CEPIMR); + val = ioread32be(gc->reg_base + CEPIMR); + iowrite32be(val | d->mask, gc->reg_base + CEPIMR); } static void qepic_end(struct irq_data *d) { - struct qepic_data *data = irq_data_get_irq_chip_data(d); + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); - iowrite32be(1 << (31 - irqd_to_hwirq(d)), data->reg + CEPIER); + iowrite32be(d->mask, gc->reg_base + CEPIER); +} + +static void qepic_calc_mask(struct irq_data *d) +{ + d->mask = 1 << (31 - irqd_to_hwirq(d)); } static int qepic_set_type(struct irq_data *d, unsigned int flow_type) { - struct qepic_data *data = irq_data_get_irq_chip_data(d); - unsigned int vec = (unsigned int)irqd_to_hwirq(d); - u32 val = ioread32be(data->reg + CEPICR); + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + u32 val; + guard(raw_spinlock)(&gc->lock); + + val = ioread32be(gc->reg_base + CEPICR); switch (flow_type & IRQ_TYPE_SENSE_MASK) { case IRQ_TYPE_EDGE_FALLING: - iowrite32be(val | 1 << (31 - vec), data->reg + CEPICR); + iowrite32be(val | d->mask, gc->reg_base + CEPICR); return 0; case IRQ_TYPE_EDGE_BOTH: case IRQ_TYPE_NONE: - iowrite32be(val & ~(1 << (31 - vec)), data->reg + CEPICR); + iowrite32be(val & ~d->mask, gc->reg_base + CEPICR); return 0; } return -EINVAL; } -static struct irq_chip qepic = { - .name = "QEPIC", - .irq_mask = qepic_mask, - .irq_unmask = qepic_unmask, - .irq_eoi = qepic_end, - .irq_set_type = qepic_set_type, -}; - static void qepic_cascade(struct irq_desc *desc) { - struct qepic_data *data = irq_desc_get_handler_data(desc); + struct irq_domain *domain = irq_desc_get_handler_data(desc); + struct irq_chip_generic *gc = irq_get_domain_generic_chip(domain, 0); struct irq_chip *chip = irq_desc_get_chip(desc); unsigned long event, bit; chained_irq_enter(chip, desc); - event = ioread32be(data->reg + CEPIER); + event = ioread32be(gc->reg_base + CEPIER); if (!event) { handle_bad_irq(desc); goto out; } for_each_set_bit(bit, &event, 32) - generic_handle_domain_irq(data->host, 31 - bit); + generic_handle_domain_irq(domain, 31 - bit); out: chained_irq_exit(chip, desc); } -static int qepic_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) +static int qepic_chip_init(struct irq_chip_generic *gc) { - irq_set_chip_data(virq, h->host_data); - irq_set_chip_and_handler(virq, &qepic, handle_fasteoi_irq); + struct qepic_data *data = gc->domain->host_data; + struct irq_chip_type *ct = gc->chip_types; + + gc->reg_base = data->reg; + + ct->chip.irq_mask = qepic_mask; + ct->chip.irq_unmask = qepic_unmask; + ct->chip.irq_eoi = qepic_end; + ct->chip.irq_set_type = qepic_set_type; + ct->chip.irq_calc_mask = qepic_calc_mask; + return 0; } -static const struct irq_domain_ops qepic_host_ops = { - .map = qepic_host_map, -}; +static int qepic_domain_init(struct irq_domain *d) +{ + struct qepic_data *data = d->host_data; + + irq_set_chained_handler_and_data(data->irq, qepic_cascade, d); + + return 0; +} -static void qepic_remove(void *res) +static void qepic_domain_exit(struct irq_domain *d) { - struct qepic_data *data = res; + struct qepic_data *data = d->host_data; irq_set_chained_handler_and_data(data->irq, NULL, NULL); - irq_domain_remove(data->host); } static int qepic_probe(struct platform_device *pdev) { + struct irq_domain_chip_generic_info dgc_info = { + .name = "QEPIC", + .handler = handle_fasteoi_irq, + .irqs_per_chip = 32, + .num_ct = 1, + .init = qepic_chip_init, + }; + struct irq_domain_info d_info = { + .fwnode = of_fwnode_handle(pdev->dev.of_node), + .domain_flags = IRQ_DOMAIN_FLAG_DESTROY_GC, + .size = 32, + .hwirq_max = 32, + .ops = &irq_generic_chip_ops, + .dgc_info = &dgc_info, + .init = qepic_domain_init, + .exit = qepic_domain_exit, + }; struct device *dev = &pdev->dev; + struct irq_domain *domain; struct qepic_data *data; data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; + d_info.host_data = data; data->reg = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(data->reg)) @@ -128,14 +165,11 @@ static int qepic_probe(struct platform_device *pdev) if (data->irq < 0) return data->irq; - data->host = irq_domain_create_linear(dev_fwnode(dev), 32, &qepic_host_ops, data); - if (!data->host) - return -ENODEV; - - irq_set_chained_handler_and_data(data->irq, qepic_cascade, data); - - return devm_add_action_or_reset(dev, qepic_remove, data); + domain = devm_irq_domain_instantiate(dev, &d_info); + if (IS_ERR(domain)) + return PTR_ERR(domain); + return 0; } static const struct of_device_id qepic_match[] = { |
