xref: /openbmc/linux/sound/soc/pxa/mmp-sspa.c (revision b6bec26c)
1 /*
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  */
41 struct 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 
50 static void mmp_sspa_write_reg(struct ssp_device *sspa, u32 reg, u32 val)
51 {
52 	__raw_writel(val, sspa->mmio_base + reg);
53 }
54 
55 static u32 mmp_sspa_read_reg(struct ssp_device *sspa, u32 reg)
56 {
57 	return __raw_readl(sspa->mmio_base + reg);
58 }
59 
60 static 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 
70 static 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 
80 static 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 
90 static 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 
100 static 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 
111 static 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  */
125 static 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 
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)
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  */
178 static 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  */
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)
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 
319 static 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 
365 static 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 
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,
389 };
390 
391 struct 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 
408 static int asoc_mmp_sspa_probe(struct platform_device *pdev)
409 {
410 	struct sspa_priv *priv;
411 	struct resource *res;
412 
413 	priv = devm_kzalloc(&pdev->dev,
414 				sizeof(struct sspa_priv), GFP_KERNEL);
415 	if (!priv)
416 		return -ENOMEM;
417 
418 	priv->sspa = devm_kzalloc(&pdev->dev,
419 				sizeof(struct ssp_device), GFP_KERNEL);
420 	if (priv->sspa == NULL)
421 		return -ENOMEM;
422 
423 	priv->dma_params = devm_kzalloc(&pdev->dev,
424 			2 * sizeof(struct pxa2xx_pcm_dma_params), GFP_KERNEL);
425 	if (priv->dma_params == NULL)
426 		return -ENOMEM;
427 
428 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
429 	if (res == NULL)
430 		return -ENOMEM;
431 
432 	priv->sspa->mmio_base = devm_request_and_ioremap(&pdev->dev, res);
433 	if (priv->sspa->mmio_base == NULL)
434 		return -ENODEV;
435 
436 	priv->sspa->clk = devm_clk_get(&pdev->dev, NULL);
437 	if (IS_ERR(priv->sspa->clk))
438 		return PTR_ERR(priv->sspa->clk);
439 
440 	priv->audio_clk = clk_get(NULL, "mmp-audio");
441 	if (IS_ERR(priv->audio_clk))
442 		return PTR_ERR(priv->audio_clk);
443 
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);
448 	}
449 	clk_enable(priv->audio_clk);
450 	priv->dai_fmt = (unsigned int) -1;
451 	platform_set_drvdata(pdev, priv);
452 
453 	return snd_soc_register_dai(&pdev->dev, &mmp_sspa_dai);
454 }
455 
456 static int asoc_mmp_sspa_remove(struct platform_device *pdev)
457 {
458 	struct sspa_priv *priv = platform_get_drvdata(pdev);
459 
460 	clk_disable(priv->audio_clk);
461 	clk_put(priv->audio_clk);
462 	clk_put(priv->sysclk);
463 	snd_soc_unregister_dai(&pdev->dev);
464 	return 0;
465 }
466 
467 static struct platform_driver asoc_mmp_sspa_driver = {
468 	.driver = {
469 		.name = "mmp-sspa-dai",
470 		.owner = THIS_MODULE,
471 	},
472 	.probe = asoc_mmp_sspa_probe,
473 	.remove = asoc_mmp_sspa_remove,
474 };
475 
476 module_platform_driver(asoc_mmp_sspa_driver);
477 
478 MODULE_AUTHOR("Leo Yan <leoy@marvell.com>");
479 MODULE_DESCRIPTION("MMP SSPA SoC Interface");
480 MODULE_LICENSE("GPL");
481