1 // SPDX-License-Identifier: GPL-2.0+
3 // AMD ALSA SoC PDM Driver
5 //Copyright 2020 Advanced Micro Devices, Inc.
7 #include <linux/platform_device.h>
8 #include <linux/module.h>
9 #include <linux/bitfield.h>
10 #include <linux/err.h>
12 #include <linux/pm_runtime.h>
13 #include <sound/pcm_params.h>
14 #include <sound/soc.h>
15 #include <sound/soc-dai.h>
19 #define DRV_NAME "acp_rn_pdm_dma"
21 static int pdm_gain
= 3;
22 module_param(pdm_gain
, int, 0644);
23 MODULE_PARM_DESC(pdm_gain
, "Gain control (0-3)");
25 static const struct snd_pcm_hardware acp_pdm_hardware_capture
= {
26 .info
= SNDRV_PCM_INFO_INTERLEAVED
|
27 SNDRV_PCM_INFO_BLOCK_TRANSFER
|
29 SNDRV_PCM_INFO_MMAP_VALID
|
30 SNDRV_PCM_INFO_PAUSE
| SNDRV_PCM_INFO_RESUME
,
31 .formats
= SNDRV_PCM_FMTBIT_S32_LE
,
34 .rates
= SNDRV_PCM_RATE_48000
,
37 .buffer_bytes_max
= CAPTURE_MAX_NUM_PERIODS
* CAPTURE_MAX_PERIOD_SIZE
,
38 .period_bytes_min
= CAPTURE_MIN_PERIOD_SIZE
,
39 .period_bytes_max
= CAPTURE_MAX_PERIOD_SIZE
,
40 .periods_min
= CAPTURE_MIN_NUM_PERIODS
,
41 .periods_max
= CAPTURE_MAX_NUM_PERIODS
,
44 static irqreturn_t
pdm_irq_handler(int irq
, void *dev_id
)
46 struct pdm_dev_data
*rn_pdm_data
;
55 val
= rn_readl(rn_pdm_data
->acp_base
+ ACP_EXTERNAL_INTR_STAT
);
56 if ((val
& BIT(PDM_DMA_STAT
)) && rn_pdm_data
->capture_stream
) {
57 rn_writel(BIT(PDM_DMA_STAT
), rn_pdm_data
->acp_base
+
58 ACP_EXTERNAL_INTR_STAT
);
59 snd_pcm_period_elapsed(rn_pdm_data
->capture_stream
);
69 static void init_pdm_ring_buffer(u32 physical_addr
,
72 void __iomem
*acp_base
)
74 rn_writel(physical_addr
, acp_base
+ ACP_WOV_RX_RINGBUFADDR
);
75 rn_writel(buffer_size
, acp_base
+ ACP_WOV_RX_RINGBUFSIZE
);
76 rn_writel(watermark_size
, acp_base
+ ACP_WOV_RX_INTR_WATERMARK_SIZE
);
77 rn_writel(0x01, acp_base
+ ACPAXI2AXI_ATU_CTRL
);
80 static void enable_pdm_clock(void __iomem
*acp_base
)
82 u32 pdm_clk_enable
, pdm_ctrl
;
84 pdm_clk_enable
= ACP_PDM_CLK_FREQ_MASK
;
86 rn_writel(pdm_clk_enable
, acp_base
+ ACP_WOV_CLK_CTRL
);
87 pdm_ctrl
= rn_readl(acp_base
+ ACP_WOV_MISC_CTRL
);
88 pdm_ctrl
&= ~ACP_WOV_GAIN_CONTROL
;
89 pdm_ctrl
|= FIELD_PREP(ACP_WOV_GAIN_CONTROL
, clamp(pdm_gain
, 0, 3));
90 rn_writel(pdm_ctrl
, acp_base
+ ACP_WOV_MISC_CTRL
);
93 static void enable_pdm_interrupts(void __iomem
*acp_base
)
97 ext_int_ctrl
= rn_readl(acp_base
+ ACP_EXTERNAL_INTR_CNTL
);
98 ext_int_ctrl
|= PDM_DMA_INTR_MASK
;
99 rn_writel(ext_int_ctrl
, acp_base
+ ACP_EXTERNAL_INTR_CNTL
);
102 static void disable_pdm_interrupts(void __iomem
*acp_base
)
106 ext_int_ctrl
= rn_readl(acp_base
+ ACP_EXTERNAL_INTR_CNTL
);
107 ext_int_ctrl
|= ~PDM_DMA_INTR_MASK
;
108 rn_writel(ext_int_ctrl
, acp_base
+ ACP_EXTERNAL_INTR_CNTL
);
111 static bool check_pdm_dma_status(void __iomem
*acp_base
)
114 u32 pdm_enable
, pdm_dma_enable
;
116 pdm_dma_status
= false;
117 pdm_enable
= rn_readl(acp_base
+ ACP_WOV_PDM_ENABLE
);
118 pdm_dma_enable
= rn_readl(acp_base
+ ACP_WOV_PDM_DMA_ENABLE
);
119 if ((pdm_enable
& ACP_PDM_ENABLE
) && (pdm_dma_enable
&
120 ACP_PDM_DMA_EN_STATUS
))
121 pdm_dma_status
= true;
122 return pdm_dma_status
;
125 static int start_pdm_dma(void __iomem
*acp_base
)
132 pdm_dma_enable
= 0x01;
134 enable_pdm_clock(acp_base
);
135 rn_writel(pdm_enable
, acp_base
+ ACP_WOV_PDM_ENABLE
);
136 rn_writel(pdm_dma_enable
, acp_base
+ ACP_WOV_PDM_DMA_ENABLE
);
138 while (++timeout
< ACP_COUNTER
) {
139 pdm_dma_enable
= rn_readl(acp_base
+ ACP_WOV_PDM_DMA_ENABLE
);
140 if ((pdm_dma_enable
& 0x02) == ACP_PDM_DMA_EN_STATUS
)
147 static int stop_pdm_dma(void __iomem
*acp_base
)
149 u32 pdm_enable
, pdm_dma_enable
;
152 pdm_enable
= rn_readl(acp_base
+ ACP_WOV_PDM_ENABLE
);
153 pdm_dma_enable
= rn_readl(acp_base
+ ACP_WOV_PDM_DMA_ENABLE
);
154 if (pdm_dma_enable
& 0x01) {
155 pdm_dma_enable
= 0x02;
156 rn_writel(pdm_dma_enable
, acp_base
+ ACP_WOV_PDM_DMA_ENABLE
);
158 while (++timeout
< ACP_COUNTER
) {
159 pdm_dma_enable
= rn_readl(acp_base
+
160 ACP_WOV_PDM_DMA_ENABLE
);
161 if ((pdm_dma_enable
& 0x02) == 0x00)
165 if (timeout
== ACP_COUNTER
)
168 if (pdm_enable
== ACP_PDM_ENABLE
) {
169 pdm_enable
= ACP_PDM_DISABLE
;
170 rn_writel(pdm_enable
, acp_base
+ ACP_WOV_PDM_ENABLE
);
172 rn_writel(0x01, acp_base
+ ACP_WOV_PDM_FIFO_FLUSH
);
176 static void config_acp_dma(struct pdm_stream_instance
*rtd
, int direction
)
182 addr
= rtd
->dma_addr
;
186 rn_writel(ACP_SRAM_PTE_OFFSET
| BIT(31), rtd
->acp_base
+
187 ACPAXI2AXI_ATU_BASE_ADDR_GRP_1
);
188 rn_writel(PAGE_SIZE_4K_ENABLE
, rtd
->acp_base
+
189 ACPAXI2AXI_ATU_PAGE_SIZE_GRP_1
);
191 for (page_idx
= 0; page_idx
< rtd
->num_pages
; page_idx
++) {
192 /* Load the low address of page int ACP SRAM through SRBM */
193 low
= lower_32_bits(addr
);
194 high
= upper_32_bits(addr
);
196 rn_writel(low
, rtd
->acp_base
+ ACP_SCRATCH_REG_0
+ val
);
198 rn_writel(high
, rtd
->acp_base
+ ACP_SCRATCH_REG_0
+ val
+ 4);
204 static int acp_pdm_dma_open(struct snd_soc_component
*component
,
205 struct snd_pcm_substream
*substream
)
207 struct snd_pcm_runtime
*runtime
;
208 struct pdm_dev_data
*adata
;
209 struct pdm_stream_instance
*pdm_data
;
212 runtime
= substream
->runtime
;
213 adata
= dev_get_drvdata(component
->dev
);
214 pdm_data
= kzalloc(sizeof(*pdm_data
), GFP_KERNEL
);
218 if (substream
->stream
== SNDRV_PCM_STREAM_CAPTURE
)
219 runtime
->hw
= acp_pdm_hardware_capture
;
221 ret
= snd_pcm_hw_constraint_integer(runtime
,
222 SNDRV_PCM_HW_PARAM_PERIODS
);
224 dev_err(component
->dev
, "set integer constraint failed\n");
229 enable_pdm_interrupts(adata
->acp_base
);
231 if (substream
->stream
== SNDRV_PCM_STREAM_CAPTURE
)
232 adata
->capture_stream
= substream
;
234 pdm_data
->acp_base
= adata
->acp_base
;
235 runtime
->private_data
= pdm_data
;
239 static int acp_pdm_dma_hw_params(struct snd_soc_component
*component
,
240 struct snd_pcm_substream
*substream
,
241 struct snd_pcm_hw_params
*params
)
243 struct pdm_stream_instance
*rtd
;
244 size_t size
, period_bytes
;
246 rtd
= substream
->runtime
->private_data
;
249 size
= params_buffer_bytes(params
);
250 period_bytes
= params_period_bytes(params
);
251 rtd
->dma_addr
= substream
->runtime
->dma_addr
;
252 rtd
->num_pages
= (PAGE_ALIGN(size
) >> PAGE_SHIFT
);
253 config_acp_dma(rtd
, substream
->stream
);
254 init_pdm_ring_buffer(MEM_WINDOW_START
, size
, period_bytes
,
259 static u64
acp_pdm_get_byte_count(struct pdm_stream_instance
*rtd
,
262 union acp_pdm_dma_count byte_count
;
264 byte_count
.bcount
.high
=
265 rn_readl(rtd
->acp_base
+
266 ACP_WOV_RX_LINEARPOSITIONCNTR_HIGH
);
267 byte_count
.bcount
.low
=
268 rn_readl(rtd
->acp_base
+
269 ACP_WOV_RX_LINEARPOSITIONCNTR_LOW
);
270 return byte_count
.bytescount
;
273 static snd_pcm_uframes_t
acp_pdm_dma_pointer(struct snd_soc_component
*comp
,
274 struct snd_pcm_substream
*stream
)
276 struct pdm_stream_instance
*rtd
;
280 rtd
= stream
->runtime
->private_data
;
281 buffersize
= frames_to_bytes(stream
->runtime
,
282 stream
->runtime
->buffer_size
);
283 bytescount
= acp_pdm_get_byte_count(rtd
, stream
->stream
);
284 if (bytescount
> rtd
->bytescount
)
285 bytescount
-= rtd
->bytescount
;
286 pos
= do_div(bytescount
, buffersize
);
287 return bytes_to_frames(stream
->runtime
, pos
);
290 static int acp_pdm_dma_new(struct snd_soc_component
*component
,
291 struct snd_soc_pcm_runtime
*rtd
)
293 struct device
*parent
= component
->dev
->parent
;
295 snd_pcm_set_managed_buffer_all(rtd
->pcm
, SNDRV_DMA_TYPE_DEV
,
296 parent
, MIN_BUFFER
, MAX_BUFFER
);
300 static int acp_pdm_dma_close(struct snd_soc_component
*component
,
301 struct snd_pcm_substream
*substream
)
303 struct pdm_dev_data
*adata
= dev_get_drvdata(component
->dev
);
305 disable_pdm_interrupts(adata
->acp_base
);
306 adata
->capture_stream
= NULL
;
310 static int acp_pdm_dai_trigger(struct snd_pcm_substream
*substream
,
311 int cmd
, struct snd_soc_dai
*dai
)
313 struct pdm_stream_instance
*rtd
;
316 unsigned int ch_mask
;
318 rtd
= substream
->runtime
->private_data
;
320 switch (substream
->runtime
->channels
) {
328 case SNDRV_PCM_TRIGGER_START
:
329 case SNDRV_PCM_TRIGGER_RESUME
:
330 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
331 rn_writel(ch_mask
, rtd
->acp_base
+ ACP_WOV_PDM_NO_OF_CHANNELS
);
332 rn_writel(PDM_DECIMATION_FACTOR
, rtd
->acp_base
+
333 ACP_WOV_PDM_DECIMATION_FACTOR
);
334 rtd
->bytescount
= acp_pdm_get_byte_count(rtd
,
336 pdm_status
= check_pdm_dma_status(rtd
->acp_base
);
338 ret
= start_pdm_dma(rtd
->acp_base
);
340 case SNDRV_PCM_TRIGGER_STOP
:
341 case SNDRV_PCM_TRIGGER_SUSPEND
:
342 case SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
343 pdm_status
= check_pdm_dma_status(rtd
->acp_base
);
345 ret
= stop_pdm_dma(rtd
->acp_base
);
354 static const struct snd_soc_dai_ops acp_pdm_dai_ops
= {
355 .trigger
= acp_pdm_dai_trigger
,
358 static struct snd_soc_dai_driver acp_pdm_dai_driver
= {
360 .rates
= SNDRV_PCM_RATE_48000
,
361 .formats
= SNDRV_PCM_FMTBIT_S24_LE
|
362 SNDRV_PCM_FMTBIT_S32_LE
,
368 .ops
= &acp_pdm_dai_ops
,
371 static const struct snd_soc_component_driver acp_pdm_component
= {
373 .open
= acp_pdm_dma_open
,
374 .close
= acp_pdm_dma_close
,
375 .hw_params
= acp_pdm_dma_hw_params
,
376 .pointer
= acp_pdm_dma_pointer
,
377 .pcm_construct
= acp_pdm_dma_new
,
378 .legacy_dai_naming
= 1,
381 static int acp_pdm_audio_probe(struct platform_device
*pdev
)
383 struct resource
*res
;
384 struct pdm_dev_data
*adata
;
385 unsigned int irqflags
;
388 if (!pdev
->dev
.platform_data
) {
389 dev_err(&pdev
->dev
, "platform_data not retrieved\n");
392 irqflags
= *((unsigned int *)(pdev
->dev
.platform_data
));
394 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
396 dev_err(&pdev
->dev
, "IORESOURCE_MEM FAILED\n");
400 adata
= devm_kzalloc(&pdev
->dev
, sizeof(*adata
), GFP_KERNEL
);
404 adata
->acp_base
= devm_ioremap(&pdev
->dev
, res
->start
,
406 if (!adata
->acp_base
)
409 status
= platform_get_irq(pdev
, 0);
412 adata
->pdm_irq
= status
;
414 adata
->capture_stream
= NULL
;
416 dev_set_drvdata(&pdev
->dev
, adata
);
417 status
= devm_snd_soc_register_component(&pdev
->dev
,
419 &acp_pdm_dai_driver
, 1);
421 dev_err(&pdev
->dev
, "Fail to register acp pdm dai\n");
425 status
= devm_request_irq(&pdev
->dev
, adata
->pdm_irq
, pdm_irq_handler
,
426 irqflags
, "ACP_PDM_IRQ", adata
);
428 dev_err(&pdev
->dev
, "ACP PDM IRQ request failed\n");
431 pm_runtime_set_autosuspend_delay(&pdev
->dev
, ACP_SUSPEND_DELAY_MS
);
432 pm_runtime_use_autosuspend(&pdev
->dev
);
433 pm_runtime_mark_last_busy(&pdev
->dev
);
434 pm_runtime_set_active(&pdev
->dev
);
435 pm_runtime_enable(&pdev
->dev
);
439 static void acp_pdm_audio_remove(struct platform_device
*pdev
)
441 pm_runtime_disable(&pdev
->dev
);
444 static int acp_pdm_resume(struct device
*dev
)
446 struct pdm_dev_data
*adata
;
447 struct snd_pcm_runtime
*runtime
;
448 struct pdm_stream_instance
*rtd
;
449 u32 period_bytes
, buffer_len
;
451 adata
= dev_get_drvdata(dev
);
452 if (adata
->capture_stream
&& adata
->capture_stream
->runtime
) {
453 runtime
= adata
->capture_stream
->runtime
;
454 rtd
= runtime
->private_data
;
455 period_bytes
= frames_to_bytes(runtime
, runtime
->period_size
);
456 buffer_len
= frames_to_bytes(runtime
, runtime
->buffer_size
);
457 config_acp_dma(rtd
, SNDRV_PCM_STREAM_CAPTURE
);
458 init_pdm_ring_buffer(MEM_WINDOW_START
, buffer_len
, period_bytes
,
461 enable_pdm_interrupts(adata
->acp_base
);
465 static int acp_pdm_runtime_suspend(struct device
*dev
)
467 struct pdm_dev_data
*adata
;
469 adata
= dev_get_drvdata(dev
);
470 disable_pdm_interrupts(adata
->acp_base
);
475 static int acp_pdm_runtime_resume(struct device
*dev
)
477 struct pdm_dev_data
*adata
;
479 adata
= dev_get_drvdata(dev
);
480 enable_pdm_interrupts(adata
->acp_base
);
484 static const struct dev_pm_ops acp_pdm_pm_ops
= {
485 .runtime_suspend
= acp_pdm_runtime_suspend
,
486 .runtime_resume
= acp_pdm_runtime_resume
,
487 .resume
= acp_pdm_resume
,
490 static struct platform_driver acp_pdm_dma_driver
= {
491 .probe
= acp_pdm_audio_probe
,
492 .remove
= acp_pdm_audio_remove
,
494 .name
= "acp_rn_pdm_dma",
495 .pm
= &acp_pdm_pm_ops
,
499 module_platform_driver(acp_pdm_dma_driver
);
501 MODULE_AUTHOR("Vijendar.Mukunda@amd.com");
502 MODULE_DESCRIPTION("AMD ACP3x Renior PDM Driver");
503 MODULE_LICENSE("GPL v2");
504 MODULE_ALIAS("platform:" DRV_NAME
);