blob: a647799801773d0baedcbffc5e9d3ddec4208b62 [file] [log] [blame]
Zhangfei Gaofa375d42012-06-11 18:04:39 +08001/*
2 * linux/sound/soc/pxa/mmp-sspa.c
3 * Base on pxa2xx-ssp.c
4 *
5 * Copyright (C) 2011 Marvell International Ltd.
6 *
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.
11 *
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.
16 *
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
20 *
21 */
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>
29#include <linux/io.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>
36#include "mmp-sspa.h"
37
38/*
39 * SSPA audio private data
40 */
41struct sspa_priv {
42 struct ssp_device *sspa;
43 struct pxa2xx_pcm_dma_params *dma_params;
44 struct clk *audio_clk;
45 struct clk *sysclk;
46 int dai_fmt;
47 int running_cnt;
48};
49
50static void mmp_sspa_write_reg(struct ssp_device *sspa, u32 reg, u32 val)
51{
52 __raw_writel(val, sspa->mmio_base + reg);
53}
54
55static u32 mmp_sspa_read_reg(struct ssp_device *sspa, u32 reg)
56{
57 return __raw_readl(sspa->mmio_base + reg);
58}
59
60static void mmp_sspa_tx_enable(struct ssp_device *sspa)
61{
62 unsigned int sspa_sp;
63
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);
68}
69
70static void mmp_sspa_tx_disable(struct ssp_device *sspa)
71{
72 unsigned int sspa_sp;
73
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);
78}
79
80static void mmp_sspa_rx_enable(struct ssp_device *sspa)
81{
82 unsigned int sspa_sp;
83
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);
88}
89
90static void mmp_sspa_rx_disable(struct ssp_device *sspa)
91{
92 unsigned int sspa_sp;
93
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);
98}
99
100static int mmp_sspa_startup(struct snd_pcm_substream *substream,
101 struct snd_soc_dai *dai)
102{
103 struct sspa_priv *priv = snd_soc_dai_get_drvdata(dai);
104
105 clk_enable(priv->sysclk);
106 clk_enable(priv->sspa->clk);
107
108 return 0;
109}
110
111static void mmp_sspa_shutdown(struct snd_pcm_substream *substream,
112 struct snd_soc_dai *dai)
113{
114 struct sspa_priv *priv = snd_soc_dai_get_drvdata(dai);
115
116 clk_disable(priv->sspa->clk);
117 clk_disable(priv->sysclk);
118
119 return;
120}
121
122/*
123 * Set the SSP ports SYSCLK.
124 */
125static int mmp_sspa_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
126 int clk_id, unsigned int freq, int dir)
127{
128 struct sspa_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
129 int ret = 0;
130
131 switch (clk_id) {
132 case MMP_SSPA_CLK_AUDIO:
133 ret = clk_set_rate(priv->audio_clk, freq);
134 if (ret)
135 return ret;
136 break;
137 case MMP_SSPA_CLK_PLL:
138 case MMP_SSPA_CLK_VCXO:
139 /* not support yet */
140 return -EINVAL;
141 default:
142 return -EINVAL;
143 }
144
145 return 0;
146}
147
148static 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)
151{
152 struct sspa_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
153 int ret = 0;
154
155 switch (pll_id) {
156 case MMP_SYSCLK:
157 ret = clk_set_rate(priv->sysclk, freq_out);
158 if (ret)
159 return ret;
160 break;
161 case MMP_SSPA_CLK:
162 ret = clk_set_rate(priv->sspa->clk, freq_out);
163 if (ret)
164 return ret;
165 break;
166 default:
167 return -ENODEV;
168 }
169
170 return 0;
171}
172
173/*
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.
177 */
178static int mmp_sspa_set_dai_fmt(struct snd_soc_dai *cpu_dai,
179 unsigned int fmt)
180{
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;
184
185 /* check if we need to change anything at all */
186 if (sspa_priv->dai_fmt == fmt)
187 return 0;
188
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");
194 return -EINVAL;
195 }
196
197 /* reset port settings */
198 sspa_sp = SSPA_SP_WEN | SSPA_SP_S_RST | SSPA_SP_FFLUSH;
199 sspa_ctrl = 0;
200
201 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
202 case SND_SOC_DAIFMT_CBS_CFS:
203 sspa_sp |= SSPA_SP_MSL;
204 break;
205 case SND_SOC_DAIFMT_CBM_CFM:
206 break;
207 default:
208 return -EINVAL;
209 }
210
211 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
212 case SND_SOC_DAIFMT_NB_NF:
213 sspa_sp |= SSPA_SP_FSP;
214 break;
215 default:
216 return -EINVAL;
217 }
218
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);
224 break;
225 default:
226 return -EINVAL;
227 }
228
229 mmp_sspa_write_reg(sspa, SSPA_TXSP, sspa_sp);
230 mmp_sspa_write_reg(sspa, SSPA_RXSP, sspa_sp);
231
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);
235
236 /*
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
241 * rx port.
242 */
243 sspa_sp &= ~SSPA_SP_MSL;
244 mmp_sspa_write_reg(sspa, SSPA_TXSP, sspa_sp);
245
246 mmp_sspa_write_reg(sspa, SSPA_TXCTL, sspa_ctrl);
247 mmp_sspa_write_reg(sspa, SSPA_RXCTL, sspa_ctrl);
248
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.
252 */
253 sspa_priv->dai_fmt = fmt;
254 return 0;
255}
256
257/*
258 * Set the SSPA audio DMA parameters and sample size.
259 * Can be called multiple times by oss emulation.
260 */
261static int mmp_sspa_hw_params(struct snd_pcm_substream *substream,
262 struct snd_pcm_hw_params *params,
263 struct snd_soc_dai *dai)
264{
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;
270 u32 sspa_ctrl;
271
272 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
273 sspa_ctrl = mmp_sspa_read_reg(sspa, SSPA_TXCTL);
274 else
275 sspa_ctrl = mmp_sspa_read_reg(sspa, SSPA_RXCTL);
276
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;
282
283 switch (params_format(params)) {
284 case SNDRV_PCM_FORMAT_S8:
285 sspa_ctrl |= SSPA_CTL_XSSZ1(SSPA_CTL_8_BITS);
286 break;
287 case SNDRV_PCM_FORMAT_S16_LE:
288 sspa_ctrl |= SSPA_CTL_XSSZ1(SSPA_CTL_16_BITS);
289 break;
290 case SNDRV_PCM_FORMAT_S20_3LE:
291 sspa_ctrl |= SSPA_CTL_XSSZ1(SSPA_CTL_20_BITS);
292 break;
293 case SNDRV_PCM_FORMAT_S24_3LE:
294 sspa_ctrl |= SSPA_CTL_XSSZ1(SSPA_CTL_24_BITS);
295 break;
296 case SNDRV_PCM_FORMAT_S32_LE:
297 sspa_ctrl |= SSPA_CTL_XSSZ1(SSPA_CTL_32_BITS);
298 break;
299 default:
300 return -EINVAL;
301 }
302
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);
306 } else {
307 mmp_sspa_write_reg(sspa, SSPA_RXCTL, sspa_ctrl);
308 mmp_sspa_write_reg(sspa, SSPA_RXFIFO_UL, 0x0);
309 }
310
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);
316 return 0;
317}
318
319static int mmp_sspa_trigger(struct snd_pcm_substream *substream, int cmd,
320 struct snd_soc_dai *dai)
321{
322 struct sspa_priv *sspa_priv = snd_soc_dai_get_drvdata(dai);
323 struct ssp_device *sspa = sspa_priv->sspa;
324 int ret = 0;
325
326 switch (cmd) {
327 case SNDRV_PCM_TRIGGER_START:
328 case SNDRV_PCM_TRIGGER_RESUME:
329 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
330 /*
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.
335 */
336 if (!sspa_priv->running_cnt)
337 mmp_sspa_rx_enable(sspa);
338
339 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
340 mmp_sspa_tx_enable(sspa);
341
342 sspa_priv->running_cnt++;
343 break;
344
345 case SNDRV_PCM_TRIGGER_STOP:
346 case SNDRV_PCM_TRIGGER_SUSPEND:
347 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
348 sspa_priv->running_cnt--;
349
350 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
351 mmp_sspa_tx_disable(sspa);
352
353 /* have no capture stream, disable rx port */
354 if (!sspa_priv->running_cnt)
355 mmp_sspa_rx_disable(sspa);
356 break;
357
358 default:
359 ret = -EINVAL;
360 }
361
362 return ret;
363}
364
365static int mmp_sspa_probe(struct snd_soc_dai *dai)
366{
367 struct sspa_priv *priv = dev_get_drvdata(dai->dev);
368
369 snd_soc_dai_set_drvdata(dai, priv);
370 return 0;
371
372}
373
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)
380
381static 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,
389};
390
391struct snd_soc_dai_driver mmp_sspa_dai = {
392 .probe = mmp_sspa_probe,
393 .playback = {
394 .channels_min = 1,
395 .channels_max = 128,
396 .rates = MMP_SSPA_RATES,
397 .formats = MMP_SSPA_FORMATS,
398 },
399 .capture = {
400 .channels_min = 1,
401 .channels_max = 2,
402 .rates = MMP_SSPA_RATES,
403 .formats = MMP_SSPA_FORMATS,
404 },
405 .ops = &mmp_sspa_dai_ops,
406};
407
Kuninori Morimoto425f3702013-03-21 03:34:48 -0700408static const struct snd_soc_component_driver mmp_sspa_component = {
409 .name = "mmp-sspa",
410};
411
Bill Pemberton570f6fe2012-12-07 09:26:17 -0500412static int asoc_mmp_sspa_probe(struct platform_device *pdev)
Zhangfei Gaofa375d42012-06-11 18:04:39 +0800413{
414 struct sspa_priv *priv;
415 struct resource *res;
416
417 priv = devm_kzalloc(&pdev->dev,
418 sizeof(struct sspa_priv), GFP_KERNEL);
419 if (!priv)
420 return -ENOMEM;
421
422 priv->sspa = devm_kzalloc(&pdev->dev,
423 sizeof(struct ssp_device), GFP_KERNEL);
424 if (priv->sspa == NULL)
425 return -ENOMEM;
426
427 priv->dma_params = devm_kzalloc(&pdev->dev,
428 2 * sizeof(struct pxa2xx_pcm_dma_params), GFP_KERNEL);
429 if (priv->dma_params == NULL)
430 return -ENOMEM;
431
432 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
433 if (res == NULL)
434 return -ENOMEM;
435
Thierry Redingb25b5aa2013-01-21 11:09:26 +0100436 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);
Zhangfei Gaofa375d42012-06-11 18:04:39 +0800439
440 priv->sspa->clk = devm_clk_get(&pdev->dev, NULL);
441 if (IS_ERR(priv->sspa->clk))
442 return PTR_ERR(priv->sspa->clk);
443
444 priv->audio_clk = clk_get(NULL, "mmp-audio");
445 if (IS_ERR(priv->audio_clk))
446 return PTR_ERR(priv->audio_clk);
447
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);
452 }
453 clk_enable(priv->audio_clk);
454 priv->dai_fmt = (unsigned int) -1;
455 platform_set_drvdata(pdev, priv);
456
Kuninori Morimoto425f3702013-03-21 03:34:48 -0700457 return snd_soc_register_component(&pdev->dev, &mmp_sspa_component,
458 &mmp_sspa_dai, 1);
Zhangfei Gaofa375d42012-06-11 18:04:39 +0800459}
460
Bill Pemberton570f6fe2012-12-07 09:26:17 -0500461static int asoc_mmp_sspa_remove(struct platform_device *pdev)
Zhangfei Gaofa375d42012-06-11 18:04:39 +0800462{
463 struct sspa_priv *priv = platform_get_drvdata(pdev);
464
465 clk_disable(priv->audio_clk);
466 clk_put(priv->audio_clk);
467 clk_put(priv->sysclk);
Kuninori Morimoto425f3702013-03-21 03:34:48 -0700468 snd_soc_unregister_component(&pdev->dev);
Zhangfei Gaofa375d42012-06-11 18:04:39 +0800469 return 0;
470}
471
472static struct platform_driver asoc_mmp_sspa_driver = {
473 .driver = {
474 .name = "mmp-sspa-dai",
475 .owner = THIS_MODULE,
476 },
477 .probe = asoc_mmp_sspa_probe,
Bill Pemberton570f6fe2012-12-07 09:26:17 -0500478 .remove = asoc_mmp_sspa_remove,
Zhangfei Gaofa375d42012-06-11 18:04:39 +0800479};
480
481module_platform_driver(asoc_mmp_sspa_driver);
482
483MODULE_AUTHOR("Leo Yan <leoy@marvell.com>");
484MODULE_DESCRIPTION("MMP SSPA SoC Interface");
485MODULE_LICENSE("GPL");