diff options
| author | Vijendar Mukunda <Vijendar.Mukunda@amd.com> | 2023-06-12 12:59:00 +0300 | 
|---|---|---|
| committer | Mark Brown <broonie@kernel.org> | 2023-06-21 01:30:30 +0300 | 
| commit | 5a06c3ac4cf9a8ca5edf99a07a1129ae25ab581e (patch) | |
| tree | 7610dafbe81458b63e59d97e6a9da32f72f6f4f2 | |
| parent | 298d4f7b176538d41356d145c044442b8456a14e (diff) | |
| download | linux-5a06c3ac4cf9a8ca5edf99a07a1129ae25ab581e.tar.xz | |
ASoC: amd: ps: add pm ops support for SoundWire dma driver
Add support pm ops support for SoundWire dma driver.
Signed-off-by: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
Link: https://lore.kernel.org/r/20230612095903.2113464-7-Vijendar.Mukunda@amd.com
Signed-off-by: Mark Brown <broonie@kernel.org>
| -rw-r--r-- | sound/soc/amd/ps/ps-sdw-dma.c | 98 | 
1 files changed, 96 insertions, 2 deletions
diff --git a/sound/soc/amd/ps/ps-sdw-dma.c b/sound/soc/amd/ps/ps-sdw-dma.c index 1de78948f859..ade130a8062a 100644 --- a/sound/soc/amd/ps/ps-sdw-dma.c +++ b/sound/soc/amd/ps/ps-sdw-dma.c @@ -12,6 +12,7 @@  #include <sound/pcm_params.h>  #include <sound/soc.h>  #include <sound/soc-dai.h> +#include <linux/pm_runtime.h>  #include <linux/soundwire/sdw_amd.h>  #include "acp63.h" @@ -102,6 +103,29 @@ static const struct snd_pcm_hardware acp63_sdw_hardware_capture = {  	.periods_max = SDW_CAPTURE_MAX_NUM_PERIODS,  }; +static void acp63_enable_disable_sdw_dma_interrupts(void __iomem *acp_base, bool enable) +{ +	u32 ext_intr_cntl, ext_intr_cntl1; +	u32 irq_mask = ACP_SDW_DMA_IRQ_MASK; +	u32 irq_mask1 = ACP_P1_SDW_DMA_IRQ_MASK; + +	if (enable) { +		ext_intr_cntl = readl(acp_base + ACP_EXTERNAL_INTR_CNTL); +		ext_intr_cntl |= irq_mask; +		writel(ext_intr_cntl, acp_base + ACP_EXTERNAL_INTR_CNTL); +		ext_intr_cntl1 = readl(acp_base + ACP_EXTERNAL_INTR_CNTL1); +		ext_intr_cntl1 |= irq_mask1; +		writel(ext_intr_cntl1, acp_base + ACP_EXTERNAL_INTR_CNTL1); +	} else { +		ext_intr_cntl = readl(acp_base + ACP_EXTERNAL_INTR_CNTL); +		ext_intr_cntl &= ~irq_mask; +		writel(ext_intr_cntl, acp_base + ACP_EXTERNAL_INTR_CNTL); +		ext_intr_cntl1 = readl(acp_base + ACP_EXTERNAL_INTR_CNTL1); +		ext_intr_cntl1 &= ~irq_mask1; +		writel(ext_intr_cntl1, acp_base + ACP_EXTERNAL_INTR_CNTL1); +	} +} +  static void acp63_config_dma(struct acp_sdw_dma_stream *stream, void __iomem *acp_base,  			     u32 stream_id)  { @@ -440,16 +464,86 @@ static int acp63_sdw_platform_probe(struct platform_device *pdev)  	status = devm_snd_soc_register_component(&pdev->dev,  						 &acp63_sdw_component,  						 NULL, 0); -	if (status) +	if (status) {  		dev_err(&pdev->dev, "Fail to register sdw dma component\n"); +		return status; +	} +	pm_runtime_set_autosuspend_delay(&pdev->dev, ACP_SUSPEND_DELAY_MS); +	pm_runtime_use_autosuspend(&pdev->dev); +	pm_runtime_mark_last_busy(&pdev->dev); +	pm_runtime_set_active(&pdev->dev); +	pm_runtime_enable(&pdev->dev); +	return 0; +} -	return status; +static int acp63_sdw_platform_remove(struct platform_device *pdev) +{ +	pm_runtime_disable(&pdev->dev); +	return 0;  } +static int acp_restore_sdw_dma_config(struct sdw_dma_dev_data *sdw_data) +{ +	struct acp_sdw_dma_stream *stream; +	struct snd_pcm_substream *substream; +	struct snd_pcm_runtime *runtime; +	u32 period_bytes, buf_size, water_mark_size_reg; +	u32 stream_count; +	int index, instance, ret; + +	for (instance = 0; instance < AMD_SDW_MAX_MANAGERS; instance++) { +		if (instance == ACP_SDW0) +			stream_count = ACP63_SDW0_DMA_MAX_STREAMS; +		else +			stream_count = ACP63_SDW1_DMA_MAX_STREAMS; + +		for (index = 0; index < stream_count; index++) { +			if (instance == ACP_SDW0) { +				substream = sdw_data->sdw0_dma_stream[index]; +				water_mark_size_reg = +						sdw0_dma_ring_buf_reg[index].water_mark_size_reg; +			} else { +				substream = sdw_data->sdw1_dma_stream[index]; +				water_mark_size_reg = +						sdw1_dma_ring_buf_reg[index].water_mark_size_reg; +			} + +			if (substream && substream->runtime) { +				runtime = substream->runtime; +				stream = runtime->private_data; +				period_bytes = frames_to_bytes(runtime, runtime->period_size); +				buf_size = frames_to_bytes(runtime, runtime->buffer_size); +				acp63_config_dma(stream, sdw_data->acp_base, index); +				ret = acp63_configure_sdw_ringbuffer(sdw_data->acp_base, index, +								     buf_size, instance); +				if (ret) +					return ret; +				writel(period_bytes, sdw_data->acp_base + water_mark_size_reg); +			} +		} +	} +	acp63_enable_disable_sdw_dma_interrupts(sdw_data->acp_base, true); +	return 0; +} + +static int __maybe_unused acp63_sdw_pcm_resume(struct device *dev) +{ +	struct sdw_dma_dev_data *sdw_data; + +	sdw_data = dev_get_drvdata(dev); +	return acp_restore_sdw_dma_config(sdw_data); +} + +static const struct dev_pm_ops acp63_pm_ops = { +	SET_SYSTEM_SLEEP_PM_OPS(NULL, acp63_sdw_pcm_resume) +}; +  static struct platform_driver acp63_sdw_dma_driver = {  	.probe = acp63_sdw_platform_probe, +	.remove = acp63_sdw_platform_remove,  	.driver = {  		.name = "amd_ps_sdw_dma", +		.pm = &acp63_pm_ops,  	},  };  | 
