Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
davinci-vcif.c
Go to the documentation of this file.
1 /*
2  * ALSA SoC Voice Codec Interface for TI DAVINCI processor
3  *
4  * Copyright (C) 2010 Texas Instruments.
5  *
6  * Author: Miguel Aguilar <[email protected]>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21  */
22 
23 #include <linux/init.h>
24 #include <linux/module.h>
25 #include <linux/device.h>
26 #include <linux/delay.h>
27 #include <linux/slab.h>
28 #include <linux/io.h>
30 
31 #include <sound/core.h>
32 #include <sound/pcm.h>
33 #include <sound/pcm_params.h>
34 #include <sound/initval.h>
35 #include <sound/soc.h>
36 
37 #include "davinci-pcm.h"
38 #include "davinci-i2s.h"
39 
40 #define MOD_REG_BIT(val, mask, set) do { \
41  if (set) { \
42  val |= mask; \
43  } else { \
44  val &= ~mask; \
45  } \
46 } while (0)
47 
51 };
52 
53 static void davinci_vcif_start(struct snd_pcm_substream *substream)
54 {
55  struct snd_soc_pcm_runtime *rtd = substream->private_data;
57  snd_soc_dai_get_drvdata(rtd->cpu_dai);
58  struct davinci_vc *davinci_vc = davinci_vcif_dev->davinci_vc;
59  u32 w;
60 
61  /* Start the sample generator and enable transmitter/receiver */
62  w = readl(davinci_vc->base + DAVINCI_VC_CTRL);
63 
64  if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
66  else
68 
69  writel(w, davinci_vc->base + DAVINCI_VC_CTRL);
70 }
71 
72 static void davinci_vcif_stop(struct snd_pcm_substream *substream)
73 {
74  struct snd_soc_pcm_runtime *rtd = substream->private_data;
75  struct davinci_vcif_dev *davinci_vcif_dev =
76  snd_soc_dai_get_drvdata(rtd->cpu_dai);
77  struct davinci_vc *davinci_vc = davinci_vcif_dev->davinci_vc;
78  u32 w;
79 
80  /* Reset transmitter/receiver and sample rate/frame sync generators */
81  w = readl(davinci_vc->base + DAVINCI_VC_CTRL);
82  if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
84  else
86 
87  writel(w, davinci_vc->base + DAVINCI_VC_CTRL);
88 }
89 
90 static int davinci_vcif_hw_params(struct snd_pcm_substream *substream,
91  struct snd_pcm_hw_params *params,
92  struct snd_soc_dai *dai)
93 {
94  struct davinci_vcif_dev *davinci_vcif_dev = snd_soc_dai_get_drvdata(dai);
95  struct davinci_vc *davinci_vc = davinci_vcif_dev->davinci_vc;
96  struct davinci_pcm_dma_params *dma_params =
97  &davinci_vcif_dev->dma_params[substream->stream];
98  u32 w;
99 
100  /* Restart the codec before setup */
101  davinci_vcif_stop(substream);
102  davinci_vcif_start(substream);
103 
104  /* General line settings */
106 
108 
110 
111  w = readl(davinci_vc->base + DAVINCI_VC_CTRL);
112 
113  /* Determine xfer data type */
114  switch (params_format(params)) {
115  case SNDRV_PCM_FORMAT_U8:
116  dma_params->data_type = 0;
117 
122  break;
123  case SNDRV_PCM_FORMAT_S8:
124  dma_params->data_type = 1;
125 
128 
131  break;
133  dma_params->data_type = 2;
134 
139  break;
140  default:
141  printk(KERN_WARNING "davinci-vcif: unsupported PCM format");
142  return -EINVAL;
143  }
144 
145  dma_params->acnt = dma_params->data_type;
146 
147  writel(w, davinci_vc->base + DAVINCI_VC_CTRL);
148 
149  return 0;
150 }
151 
152 static int davinci_vcif_trigger(struct snd_pcm_substream *substream, int cmd,
153  struct snd_soc_dai *dai)
154 {
155  int ret = 0;
156 
157  switch (cmd) {
161  davinci_vcif_start(substream);
162  break;
166  davinci_vcif_stop(substream);
167  break;
168  default:
169  ret = -EINVAL;
170  }
171 
172  return ret;
173 }
174 
175 static int davinci_vcif_startup(struct snd_pcm_substream *substream,
176  struct snd_soc_dai *dai)
177 {
178  struct davinci_vcif_dev *dev = snd_soc_dai_get_drvdata(dai);
179 
180  snd_soc_dai_set_dma_data(dai, substream, dev->dma_params);
181  return 0;
182 }
183 
184 #define DAVINCI_VCIF_RATES SNDRV_PCM_RATE_8000_48000
185 
186 static const struct snd_soc_dai_ops davinci_vcif_dai_ops = {
187  .startup = davinci_vcif_startup,
188  .trigger = davinci_vcif_trigger,
189  .hw_params = davinci_vcif_hw_params,
190 };
191 
192 static struct snd_soc_dai_driver davinci_vcif_dai = {
193  .playback = {
194  .channels_min = 1,
195  .channels_max = 2,
196  .rates = DAVINCI_VCIF_RATES,
197  .formats = SNDRV_PCM_FMTBIT_S16_LE,},
198  .capture = {
199  .channels_min = 1,
200  .channels_max = 2,
201  .rates = DAVINCI_VCIF_RATES,
202  .formats = SNDRV_PCM_FMTBIT_S16_LE,},
203  .ops = &davinci_vcif_dai_ops,
204 
205 };
206 
207 static int davinci_vcif_probe(struct platform_device *pdev)
208 {
209  struct davinci_vc *davinci_vc = pdev->dev.platform_data;
210  struct davinci_vcif_dev *davinci_vcif_dev;
211  int ret;
212 
213  davinci_vcif_dev = devm_kzalloc(&pdev->dev,
214  sizeof(struct davinci_vcif_dev),
215  GFP_KERNEL);
216  if (!davinci_vcif_dev) {
217  dev_dbg(&pdev->dev,
218  "could not allocate memory for private data\n");
219  return -ENOMEM;
220  }
221 
222  /* DMA tx params */
223  davinci_vcif_dev->davinci_vc = davinci_vc;
224  davinci_vcif_dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].channel =
225  davinci_vc->davinci_vcif.dma_tx_channel;
226  davinci_vcif_dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].dma_addr =
227  davinci_vc->davinci_vcif.dma_tx_addr;
228 
229  /* DMA rx params */
230  davinci_vcif_dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].channel =
231  davinci_vc->davinci_vcif.dma_rx_channel;
232  davinci_vcif_dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].dma_addr =
233  davinci_vc->davinci_vcif.dma_rx_addr;
234 
235  dev_set_drvdata(&pdev->dev, davinci_vcif_dev);
236 
237  ret = snd_soc_register_dai(&pdev->dev, &davinci_vcif_dai);
238  if (ret != 0) {
239  dev_err(&pdev->dev, "could not register dai\n");
240  return ret;
241  }
242 
243  ret = davinci_soc_platform_register(&pdev->dev);
244  if (ret) {
245  dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
246  snd_soc_unregister_dai(&pdev->dev);
247  return ret;
248  }
249 
250  return 0;
251 }
252 
253 static int davinci_vcif_remove(struct platform_device *pdev)
254 {
255  snd_soc_unregister_dai(&pdev->dev);
257 
258  return 0;
259 }
260 
261 static struct platform_driver davinci_vcif_driver = {
262  .probe = davinci_vcif_probe,
263  .remove = davinci_vcif_remove,
264  .driver = {
265  .name = "davinci-vcif",
266  .owner = THIS_MODULE,
267  },
268 };
269 
270 module_platform_driver(davinci_vcif_driver);
271 
272 MODULE_AUTHOR("Miguel Aguilar");
273 MODULE_DESCRIPTION("Texas Instruments DaVinci ASoC Voice Codec Interface");
274 MODULE_LICENSE("GPL");