From: Benedikt Spranger <b.spran...@linutronix.de>

The Flexcard comprise an interrupt controller for the attached
tinys, timer, a Flexray related trigger and a second one for DMA.
Both controllers share a single IRQ line.

Add an interrupt domain for the DMA Controller interrupts.

Signed-off-by: Holger Dengler <deng...@linutronix.de>
Signed-off-by: Benedikt Spranger <b.spran...@linutronix.de>
cc: Samuel Ortiz <sa...@linux.intel.com>
cc: Lee Jones <lee.jo...@linaro.org>
---
 drivers/mfd/flexcard/irq.c   | 95 +++++++++++++++++++++++++++++++++++++++++---
 drivers/mfd/flexcard/irq.h   | 11 +++++
 include/linux/mfd/flexcard.h | 23 +++++++++++
 3 files changed, 124 insertions(+), 5 deletions(-)

diff --git a/drivers/mfd/flexcard/irq.c b/drivers/mfd/flexcard/irq.c
index fefcb24..17e8b2c 100644
--- a/drivers/mfd/flexcard/irq.c
+++ b/drivers/mfd/flexcard/irq.c
@@ -27,11 +27,13 @@
 static irqreturn_t flexcard_demux(int irq, void *data)
 {
        struct flexcard_device *priv = data;
-       u32 stat;
+       u32 stat, dma_stat;
        int i, cur;
 
        stat = readl(&priv->conf->irs);
-       if (!stat)
+       dma_stat = readl(&priv->conf->dma_irsr);
+
+       if (!stat && !dma_stat)
                return IRQ_NONE;
 
        for (i = 0; i < NR_FLEXCARD_IRQ; i++) {
@@ -41,6 +43,15 @@ static irqreturn_t flexcard_demux(int irq, void *data)
                                generic_handle_irq(cur);
                }
        }
+
+       for (i = 0; i < NR_FLEXCARD_DMA_IRQ; i++) {
+               if (dma_stat & flexcard_dma_irq_tab[i].status) {
+                       cur = irq_find_mapping(priv->dma_domain, i);
+                       if (cur)
+                               generic_handle_irq(cur);
+               }
+       }
+
        return IRQ_HANDLED;
 }
 
@@ -125,6 +136,63 @@ static struct irq_domain_ops flexcard_irq_domain_ops = {
        .map = flexcard_irq_domain_map,
 };
 
+static void flexcard_dma_irq_ack(struct irq_data *d)
+{
+       struct flexcard_device *priv = irq_data_get_irq_chip_data(d);
+
+       writel(flexcard_dma_irq_tab[d->hwirq].reset, &priv->conf->dma_irsr);
+}
+
+static void flexcard_dma_irq_mask(struct irq_data *d)
+{
+       struct flexcard_device *priv = irq_data_get_irq_chip_data(d);
+       unsigned long flags;
+       u32 irer;
+
+       raw_spin_lock_irqsave(&priv->irq_lock, flags);
+       irer = readl(&priv->conf->dma_irer);
+       irer &= ~flexcard_dma_irq_tab[d->hwirq].enable;
+       writel(irer, &priv->conf->dma_irer);
+       raw_spin_unlock_irqrestore(&priv->irq_lock, flags);
+}
+
+static void flexcard_dma_irq_unmask(struct irq_data *d)
+{
+       struct flexcard_device *priv = irq_data_get_irq_chip_data(d);
+       unsigned long flags;
+       u32 irer;
+
+       raw_spin_lock_irqsave(&priv->irq_lock, flags);
+       irer = readl(&priv->conf->dma_irer);
+       irer |= FLEXCARD_DMA_IRER_DIRE | flexcard_dma_irq_tab[d->hwirq].enable;
+       writel(irer, &priv->conf->dma_irer);
+       raw_spin_unlock_irqrestore(&priv->irq_lock, flags);
+}
+
+static struct irq_chip flexcard_dma_irq_chip = {
+       .name           = "flexcard_dma_irq",
+       .irq_ack        = flexcard_dma_irq_ack,
+       .irq_mask       = flexcard_dma_irq_mask,
+       .irq_unmask     = flexcard_dma_irq_unmask,
+};
+
+static int flexcard_dma_irq_domain_map(struct irq_domain *d, unsigned int irq,
+                                      irq_hw_number_t hw)
+{
+       struct flexcard_device *priv = d->host_data;
+
+       irq_set_chip_and_handler_name(irq, &flexcard_dma_irq_chip,
+                                     handle_level_irq, "flexcard-dma");
+       irq_set_chip_data(irq, priv);
+       irq_modify_status(irq, IRQ_NOREQUEST | IRQ_NOAUTOEN, IRQ_NOPROBE);
+
+       return 0;
+}
+
+static struct irq_domain_ops flexcard_dma_irq_domain_ops = {
+       .map = flexcard_dma_irq_domain_map,
+};
+
 int flexcard_setup_irq(struct pci_dev *pdev)
 {
        struct flexcard_device *priv = pci_get_drvdata(pdev);
@@ -143,12 +211,27 @@ int flexcard_setup_irq(struct pci_dev *pdev)
                dev_err(&pdev->dev, "could not request irq domain\n");
                return -ENODEV;
        }
