mfd: stm32-timers: Add support for interrupts
authorFabrice Gasnier <fabrice.gasnier@foss.st.com>
Tue, 29 Aug 2023 13:40:25 +0000 (15:40 +0200)
committerLee Jones <lee@kernel.org>
Wed, 1 Nov 2023 10:02:12 +0000 (10:02 +0000)
There are two types of STM32 timers that may have:

- a global interrupt line
- 4 dedicated interrupt lines.

Those interrupts are optional as defined in the dt-bindings. Enforce checks
on either one, four or no interrupts are provided with their names.
Optionally get them here, to be used by child devices.

Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com>
Link: https://lore.kernel.org/r/20230829134029.2402868-5-fabrice.gasnier@foss.st.com
Signed-off-by: Lee Jones <lee@kernel.org>
drivers/mfd/stm32-timers.c
include/linux/mfd/stm32-timers.h

index 732a28db80fadefc1b2be7d02ad56fdeec0d5145..a656a1c186a896b200a7d8c5518162d315439fd6 100644 (file)
@@ -215,6 +215,48 @@ static void stm32_timers_dma_remove(struct device *dev,
                        dma_release_channel(ddata->dma.chans[i]);
 }
 
+static const char * const stm32_timers_irq_name[STM32_TIMERS_MAX_IRQS] = {
+       "brk", "up", "trg-com", "cc"
+};
+
+static int stm32_timers_irq_probe(struct platform_device *pdev,
+                                 struct stm32_timers *ddata)
+{
+       int i, ret;
+
+       /*
+        * STM32 Timer may have either:
+        * - a unique global interrupt line
+        * - four dedicated interrupt lines that may be handled separately.
+        * Optionally get them here, to be used by child devices.
+        */
+       ret = platform_get_irq_byname_optional(pdev, "global");
+       if (ret < 0 && ret != -ENXIO) {
+               return ret;
+       } else if (ret != -ENXIO) {
+               ddata->irq[STM32_TIMERS_IRQ_GLOBAL_BRK] = ret;
+               ddata->nr_irqs = 1;
+               return 0;
+       }
+
+       for (i = 0; i < STM32_TIMERS_MAX_IRQS; i++) {
+               ret = platform_get_irq_byname_optional(pdev, stm32_timers_irq_name[i]);
+               if (ret < 0 && ret != -ENXIO) {
+                       return ret;
+               } else if (ret != -ENXIO) {
+                       ddata->irq[i] = ret;
+                       ddata->nr_irqs++;
+               }
+       }
+
+       if (ddata->nr_irqs && ddata->nr_irqs != STM32_TIMERS_MAX_IRQS) {
+               dev_err(&pdev->dev, "Invalid number of IRQs %d\n", ddata->nr_irqs);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static int stm32_timers_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
@@ -245,6 +287,10 @@ static int stm32_timers_probe(struct platform_device *pdev)
 
        stm32_timers_get_arr_size(ddata);
 
+       ret = stm32_timers_irq_probe(pdev, ddata);
+       if (ret)
+               return ret;
+
        ret = stm32_timers_dma_probe(dev, ddata);
        if (ret) {
                stm32_timers_dma_remove(dev, ddata);
index 1b94325febb31845c7ac711ec7cd90bb0576ed6c..ca35af30745f7fdf86867f50be2e9e87c6b8a778 100644 (file)
@@ -102,6 +102,15 @@ enum stm32_timers_dmas {
        STM32_TIMERS_MAX_DMAS,
 };
 
+/* STM32 Timer may have either a unique global interrupt or 4 interrupt lines */
+enum stm32_timers_irqs {
+       STM32_TIMERS_IRQ_GLOBAL_BRK, /* global or brk IRQ */
+       STM32_TIMERS_IRQ_UP,
+       STM32_TIMERS_IRQ_TRG_COM,
+       STM32_TIMERS_IRQ_CC,
+       STM32_TIMERS_MAX_IRQS,
+};
+
 /**
  * struct stm32_timers_dma - STM32 timer DMA handling.
  * @completion:                end of DMA transfer completion
@@ -123,6 +132,8 @@ struct stm32_timers {
        struct regmap *regmap;
        u32 max_arr;
        struct stm32_timers_dma dma; /* Only to be used by the parent */
+       unsigned int nr_irqs;
+       int irq[STM32_TIMERS_MAX_IRQS];
 };
 
 #if IS_REACHABLE(CONFIG_MFD_STM32_TIMERS)