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 <sound/core.h>
31 #include <sound/pcm.h>
32 #include <sound/initval.h>
33 #include <sound/pcm_params.h>
34 #include <sound/soc.h>
35 #include <sound/pxa2xx-lib.h>
39 * SSPA audio private data
42 struct ssp_device
*sspa
;
43 struct pxa2xx_pcm_dma_params
*dma_params
;
44 struct clk
*audio_clk
;
50 static void mmp_sspa_write_reg(struct ssp_device
*sspa
, u32 reg
, u32 val
)
52 __raw_writel(val
, sspa
->mmio_base
+ reg
);
55 static u32
mmp_sspa_read_reg(struct ssp_device
*sspa
, u32 reg
)
57 return __raw_readl(sspa
->mmio_base
+ reg
);
60 static void mmp_sspa_tx_enable(struct ssp_device
*sspa
)
64 sspa_sp
= mmp_sspa_read_reg(sspa
, SSPA_TXSP
);
65 sspa_sp
|= SSPA_SP_S_EN
;
66 sspa_sp
|= SSPA_SP_WEN
;
67 mmp_sspa_write_reg(sspa
, SSPA_TXSP
, sspa_sp
);
70 static void mmp_sspa_tx_disable(struct ssp_device
*sspa
)
74 sspa_sp
= mmp_sspa_read_reg(sspa
, SSPA_TXSP
);
75 sspa_sp
&= ~SSPA_SP_S_EN
;
76 sspa_sp
|= SSPA_SP_WEN
;
77 mmp_sspa_write_reg(sspa
, SSPA_TXSP
, sspa_sp
);
80 static void mmp_sspa_rx_enable(struct ssp_device
*sspa
)
84 sspa_sp
= mmp_sspa_read_reg(sspa
, SSPA_RXSP
);
85 sspa_sp
|= SSPA_SP_S_EN
;
86 sspa_sp
|= SSPA_SP_WEN
;
87 mmp_sspa_write_reg(sspa
, SSPA_RXSP
, sspa_sp
);
90 static void mmp_sspa_rx_disable(struct ssp_device
*sspa
)
94 sspa_sp
= mmp_sspa_read_reg(sspa
, SSPA_RXSP
);
95 sspa_sp
&= ~SSPA_SP_S_EN
;
96 sspa_sp
|= SSPA_SP_WEN
;
97 mmp_sspa_write_reg(sspa
, SSPA_RXSP
, sspa_sp
);
100 static int mmp_sspa_startup(struct snd_pcm_substream
*substream
,
101 struct snd_soc_dai
*dai
)
103 struct sspa_priv
*priv
= snd_soc_dai_get_drvdata(dai
);
105 clk_enable(priv
->sysclk
);
106 clk_enable(priv
->sspa
->clk
);
111 static void mmp_sspa_shutdown(struct snd_pcm_substream
*substream
,
112 struct snd_soc_dai
*dai
)
114 struct sspa_priv
*priv
= snd_soc_dai_get_drvdata(dai
);
116 clk_disable(priv
->sspa
->clk
);
117 clk_disable(priv
->sysclk
);
123 * Set the SSP ports SYSCLK.
125 static int mmp_sspa_set_dai_sysclk(struct snd_soc_dai
*cpu_dai
,
126 int clk_id
, unsigned int freq
, int dir
)
128 struct sspa_priv
*priv
= snd_soc_dai_get_drvdata(cpu_dai
);
132 case MMP_SSPA_CLK_AUDIO
:
133 ret
= clk_set_rate(priv
->audio_clk
, freq
);
137 case MMP_SSPA_CLK_PLL
:
138 case MMP_SSPA_CLK_VCXO
:
139 /* not support yet */
148 static int mmp_sspa_set_dai_pll(struct snd_soc_dai
*cpu_dai
, int pll_id
,
149 int source
, unsigned int freq_in
,
150 unsigned int freq_out
)
152 struct sspa_priv
*priv
= snd_soc_dai_get_drvdata(cpu_dai
);
157 ret
= clk_set_rate(priv
->sysclk
, freq_out
);
162 ret
= clk_set_rate(priv
->sspa
->clk
, freq_out
);
174 * Set up the sspa dai format. The sspa port must be inactive
175 * before calling this function as the physical
176 * interface format is changed.
178 static int mmp_sspa_set_dai_fmt(struct snd_soc_dai
*cpu_dai
,
181 struct sspa_priv
*sspa_priv
= snd_soc_dai_get_drvdata(cpu_dai
);
182 struct ssp_device
*sspa
= sspa_priv
->sspa
;
183 u32 sspa_sp
, sspa_ctrl
;
185 /* check if we need to change anything at all */
186 if (sspa_priv
->dai_fmt
== fmt
)
189 /* we can only change the settings if the port is not in use */
190 if ((mmp_sspa_read_reg(sspa
, SSPA_TXSP
) & SSPA_SP_S_EN
) ||
191 (mmp_sspa_read_reg(sspa
, SSPA_RXSP
) & SSPA_SP_S_EN
)) {
192 dev_err(&sspa
->pdev
->dev
,
193 "can't change hardware dai format: stream is in use\n");
197 /* reset port settings */
198 sspa_sp
= SSPA_SP_WEN
| SSPA_SP_S_RST
| SSPA_SP_FFLUSH
;
201 switch (fmt
& SND_SOC_DAIFMT_MASTER_MASK
) {
202 case SND_SOC_DAIFMT_CBS_CFS
:
203 sspa_sp
|= SSPA_SP_MSL
;
205 case SND_SOC_DAIFMT_CBM_CFM
:
211 switch (fmt
& SND_SOC_DAIFMT_INV_MASK
) {
212 case SND_SOC_DAIFMT_NB_NF
:
213 sspa_sp
|= SSPA_SP_FSP
;
219 switch (fmt
& SND_SOC_DAIFMT_FORMAT_MASK
) {
220 case SND_SOC_DAIFMT_I2S
:
221 sspa_sp
|= SSPA_TXSP_FPER(63);
222 sspa_sp
|= SSPA_SP_FWID(31);
223 sspa_ctrl
|= SSPA_CTL_XDATDLY(1);
229 mmp_sspa_write_reg(sspa
, SSPA_TXSP
, sspa_sp
);
230 mmp_sspa_write_reg(sspa
, SSPA_RXSP
, sspa_sp
);
232 sspa_sp
&= ~(SSPA_SP_S_RST
| SSPA_SP_FFLUSH
);
233 mmp_sspa_write_reg(sspa
, SSPA_TXSP
, sspa_sp
);
234 mmp_sspa_write_reg(sspa
, SSPA_RXSP
, sspa_sp
);
237 * FIXME: hw issue, for the tx serial port,
238 * can not config the master/slave mode;
239 * so must clean this bit.
240 * The master/slave mode has been set in the
243 sspa_sp
&= ~SSPA_SP_MSL
;
244 mmp_sspa_write_reg(sspa
, SSPA_TXSP
, sspa_sp
);
246 mmp_sspa_write_reg(sspa
, SSPA_TXCTL
, sspa_ctrl
);
247 mmp_sspa_write_reg(sspa
, SSPA_RXCTL
, sspa_ctrl
);
249 /* Since we are configuring the timings for the format by hand
250 * we have to defer some things until hw_params() where we
251 * know parameters like the sample size.
253 sspa_priv
->dai_fmt
= fmt
;
258 * Set the SSPA audio DMA parameters and sample size.
259 * Can be called multiple times by oss emulation.
261 static int mmp_sspa_hw_params(struct snd_pcm_substream
*substream
,
262 struct snd_pcm_hw_params
*params
,
263 struct snd_soc_dai
*dai
)
265 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
266 struct snd_soc_dai
*cpu_dai
= rtd
->cpu_dai
;
267 struct sspa_priv
*sspa_priv
= snd_soc_dai_get_drvdata(dai
);
268 struct ssp_device
*sspa
= sspa_priv
->sspa
;
269 struct pxa2xx_pcm_dma_params
*dma_params
;
272 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
)
273 sspa_ctrl
= mmp_sspa_read_reg(sspa
, SSPA_TXCTL
);
275 sspa_ctrl
= mmp_sspa_read_reg(sspa
, SSPA_RXCTL
);
277 sspa_ctrl
&= ~SSPA_CTL_XFRLEN1_MASK
;
278 sspa_ctrl
|= SSPA_CTL_XFRLEN1(params_channels(params
) - 1);
279 sspa_ctrl
&= ~SSPA_CTL_XWDLEN1_MASK
;
280 sspa_ctrl
|= SSPA_CTL_XWDLEN1(SSPA_CTL_32_BITS
);
281 sspa_ctrl
&= ~SSPA_CTL_XSSZ1_MASK
;
283 switch (params_format(params
)) {
284 case SNDRV_PCM_FORMAT_S8
:
285 sspa_ctrl
|= SSPA_CTL_XSSZ1(SSPA_CTL_8_BITS
);
287 case SNDRV_PCM_FORMAT_S16_LE
:
288 sspa_ctrl
|= SSPA_CTL_XSSZ1(SSPA_CTL_16_BITS
);
290 case SNDRV_PCM_FORMAT_S20_3LE
:
291 sspa_ctrl
|= SSPA_CTL_XSSZ1(SSPA_CTL_20_BITS
);
293 case SNDRV_PCM_FORMAT_S24_3LE
:
294 sspa_ctrl
|= SSPA_CTL_XSSZ1(SSPA_CTL_24_BITS
);
296 case SNDRV_PCM_FORMAT_S32_LE
:
297 sspa_ctrl
|= SSPA_CTL_XSSZ1(SSPA_CTL_32_BITS
);
303 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
) {
304 mmp_sspa_write_reg(sspa
, SSPA_TXCTL
, sspa_ctrl
);
305 mmp_sspa_write_reg(sspa
, SSPA_TXFIFO_LL
, 0x1);
307 mmp_sspa_write_reg(sspa
, SSPA_RXCTL
, sspa_ctrl
);
308 mmp_sspa_write_reg(sspa
, SSPA_RXFIFO_UL
, 0x0);
311 dma_params
= &sspa_priv
->dma_params
[substream
->stream
];
312 dma_params
->dev_addr
= substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
?
313 (sspa
->phys_base
+ SSPA_TXD
) :
314 (sspa
->phys_base
+ SSPA_RXD
);
315 snd_soc_dai_set_dma_data(cpu_dai
, substream
, dma_params
);
319 static int mmp_sspa_trigger(struct snd_pcm_substream
*substream
, int cmd
,
320 struct snd_soc_dai
*dai
)
322 struct sspa_priv
*sspa_priv
= snd_soc_dai_get_drvdata(dai
);
323 struct ssp_device
*sspa
= sspa_priv
->sspa
;
327 case SNDRV_PCM_TRIGGER_START
:
328 case SNDRV_PCM_TRIGGER_RESUME
:
329 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
331 * whatever playback or capture, must enable rx.
332 * this is a hw issue, so need check if rx has been
333 * enabled or not; if has been enabled by another
334 * stream, do not enable again.
336 if (!sspa_priv
->running_cnt
)
337 mmp_sspa_rx_enable(sspa
);
339 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
)
340 mmp_sspa_tx_enable(sspa
);
342 sspa_priv
->running_cnt
++;
345 case SNDRV_PCM_TRIGGER_STOP
:
346 case SNDRV_PCM_TRIGGER_SUSPEND
:
347 case SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
348 sspa_priv
->running_cnt
--;
350 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
)
351 mmp_sspa_tx_disable(sspa
);
353 /* have no capture stream, disable rx port */
354 if (!sspa_priv
->running_cnt
)
355 mmp_sspa_rx_disable(sspa
);
365 static int mmp_sspa_probe(struct snd_soc_dai
*dai
)
367 struct sspa_priv
*priv
= dev_get_drvdata(dai
->dev
);
369 snd_soc_dai_set_drvdata(dai
, priv
);
374 #define MMP_SSPA_RATES SNDRV_PCM_RATE_8000_192000
375 #define MMP_SSPA_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
376 SNDRV_PCM_FMTBIT_S16_LE | \
377 SNDRV_PCM_FMTBIT_S24_LE | \
378 SNDRV_PCM_FMTBIT_S24_LE | \
379 SNDRV_PCM_FMTBIT_S32_LE)
381 static struct snd_soc_dai_ops mmp_sspa_dai_ops
= {
382 .startup
= mmp_sspa_startup
,
383 .shutdown
= mmp_sspa_shutdown
,
384 .trigger
= mmp_sspa_trigger
,
385 .hw_params
= mmp_sspa_hw_params
,
386 .set_sysclk
= mmp_sspa_set_dai_sysclk
,
387 .set_pll
= mmp_sspa_set_dai_pll
,
388 .set_fmt
= mmp_sspa_set_dai_fmt
,
391 struct snd_soc_dai_driver mmp_sspa_dai
= {
392 .probe
= mmp_sspa_probe
,
396 .rates
= MMP_SSPA_RATES
,
397 .formats
= MMP_SSPA_FORMATS
,
402 .rates
= MMP_SSPA_RATES
,
403 .formats
= MMP_SSPA_FORMATS
,
405 .ops
= &mmp_sspa_dai_ops
,
408 static __devinit
int asoc_mmp_sspa_probe(struct platform_device
*pdev
)
410 struct sspa_priv
*priv
;
411 struct resource
*res
;
413 priv
= devm_kzalloc(&pdev
->dev
,
414 sizeof(struct sspa_priv
), GFP_KERNEL
);
418 priv
->sspa
= devm_kzalloc(&pdev
->dev
,
419 sizeof(struct ssp_device
), GFP_KERNEL
);
420 if (priv
->sspa
== NULL
)
423 priv
->dma_params
= devm_kzalloc(&pdev
->dev
,
424 2 * sizeof(struct pxa2xx_pcm_dma_params
), GFP_KERNEL
);
425 if (priv
->dma_params
== NULL
)
428 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
432 priv
->sspa
->mmio_base
= devm_request_and_ioremap(&pdev
->dev
, res
);
433 if (priv
->sspa
->mmio_base
== NULL
)
436 priv
->sspa
->clk
= devm_clk_get(&pdev
->dev
, NULL
);
437 if (IS_ERR(priv
->sspa
->clk
))
438 return PTR_ERR(priv
->sspa
->clk
);
440 priv
->audio_clk
= clk_get(NULL
, "mmp-audio");
441 if (IS_ERR(priv
->audio_clk
))
442 return PTR_ERR(priv
->audio_clk
);
444 priv
->sysclk
= clk_get(NULL
, "mmp-sysclk");
445 if (IS_ERR(priv
->sysclk
)) {
446 clk_put(priv
->audio_clk
);
447 return PTR_ERR(priv
->sysclk
);
449 clk_enable(priv
->audio_clk
);
450 priv
->dai_fmt
= (unsigned int) -1;
451 platform_set_drvdata(pdev
, priv
);
453 return snd_soc_register_dai(&pdev
->dev
, &mmp_sspa_dai
);
456 static int __devexit
asoc_mmp_sspa_remove(struct platform_device
*pdev
)
458 struct sspa_priv
*priv
= platform_get_drvdata(pdev
);
460 clk_disable(priv
->audio_clk
);
461 clk_put(priv
->audio_clk
);
462 clk_put(priv
->sysclk
);
463 snd_soc_unregister_dai(&pdev
->dev
);
467 static struct platform_driver asoc_mmp_sspa_driver
= {
469 .name
= "mmp-sspa-dai",
470 .owner
= THIS_MODULE
,
472 .probe
= asoc_mmp_sspa_probe
,
473 .remove
= __devexit_p(asoc_mmp_sspa_remove
),
476 module_platform_driver(asoc_mmp_sspa_driver
);
478 MODULE_AUTHOR("Leo Yan <leoy@marvell.com>");
479 MODULE_DESCRIPTION("MMP SSPA SoC Interface");
480 MODULE_LICENSE("GPL");