diff mbox series

[V2,17/23] ASoC: amd: acp70: add soundwire wake interrupt handling

Message ID 20250120100130.3710412-18-Vijendar.Mukunda@amd.com (mailing list archive)
State New
Headers show
Series ASoC: amd: acp70: add soundwire and acp pdm support | expand

Commit Message

Mukunda,Vijendar Jan. 20, 2025, 10:01 a.m. UTC
For Soundwire wake event, SoundWire Host wake interrupt will be asserted
when ACP is in D0 state and SoundWire manager instance is in D3 state and
PME status is set when ACP is in D3 state and SoundWire manager instance
is in D3 state.

Add code to handle SoundWire PME status and host wake interrupts in
ACP7.0 interrupt handler.

Signed-off-by: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
---
 sound/soc/amd/acp70/acp70.h     |  8 ++++++
 sound/soc/amd/acp70/pci-acp70.c | 51 +++++++++++++++++++++++++++++++++
 2 files changed, 59 insertions(+)
diff mbox series

Patch

diff --git a/sound/soc/amd/acp70/acp70.h b/sound/soc/amd/acp70/acp70.h
index c3b3b6c38902..ab4d6a5c1cd2 100644
--- a/sound/soc/amd/acp70/acp70.h
+++ b/sound/soc/amd/acp70/acp70.h
@@ -60,6 +60,10 @@ 
 
 #define ACP_SDW0_STAT			BIT(21)
 #define ACP_SDW1_STAT			BIT(2)
+#define ACP_SDW0_HOST_WAKE_STAT		BIT(24)
+#define ACP_SDW1_HOST_WAKE_STAT		BIT(25)
+#define ACP_SDW0_PME_STAT		BIT(26)
+#define ACP_SDW1_PME_STAT		BIT(27)
 #define ACP_ERROR_IRQ			BIT(29)
 
 #define ACP_AUDIO0_TX_THRESHOLD		0x1c
@@ -248,6 +252,8 @@  struct sdw_dma_dev_data {
  * @is_pdm_config: flat set to true when PDM configuration is selected from BIOS
  * @is_sdw_config: flag set to true when SDW configuration is selected from BIOS
  * @sdw_en_stat: flag set to true when any one of the SoundWire manager instance is enabled
+ * @sdw0_wake_event: flag set to true when wake irq asserted for SW0 instance
+ * @sdw1_wake_event: flag set to true when wake irq asserted for SW1 instance
  */
 
 struct acp70_dev_data {
@@ -270,6 +276,8 @@  struct acp70_dev_data {
 	bool is_pdm_config;
 	bool is_sdw_config;
 	bool sdw_en_stat;
+	bool sdw0_wake_event;
+	bool sdw1_wake_event;
 };
 
 int snd_amd_acp_find_config(struct pci_dev *pci);
diff --git a/sound/soc/amd/acp70/pci-acp70.c b/sound/soc/amd/acp70/pci-acp70.c
index 1e22be4f11bd..ff03fd493e98 100644
--- a/sound/soc/amd/acp70/pci-acp70.c
+++ b/sound/soc/amd/acp70/pci-acp70.c
@@ -99,6 +99,25 @@  static int acp70_deinit(void __iomem *acp_base, struct device *dev)
 	return 0;
 }
 
+static void handle_acp70_sdw_wake_event(struct acp70_dev_data *adata)
+{
+	struct amd_sdw_manager *amd_manager;
+
+	if (adata->sdw0_wake_event) {
+		amd_manager = dev_get_drvdata(&adata->sdw->pdev[0]->dev);
+		if (amd_manager && pm_runtime_suspended(amd_manager->dev))
+			pm_request_resume(amd_manager->dev);
+		adata->sdw0_wake_event = 0;
+	}
+
+	if (adata->sdw1_wake_event) {
+		amd_manager = dev_get_drvdata(&adata->sdw->pdev[1]->dev);
+		if (amd_manager && pm_runtime_suspended(amd_manager->dev))
+			pm_request_resume(amd_manager->dev);
+		adata->sdw1_wake_event = 0;
+	}
+}
+
 static irqreturn_t acp70_irq_thread(int irq, void *context)
 {
 	struct sdw_dma_dev_data *sdw_dma_data;
@@ -133,6 +152,7 @@  static irqreturn_t acp70_irq_handler(int irq, void *dev_id)
 	u32 stream_id = 0;
 	u16 irq_flag = 0;
 	u16 sdw_dma_irq_flag = 0;
+	bool sdw_wake_irq = false;
 	u16 index;
 
 	adata = dev_id;
@@ -169,6 +189,37 @@  static irqreturn_t acp70_irq_handler(int irq, void *dev_id)
 		irq_flag = 1;
 	}
 
+	if (ext_intr_stat1 & ACP_SDW0_HOST_WAKE_STAT) {
+		writel(ACP_SDW0_HOST_WAKE_STAT, adata->acp70_base + ACP_EXTERNAL_INTR_STAT1);
+		adata->sdw0_wake_event = true;
+		sdw_wake_irq = true;
+	}
+
+	if (ext_intr_stat1 & ACP_SDW1_HOST_WAKE_STAT) {
+		writel(ACP_SDW1_HOST_WAKE_STAT, adata->acp70_base + ACP_EXTERNAL_INTR_STAT1);
+		adata->sdw1_wake_event = true;
+		sdw_wake_irq = true;
+	}
+
+	if (ext_intr_stat1 & ACP_SDW0_PME_STAT) {
+		writel(0, adata->acp70_base + ACP_SW0_WAKE_EN);
+		writel(ACP_SDW0_PME_STAT, adata->acp70_base + ACP_EXTERNAL_INTR_STAT1);
+		adata->sdw0_wake_event = true;
+		sdw_wake_irq = true;
+	}
+
+	if (ext_intr_stat1 & ACP_SDW1_PME_STAT) {
+		writel(0, adata->acp70_base + ACP_SW1_WAKE_EN);
+		writel(ACP_SDW1_PME_STAT, adata->acp70_base + ACP_EXTERNAL_INTR_STAT1);
+		adata->sdw1_wake_event = true;
+		sdw_wake_irq = true;
+	}
+
+	if (sdw_wake_irq) {
+		handle_acp70_sdw_wake_event(adata);
+		irq_flag = 1;
+	}
+
 	if (ext_intr_stat & BIT(PDM_DMA_STAT)) {
 		ps_pdm_data = dev_get_drvdata(&adata->pdm_dev->dev);
 		writel(BIT(PDM_DMA_STAT), adata->acp70_base + ACP_EXTERNAL_INTR_STAT);