2 * linux/sound/soc/pxa/mmp-sspa.c
5 * Copyright (C) 2011 Marvell International Ltd.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include <linux/init.h>
23 #include <linux/module.h>
24 #include <linux/platform_device.h>
25 #include <linux/delay.h>
26 #include <linux/clk.h>
27 #include <linux/slab.h>
28 #include <linux/pxa2xx_ssp.h>
30 #include <linux/dmaengine.h>
32 #include <sound/core.h>
33 #include <sound/pcm.h>
34 #include <sound/initval.h>
35 #include <sound/pcm_params.h>
36 #include <sound/soc.h>
37 #include <sound/pxa2xx-lib.h>
38 #include <sound/dmaengine_pcm.h>
42 * SSPA audio private data
45 struct ssp_device
*sspa
;
46 struct snd_dmaengine_dai_dma_data
*dma_params
;
47 struct clk
*audio_clk
;
53 static void mmp_sspa_write_reg(struct ssp_device
*sspa
, u32 reg
, u32 val
)
55 __raw_writel(val
, sspa
->mmio_base
+ reg
);
58 static u32
mmp_sspa_read_reg(struct ssp_device
*sspa
, u32 reg
)
60 return __raw_readl(sspa
->mmio_base
+ reg
);
63 static void mmp_sspa_tx_enable(struct ssp_device
*sspa
)
67 sspa_sp
= mmp_sspa_read_reg(sspa
, SSPA_TXSP
);
68 sspa_sp
|= SSPA_SP_S_EN
;
69 sspa_sp
|= SSPA_SP_WEN
;
70 mmp_sspa_write_reg(sspa
, SSPA_TXSP
, sspa_sp
);
73 static void mmp_sspa_tx_disable(struct ssp_device
*sspa
)
77 sspa_sp
= mmp_sspa_read_reg(sspa
, SSPA_TXSP
);
78 sspa_sp
&= ~SSPA_SP_S_EN
;
79 sspa_sp
|= SSPA_SP_WEN
;
80 mmp_sspa_write_reg(sspa
, SSPA_TXSP
, sspa_sp
);
83 static void mmp_sspa_rx_enable(struct ssp_device
*sspa
)
87 sspa_sp
= mmp_sspa_read_reg(sspa
, SSPA_RXSP
);
88 sspa_sp
|= SSPA_SP_S_EN
;
89 sspa_sp
|= SSPA_SP_WEN
;
90 mmp_sspa_write_reg(sspa
, SSPA_RXSP
, sspa_sp
);
93 static void mmp_sspa_rx_disable(struct ssp_device
*sspa
)
97 sspa_sp
= mmp_sspa_read_reg(sspa
, SSPA_RXSP
);
98 sspa_sp
&= ~SSPA_SP_S_EN
;
99 sspa_sp
|= SSPA_SP_WEN
;
100 mmp_sspa_write_reg(sspa
, SSPA_RXSP
, sspa_sp
);
103 static int mmp_sspa_startup(struct snd_pcm_substream
*substream
,
104 struct snd_soc_dai
*dai
)
106 struct sspa_priv
*priv
= snd_soc_dai_get_drvdata(dai
);
108 clk_enable(priv
->sysclk
);
109 clk_enable(priv
->sspa
->clk
);
114 static void mmp_sspa_shutdown(struct snd_pcm_substream
*substream
,
115 struct snd_soc_dai
*dai
)
117 struct sspa_priv
*priv
= snd_soc_dai_get_drvdata(dai
);
119 clk_disable(priv
->sspa
->clk
);
120 clk_disable(priv
->sysclk
);
125 * Set the SSP ports SYSCLK.
127 static int mmp_sspa_set_dai_sysclk(struct snd_soc_dai
*cpu_dai
,
128 int clk_id
, unsigned int freq
, int dir
)
130 struct sspa_priv
*priv
= snd_soc_dai_get_drvdata(cpu_dai
);
134 case MMP_SSPA_CLK_AUDIO
:
135 ret
= clk_set_rate(priv
->audio_clk
, freq
);
139 case MMP_SSPA_CLK_PLL
:
140 case MMP_SSPA_CLK_VCXO
:
141 /* not support yet */
150 static int mmp_sspa_set_dai_pll(struct snd_soc_dai
*cpu_dai
, int pll_id
,
151 int source
, unsigned int freq_in
,
152 unsigned int freq_out
)
154 struct sspa_priv
*priv
= snd_soc_dai_get_drvdata(cpu_dai
);
159 ret
= clk_set_rate(priv
->sysclk
, freq_out
);
164 ret
= clk_set_rate(priv
->sspa
->clk
, freq_out
);
176 * Set up the sspa dai format. The sspa port must be inactive
177 * before calling this function as the physical
178 * interface format is changed.
180 static int mmp_sspa_set_dai_fmt(struct snd_soc_dai
*cpu_dai
,
183 struct sspa_priv
*sspa_priv
= snd_soc_dai_get_drvdata(cpu_dai
);
184 struct ssp_device
*sspa
= sspa_priv
->sspa
;
185 u32 sspa_sp
, sspa_ctrl
;
187 /* check if we need to change anything at all */
188 if (sspa_priv
->dai_fmt
== fmt
)
191 /* we can only change the settings if the port is not in use */
192 if ((mmp_sspa_read_reg(sspa
, SSPA_TXSP
) & SSPA_SP_S_EN
) ||
193 (mmp_sspa_read_reg(sspa
, SSPA_RXSP
) & SSPA_SP_S_EN
)) {
194 dev_err(&sspa
->pdev
->dev
,
195 "can't change hardware dai format: stream is in use\n");
199 /* reset port settings */
200 sspa_sp
= SSPA_SP_WEN
| SSPA_SP_S_RST
| SSPA_SP_FFLUSH
;
203 switch (fmt
& SND_SOC_DAIFMT_MASTER_MASK
) {
204 case SND_SOC_DAIFMT_CBS_CFS
:
205 sspa_sp
|= SSPA_SP_MSL
;
207 case SND_SOC_DAIFMT_CBM_CFM
:
213 switch (fmt
& SND_SOC_DAIFMT_INV_MASK
) {
214 case SND_SOC_DAIFMT_NB_NF
:
215 sspa_sp
|= SSPA_SP_FSP
;
221 switch (fmt
& SND_SOC_DAIFMT_FORMAT_MASK
) {
222 case SND_SOC_DAIFMT_I2S
:
223 sspa_sp
|= SSPA_TXSP_FPER(63);
224 sspa_sp
|= SSPA_SP_FWID(31);
225 sspa_ctrl
|= SSPA_CTL_XDATDLY(1);
231 mmp_sspa_write_reg(sspa
, SSPA_TXSP
, sspa_sp
);
232 mmp_sspa_write_reg(sspa
, SSPA_RXSP
, sspa_sp
);
234 sspa_sp
&= ~(SSPA_SP_S_RST
| SSPA_SP_FFLUSH
);
235 mmp_sspa_write_reg(sspa
, SSPA_TXSP
, sspa_sp
);
236 mmp_sspa_write_reg(sspa
, SSPA_RXSP
, sspa_sp
);
239 * FIXME: hw issue, for the tx serial port,
240 * can not config the master/slave mode;
241 * so must clean this bit.
242 * The master/slave mode has been set in the
245 sspa_sp
&= ~SSPA_SP_MSL
;
246 mmp_sspa_write_reg(sspa
, SSPA_TXSP
, sspa_sp
);
248 mmp_sspa_write_reg(sspa
, SSPA_TXCTL
, sspa_ctrl
);
249 mmp_sspa_write_reg(sspa
, SSPA_RXCTL
, sspa_ctrl
);
251 /* Since we are configuring the timings for the format by hand
252 * we have to defer some things until hw_params() where we
253 * know parameters like the sample size.
255 sspa_priv
->dai_fmt
= fmt
;
260 * Set the SSPA audio DMA parameters and sample size.
261 * Can be called multiple times by oss emulation.
263 static int mmp_sspa_hw_params(struct snd_pcm_substream
*substream
,
264 struct snd_pcm_hw_params
*params
,
265 struct snd_soc_dai
*dai
)
267 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
268 struct snd_soc_dai
*cpu_dai
= rtd
->cpu_dai
;
269 struct sspa_priv
*sspa_priv
= snd_soc_dai_get_drvdata(dai
);
270 struct ssp_device
*sspa
= sspa_priv
->sspa
;
271 struct snd_dmaengine_dai_dma_data
*dma_params
;
274 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
)
275 sspa_ctrl
= mmp_sspa_read_reg(sspa
, SSPA_TXCTL
);
277 sspa_ctrl
= mmp_sspa_read_reg(sspa
, SSPA_RXCTL
);
279 sspa_ctrl
&= ~SSPA_CTL_XFRLEN1_MASK
;
280 sspa_ctrl
|= SSPA_CTL_XFRLEN1(params_channels(params
) - 1);
281 sspa_ctrl
&= ~SSPA_CTL_XWDLEN1_MASK
;
282 sspa_ctrl
|= SSPA_CTL_XWDLEN1(SSPA_CTL_32_BITS
);
283 sspa_ctrl
&= ~SSPA_CTL_XSSZ1_MASK
;
285 switch (params_format(params
)) {
286 case SNDRV_PCM_FORMAT_S8
:
287 sspa_ctrl
|= SSPA_CTL_XSSZ1(SSPA_CTL_8_BITS
);
289 case SNDRV_PCM_FORMAT_S16_LE
:
290 sspa_ctrl
|= SSPA_CTL_XSSZ1(SSPA_CTL_16_BITS
);
292 case SNDRV_PCM_FORMAT_S20_3LE
:
293 sspa_ctrl
|= SSPA_CTL_XSSZ1(SSPA_CTL_20_BITS
);
295 case SNDRV_PCM_FORMAT_S24_3LE
:
296 sspa_ctrl
|= SSPA_CTL_XSSZ1(SSPA_CTL_24_BITS
);
298 case SNDRV_PCM_FORMAT_S32_LE
:
299 sspa_ctrl
|= SSPA_CTL_XSSZ1(SSPA_CTL_32_BITS
);
305 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
) {
306 mmp_sspa_write_reg(sspa
, SSPA_TXCTL
, sspa_ctrl
);
307 mmp_sspa_write_reg(sspa
, SSPA_TXFIFO_LL
, 0x1);
309 mmp_sspa_write_reg(sspa
, SSPA_RXCTL
, sspa_ctrl
);
310 mmp_sspa_write_reg(sspa
, SSPA_RXFIFO_UL
, 0x0);
313 dma_params
= &sspa_priv
->dma_params
[substream
->stream
];
314 dma_params
->addr
= substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
?
315 (sspa
->phys_base
+ SSPA_TXD
) :
316 (sspa
->phys_base
+ SSPA_RXD
);
317 snd_soc_dai_set_dma_data(cpu_dai
, substream
, dma_params
);
321 static int mmp_sspa_trigger(struct snd_pcm_substream
*substream
, int cmd
,
322 struct snd_soc_dai
*dai
)
324 struct sspa_priv
*sspa_priv
= snd_soc_dai_get_drvdata(dai
);
325 struct ssp_device
*sspa
= sspa_priv
->sspa
;
329 case SNDRV_PCM_TRIGGER_START
:
330 case SNDRV_PCM_TRIGGER_RESUME
:
331 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
333 * whatever playback or capture, must enable rx.
334 * this is a hw issue, so need check if rx has been
335 * enabled or not; if has been enabled by another
336 * stream, do not enable again.
338 if (!sspa_priv
->running_cnt
)
339 mmp_sspa_rx_enable(sspa
);
341 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
)
342 mmp_sspa_tx_enable(sspa
);
344 sspa_priv
->running_cnt
++;
347 case SNDRV_PCM_TRIGGER_STOP
:
348 case SNDRV_PCM_TRIGGER_SUSPEND
:
349 case SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
350 sspa_priv
->running_cnt
--;
352 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
)
353 mmp_sspa_tx_disable(sspa
);
355 /* have no capture stream, disable rx port */
356 if (!sspa_priv
->running_cnt
)
357 mmp_sspa_rx_disable(sspa
);
367 static int mmp_sspa_probe(struct snd_soc_dai
*dai
)
369 struct sspa_priv
*priv
= dev_get_drvdata(dai
->dev
);
371 snd_soc_dai_set_drvdata(dai
, priv
);
376 #define MMP_SSPA_RATES SNDRV_PCM_RATE_8000_192000
377 #define MMP_SSPA_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
378 SNDRV_PCM_FMTBIT_S16_LE | \
379 SNDRV_PCM_FMTBIT_S24_LE | \
380 SNDRV_PCM_FMTBIT_S24_LE | \
381 SNDRV_PCM_FMTBIT_S32_LE)
383 static const struct snd_soc_dai_ops mmp_sspa_dai_ops
= {
384 .startup
= mmp_sspa_startup
,
385 .shutdown
= mmp_sspa_shutdown
,
386 .trigger
= mmp_sspa_trigger
,
387 .hw_params
= mmp_sspa_hw_params
,
388 .set_sysclk
= mmp_sspa_set_dai_sysclk
,
389 .set_pll
= mmp_sspa_set_dai_pll
,
390 .set_fmt
= mmp_sspa_set_dai_fmt
,
393 static struct snd_soc_dai_driver mmp_sspa_dai
= {
394 .probe
= mmp_sspa_probe
,
398 .rates
= MMP_SSPA_RATES
,
399 .formats
= MMP_SSPA_FORMATS
,
404 .rates
= MMP_SSPA_RATES
,
405 .formats
= MMP_SSPA_FORMATS
,
407 .ops
= &mmp_sspa_dai_ops
,
410 static const struct snd_soc_component_driver mmp_sspa_component
= {
414 static int asoc_mmp_sspa_probe(struct platform_device
*pdev
)
416 struct sspa_priv
*priv
;
417 struct resource
*res
;
419 priv
= devm_kzalloc(&pdev
->dev
,
420 sizeof(struct sspa_priv
), GFP_KERNEL
);
424 priv
->sspa
= devm_kzalloc(&pdev
->dev
,
425 sizeof(struct ssp_device
), GFP_KERNEL
);
426 if (priv
->sspa
== NULL
)
429 priv
->dma_params
= devm_kzalloc(&pdev
->dev
,
430 2 * sizeof(struct snd_dmaengine_dai_dma_data
),
432 if (priv
->dma_params
== NULL
)
435 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
436 priv
->sspa
->mmio_base
= devm_ioremap_resource(&pdev
->dev
, res
);
437 if (IS_ERR(priv
->sspa
->mmio_base
))
438 return PTR_ERR(priv
->sspa
->mmio_base
);
440 priv
->sspa
->clk
= devm_clk_get(&pdev
->dev
, NULL
);
441 if (IS_ERR(priv
->sspa
->clk
))
442 return PTR_ERR(priv
->sspa
->clk
);
444 priv
->audio_clk
= clk_get(NULL
, "mmp-audio");
445 if (IS_ERR(priv
->audio_clk
))
446 return PTR_ERR(priv
->audio_clk
);
448 priv
->sysclk
= clk_get(NULL
, "mmp-sysclk");
449 if (IS_ERR(priv
->sysclk
)) {
450 clk_put(priv
->audio_clk
);
451 return PTR_ERR(priv
->sysclk
);
453 clk_enable(priv
->audio_clk
);
454 priv
->dai_fmt
= (unsigned int) -1;
455 platform_set_drvdata(pdev
, priv
);
457 return devm_snd_soc_register_component(&pdev
->dev
, &mmp_sspa_component
,
461 static int asoc_mmp_sspa_remove(struct platform_device
*pdev
)
463 struct sspa_priv
*priv
= platform_get_drvdata(pdev
);
465 clk_disable(priv
->audio_clk
);
466 clk_put(priv
->audio_clk
);
467 clk_put(priv
->sysclk
);
471 static struct platform_driver asoc_mmp_sspa_driver
= {
473 .name
= "mmp-sspa-dai",
475 .probe
= asoc_mmp_sspa_probe
,
476 .remove
= asoc_mmp_sspa_remove
,
479 module_platform_driver(asoc_mmp_sspa_driver
);
481 MODULE_AUTHOR("Leo Yan <leoy@marvell.com>");
482 MODULE_DESCRIPTION("MMP SSPA SoC Interface");
483 MODULE_LICENSE("GPL");
484 MODULE_ALIAS("platform:mmp-sspa-dai");