summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/soc/fsl/qe/Kconfig1
-rw-r--r--drivers/soc/fsl/qe/qe_ports_ic.c116
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[] = {