@@ -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);
@@ -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);
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(+)