]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ASoC: amd: ps: fix for soundwire failures during hibernation exit sequence
authorVijendar Mukunda <Vijendar.Mukunda@amd.com>
Mon, 23 Jun 2025 08:44:55 +0000 (14:14 +0530)
committerMark Brown <broonie@kernel.org>
Mon, 23 Jun 2025 13:20:29 +0000 (14:20 +0100)
During the hibernate entry sequence, ACP registers will be reset to
default values and acp ip will be completely powered off including acp
SoundWire pads. During resume sequence, if acp SoundWire pad keeper enable
register is not restored along with pad pulldown control register value,
then SoundWire manager links won't be powered on correctly results in
peripheral register access failures and completely audio function is
broken.

Add code to store the acp SoundWire pad keeper enable register and acp pad
pulldown ctrl register values before entering into suspend state and
restore the register values during resume sequence based on condition check
for acp SoundWire pad keeper enable register for ACP6.3, ACP7.0 & ACP7.1
platforms.

Fixes: 491628388005 ("ASoC: amd: ps: add callback functions for acp pci driver pm ops")
Signed-off-by: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
Link: https://patch.msgid.link/20250623084630.3100279-1-Vijendar.Mukunda@amd.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/amd/ps/acp63.h
sound/soc/amd/ps/ps-common.c

index 85feae45c44c5c06a0fcf1ae257a845e5f7054ff..d7c994e26e4dfa5b8cd806725c38801e5967c0ba 100644 (file)
@@ -334,6 +334,8 @@ struct acp_hw_ops {
  * @addr: pci ioremap address
  * @reg_range: ACP reigister range
  * @acp_rev: ACP PCI revision id
+ * @acp_sw_pad_keeper_en: store acp SoundWire pad keeper enable register value
+ * @acp_pad_pulldown_ctrl: store acp pad pulldown control register value
  * @acp63_sdw0-dma_intr_stat: DMA interrupt status array for ACP6.3 platform SoundWire
  * manager-SW0 instance
  * @acp63_sdw_dma_intr_stat: DMA interrupt status array for ACP6.3 platform SoundWire
@@ -367,6 +369,8 @@ struct acp63_dev_data {
        u32 addr;
        u32 reg_range;
        u32 acp_rev;
+       u32 acp_sw_pad_keeper_en;
+       u32 acp_pad_pulldown_ctrl;
        u16 acp63_sdw0_dma_intr_stat[ACP63_SDW0_DMA_MAX_STREAMS];
        u16 acp63_sdw1_dma_intr_stat[ACP63_SDW1_DMA_MAX_STREAMS];
        u16 acp70_sdw0_dma_intr_stat[ACP70_SDW0_DMA_MAX_STREAMS];
index 1c89fb5fe1da5d9b83473b26ecc2a5c1defda7c6..7b4966b75dc6759daf2800ba961289f0e8eeaf87 100644 (file)
@@ -160,6 +160,8 @@ static int __maybe_unused snd_acp63_suspend(struct device *dev)
 
        adata = dev_get_drvdata(dev);
        if (adata->is_sdw_dev) {
+               adata->acp_sw_pad_keeper_en = readl(adata->acp63_base + ACP_SW0_PAD_KEEPER_EN);
+               adata->acp_pad_pulldown_ctrl = readl(adata->acp63_base + ACP_PAD_PULLDOWN_CTRL);
                adata->sdw_en_stat = check_acp_sdw_enable_status(adata);
                if (adata->sdw_en_stat) {
                        writel(1, adata->acp63_base + ACP_ZSC_DSP_CTRL);
@@ -197,6 +199,7 @@ static int __maybe_unused snd_acp63_runtime_resume(struct device *dev)
 static int __maybe_unused snd_acp63_resume(struct device *dev)
 {
        struct acp63_dev_data *adata;
+       u32 acp_sw_pad_keeper_en;
        int ret;
 
        adata = dev_get_drvdata(dev);
@@ -209,6 +212,12 @@ static int __maybe_unused snd_acp63_resume(struct device *dev)
        if (ret)
                dev_err(dev, "ACP init failed\n");
 
+       acp_sw_pad_keeper_en = readl(adata->acp63_base + ACP_SW0_PAD_KEEPER_EN);
+       dev_dbg(dev, "ACP_SW0_PAD_KEEPER_EN:0x%x\n", acp_sw_pad_keeper_en);
+       if (!acp_sw_pad_keeper_en) {
+               writel(adata->acp_sw_pad_keeper_en, adata->acp63_base + ACP_SW0_PAD_KEEPER_EN);
+               writel(adata->acp_pad_pulldown_ctrl, adata->acp63_base + ACP_PAD_PULLDOWN_CTRL);
+       }
        return ret;
 }
 
@@ -408,6 +417,8 @@ static int __maybe_unused snd_acp70_suspend(struct device *dev)
 
        adata = dev_get_drvdata(dev);
        if (adata->is_sdw_dev) {
+               adata->acp_sw_pad_keeper_en = readl(adata->acp63_base + ACP_SW0_PAD_KEEPER_EN);
+               adata->acp_pad_pulldown_ctrl = readl(adata->acp63_base + ACP_PAD_PULLDOWN_CTRL);
                adata->sdw_en_stat = check_acp_sdw_enable_status(adata);
                if (adata->sdw_en_stat) {
                        writel(1, adata->acp63_base + ACP_ZSC_DSP_CTRL);
@@ -445,6 +456,7 @@ static int __maybe_unused snd_acp70_runtime_resume(struct device *dev)
 static int __maybe_unused snd_acp70_resume(struct device *dev)
 {
        struct acp63_dev_data *adata;
+       u32 acp_sw_pad_keeper_en;
        int ret;
 
        adata = dev_get_drvdata(dev);
@@ -459,6 +471,12 @@ static int __maybe_unused snd_acp70_resume(struct device *dev)
        if (ret)
                dev_err(dev, "ACP init failed\n");
 
+       acp_sw_pad_keeper_en = readl(adata->acp63_base + ACP_SW0_PAD_KEEPER_EN);
+       dev_dbg(dev, "ACP_SW0_PAD_KEEPER_EN:0x%x\n", acp_sw_pad_keeper_en);
+       if (!acp_sw_pad_keeper_en) {
+               writel(adata->acp_sw_pad_keeper_en, adata->acp63_base + ACP_SW0_PAD_KEEPER_EN);
+               writel(adata->acp_pad_pulldown_ctrl, adata->acp63_base + ACP_PAD_PULLDOWN_CTRL);
+       }
        return ret;
 }