1 // SPDX-License-Identifier: GPL-2.0+
3 * AMD ALSA SoC Yellow Carp PDM Driver
5 * Copyright 2021 Advanced Micro Devices, Inc.
8 #include <linux/platform_device.h>
9 #include <linux/module.h>
10 #include <linux/bitfield.h>
11 #include <linux/err.h>
13 #include <sound/pcm_params.h>
14 #include <sound/soc.h>
15 #include <sound/soc-dai.h>
16 #include <linux/pm_runtime.h>
20 #define DRV_NAME "acp_yc_pdm_dma"
22 static int pdm_gain
= 3;
23 module_param(pdm_gain
, int, 0644);
24 MODULE_PARM_DESC(pdm_gain
, "Gain control (0-3)");
26 static const struct snd_pcm_hardware acp6x_pdm_hardware_capture
= {
27 .info
= SNDRV_PCM_INFO_INTERLEAVED
|
28 SNDRV_PCM_INFO_BLOCK_TRANSFER
|
30 SNDRV_PCM_INFO_MMAP_VALID
|
31 SNDRV_PCM_INFO_PAUSE
| SNDRV_PCM_INFO_RESUME
,
32 .formats
= SNDRV_PCM_FMTBIT_S32_LE
,
35 .rates
= SNDRV_PCM_RATE_48000
,
38 .buffer_bytes_max
= CAPTURE_MAX_NUM_PERIODS
* CAPTURE_MAX_PERIOD_SIZE
,
39 .period_bytes_min
= CAPTURE_MIN_PERIOD_SIZE
,
40 .period_bytes_max
= CAPTURE_MAX_PERIOD_SIZE
,
41 .periods_min
= CAPTURE_MIN_NUM_PERIODS
,
42 .periods_max
= CAPTURE_MAX_NUM_PERIODS
,
45 static void acp6x_init_pdm_ring_buffer(u32 physical_addr
, u32 buffer_size
,
46 u32 watermark_size
, void __iomem
*acp_base
)
48 acp6x_writel(physical_addr
, acp_base
+ ACP_WOV_RX_RINGBUFADDR
);
49 acp6x_writel(buffer_size
, acp_base
+ ACP_WOV_RX_RINGBUFSIZE
);
50 acp6x_writel(watermark_size
, acp_base
+ ACP_WOV_RX_INTR_WATERMARK_SIZE
);
51 acp6x_writel(0x01, acp_base
+ ACPAXI2AXI_ATU_CTRL
);
54 static void acp6x_enable_pdm_clock(void __iomem
*acp_base
)
56 u32 pdm_clk_enable
, pdm_ctrl
;
58 pdm_clk_enable
= ACP_PDM_CLK_FREQ_MASK
;
61 acp6x_writel(pdm_clk_enable
, acp_base
+ ACP_WOV_CLK_CTRL
);
62 pdm_ctrl
= acp6x_readl(acp_base
+ ACP_WOV_MISC_CTRL
);
63 pdm_ctrl
&= ~ACP_WOV_GAIN_CONTROL
;
64 pdm_ctrl
|= FIELD_PREP(ACP_WOV_GAIN_CONTROL
, clamp(pdm_gain
, 0, 3));
65 acp6x_writel(pdm_ctrl
, acp_base
+ ACP_WOV_MISC_CTRL
);
68 static void acp6x_enable_pdm_interrupts(void __iomem
*acp_base
)
72 ext_int_ctrl
= acp6x_readl(acp_base
+ ACP_EXTERNAL_INTR_CNTL
);
73 ext_int_ctrl
|= PDM_DMA_INTR_MASK
;
74 acp6x_writel(ext_int_ctrl
, acp_base
+ ACP_EXTERNAL_INTR_CNTL
);
77 static void acp6x_disable_pdm_interrupts(void __iomem
*acp_base
)
81 ext_int_ctrl
= acp6x_readl(acp_base
+ ACP_EXTERNAL_INTR_CNTL
);
82 ext_int_ctrl
&= ~PDM_DMA_INTR_MASK
;
83 acp6x_writel(ext_int_ctrl
, acp_base
+ ACP_EXTERNAL_INTR_CNTL
);
86 static bool acp6x_check_pdm_dma_status(void __iomem
*acp_base
)
89 u32 pdm_enable
, pdm_dma_enable
;
91 pdm_dma_status
= false;
92 pdm_enable
= acp6x_readl(acp_base
+ ACP_WOV_PDM_ENABLE
);
93 pdm_dma_enable
= acp6x_readl(acp_base
+ ACP_WOV_PDM_DMA_ENABLE
);
94 if ((pdm_enable
& ACP_PDM_ENABLE
) && (pdm_dma_enable
& ACP_PDM_DMA_EN_STATUS
))
95 pdm_dma_status
= true;
97 return pdm_dma_status
;
100 static int acp6x_start_pdm_dma(void __iomem
*acp_base
)
107 pdm_dma_enable
= 0x01;
109 acp6x_enable_pdm_clock(acp_base
);
110 acp6x_writel(pdm_enable
, acp_base
+ ACP_WOV_PDM_ENABLE
);
111 acp6x_writel(pdm_dma_enable
, acp_base
+ ACP_WOV_PDM_DMA_ENABLE
);
113 while (++timeout
< ACP_COUNTER
) {
114 pdm_dma_enable
= acp6x_readl(acp_base
+ ACP_WOV_PDM_DMA_ENABLE
);
115 if ((pdm_dma_enable
& 0x02) == ACP_PDM_DMA_EN_STATUS
)
122 static int acp6x_stop_pdm_dma(void __iomem
*acp_base
)
124 u32 pdm_enable
, pdm_dma_enable
;
128 pdm_dma_enable
= 0x00;
130 pdm_enable
= acp6x_readl(acp_base
+ ACP_WOV_PDM_ENABLE
);
131 pdm_dma_enable
= acp6x_readl(acp_base
+ ACP_WOV_PDM_DMA_ENABLE
);
132 if (pdm_dma_enable
& 0x01) {
133 pdm_dma_enable
= 0x02;
134 acp6x_writel(pdm_dma_enable
, acp_base
+ ACP_WOV_PDM_DMA_ENABLE
);
136 while (++timeout
< ACP_COUNTER
) {
137 pdm_dma_enable
= acp6x_readl(acp_base
+ ACP_WOV_PDM_DMA_ENABLE
);
138 if ((pdm_dma_enable
& 0x02) == 0x00)
142 if (timeout
== ACP_COUNTER
)
145 if (pdm_enable
== ACP_PDM_ENABLE
) {
146 pdm_enable
= ACP_PDM_DISABLE
;
147 acp6x_writel(pdm_enable
, acp_base
+ ACP_WOV_PDM_ENABLE
);
149 acp6x_writel(0x01, acp_base
+ ACP_WOV_PDM_FIFO_FLUSH
);
153 static void acp6x_config_dma(struct pdm_stream_instance
*rtd
, int direction
)
159 addr
= rtd
->dma_addr
;
160 val
= PDM_PTE_OFFSET
;
163 acp6x_writel(ACP_SRAM_PTE_OFFSET
| BIT(31), rtd
->acp6x_base
+
164 ACPAXI2AXI_ATU_BASE_ADDR_GRP_1
);
165 acp6x_writel(PAGE_SIZE_4K_ENABLE
, rtd
->acp6x_base
+
166 ACPAXI2AXI_ATU_PAGE_SIZE_GRP_1
);
167 for (page_idx
= 0; page_idx
< rtd
->num_pages
; page_idx
++) {
168 /* Load the low address of page int ACP SRAM through SRBM */
169 low
= lower_32_bits(addr
);
170 high
= upper_32_bits(addr
);
172 acp6x_writel(low
, rtd
->acp6x_base
+ ACP_SCRATCH_REG_0
+ val
);
174 acp6x_writel(high
, rtd
->acp6x_base
+ ACP_SCRATCH_REG_0
+ val
+ 4);
180 static int acp6x_pdm_dma_open(struct snd_soc_component
*component
,
181 struct snd_pcm_substream
*substream
)
183 struct snd_pcm_runtime
*runtime
;
184 struct pdm_dev_data
*adata
;
185 struct pdm_stream_instance
*pdm_data
;
188 runtime
= substream
->runtime
;
189 adata
= dev_get_drvdata(component
->dev
);
190 pdm_data
= kzalloc(sizeof(*pdm_data
), GFP_KERNEL
);
194 if (substream
->stream
== SNDRV_PCM_STREAM_CAPTURE
)
195 runtime
->hw
= acp6x_pdm_hardware_capture
;
197 ret
= snd_pcm_hw_constraint_integer(runtime
,
198 SNDRV_PCM_HW_PARAM_PERIODS
);
200 dev_err(component
->dev
, "set integer constraint failed\n");
205 acp6x_enable_pdm_interrupts(adata
->acp6x_base
);
207 if (substream
->stream
== SNDRV_PCM_STREAM_CAPTURE
)
208 adata
->capture_stream
= substream
;
210 pdm_data
->acp6x_base
= adata
->acp6x_base
;
211 runtime
->private_data
= pdm_data
;
215 static int acp6x_pdm_dma_hw_params(struct snd_soc_component
*component
,
216 struct snd_pcm_substream
*substream
,
217 struct snd_pcm_hw_params
*params
)
219 struct pdm_stream_instance
*rtd
;
220 size_t size
, period_bytes
;
222 rtd
= substream
->runtime
->private_data
;
225 size
= params_buffer_bytes(params
);
226 period_bytes
= params_period_bytes(params
);
227 rtd
->dma_addr
= substream
->runtime
->dma_addr
;
228 rtd
->num_pages
= (PAGE_ALIGN(size
) >> PAGE_SHIFT
);
229 acp6x_config_dma(rtd
, substream
->stream
);
230 acp6x_init_pdm_ring_buffer(PDM_MEM_WINDOW_START
, size
,
231 period_bytes
, rtd
->acp6x_base
);
235 static u64
acp6x_pdm_get_byte_count(struct pdm_stream_instance
*rtd
,
238 union acp_pdm_dma_count byte_count
;
240 byte_count
.bcount
.high
=
241 acp6x_readl(rtd
->acp6x_base
+ ACP_WOV_RX_LINEARPOSITIONCNTR_HIGH
);
242 byte_count
.bcount
.low
=
243 acp6x_readl(rtd
->acp6x_base
+ ACP_WOV_RX_LINEARPOSITIONCNTR_LOW
);
244 return byte_count
.bytescount
;
247 static snd_pcm_uframes_t
acp6x_pdm_dma_pointer(struct snd_soc_component
*comp
,
248 struct snd_pcm_substream
*stream
)
250 struct pdm_stream_instance
*rtd
;
254 rtd
= stream
->runtime
->private_data
;
255 buffersize
= frames_to_bytes(stream
->runtime
,
256 stream
->runtime
->buffer_size
);
257 bytescount
= acp6x_pdm_get_byte_count(rtd
, stream
->stream
);
258 if (bytescount
> rtd
->bytescount
)
259 bytescount
-= rtd
->bytescount
;
260 pos
= do_div(bytescount
, buffersize
);
261 return bytes_to_frames(stream
->runtime
, pos
);
264 static int acp6x_pdm_dma_new(struct snd_soc_component
*component
,
265 struct snd_soc_pcm_runtime
*rtd
)
267 struct device
*parent
= component
->dev
->parent
;
269 snd_pcm_set_managed_buffer_all(rtd
->pcm
, SNDRV_DMA_TYPE_DEV
,
270 parent
, MIN_BUFFER
, MAX_BUFFER
);
274 static int acp6x_pdm_dma_close(struct snd_soc_component
*component
,
275 struct snd_pcm_substream
*substream
)
277 struct pdm_dev_data
*adata
= dev_get_drvdata(component
->dev
);
279 acp6x_disable_pdm_interrupts(adata
->acp6x_base
);
280 adata
->capture_stream
= NULL
;
284 static int acp6x_pdm_dai_trigger(struct snd_pcm_substream
*substream
,
285 int cmd
, struct snd_soc_dai
*dai
)
287 struct pdm_stream_instance
*rtd
;
290 unsigned int ch_mask
;
292 rtd
= substream
->runtime
->private_data
;
294 switch (substream
->runtime
->channels
) {
302 case SNDRV_PCM_TRIGGER_START
:
303 case SNDRV_PCM_TRIGGER_RESUME
:
304 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
305 acp6x_writel(ch_mask
, rtd
->acp6x_base
+ ACP_WOV_PDM_NO_OF_CHANNELS
);
306 acp6x_writel(PDM_DECIMATION_FACTOR
, rtd
->acp6x_base
+
307 ACP_WOV_PDM_DECIMATION_FACTOR
);
308 rtd
->bytescount
= acp6x_pdm_get_byte_count(rtd
, substream
->stream
);
309 pdm_status
= acp6x_check_pdm_dma_status(rtd
->acp6x_base
);
311 ret
= acp6x_start_pdm_dma(rtd
->acp6x_base
);
313 case SNDRV_PCM_TRIGGER_STOP
:
314 case SNDRV_PCM_TRIGGER_SUSPEND
:
315 case SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
316 pdm_status
= acp6x_check_pdm_dma_status(rtd
->acp6x_base
);
318 ret
= acp6x_stop_pdm_dma(rtd
->acp6x_base
);
327 static const struct snd_soc_dai_ops acp6x_pdm_dai_ops
= {
328 .trigger
= acp6x_pdm_dai_trigger
,
331 static struct snd_soc_dai_driver acp6x_pdm_dai_driver
= {
333 .rates
= SNDRV_PCM_RATE_48000
,
334 .formats
= SNDRV_PCM_FMTBIT_S32_LE
,
340 .ops
= &acp6x_pdm_dai_ops
,
343 static const struct snd_soc_component_driver acp6x_pdm_component
= {
345 .open
= acp6x_pdm_dma_open
,
346 .close
= acp6x_pdm_dma_close
,
347 .hw_params
= acp6x_pdm_dma_hw_params
,
348 .pointer
= acp6x_pdm_dma_pointer
,
349 .pcm_construct
= acp6x_pdm_dma_new
,
350 .legacy_dai_naming
= 1,
353 static int acp6x_pdm_audio_probe(struct platform_device
*pdev
)
355 struct resource
*res
;
356 struct pdm_dev_data
*adata
;
359 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
361 dev_err(&pdev
->dev
, "IORESOURCE_MEM FAILED\n");
365 adata
= devm_kzalloc(&pdev
->dev
, sizeof(*adata
), GFP_KERNEL
);
369 adata
->acp6x_base
= devm_ioremap(&pdev
->dev
, res
->start
, resource_size(res
));
370 if (!adata
->acp6x_base
)
373 adata
->capture_stream
= NULL
;
375 dev_set_drvdata(&pdev
->dev
, adata
);
376 status
= devm_snd_soc_register_component(&pdev
->dev
,
377 &acp6x_pdm_component
,
378 &acp6x_pdm_dai_driver
, 1);
380 dev_err(&pdev
->dev
, "Fail to register acp pdm dai\n");
384 pm_runtime_set_autosuspend_delay(&pdev
->dev
, ACP_SUSPEND_DELAY_MS
);
385 pm_runtime_use_autosuspend(&pdev
->dev
);
386 pm_runtime_mark_last_busy(&pdev
->dev
);
387 pm_runtime_set_active(&pdev
->dev
);
388 pm_runtime_enable(&pdev
->dev
);
392 static void acp6x_pdm_audio_remove(struct platform_device
*pdev
)
394 pm_runtime_disable(&pdev
->dev
);
397 static int __maybe_unused
acp6x_pdm_resume(struct device
*dev
)
399 struct pdm_dev_data
*adata
;
400 struct snd_pcm_runtime
*runtime
;
401 struct pdm_stream_instance
*rtd
;
402 u32 period_bytes
, buffer_len
;
404 adata
= dev_get_drvdata(dev
);
405 if (adata
->capture_stream
&& adata
->capture_stream
->runtime
) {
406 runtime
= adata
->capture_stream
->runtime
;
407 rtd
= runtime
->private_data
;
408 period_bytes
= frames_to_bytes(runtime
, runtime
->period_size
);
409 buffer_len
= frames_to_bytes(runtime
, runtime
->buffer_size
);
410 acp6x_config_dma(rtd
, SNDRV_PCM_STREAM_CAPTURE
);
411 acp6x_init_pdm_ring_buffer(PDM_MEM_WINDOW_START
, buffer_len
,
412 period_bytes
, adata
->acp6x_base
);
414 acp6x_enable_pdm_interrupts(adata
->acp6x_base
);
418 static int __maybe_unused
acp6x_pdm_suspend(struct device
*dev
)
420 struct pdm_dev_data
*adata
;
422 adata
= dev_get_drvdata(dev
);
423 acp6x_disable_pdm_interrupts(adata
->acp6x_base
);
427 static int __maybe_unused
acp6x_pdm_runtime_resume(struct device
*dev
)
429 struct pdm_dev_data
*adata
;
431 adata
= dev_get_drvdata(dev
);
432 acp6x_enable_pdm_interrupts(adata
->acp6x_base
);
436 static const struct dev_pm_ops acp6x_pdm_pm_ops
= {
437 SET_RUNTIME_PM_OPS(acp6x_pdm_suspend
, acp6x_pdm_runtime_resume
, NULL
)
438 SET_SYSTEM_SLEEP_PM_OPS(acp6x_pdm_suspend
, acp6x_pdm_resume
)
441 static struct platform_driver acp6x_pdm_dma_driver
= {
442 .probe
= acp6x_pdm_audio_probe
,
443 .remove
= acp6x_pdm_audio_remove
,
445 .name
= "acp_yc_pdm_dma",
446 .pm
= &acp6x_pdm_pm_ops
,
450 module_platform_driver(acp6x_pdm_dma_driver
);
452 MODULE_AUTHOR("Vijendar.Mukunda@amd.com");
453 MODULE_DESCRIPTION("AMD ACP6x YC PDM Driver");
454 MODULE_LICENSE("GPL v2");
455 MODULE_ALIAS("platform:" DRV_NAME
);