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
);
126 * Set the SSP ports SYSCLK.
128 static int mmp_sspa_set_dai_sysclk(struct snd_soc_dai
*cpu_dai
,
129 int clk_id
, unsigned int freq
, int dir
)
131 struct sspa_priv
*priv
= snd_soc_dai_get_drvdata(cpu_dai
);
135 case MMP_SSPA_CLK_AUDIO
:
136 ret
= clk_set_rate(priv
->audio_clk
, freq
);
140 case MMP_SSPA_CLK_PLL
:
141 case MMP_SSPA_CLK_VCXO
:
142 /* not support yet */
151 static int mmp_sspa_set_dai_pll(struct snd_soc_dai
*cpu_dai
, int pll_id
,
152 int source
, unsigned int freq_in
,
153 unsigned int freq_out
)
155 struct sspa_priv
*priv
= snd_soc_dai_get_drvdata(cpu_dai
);
160 ret
= clk_set_rate(priv
->sysclk
, freq_out
);
165 ret
= clk_set_rate(priv
->sspa
->clk
, freq_out
);
177 * Set up the sspa dai format. The sspa port must be inactive
178 * before calling this function as the physical
179 * interface format is changed.
181 static int mmp_sspa_set_dai_fmt(struct snd_soc_dai
*cpu_dai
,
184 struct sspa_priv
*sspa_priv
= snd_soc_dai_get_drvdata(cpu_dai
);
185 struct ssp_device
*sspa
= sspa_priv
->sspa
;
186 u32 sspa_sp
, sspa_ctrl
;
188 /* check if we need to change anything at all */
189 if (sspa_priv
->dai_fmt
== fmt
)
192 /* we can only change the settings if the port is not in use */
193 if ((mmp_sspa_read_reg(sspa
, SSPA_TXSP
) & SSPA_SP_S_EN
) ||
194 (mmp_sspa_read_reg(sspa
, SSPA_RXSP
) & SSPA_SP_S_EN
)) {
195 dev_err(&sspa
->pdev
->dev
,
196 "can't change hardware dai format: stream is in use\n");
200 /* reset port settings */
201 sspa_sp
= SSPA_SP_WEN
| SSPA_SP_S_RST
| SSPA_SP_FFLUSH
;
204 switch (fmt
& SND_SOC_DAIFMT_MASTER_MASK
) {
205 case SND_SOC_DAIFMT_CBS_CFS
:
206 sspa_sp
|= SSPA_SP_MSL
;
208 case SND_SOC_DAIFMT_CBM_CFM
:
214 switch (fmt
& SND_SOC_DAIFMT_INV_MASK
) {
215 case SND_SOC_DAIFMT_NB_NF
:
216 sspa_sp
|= SSPA_SP_FSP
;
222 switch (fmt
& SND_SOC_DAIFMT_FORMAT_MASK
) {
223 case SND_SOC_DAIFMT_I2S
:
224 sspa_sp
|= SSPA_TXSP_FPER(63);
225 sspa_sp
|= SSPA_SP_FWID(31);
226 sspa_ctrl
|= SSPA_CTL_XDATDLY(1);
232 mmp_sspa_write_reg(sspa
, SSPA_TXSP
, sspa_sp
);
233 mmp_sspa_write_reg(sspa
, SSPA_RXSP
, sspa_sp
);
235 sspa_sp
&= ~(SSPA_SP_S_RST
| SSPA_SP_FFLUSH
);
236 mmp_sspa_write_reg(sspa
, SSPA_TXSP
, sspa_sp
);
237 mmp_sspa_write_reg(sspa
, SSPA_RXSP
, sspa_sp
);
240 * FIXME: hw issue, for the tx serial port,
241 * can not config the master/slave mode;
242 * so must clean this bit.
243 * The master/slave mode has been set in the
246 sspa_sp
&= ~SSPA_SP_MSL
;
247 mmp_sspa_write_reg(sspa
, SSPA_TXSP
, sspa_sp
);
249 mmp_sspa_write_reg(sspa
, SSPA_TXCTL
, sspa_ctrl
);
250 mmp_sspa_write_reg(sspa
, SSPA_RXCTL
, sspa_ctrl
);
252 /* Since we are configuring the timings for the format by hand
253 * we have to defer some things until hw_params() where we
254 * know parameters like the sample size.
256 sspa_priv
->dai_fmt
= fmt
;
261 * Set the SSPA audio DMA parameters and sample size.
262 * Can be called multiple times by oss emulation.
264 static int mmp_sspa_hw_params(struct snd_pcm_substream
*substream
,
265 struct snd_pcm_hw_params
*params
,
266 struct snd_soc_dai
*dai
)
268 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
269 struct snd_soc_dai
*cpu_dai
= rtd
->cpu_dai
;
270 struct sspa_priv
*sspa_priv
= snd_soc_dai_get_drvdata(dai
);
271 struct ssp_device
*sspa
= sspa_priv
->sspa
;
272 struct snd_dmaengine_dai_dma_data
*dma_params
;
275 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
)
276 sspa_ctrl
= mmp_sspa_read_reg(sspa
, SSPA_TXCTL
);
278 sspa_ctrl
= mmp_sspa_read_reg(sspa
, SSPA_RXCTL
);
280 sspa_ctrl
&= ~SSPA_CTL_XFRLEN1_MASK
;
281 sspa_ctrl
|= SSPA_CTL_XFRLEN1(params_channels(params
) - 1);
282 sspa_ctrl
&= ~SSPA_CTL_XWDLEN1_MASK
;
283 sspa_ctrl
|= SSPA_CTL_XWDLEN1(SSPA_CTL_32_BITS
);
284 sspa_ctrl
&= ~SSPA_CTL_XSSZ1_MASK
;
286 switch (params_format(params
)) {
287 case SNDRV_PCM_FORMAT_S8
:
288 sspa_ctrl
|= SSPA_CTL_XSSZ1(SSPA_CTL_8_BITS
);
290 case SNDRV_PCM_FORMAT_S16_LE
:
291 sspa_ctrl
|= SSPA_CTL_XSSZ1(SSPA_CTL_16_BITS
);
293 case SNDRV_PCM_FORMAT_S20_3LE
:
294 sspa_ctrl
|= SSPA_CTL_XSSZ1(SSPA_CTL_20_BITS
);
296 case SNDRV_PCM_FORMAT_S24_3LE
:
297 sspa_ctrl
|= SSPA_CTL_XSSZ1(SSPA_CTL_24_BITS
);
299 case SNDRV_PCM_FORMAT_S32_LE
:
300 sspa_ctrl
|= SSPA_CTL_XSSZ1(SSPA_CTL_32_BITS
);
306 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
) {
307 mmp_sspa_write_reg(sspa
, SSPA_TXCTL
, sspa_ctrl
);
308 mmp_sspa_write_reg(sspa
, SSPA_TXFIFO_LL
, 0x1);
310 mmp_sspa_write_reg(sspa
, SSPA_RXCTL
, sspa_ctrl
);
311 mmp_sspa_write_reg(sspa
, SSPA_RXFIFO_UL
, 0x0);
314 dma_params
= &sspa_priv
->dma_params
[substream
->stream
];
315 dma_params
->addr
= substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
?
316 (sspa
->phys_base
+ SSPA_TXD
) :
317 (sspa
->phys_base
+ SSPA_RXD
);
318 snd_soc_dai_set_dma_data(cpu_dai
, substream
, dma_params
);
322 static int mmp_sspa_trigger(struct snd_pcm_substream
*substream
, int cmd
,
323 struct snd_soc_dai
*dai
)
325 struct sspa_priv
*sspa_priv
= snd_soc_dai_get_drvdata(dai
);
326 struct ssp_device
*sspa
= sspa_priv
->sspa
;
330 case SNDRV_PCM_TRIGGER_START
:
331 case SNDRV_PCM_TRIGGER_RESUME
:
332 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
334 * whatever playback or capture, must enable rx.
335 * this is a hw issue, so need check if rx has been
336 * enabled or not; if has been enabled by another
337 * stream, do not enable again.
339 if (!sspa_priv
->running_cnt
)
340 mmp_sspa_rx_enable(sspa
);
342 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
)
343 mmp_sspa_tx_enable(sspa
);
345 sspa_priv
->running_cnt
++;
348 case SNDRV_PCM_TRIGGER_STOP
:
349 case SNDRV_PCM_TRIGGER_SUSPEND
:
350 case SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
351 sspa_priv
->running_cnt
--;
353 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
)
354 mmp_sspa_tx_disable(sspa
);
356 /* have no capture stream, disable rx port */
357 if (!sspa_priv
->running_cnt
)
358 mmp_sspa_rx_disable(sspa
);
368 static int mmp_sspa_probe(struct snd_soc_dai
*dai
)
370 struct sspa_priv
*priv
= dev_get_drvdata(dai
->dev
);
372 snd_soc_dai_set_drvdata(dai
, priv
);
377 #define MMP_SSPA_RATES SNDRV_PCM_RATE_8000_192000
378 #define MMP_SSPA_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
379 SNDRV_PCM_FMTBIT_S16_LE | \
380 SNDRV_PCM_FMTBIT_S24_LE | \
381 SNDRV_PCM_FMTBIT_S24_LE | \
382 SNDRV_PCM_FMTBIT_S32_LE)
384 static struct snd_soc_dai_ops mmp_sspa_dai_ops
= {
385 .startup
= mmp_sspa_startup
,
386 .shutdown
= mmp_sspa_shutdown
,
387 .trigger
= mmp_sspa_trigger
,
388 .hw_params
= mmp_sspa_hw_params
,
389 .set_sysclk
= mmp_sspa_set_dai_sysclk
,
390 .set_pll
= mmp_sspa_set_dai_pll
,
391 .set_fmt
= mmp_sspa_set_dai_fmt
,
394 static struct snd_soc_dai_driver mmp_sspa_dai
= {
395 .probe
= mmp_sspa_probe
,
399 .rates
= MMP_SSPA_RATES
,
400 .formats
= MMP_SSPA_FORMATS
,
405 .rates
= MMP_SSPA_RATES
,
406 .formats
= MMP_SSPA_FORMATS
,
408 .ops
= &mmp_sspa_dai_ops
,
411 static const struct snd_soc_component_driver mmp_sspa_component
= {
415 static int asoc_mmp_sspa_probe(struct platform_device
*pdev
)
417 struct sspa_priv
*priv
;
418 struct resource
*res
;
420 priv
= devm_kzalloc(&pdev
->dev
,
421 sizeof(struct sspa_priv
), GFP_KERNEL
);
425 priv
->sspa
= devm_kzalloc(&pdev
->dev
,
426 sizeof(struct ssp_device
), GFP_KERNEL
);
427 if (priv
->sspa
== NULL
)
430 priv
->dma_params
= devm_kzalloc(&pdev
->dev
,
431 2 * sizeof(struct snd_dmaengine_dai_dma_data
),
433 if (priv
->dma_params
== NULL
)
436 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
437 priv
->sspa
->mmio_base
= devm_ioremap_resource(&pdev
->dev
, res
);
438 if (IS_ERR(priv
->sspa
->mmio_base
))
439 return PTR_ERR(priv
->sspa
->mmio_base
);
441 priv
->sspa
->clk
= devm_clk_get(&pdev
->dev
, NULL
);
442 if (IS_ERR(priv
->sspa
->clk
))
443 return PTR_ERR(priv
->sspa
->clk
);
445 priv
->audio_clk
= clk_get(NULL
, "mmp-audio");
446 if (IS_ERR(priv
->audio_clk
))
447 return PTR_ERR(priv
->audio_clk
);
449 priv
->sysclk
= clk_get(NULL
, "mmp-sysclk");
450 if (IS_ERR(priv
->sysclk
)) {
451 clk_put(priv
->audio_clk
);
452 return PTR_ERR(priv
->sysclk
);
454 clk_enable(priv
->audio_clk
);
455 priv
->dai_fmt
= (unsigned int) -1;
456 platform_set_drvdata(pdev
, priv
);
458 return devm_snd_soc_register_component(&pdev
->dev
, &mmp_sspa_component
,
462 static int asoc_mmp_sspa_remove(struct platform_device
*pdev
)
464 struct sspa_priv
*priv
= platform_get_drvdata(pdev
);
466 clk_disable(priv
->audio_clk
);
467 clk_put(priv
->audio_clk
);
468 clk_put(priv
->sysclk
);
472 static struct platform_driver asoc_mmp_sspa_driver
= {
474 .name
= "mmp-sspa-dai",
476 .probe
= asoc_mmp_sspa_probe
,
477 .remove
= asoc_mmp_sspa_remove
,
480 module_platform_driver(asoc_mmp_sspa_driver
);
482 MODULE_AUTHOR("Leo Yan <leoy@marvell.com>");
483 MODULE_DESCRIPTION("MMP SSPA SoC Interface");
484 MODULE_LICENSE("GPL");
485 MODULE_ALIAS("platform:mmp-sspa-dai");