ASoC: amd: ps: handle SoundWire interrupts in acp pci driver
authorVijendar Mukunda <Vijendar.Mukunda@amd.com>
Mon, 12 Jun 2023 09:58:56 +0000 (15:28 +0530)
committerMark Brown <broonie@kernel.org>
Tue, 20 Jun 2023 22:30:26 +0000 (23:30 +0100)
Handle SoundWire manager related interrupts in ACP PCI driver
interrupt handler and schedule SoundWire manager work queue for
further processing.

Signed-off-by: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
Link: https://lore.kernel.org/r/20230612095903.2113464-3-Vijendar.Mukunda@amd.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/amd/ps/acp63.h
sound/soc/amd/ps/pci-ps.c

index 80ab542..494f498 100644 (file)
@@ -99,6 +99,9 @@
  * manager instance combination.
  */
 #define ACP63_SDW_PDM_DEV_CONFIG       GENMASK(1, 0)
+#define ACP_SDW0_STAT                  BIT(21)
+#define ACP_SDW1_STAT                  BIT(2)
+#define ACP_ERROR_IRQ                  BIT(29)
 
 enum acp_config {
        ACP_CONFIG_0 = 0,
index cf57ad2..ac82dbe 100644 (file)
@@ -56,6 +56,7 @@ static int acp63_reset(void __iomem *acp_base)
 static void acp63_enable_interrupts(void __iomem *acp_base)
 {
        writel(1, acp_base + ACP_EXTERNAL_INTR_ENB);
+       writel(ACP_ERROR_IRQ, acp_base + ACP_EXTERNAL_INTR_CNTL);
 }
 
 static void acp63_disable_interrupts(void __iomem *acp_base)
@@ -102,23 +103,60 @@ static irqreturn_t acp63_irq_handler(int irq, void *dev_id)
 {
        struct acp63_dev_data *adata;
        struct pdm_dev_data *ps_pdm_data;
-       u32 val;
+       struct amd_sdw_manager *amd_manager;
+       u32 ext_intr_stat, ext_intr_stat1;
+       u16 irq_flag = 0;
        u16 pdev_index;
 
        adata = dev_id;
        if (!adata)
                return IRQ_NONE;
+       /* ACP interrupts will be cleared by reading particular bit and writing
+        * same value to the status register. writing zero's doesn't have any
+        * effect.
+        * Bit by bit checking of IRQ field is implemented.
+        */
+       ext_intr_stat = readl(adata->acp63_base + ACP_EXTERNAL_INTR_STAT);
+       if (ext_intr_stat & ACP_SDW0_STAT) {
+               writel(ACP_SDW0_STAT, adata->acp63_base + ACP_EXTERNAL_INTR_STAT);
+               pdev_index = adata->sdw0_dev_index;
+               amd_manager = dev_get_drvdata(&adata->pdev[pdev_index]->dev);
+               if (amd_manager)
+                       schedule_work(&amd_manager->amd_sdw_irq_thread);
+               irq_flag = 1;
+       }
+
+       ext_intr_stat1 = readl(adata->acp63_base + ACP_EXTERNAL_INTR_STAT1);
+       if (ext_intr_stat1 & ACP_SDW1_STAT) {
+               writel(ACP_SDW1_STAT, adata->acp63_base + ACP_EXTERNAL_INTR_STAT1);
+               pdev_index = adata->sdw1_dev_index;
+               amd_manager = dev_get_drvdata(&adata->pdev[pdev_index]->dev);
+               if (amd_manager)
+                       schedule_work(&amd_manager->amd_sdw_irq_thread);
+               irq_flag = 1;
+       }
 
-       val = readl(adata->acp63_base + ACP_EXTERNAL_INTR_STAT);
-       if (val & BIT(PDM_DMA_STAT)) {
+       if (ext_intr_stat & ACP_ERROR_IRQ) {
+               writel(ACP_ERROR_IRQ, adata->acp63_base + ACP_EXTERNAL_INTR_STAT);
+               /* TODO: Report SoundWire Manager instance errors */
+               writel(0, adata->acp63_base + ACP_SW0_I2S_ERROR_REASON);
+               writel(0, adata->acp63_base + ACP_SW1_I2S_ERROR_REASON);
+               writel(0, adata->acp63_base + ACP_ERROR_STATUS);
+               irq_flag = 1;
+       }
+
+       if (ext_intr_stat & BIT(PDM_DMA_STAT)) {
                pdev_index = adata->pdm_dev_index;
                ps_pdm_data = dev_get_drvdata(&adata->pdev[pdev_index]->dev);
                writel(BIT(PDM_DMA_STAT), adata->acp63_base + ACP_EXTERNAL_INTR_STAT);
                if (ps_pdm_data->capture_stream)
                        snd_pcm_period_elapsed(ps_pdm_data->capture_stream);
-               return IRQ_HANDLED;
+               irq_flag = 1;
        }
-       return IRQ_NONE;
+       if (irq_flag)
+               return IRQ_HANDLED;
+       else
+               return IRQ_NONE;
 }
 
 static int sdw_amd_scan_controller(struct device *dev)