-
        priv->irq_domain = domain;
 
+       domain = irq_domain_add_linear(NULL, NR_FLEXCARD_DMA_IRQ,
+                                      &flexcard_dma_irq_domain_ops, priv);
+       if (!domain) {
+               dev_err(&pdev->dev, "could not request dma irq domain\n");
+               ret = -ENODEV;
+               goto out_irq;
+       }
+       priv->dma_domain = domain;
+
        ret = flexcard_req_irq(pdev);
        if (ret)
-               irq_domain_remove(priv->dma_domain);
+               goto out_dma;
+
+       return 0;
+
+out_dma:
+       irq_domain_remove(priv->dma_domain);
+out_irq:
+       irq_domain_remove(priv->irq_domain);
 
        return ret;
 }
@@ -161,7 +244,9 @@ void flexcard_remove_irq(struct pci_dev *pdev)
        writel(0, &priv->conf->irc);
        writel(0, &priv->conf->dma_irer);
 
+       irq_domain_remove(priv->dma_domain);
+       irq_domain_remove(priv->irq_domain);
+
        free_irq(pdev->irq, priv);
        pci_disable_msi(pdev);
-       irq_domain_remove(priv->irq_domain);
 }
diff --git a/drivers/mfd/flexcard/irq.h b/drivers/mfd/flexcard/irq.h
index b18fb5b..0e6fe18 100644
--- a/drivers/mfd/flexcard/irq.h
+++ b/drivers/mfd/flexcard/irq.h
@@ -1,6 +1,8 @@
 #ifndef FLEXCARD_IRQ_H
 #define FLEXCARD_IRQ_H
 
+#define FLEXCARD_DMA_IRER_DIRE         (1 << 31)
+
 struct flexcard_irq_tab {
        u32 enable;
        u32 reset;
@@ -47,4 +49,13 @@ static const struct flexcard_irq_tab flexcard_irq_tab[] = {
 
 #define NR_FLEXCARD_IRQ                ARRAY_SIZE(flexcard_irq_tab)
 
+static const struct flexcard_irq_tab flexcard_dma_irq_tab[] = {
+       to_irq_tab_ack(0, 0, 0),        /* DMA_C0  */
+       to_irq_tab_ack(1, 1, 1),        /* DMA_TE  */
+       to_irq_tab_ack(4, 4, 4),        /* DMA_TI  */
+       to_irq_tab_ack(5, 5, 5),        /* DMA_CBL */
+};
+
+#define NR_FLEXCARD_DMA_IRQ    ARRAY_SIZE(flexcard_dma_irq_tab)
+
 #endif /* FLEXCARD_IRQ_H */
diff --git a/include/linux/mfd/flexcard.h b/include/linux/mfd/flexcard.h
index f5b789f..f9b0962 100644
--- a/include/linux/mfd/flexcard.h
+++ b/include/linux/mfd/flexcard.h
@@ -30,6 +30,7 @@ struct flexcard_device {
        struct miscdevice dev;
        struct kref ref;
        struct irq_domain *irq_domain;
+       struct irq_domain *dma_domain;
        int cardnr;
        char name[FLEXCARD_MAX_NAME];
 };
@@ -39,4 +40,26 @@ enum flexcard_cell_id {
        FLEXCARD_CELL_FLEXRAY,
 };
 
+#define FLEXCARD_IRQ_CC1CCYS_OFF       0
+#define FLEXCARD_IRQ_CC2CCYS_OFF       1
+#define FLEXCARD_IRQ_CC3CCYS_OFF       2
+#define FLEXCARD_IRQ_CC4CCYS_OFF       3
+#define FLEXCARD_IRQ_WAKE4A_OFF                4
+#define FLEXCARD_IRQ_WAKE4B_OFF                5
+#define FLEXCARD_IRQ_WAKE3A_OFF                6
+#define FLEXCARD_IRQ_WAKE3B_OFF                7
+#define FLEXCARD_IRQ_WAKE2A_OFF                8
+#define FLEXCARD_IRQ_WAKE2B_OFF                9
+#define FLEXCARD_IRQ_WAKE1A_OFF                10
+#define FLEXCARD_IRQ_WAKE1B_OFF                11
+#define FLEXCARD_IRQ_CC1T0_OFF         12
+#define FLEXCARD_IRQ_CC2T0_OFF         13
+#define FLEXCARD_IRQ_CC3T0_OFF         14
+#define FLEXCARD_IRQ_CC4T0_OFF         15
+
+#define FLEXCARD_DMA_IRQ_CO            0
+#define FLEXCARD_DMA_IRQ_TE            1
+#define FLEXCARD_DMA_IRQ_TI            2
+#define FLEXCARD_DMA_IRQ_CBL           3
+
 #endif /* FLEXCARD_H */
-- 
2.1.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to