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>
14 #include <linux/pxa2xx_ssp.h>
16 #include <linux/dmaengine.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 struct ssp_device
*sspa
;
32 struct snd_dmaengine_dai_dma_data
*dma_params
;
33 struct clk
*audio_clk
;
39 static void mmp_sspa_write_reg(struct ssp_device
*sspa
, u32 reg
, u32 val
)
41 __raw_writel(val
, sspa
->mmio_base
+ reg
);
44 static u32
mmp_sspa_read_reg(struct ssp_device
*sspa
, u32 reg
)
46 return __raw_readl(sspa
->mmio_base
+ reg
);
49 static void mmp_sspa_tx_enable(struct ssp_device
*sspa
)
53 sspa_sp
= mmp_sspa_read_reg(sspa
, SSPA_TXSP
);
54 sspa_sp
|= SSPA_SP_S_EN
;
55 sspa_sp
|= SSPA_SP_WEN
;
56 mmp_sspa_write_reg(sspa
, SSPA_TXSP
, sspa_sp
);
59 static void mmp_sspa_tx_disable(struct ssp_device
*sspa
)
63 sspa_sp
= mmp_sspa_read_reg(sspa
, SSPA_TXSP
);
64 sspa_sp
&= ~SSPA_SP_S_EN
;
65 sspa_sp
|= SSPA_SP_WEN
;
66 mmp_sspa_write_reg(sspa
, SSPA_TXSP
, sspa_sp
);
69 static void mmp_sspa_rx_enable(struct ssp_device
*sspa
)
73 sspa_sp
= mmp_sspa_read_reg(sspa
, SSPA_RXSP
);
74 sspa_sp
|= SSPA_SP_S_EN
;
75 sspa_sp
|= SSPA_SP_WEN
;
76 mmp_sspa_write_reg(sspa
, SSPA_RXSP
, sspa_sp
);
79 static void mmp_sspa_rx_disable(struct ssp_device
*sspa
)
83 sspa_sp
= mmp_sspa_read_reg(sspa
, SSPA_RXSP
);
84 sspa_sp
&= ~SSPA_SP_S_EN
;
85 sspa_sp
|= SSPA_SP_WEN
;
86 mmp_sspa_write_reg(sspa
, SSPA_RXSP
, sspa_sp
);
89 static int mmp_sspa_startup(struct snd_pcm_substream
*substream
,
90 struct snd_soc_dai
*dai
)
92 struct sspa_priv
*priv
= snd_soc_dai_get_drvdata(dai
);
94 clk_enable(priv
->sysclk
);
95 clk_enable(priv
->sspa
->clk
);
100 static void mmp_sspa_shutdown(struct snd_pcm_substream
*substream
,
101 struct snd_soc_dai
*dai
)
103 struct sspa_priv
*priv
= snd_soc_dai_get_drvdata(dai
);
105 clk_disable(priv
->sspa
->clk
);
106 clk_disable(priv
->sysclk
);
111 * Set the SSP ports SYSCLK.
113 static int mmp_sspa_set_dai_sysclk(struct snd_soc_dai
*cpu_dai
,
114 int clk_id
, unsigned int freq
, int dir
)
116 struct sspa_priv
*priv
= snd_soc_dai_get_drvdata(cpu_dai
);
120 case MMP_SSPA_CLK_AUDIO
:
121 ret
= clk_set_rate(priv
->audio_clk
, freq
);
125 case MMP_SSPA_CLK_PLL
:
126 case MMP_SSPA_CLK_VCXO
:
127 /* not support yet */
136 static int mmp_sspa_set_dai_pll(struct snd_soc_dai
*cpu_dai
, int pll_id
,
137 int source
, unsigned int freq_in
,
138 unsigned int freq_out
)
140 struct sspa_priv
*priv
= snd_soc_dai_get_drvdata(cpu_dai
);
145 ret
= clk_set_rate(priv
->sysclk
, freq_out
);
150 ret
= clk_set_rate(priv
->sspa
->clk
, freq_out
);
162 * Set up the sspa dai format. The sspa port must be inactive
163 * before calling this function as the physical
164 * interface format is changed.
166 static int mmp_sspa_set_dai_fmt(struct snd_soc_dai
*cpu_dai
,
169 struct sspa_priv
*sspa_priv
= snd_soc_dai_get_drvdata(cpu_dai
);
170 struct ssp_device
*sspa
= sspa_priv
->sspa
;
171 u32 sspa_sp
, sspa_ctrl
;
173 /* check if we need to change anything at all */
174 if (sspa_priv
->dai_fmt
== fmt
)
177 /* we can only change the settings if the port is not in use */
178 if ((mmp_sspa_read_reg(sspa
, SSPA_TXSP
) & SSPA_SP_S_EN
) ||
179 (mmp_sspa_read_reg(sspa
, SSPA_RXSP
) & SSPA_SP_S_EN
)) {
181 "can't change hardware dai format: stream is in use\n");
185 /* reset port settings */
186 sspa_sp
= SSPA_SP_WEN
| SSPA_SP_S_RST
| SSPA_SP_FFLUSH
;
189 switch (fmt
& SND_SOC_DAIFMT_MASTER_MASK
) {
190 case SND_SOC_DAIFMT_CBS_CFS
:
191 sspa_sp
|= SSPA_SP_MSL
;
193 case SND_SOC_DAIFMT_CBM_CFM
:
199 switch (fmt
& SND_SOC_DAIFMT_INV_MASK
) {
200 case SND_SOC_DAIFMT_NB_NF
:
201 sspa_sp
|= SSPA_SP_FSP
;
207 switch (fmt
& SND_SOC_DAIFMT_FORMAT_MASK
) {
208 case SND_SOC_DAIFMT_I2S
:
209 sspa_sp
|= SSPA_TXSP_FPER(63);
210 sspa_sp
|= SSPA_SP_FWID(31);
211 sspa_ctrl
|= SSPA_CTL_XDATDLY(1);
217 mmp_sspa_write_reg(sspa
, SSPA_TXSP
, sspa_sp
);
218 mmp_sspa_write_reg(sspa
, SSPA_RXSP
, sspa_sp
);
220 sspa_sp
&= ~(SSPA_SP_S_RST
| SSPA_SP_FFLUSH
);
221 mmp_sspa_write_reg(sspa
, SSPA_TXSP
, sspa_sp
);
222 mmp_sspa_write_reg(sspa
, SSPA_RXSP
, sspa_sp
);
225 * FIXME: hw issue, for the tx serial port,
226 * can not config the master/slave mode;
227 * so must clean this bit.
228 * The master/slave mode has been set in the
231 sspa_sp
&= ~SSPA_SP_MSL
;
232 mmp_sspa_write_reg(sspa
, SSPA_TXSP
, sspa_sp
);
234 mmp_sspa_write_reg(sspa
, SSPA_TXCTL
, sspa_ctrl
);
235 mmp_sspa_write_reg(sspa
, SSPA_RXCTL
, sspa_ctrl
);
237 /* Since we are configuring the timings for the format by hand
238 * we have to defer some things until hw_params() where we
239 * know parameters like the sample size.
241 sspa_priv
->dai_fmt
= fmt
;
246 * Set the SSPA audio DMA parameters and sample size.
247 * Can be called multiple times by oss emulation.
249 static int mmp_sspa_hw_params(struct snd_pcm_substream
*substream
,
250 struct snd_pcm_hw_params
*params
,
251 struct snd_soc_dai
*dai
)
253 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
254 struct snd_soc_dai
*cpu_dai
= rtd
->cpu_dai
;
255 struct sspa_priv
*sspa_priv
= snd_soc_dai_get_drvdata(dai
);
256 struct ssp_device
*sspa
= sspa_priv
->sspa
;
257 struct snd_dmaengine_dai_dma_data
*dma_params
;
260 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
)
261 sspa_ctrl
= mmp_sspa_read_reg(sspa
, SSPA_TXCTL
);
263 sspa_ctrl
= mmp_sspa_read_reg(sspa
, SSPA_RXCTL
);
265 sspa_ctrl
&= ~SSPA_CTL_XFRLEN1_MASK
;
266 sspa_ctrl
|= SSPA_CTL_XFRLEN1(params_channels(params
) - 1);
267 sspa_ctrl
&= ~SSPA_CTL_XWDLEN1_MASK
;
268 sspa_ctrl
|= SSPA_CTL_XWDLEN1(SSPA_CTL_32_BITS
);
269 sspa_ctrl
&= ~SSPA_CTL_XSSZ1_MASK
;
271 switch (params_format(params
)) {
272 case SNDRV_PCM_FORMAT_S8
:
273 sspa_ctrl
|= SSPA_CTL_XSSZ1(SSPA_CTL_8_BITS
);
275 case SNDRV_PCM_FORMAT_S16_LE
:
276 sspa_ctrl
|= SSPA_CTL_XSSZ1(SSPA_CTL_16_BITS
);
278 case SNDRV_PCM_FORMAT_S20_3LE
:
279 sspa_ctrl
|= SSPA_CTL_XSSZ1(SSPA_CTL_20_BITS
);
281 case SNDRV_PCM_FORMAT_S24_3LE
:
282 sspa_ctrl
|= SSPA_CTL_XSSZ1(SSPA_CTL_24_BITS
);
284 case SNDRV_PCM_FORMAT_S32_LE
:
285 sspa_ctrl
|= SSPA_CTL_XSSZ1(SSPA_CTL_32_BITS
);
291 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
) {
292 mmp_sspa_write_reg(sspa
, SSPA_TXCTL
, sspa_ctrl
);
293 mmp_sspa_write_reg(sspa
, SSPA_TXFIFO_LL
, 0x1);
295 mmp_sspa_write_reg(sspa
, SSPA_RXCTL
, sspa_ctrl
);
296 mmp_sspa_write_reg(sspa
, SSPA_RXFIFO_UL
, 0x0);
299 dma_params
= &sspa_priv
->dma_params
[substream
->stream
];
300 dma_params
->addr
= substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
?
301 (sspa
->phys_base
+ SSPA_TXD
) :
302 (sspa
->phys_base
+ SSPA_RXD
);
303 snd_soc_dai_set_dma_data(cpu_dai
, substream
, dma_params
);
307 static int mmp_sspa_trigger(struct snd_pcm_substream
*substream
, int cmd
,
308 struct snd_soc_dai
*dai
)
310 struct sspa_priv
*sspa_priv
= snd_soc_dai_get_drvdata(dai
);
311 struct ssp_device
*sspa
= sspa_priv
->sspa
;
315 case SNDRV_PCM_TRIGGER_START
:
316 case SNDRV_PCM_TRIGGER_RESUME
:
317 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
319 * whatever playback or capture, must enable rx.
320 * this is a hw issue, so need check if rx has been
321 * enabled or not; if has been enabled by another
322 * stream, do not enable again.
324 if (!sspa_priv
->running_cnt
)
325 mmp_sspa_rx_enable(sspa
);
327 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
)
328 mmp_sspa_tx_enable(sspa
);
330 sspa_priv
->running_cnt
++;
333 case SNDRV_PCM_TRIGGER_STOP
:
334 case SNDRV_PCM_TRIGGER_SUSPEND
:
335 case SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
336 sspa_priv
->running_cnt
--;
338 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
)
339 mmp_sspa_tx_disable(sspa
);
341 /* have no capture stream, disable rx port */
342 if (!sspa_priv
->running_cnt
)
343 mmp_sspa_rx_disable(sspa
);
353 static int mmp_sspa_probe(struct snd_soc_dai
*dai
)
355 struct sspa_priv
*priv
= dev_get_drvdata(dai
->dev
);
357 snd_soc_dai_set_drvdata(dai
, priv
);
362 #define MMP_SSPA_RATES SNDRV_PCM_RATE_8000_192000
363 #define MMP_SSPA_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
364 SNDRV_PCM_FMTBIT_S16_LE | \
365 SNDRV_PCM_FMTBIT_S24_LE | \
366 SNDRV_PCM_FMTBIT_S32_LE)
368 static const struct snd_soc_dai_ops mmp_sspa_dai_ops
= {
369 .startup
= mmp_sspa_startup
,
370 .shutdown
= mmp_sspa_shutdown
,
371 .trigger
= mmp_sspa_trigger
,
372 .hw_params
= mmp_sspa_hw_params
,
373 .set_sysclk
= mmp_sspa_set_dai_sysclk
,
374 .set_pll
= mmp_sspa_set_dai_pll
,
375 .set_fmt
= mmp_sspa_set_dai_fmt
,
378 static struct snd_soc_dai_driver mmp_sspa_dai
= {
379 .probe
= mmp_sspa_probe
,
383 .rates
= MMP_SSPA_RATES
,
384 .formats
= MMP_SSPA_FORMATS
,
389 .rates
= MMP_SSPA_RATES
,
390 .formats
= MMP_SSPA_FORMATS
,
392 .ops
= &mmp_sspa_dai_ops
,
395 static const struct snd_soc_component_driver mmp_sspa_component
= {
399 static int asoc_mmp_sspa_probe(struct platform_device
*pdev
)
401 struct sspa_priv
*priv
;
403 priv
= devm_kzalloc(&pdev
->dev
,
404 sizeof(struct sspa_priv
), GFP_KERNEL
);
408 priv
->sspa
= devm_kzalloc(&pdev
->dev
,
409 sizeof(struct ssp_device
), GFP_KERNEL
);
410 if (priv
->sspa
== NULL
)
413 priv
->dma_params
= devm_kcalloc(&pdev
->dev
,
414 2, sizeof(struct snd_dmaengine_dai_dma_data
),
416 if (priv
->dma_params
== NULL
)
419 priv
->sspa
->mmio_base
= devm_platform_ioremap_resource(pdev
, 0);
420 if (IS_ERR(priv
->sspa
->mmio_base
))
421 return PTR_ERR(priv
->sspa
->mmio_base
);
423 priv
->sspa
->clk
= devm_clk_get(&pdev
->dev
, NULL
);
424 if (IS_ERR(priv
->sspa
->clk
))
425 return PTR_ERR(priv
->sspa
->clk
);
427 priv
->audio_clk
= clk_get(NULL
, "mmp-audio");
428 if (IS_ERR(priv
->audio_clk
))
429 return PTR_ERR(priv
->audio_clk
);
431 priv
->sysclk
= clk_get(NULL
, "mmp-sysclk");
432 if (IS_ERR(priv
->sysclk
)) {
433 clk_put(priv
->audio_clk
);
434 return PTR_ERR(priv
->sysclk
);
436 clk_enable(priv
->audio_clk
);
437 priv
->dai_fmt
= (unsigned int) -1;
438 platform_set_drvdata(pdev
, priv
);
440 return devm_snd_soc_register_component(&pdev
->dev
, &mmp_sspa_component
,
444 static int asoc_mmp_sspa_remove(struct platform_device
*pdev
)
446 struct sspa_priv
*priv
= platform_get_drvdata(pdev
);
448 clk_disable(priv
->audio_clk
);
449 clk_put(priv
->audio_clk
);
450 clk_put(priv
->sysclk
);
454 static struct platform_driver asoc_mmp_sspa_driver
= {
456 .name
= "mmp-sspa-dai",
458 .probe
= asoc_mmp_sspa_probe
,
459 .remove
= asoc_mmp_sspa_remove
,
462 module_platform_driver(asoc_mmp_sspa_driver
);
464 MODULE_AUTHOR("Leo Yan <leoy@marvell.com>");
465 MODULE_DESCRIPTION("MMP SSPA SoC Interface");
466 MODULE_LICENSE("GPL");
467 MODULE_ALIAS("platform:mmp-sspa-dai");