aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/davinci/davinci-i2s.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/davinci/davinci-i2s.c')
-rw-r--r--sound/soc/davinci/davinci-i2s.c153
1 files changed, 121 insertions, 32 deletions
diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c
index abb5fedb0b1e..81ff5c37ab56 100644
--- a/sound/soc/davinci/davinci-i2s.c
+++ b/sound/soc/davinci/davinci-i2s.c
@@ -59,6 +59,7 @@
59#define DAVINCI_MCBSP_PCR_CLKXP (1 << 1) 59#define DAVINCI_MCBSP_PCR_CLKXP (1 << 1)
60#define DAVINCI_MCBSP_PCR_FSRP (1 << 2) 60#define DAVINCI_MCBSP_PCR_FSRP (1 << 2)
61#define DAVINCI_MCBSP_PCR_FSXP (1 << 3) 61#define DAVINCI_MCBSP_PCR_FSXP (1 << 3)
62#define DAVINCI_MCBSP_PCR_SCLKME (1 << 7)
62#define DAVINCI_MCBSP_PCR_CLKRM (1 << 8) 63#define DAVINCI_MCBSP_PCR_CLKRM (1 << 8)
63#define DAVINCI_MCBSP_PCR_CLKXM (1 << 9) 64#define DAVINCI_MCBSP_PCR_CLKXM (1 << 9)
64#define DAVINCI_MCBSP_PCR_FSRM (1 << 10) 65#define DAVINCI_MCBSP_PCR_FSRM (1 << 10)
@@ -110,16 +111,59 @@ static void davinci_mcbsp_start(struct snd_pcm_substream *substream)
110{ 111{
111 struct snd_soc_pcm_runtime *rtd = substream->private_data; 112 struct snd_soc_pcm_runtime *rtd = substream->private_data;
112 struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data; 113 struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data;
114 struct snd_soc_device *socdev = rtd->socdev;
115 struct snd_soc_platform *platform = socdev->card->platform;
113 u32 w; 116 u32 w;
117 int ret;
114 118
115 /* Start the sample generator and enable transmitter/receiver */ 119 /* Start the sample generator and enable transmitter/receiver */
116 w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); 120 w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
117 MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_GRST, 1); 121 MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_GRST, 1);
118 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 122 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w);
123
124 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
125 /* Stop the DMA to avoid data loss */
126 /* while the transmitter is out of reset to handle XSYNCERR */
127 if (platform->pcm_ops->trigger) {
128 ret = platform->pcm_ops->trigger(substream,
129 SNDRV_PCM_TRIGGER_STOP);
130 if (ret < 0)
131 printk(KERN_DEBUG "Playback DMA stop failed\n");
132 }
133
134 /* Enable the transmitter */
135 w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
119 MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_XRST, 1); 136 MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_XRST, 1);
120 else 137 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w);
138
139 /* wait for any unexpected frame sync error to occur */
140 udelay(100);
141
142 /* Disable the transmitter to clear any outstanding XSYNCERR */
143 w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
144 MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_XRST, 0);
145 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w);
146
147 /* Restart the DMA */
148 if (platform->pcm_ops->trigger) {
149 ret = platform->pcm_ops->trigger(substream,
150 SNDRV_PCM_TRIGGER_START);
151 if (ret < 0)
152 printk(KERN_DEBUG "Playback DMA start failed\n");
153 }
154 /* Enable the transmitter */
155 w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
156 MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_XRST, 1);
157 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w);
158
159 } else {
160
161 /* Enable the reciever */
162 w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
121 MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_RRST, 1); 163 MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_RRST, 1);
122 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); 164 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w);
165 }
166
123 167
124 /* Start frame sync */ 168 /* Start frame sync */
125 w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); 169 w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
@@ -144,7 +188,8 @@ static void davinci_mcbsp_stop(struct snd_pcm_substream *substream)
144 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); 188 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w);
145} 189}
146 190
147static int davinci_i2s_startup(struct snd_pcm_substream *substream) 191static int davinci_i2s_startup(struct snd_pcm_substream *substream,
192 struct snd_soc_dai *dai)
148{ 193{
149 struct snd_soc_pcm_runtime *rtd = substream->private_data; 194 struct snd_soc_pcm_runtime *rtd = substream->private_data;
150 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; 195 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
@@ -171,6 +216,16 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
171 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, 216 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG,
172 DAVINCI_MCBSP_SRGR_FSGM); 217 DAVINCI_MCBSP_SRGR_FSGM);
173 break; 218 break;
219 case SND_SOC_DAIFMT_CBM_CFS:
220 /* McBSP CLKR pin is the input for the Sample Rate Generator.
221 * McBSP FSR and FSX are driven by the Sample Rate Generator. */
222 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG,
223 DAVINCI_MCBSP_PCR_SCLKME |
224 DAVINCI_MCBSP_PCR_FSXM |
225 DAVINCI_MCBSP_PCR_FSRM);
226 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG,
227 DAVINCI_MCBSP_SRGR_FSGM);
228 break;
174 case SND_SOC_DAIFMT_CBM_CFM: 229 case SND_SOC_DAIFMT_CBM_CFM:
175 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, 0); 230 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, 0);
176 break; 231 break;
@@ -205,11 +260,34 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
205 return -EINVAL; 260 return -EINVAL;
206 } 261 }
207 262
263 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
264 case SND_SOC_DAIFMT_RIGHT_J:
265 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG,
266 DAVINCI_MCBSP_RCR_RFRLEN1(1) |
267 DAVINCI_MCBSP_RCR_RDATDLY(0));
268 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG,
269 DAVINCI_MCBSP_XCR_XFRLEN1(1) |
270 DAVINCI_MCBSP_XCR_XDATDLY(0) |
271 DAVINCI_MCBSP_XCR_XFIG);
272 break;
273 case SND_SOC_DAIFMT_I2S:
274 default:
275 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG,
276 DAVINCI_MCBSP_RCR_RFRLEN1(1) |
277 DAVINCI_MCBSP_RCR_RDATDLY(1));
278 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG,
279 DAVINCI_MCBSP_XCR_XFRLEN1(1) |
280 DAVINCI_MCBSP_XCR_XDATDLY(1) |
281 DAVINCI_MCBSP_XCR_XFIG);
282 break;
283 }
284
208 return 0; 285 return 0;
209} 286}
210 287
211static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, 288static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
212 struct snd_pcm_hw_params *params) 289 struct snd_pcm_hw_params *params,
290 struct snd_soc_dai *dai)
213{ 291{
214 struct snd_soc_pcm_runtime *rtd = substream->private_data; 292 struct snd_soc_pcm_runtime *rtd = substream->private_data;
215 struct davinci_pcm_dma_params *dma_params = rtd->dai->cpu_dai->dma_data; 293 struct davinci_pcm_dma_params *dma_params = rtd->dai->cpu_dai->dma_data;
@@ -219,17 +297,14 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
219 u32 w; 297 u32 w;
220 298
221 /* general line settings */ 299 /* general line settings */
222 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, 300 w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
223 DAVINCI_MCBSP_SPCR_RINTM(3) | 301 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
224 DAVINCI_MCBSP_SPCR_XINTM(3) | 302 w |= DAVINCI_MCBSP_SPCR_RINTM(3) | DAVINCI_MCBSP_SPCR_FREE;
225 DAVINCI_MCBSP_SPCR_FREE); 303 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w);
226 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, 304 } else {
227 DAVINCI_MCBSP_RCR_RFRLEN1(1) | 305 w |= DAVINCI_MCBSP_SPCR_XINTM(3) | DAVINCI_MCBSP_SPCR_FREE;
228 DAVINCI_MCBSP_RCR_RDATDLY(1)); 306 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w);
229 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, 307 }
230 DAVINCI_MCBSP_XCR_XFRLEN1(1) |
231 DAVINCI_MCBSP_XCR_XDATDLY(1) |
232 DAVINCI_MCBSP_XCR_XFIG);
233 308
234 i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); 309 i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS);
235 w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SRGR_REG); 310 w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SRGR_REG);
@@ -260,20 +335,24 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
260 return -EINVAL; 335 return -EINVAL;
261 } 336 }
262 337
263 w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_RCR_REG); 338 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
264 MOD_REG_BIT(w, DAVINCI_MCBSP_RCR_RWDLEN1(mcbsp_word_length) | 339 w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_RCR_REG);
265 DAVINCI_MCBSP_RCR_RWDLEN2(mcbsp_word_length), 1); 340 MOD_REG_BIT(w, DAVINCI_MCBSP_RCR_RWDLEN1(mcbsp_word_length) |
266 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, w); 341 DAVINCI_MCBSP_RCR_RWDLEN2(mcbsp_word_length), 1);
342 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, w);
267 343
268 w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_XCR_REG); 344 } else {
269 MOD_REG_BIT(w, DAVINCI_MCBSP_XCR_XWDLEN1(mcbsp_word_length) | 345 w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_XCR_REG);
270 DAVINCI_MCBSP_XCR_XWDLEN2(mcbsp_word_length), 1); 346 MOD_REG_BIT(w, DAVINCI_MCBSP_XCR_XWDLEN1(mcbsp_word_length) |
271 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, w); 347 DAVINCI_MCBSP_XCR_XWDLEN2(mcbsp_word_length), 1);
348 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, w);
272 349
350 }
273 return 0; 351 return 0;
274} 352}
275 353
276static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd) 354static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
355 struct snd_soc_dai *dai)
277{ 356{
278 int ret = 0; 357 int ret = 0;
279 358
@@ -299,8 +378,8 @@ static int davinci_i2s_probe(struct platform_device *pdev,
299 struct snd_soc_dai *dai) 378 struct snd_soc_dai *dai)
300{ 379{
301 struct snd_soc_device *socdev = platform_get_drvdata(pdev); 380 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
302 struct snd_soc_machine *machine = socdev->machine; 381 struct snd_soc_card *card = socdev->card;
303 struct snd_soc_dai *cpu_dai = machine->dai_link[pdev->id].cpu_dai; 382 struct snd_soc_dai *cpu_dai = card->dai_link[pdev->id].cpu_dai;
304 struct davinci_mcbsp_dev *dev; 383 struct davinci_mcbsp_dev *dev;
305 struct resource *mem, *ioarea; 384 struct resource *mem, *ioarea;
306 struct evm_snd_platform_data *pdata; 385 struct evm_snd_platform_data *pdata;
@@ -361,8 +440,8 @@ static void davinci_i2s_remove(struct platform_device *pdev,
361 struct snd_soc_dai *dai) 440 struct snd_soc_dai *dai)
362{ 441{
363 struct snd_soc_device *socdev = platform_get_drvdata(pdev); 442 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
364 struct snd_soc_machine *machine = socdev->machine; 443 struct snd_soc_card *card = socdev->card;
365 struct snd_soc_dai *cpu_dai = machine->dai_link[pdev->id].cpu_dai; 444 struct snd_soc_dai *cpu_dai = card->dai_link[pdev->id].cpu_dai;
366 struct davinci_mcbsp_dev *dev = cpu_dai->private_data; 445 struct davinci_mcbsp_dev *dev = cpu_dai->private_data;
367 struct resource *mem; 446 struct resource *mem;
368 447
@@ -381,7 +460,6 @@ static void davinci_i2s_remove(struct platform_device *pdev,
381struct snd_soc_dai davinci_i2s_dai = { 460struct snd_soc_dai davinci_i2s_dai = {
382 .name = "davinci-i2s", 461 .name = "davinci-i2s",
383 .id = 0, 462 .id = 0,
384 .type = SND_SOC_DAI_I2S,
385 .probe = davinci_i2s_probe, 463 .probe = davinci_i2s_probe,
386 .remove = davinci_i2s_remove, 464 .remove = davinci_i2s_remove,
387 .playback = { 465 .playback = {
@@ -397,13 +475,24 @@ struct snd_soc_dai davinci_i2s_dai = {
397 .ops = { 475 .ops = {
398 .startup = davinci_i2s_startup, 476 .startup = davinci_i2s_startup,
399 .trigger = davinci_i2s_trigger, 477 .trigger = davinci_i2s_trigger,
400 .hw_params = davinci_i2s_hw_params,}, 478 .hw_params = davinci_i2s_hw_params,
401 .dai_ops = {
402 .set_fmt = davinci_i2s_set_dai_fmt, 479 .set_fmt = davinci_i2s_set_dai_fmt,
403 }, 480 },
404}; 481};
405EXPORT_SYMBOL_GPL(davinci_i2s_dai); 482EXPORT_SYMBOL_GPL(davinci_i2s_dai);
406 483
484static int __init davinci_i2s_init(void)
485{
486 return snd_soc_register_dai(&davinci_i2s_dai);
487}
488module_init(davinci_i2s_init);
489
490static void __exit davinci_i2s_exit(void)
491{
492 snd_soc_unregister_dai(&davinci_i2s_dai);
493}
494module_exit(davinci_i2s_exit);
495
407MODULE_AUTHOR("Vladimir Barinov"); 496MODULE_AUTHOR("Vladimir Barinov");
408MODULE_DESCRIPTION("TI DAVINCI I2S (McBSP) SoC Interface"); 497MODULE_DESCRIPTION("TI DAVINCI I2S (McBSP) SoC Interface");
409MODULE_LICENSE("GPL"); 498MODULE_LICENSE("GPL");