The generic IRQ chip framework is available to handle IRQ chips. Using this framework for the QE interrupt controller allows to simplify the driver. Indeed, the framework internally handles operations coded directly in the driver.
Signed-off-by: Paul Louvel <[email protected]> --- drivers/soc/fsl/qe/Kconfig | 1 + 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[] = { -- 2.55.0
