1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * linux/sound/soc/pxa/mmp-sspa.c
6 * Copyright (C) 2011 Marvell International Ltd.
8 #include <linux/init.h>
9 #include <linux/module.h>
10 #include <linux/platform_device.h>
11 #include <linux/delay.h>
12 #include <linux/clk.h>
13 #include <linux/slab.h>
15 #include <linux/dmaengine.h>
16 #include <linux/pm_runtime.h>
18 #include <sound/core.h>
19 #include <sound/pcm.h>
20 #include <sound/initval.h>
21 #include <sound/pcm_params.h>
22 #include <sound/soc.h>
23 #include <sound/pxa2xx-lib.h>
24 #include <sound/dmaengine_pcm.h>
28 * SSPA audio private data
31 void __iomem
*tx_base
;
32 void __iomem
*rx_base
;
34 struct snd_dmaengine_dai_dma_data playback_dma_data
;
35 struct snd_dmaengine_dai_dma_data capture_dma_data
;
37 struct clk
*audio_clk
;
45 static void mmp_sspa_tx_enable(struct sspa_priv
*sspa
)
47 unsigned int sspa_sp
= sspa
->sp
;
49 sspa_sp
&= ~SSPA_SP_MSL
;
50 sspa_sp
|= SSPA_SP_S_EN
;
51 sspa_sp
|= SSPA_SP_WEN
;
52 __raw_writel(sspa_sp
, sspa
->tx_base
+ SSPA_SP
);
55 static void mmp_sspa_tx_disable(struct sspa_priv
*sspa
)
57 unsigned int sspa_sp
= sspa
->sp
;
59 sspa_sp
&= ~SSPA_SP_MSL
;
60 sspa_sp
&= ~SSPA_SP_S_EN
;
61 sspa_sp
|= SSPA_SP_WEN
;
62 __raw_writel(sspa_sp
, sspa
->tx_base
+ SSPA_SP
);
65 static void mmp_sspa_rx_enable(struct sspa_priv
*sspa
)
67 unsigned int sspa_sp
= sspa
->sp
;
69 sspa_sp
|= SSPA_SP_S_EN
;
70 sspa_sp
|= SSPA_SP_WEN
;
71 __raw_writel(sspa_sp
, sspa
->rx_base
+ SSPA_SP
);
74 static void mmp_sspa_rx_disable(struct sspa_priv
*sspa
)
76 unsigned int sspa_sp
= sspa
->sp
;
78 sspa_sp
&= ~SSPA_SP_S_EN
;
79 sspa_sp
|= SSPA_SP_WEN
;
80 __raw_writel(sspa_sp
, sspa
->rx_base
+ SSPA_SP
);
83 static int mmp_sspa_startup(struct snd_pcm_substream
*substream
,
84 struct snd_soc_dai
*dai
)
86 struct sspa_priv
*sspa
= snd_soc_dai_get_drvdata(dai
);
88 clk_prepare_enable(sspa
->sysclk
);
89 clk_prepare_enable(sspa
->clk
);
94 static void mmp_sspa_shutdown(struct snd_pcm_substream
*substream
,
95 struct snd_soc_dai
*dai
)
97 struct sspa_priv
*sspa
= snd_soc_dai_get_drvdata(dai
);
99 clk_disable_unprepare(sspa
->clk
);
100 clk_disable_unprepare(sspa
->sysclk
);
104 * Set the SSP ports SYSCLK.
106 static int mmp_sspa_set_dai_sysclk(struct snd_soc_dai
*cpu_dai
,
107 int clk_id
, unsigned int freq
, int dir
)
109 struct sspa_priv
*sspa
= snd_soc_dai_get_drvdata(cpu_dai
);
110 struct device
*dev
= cpu_dai
->component
->dev
;
117 case MMP_SSPA_CLK_AUDIO
:
118 ret
= clk_set_rate(sspa
->audio_clk
, freq
);
122 case MMP_SSPA_CLK_PLL
:
123 case MMP_SSPA_CLK_VCXO
:
124 /* not support yet */
133 static int mmp_sspa_set_dai_pll(struct snd_soc_dai
*cpu_dai
, int pll_id
,
134 int source
, unsigned int freq_in
,
135 unsigned int freq_out
)
137 struct sspa_priv
*sspa
= snd_soc_dai_get_drvdata(cpu_dai
);
138 struct device
*dev
= cpu_dai
->component
->dev
;
146 ret
= clk_set_rate(sspa
->sysclk
, freq_out
);
151 ret
= clk_set_rate(sspa
->clk
, freq_out
);
163 * Set up the sspa dai format.
165 static int mmp_sspa_set_dai_fmt(struct snd_soc_dai
*cpu_dai
,
168 struct sspa_priv
*sspa
= snd_soc_dai_get_drvdata(cpu_dai
);
170 /* reset port settings */
171 sspa
->sp
= SSPA_SP_WEN
| SSPA_SP_S_RST
| SSPA_SP_FFLUSH
;
174 switch (fmt
& SND_SOC_DAIFMT_MASTER_MASK
) {
175 case SND_SOC_DAIFMT_CBS_CFS
:
176 sspa
->sp
|= SSPA_SP_MSL
;
178 case SND_SOC_DAIFMT_CBM_CFM
:
184 switch (fmt
& SND_SOC_DAIFMT_INV_MASK
) {
185 case SND_SOC_DAIFMT_NB_NF
:
186 sspa
->sp
|= SSPA_SP_FSP
;
192 switch (fmt
& SND_SOC_DAIFMT_FORMAT_MASK
) {
193 case SND_SOC_DAIFMT_I2S
:
194 sspa
->ctrl
|= SSPA_CTL_XDATDLY(1);
200 /* Since we are configuring the timings for the format by hand
201 * we have to defer some things until hw_params() where we
202 * know parameters like the sample size.
208 * Set the SSPA audio DMA parameters and sample size.
209 * Can be called multiple times by oss emulation.
211 static int mmp_sspa_hw_params(struct snd_pcm_substream
*substream
,
212 struct snd_pcm_hw_params
*params
,
213 struct snd_soc_dai
*dai
)
215 struct sspa_priv
*sspa
= snd_soc_dai_get_drvdata(dai
);
216 struct device
*dev
= dai
->component
->dev
;
217 u32 sspa_ctrl
= sspa
->ctrl
;
221 switch (params_format(params
)) {
222 case SNDRV_PCM_FORMAT_S8
:
224 bitval
= SSPA_CTL_8_BITS
;
226 case SNDRV_PCM_FORMAT_S16_LE
:
228 bitval
= SSPA_CTL_16_BITS
;
230 case SNDRV_PCM_FORMAT_S24_3LE
:
232 bitval
= SSPA_CTL_24_BITS
;
234 case SNDRV_PCM_FORMAT_S32_LE
:
236 bitval
= SSPA_CTL_32_BITS
;
242 sspa_ctrl
&= ~SSPA_CTL_XPH
;
243 if (dev
->of_node
|| params_channels(params
) == 2)
244 sspa_ctrl
|= SSPA_CTL_XPH
;
246 sspa_ctrl
&= ~SSPA_CTL_XWDLEN1_MASK
;
247 sspa_ctrl
|= SSPA_CTL_XWDLEN1(bitval
);
249 sspa_ctrl
&= ~SSPA_CTL_XWDLEN2_MASK
;
250 sspa_ctrl
|= SSPA_CTL_XWDLEN2(bitval
);
252 sspa_ctrl
&= ~SSPA_CTL_XSSZ1_MASK
;
253 sspa_ctrl
|= SSPA_CTL_XSSZ1(bitval
);
255 sspa_ctrl
&= ~SSPA_CTL_XSSZ2_MASK
;
256 sspa_ctrl
|= SSPA_CTL_XSSZ2(bitval
);
258 sspa
->sp
&= ~SSPA_SP_FWID_MASK
;
259 sspa
->sp
|= SSPA_SP_FWID(bits
- 1);
261 sspa
->sp
&= ~SSPA_TXSP_FPER_MASK
;
262 sspa
->sp
|= SSPA_TXSP_FPER(bits
* 2 - 1);
265 clk_set_rate(sspa
->clk
, params_rate(params
) *
266 params_channels(params
) * bits
);
269 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
) {
270 __raw_writel(sspa_ctrl
, sspa
->tx_base
+ SSPA_CTL
);
271 __raw_writel(0x1, sspa
->tx_base
+ SSPA_FIFO_UL
);
273 __raw_writel(sspa_ctrl
, sspa
->rx_base
+ SSPA_CTL
);
274 __raw_writel(0x0, sspa
->rx_base
+ SSPA_FIFO_UL
);
280 static int mmp_sspa_trigger(struct snd_pcm_substream
*substream
, int cmd
,
281 struct snd_soc_dai
*dai
)
283 struct sspa_priv
*sspa
= snd_soc_dai_get_drvdata(dai
);
287 case SNDRV_PCM_TRIGGER_START
:
288 case SNDRV_PCM_TRIGGER_RESUME
:
289 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
291 * whatever playback or capture, must enable rx.
292 * this is a hw issue, so need check if rx has been
293 * enabled or not; if has been enabled by another
294 * stream, do not enable again.
296 if (!sspa
->running_cnt
)
297 mmp_sspa_rx_enable(sspa
);
299 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
)
300 mmp_sspa_tx_enable(sspa
);
305 case SNDRV_PCM_TRIGGER_STOP
:
306 case SNDRV_PCM_TRIGGER_SUSPEND
:
307 case SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
310 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
)
311 mmp_sspa_tx_disable(sspa
);
313 /* have no capture stream, disable rx port */
314 if (!sspa
->running_cnt
)
315 mmp_sspa_rx_disable(sspa
);
325 static int mmp_sspa_probe(struct snd_soc_dai
*dai
)
327 struct sspa_priv
*sspa
= dev_get_drvdata(dai
->dev
);
329 snd_soc_dai_init_dma_data(dai
,
330 &sspa
->playback_dma_data
,
331 &sspa
->capture_dma_data
);
333 snd_soc_dai_set_drvdata(dai
, sspa
);
337 #define MMP_SSPA_RATES SNDRV_PCM_RATE_8000_192000
338 #define MMP_SSPA_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
339 SNDRV_PCM_FMTBIT_S16_LE | \
340 SNDRV_PCM_FMTBIT_S24_3LE | \
341 SNDRV_PCM_FMTBIT_S32_LE)
343 static const struct snd_soc_dai_ops mmp_sspa_dai_ops
= {
344 .startup
= mmp_sspa_startup
,
345 .shutdown
= mmp_sspa_shutdown
,
346 .trigger
= mmp_sspa_trigger
,
347 .hw_params
= mmp_sspa_hw_params
,
348 .set_sysclk
= mmp_sspa_set_dai_sysclk
,
349 .set_pll
= mmp_sspa_set_dai_pll
,
350 .set_fmt
= mmp_sspa_set_dai_fmt
,
353 static struct snd_soc_dai_driver mmp_sspa_dai
= {
354 .probe
= mmp_sspa_probe
,
358 .rates
= MMP_SSPA_RATES
,
359 .formats
= MMP_SSPA_FORMATS
,
364 .rates
= MMP_SSPA_RATES
,
365 .formats
= MMP_SSPA_FORMATS
,
367 .ops
= &mmp_sspa_dai_ops
,
370 #define MMP_PCM_INFO (SNDRV_PCM_INFO_MMAP | \
371 SNDRV_PCM_INFO_MMAP_VALID | \
372 SNDRV_PCM_INFO_INTERLEAVED | \
373 SNDRV_PCM_INFO_PAUSE | \
374 SNDRV_PCM_INFO_RESUME | \
375 SNDRV_PCM_INFO_NO_PERIOD_WAKEUP)
377 static const struct snd_pcm_hardware mmp_pcm_hardware
[] = {
379 .info
= MMP_PCM_INFO
,
380 .period_bytes_min
= 1024,
381 .period_bytes_max
= 2048,
384 .buffer_bytes_max
= 4096,
388 .info
= MMP_PCM_INFO
,
389 .period_bytes_min
= 1024,
390 .period_bytes_max
= 2048,
393 .buffer_bytes_max
= 4096,
398 static const struct snd_dmaengine_pcm_config mmp_pcm_config
= {
399 .prepare_slave_config
= snd_dmaengine_pcm_prepare_slave_config
,
400 .pcm_hardware
= mmp_pcm_hardware
,
401 .prealloc_buffer_size
= 4096,
404 static int mmp_pcm_mmap(struct snd_soc_component
*component
,
405 struct snd_pcm_substream
*substream
,
406 struct vm_area_struct
*vma
)
408 vma
->vm_flags
|= VM_DONTEXPAND
| VM_DONTDUMP
;
409 vma
->vm_page_prot
= pgprot_noncached(vma
->vm_page_prot
);
410 return remap_pfn_range(vma
, vma
->vm_start
,
411 substream
->dma_buffer
.addr
>> PAGE_SHIFT
,
412 vma
->vm_end
- vma
->vm_start
, vma
->vm_page_prot
);
415 static int mmp_sspa_open(struct snd_soc_component
*component
,
416 struct snd_pcm_substream
*substream
)
418 struct sspa_priv
*sspa
= snd_soc_component_get_drvdata(component
);
420 pm_runtime_get_sync(component
->dev
);
422 /* we can only change the settings if the port is not in use */
423 if ((__raw_readl(sspa
->tx_base
+ SSPA_SP
) & SSPA_SP_S_EN
) ||
424 (__raw_readl(sspa
->rx_base
+ SSPA_SP
) & SSPA_SP_S_EN
)) {
425 dev_err(component
->dev
,
426 "can't change hardware dai format: stream is in use\n");
430 __raw_writel(sspa
->sp
, sspa
->tx_base
+ SSPA_SP
);
431 __raw_writel(sspa
->sp
, sspa
->rx_base
+ SSPA_SP
);
433 sspa
->sp
&= ~(SSPA_SP_S_RST
| SSPA_SP_FFLUSH
);
434 __raw_writel(sspa
->sp
, sspa
->tx_base
+ SSPA_SP
);
435 __raw_writel(sspa
->sp
, sspa
->rx_base
+ SSPA_SP
);
438 * FIXME: hw issue, for the tx serial port,
439 * can not config the master/slave mode;
440 * so must clean this bit.
441 * The master/slave mode has been set in the
444 __raw_writel(sspa
->sp
& ~SSPA_SP_MSL
, sspa
->tx_base
+ SSPA_SP
);
446 __raw_writel(sspa
->ctrl
, sspa
->tx_base
+ SSPA_CTL
);
447 __raw_writel(sspa
->ctrl
, sspa
->rx_base
+ SSPA_CTL
);
452 static int mmp_sspa_close(struct snd_soc_component
*component
,
453 struct snd_pcm_substream
*substream
)
455 pm_runtime_put_sync(component
->dev
);
459 static const struct snd_soc_component_driver mmp_sspa_component
= {
461 .mmap
= mmp_pcm_mmap
,
462 .open
= mmp_sspa_open
,
463 .close
= mmp_sspa_close
,
466 static int asoc_mmp_sspa_probe(struct platform_device
*pdev
)
468 struct sspa_priv
*sspa
;
471 sspa
= devm_kzalloc(&pdev
->dev
,
472 sizeof(struct sspa_priv
), GFP_KERNEL
);
476 if (pdev
->dev
.of_node
) {
477 sspa
->rx_base
= devm_platform_ioremap_resource(pdev
, 0);
478 if (IS_ERR(sspa
->rx_base
))
479 return PTR_ERR(sspa
->rx_base
);
481 sspa
->tx_base
= devm_platform_ioremap_resource(pdev
, 1);
482 if (IS_ERR(sspa
->tx_base
))
483 return PTR_ERR(sspa
->tx_base
);
485 sspa
->clk
= devm_clk_get(&pdev
->dev
, "bitclk");
486 if (IS_ERR(sspa
->clk
))
487 return PTR_ERR(sspa
->clk
);
489 sspa
->audio_clk
= devm_clk_get(&pdev
->dev
, "audio");
490 if (IS_ERR(sspa
->audio_clk
))
491 return PTR_ERR(sspa
->audio_clk
);
493 struct resource
*res
;
495 res
= platform_get_resource(pdev
, IORESOURCE_IO
, 0);
499 sspa
->rx_base
= devm_ioremap(&pdev
->dev
, res
->start
, 0x30);
503 sspa
->tx_base
= devm_ioremap(&pdev
->dev
,
504 res
->start
+ 0x80, 0x30);
508 sspa
->clk
= devm_clk_get(&pdev
->dev
, NULL
);
509 if (IS_ERR(sspa
->clk
))
510 return PTR_ERR(sspa
->clk
);
512 sspa
->audio_clk
= clk_get(NULL
, "mmp-audio");
513 if (IS_ERR(sspa
->audio_clk
))
514 return PTR_ERR(sspa
->audio_clk
);
516 sspa
->sysclk
= clk_get(NULL
, "mmp-sysclk");
517 if (IS_ERR(sspa
->sysclk
)) {
518 clk_put(sspa
->audio_clk
);
519 return PTR_ERR(sspa
->sysclk
);
522 platform_set_drvdata(pdev
, sspa
);
524 sspa
->playback_dma_data
.maxburst
= 4;
525 sspa
->capture_dma_data
.maxburst
= 4;
526 /* You know, these addresses are actually ignored. */
527 sspa
->capture_dma_data
.addr
= SSPA_D
;
528 sspa
->playback_dma_data
.addr
= 0x80 + SSPA_D
;
530 if (pdev
->dev
.of_node
) {
531 ret
= devm_snd_dmaengine_pcm_register(&pdev
->dev
,
537 ret
= devm_snd_soc_register_component(&pdev
->dev
, &mmp_sspa_component
,
542 pm_runtime_enable(&pdev
->dev
);
543 clk_prepare_enable(sspa
->audio_clk
);
548 static int asoc_mmp_sspa_remove(struct platform_device
*pdev
)
550 struct sspa_priv
*sspa
= platform_get_drvdata(pdev
);
552 clk_disable_unprepare(sspa
->audio_clk
);
553 pm_runtime_disable(&pdev
->dev
);
555 if (pdev
->dev
.of_node
)
558 clk_put(sspa
->audio_clk
);
559 clk_put(sspa
->sysclk
);
564 static const struct of_device_id mmp_sspa_of_match
[] = {
565 { .compatible
= "marvell,mmp-sspa" },
569 MODULE_DEVICE_TABLE(of
, mmp_sspa_of_match
);
572 static struct platform_driver asoc_mmp_sspa_driver
= {
574 .name
= "mmp-sspa-dai",
575 .of_match_table
= of_match_ptr(mmp_sspa_of_match
),
577 .probe
= asoc_mmp_sspa_probe
,
578 .remove
= asoc_mmp_sspa_remove
,
581 module_platform_driver(asoc_mmp_sspa_driver
);
583 MODULE_AUTHOR("Leo Yan <leoy@marvell.com>");
584 MODULE_DESCRIPTION("MMP SSPA SoC Interface");
585 MODULE_LICENSE("GPL");
586 MODULE_ALIAS("platform:mmp-sspa-dai");