Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
mmp-sspa.c
Go to the documentation of this file.
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;
44  struct clk *audio_clk;
45  struct clk *sysclk;
46  int dai_fmt;
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 */
199  sspa_ctrl = 0;
200 
201  switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
203  sspa_sp |= SSPA_SP_MSL;
204  break;
206  break;
207  default:
208  return -EINVAL;
209  }
210 
211  switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
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;
288  sspa_ctrl |= SSPA_CTL_XSSZ1(SSPA_CTL_16_BITS);
289  break;
291  sspa_ctrl |= SSPA_CTL_XSSZ1(SSPA_CTL_20_BITS);
292  break;
294  sspa_ctrl |= SSPA_CTL_XSSZ1(SSPA_CTL_24_BITS);
295  break;
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) {
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 
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 
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 __devinit 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 __devexit 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 = __devexit_p(asoc_mmp_sspa_remove),
474 };
475 
476 module_platform_driver(asoc_mmp_sspa_driver);
477 
478 MODULE_AUTHOR("Leo Yan <[email protected]>");
479 MODULE_DESCRIPTION("MMP SSPA SoC Interface");
480 MODULE_LICENSE("GPL");