upload tizen1.0 source
[kernel/linux-2.6.36.git] / sound / soc / kirkwood / kirkwood-i2s.c
1 /*
2  * kirkwood-i2s.c
3  *
4  * (c) 2010 Arnaud Patard <apatard@mandriva.com>
5  *
6  *  This program is free software; you can redistribute  it and/or modify it
7  *  under  the terms of  the GNU General  Public License as published by the
8  *  Free Software Foundation;  either version 2 of the  License, or (at your
9  *  option) any later version.
10  */
11
12 #include <linux/init.h>
13 #include <linux/module.h>
14 #include <linux/platform_device.h>
15 #include <linux/io.h>
16 #include <linux/slab.h>
17 #include <linux/mbus.h>
18 #include <linux/delay.h>
19 #include <sound/pcm.h>
20 #include <sound/pcm_params.h>
21 #include <sound/soc.h>
22 #include <plat/audio.h>
23 #include "kirkwood-i2s.h"
24 #include "kirkwood.h"
25
26 #define DRV_NAME        "kirkwood-i2s"
27
28 #define KIRKWOOD_I2S_RATES \
29         (SNDRV_PCM_RATE_44100 | \
30          SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
31 #define KIRKWOOD_I2S_FORMATS \
32         (SNDRV_PCM_FMTBIT_S16_LE | \
33          SNDRV_PCM_FMTBIT_S24_LE | \
34          SNDRV_PCM_FMTBIT_S32_LE)
35
36
37 struct snd_soc_dai kirkwood_i2s_dai;
38 static struct kirkwood_dma_data *priv;
39
40 static int kirkwood_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
41                 unsigned int fmt)
42 {
43         unsigned long mask;
44         unsigned long value;
45
46         switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
47         case SND_SOC_DAIFMT_RIGHT_J:
48                 mask = KIRKWOOD_I2S_CTL_RJ;
49                 break;
50         case SND_SOC_DAIFMT_LEFT_J:
51                 mask = KIRKWOOD_I2S_CTL_LJ;
52                 break;
53         case SND_SOC_DAIFMT_I2S:
54                 mask = KIRKWOOD_I2S_CTL_I2S;
55                 break;
56         default:
57                 return -EINVAL;
58         }
59
60         /*
61          * Set same format for playback and record
62          * This avoids some troubles.
63          */
64         value = readl(priv->io+KIRKWOOD_I2S_PLAYCTL);
65         value &= ~KIRKWOOD_I2S_CTL_JUST_MASK;
66         value |= mask;
67         writel(value, priv->io+KIRKWOOD_I2S_PLAYCTL);
68
69         value = readl(priv->io+KIRKWOOD_I2S_RECCTL);
70         value &= ~KIRKWOOD_I2S_CTL_JUST_MASK;
71         value |= mask;
72         writel(value, priv->io+KIRKWOOD_I2S_RECCTL);
73
74         return 0;
75 }
76
77 static inline void kirkwood_set_dco(void __iomem *io, unsigned long rate)
78 {
79         unsigned long value;
80
81         value = KIRKWOOD_DCO_CTL_OFFSET_0;
82         switch (rate) {
83         default:
84         case 44100:
85                 value |= KIRKWOOD_DCO_CTL_FREQ_11;
86                 break;
87         case 48000:
88                 value |= KIRKWOOD_DCO_CTL_FREQ_12;
89                 break;
90         case 96000:
91                 value |= KIRKWOOD_DCO_CTL_FREQ_24;
92                 break;
93         }
94         writel(value, io + KIRKWOOD_DCO_CTL);
95
96         /* wait for dco locked */
97         do {
98                 cpu_relax();
99                 value = readl(io + KIRKWOOD_DCO_SPCR_STATUS);
100                 value &= KIRKWOOD_DCO_SPCR_STATUS;
101         } while (value == 0);
102 }
103
104 static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream,
105                                  struct snd_pcm_hw_params *params,
106                                  struct snd_soc_dai *dai)
107 {
108         unsigned int i2s_reg, reg;
109         unsigned long i2s_value, value;
110
111         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
112                 i2s_reg = KIRKWOOD_I2S_PLAYCTL;
113                 reg = KIRKWOOD_PLAYCTL;
114         } else {
115                 i2s_reg = KIRKWOOD_I2S_RECCTL;
116                 reg = KIRKWOOD_RECCTL;
117         }
118
119         /* set dco conf */
120         kirkwood_set_dco(priv->io, params_rate(params));
121
122         i2s_value = readl(priv->io+i2s_reg);
123         i2s_value &= ~KIRKWOOD_I2S_CTL_SIZE_MASK;
124
125         value = readl(priv->io+reg);
126         value &= ~KIRKWOOD_PLAYCTL_SIZE_MASK;
127
128         /*
129          * Size settings in play/rec i2s control regs and play/rec control
130          * regs must be the same.
131          */
132         switch (params_format(params)) {
133         case SNDRV_PCM_FORMAT_S16_LE:
134                 i2s_value |= KIRKWOOD_I2S_CTL_SIZE_16;
135                 value |= KIRKWOOD_PLAYCTL_SIZE_16_C;
136                 break;
137         /*
138          * doesn't work... S20_3LE != kirkwood 20bit format ?
139          *
140         case SNDRV_PCM_FORMAT_S20_3LE:
141                 i2s_value |= KIRKWOOD_I2S_CTL_SIZE_20;
142                 value |= KIRKWOOD_PLAYCTL_SIZE_20;
143                 break;
144         */
145         case SNDRV_PCM_FORMAT_S24_LE:
146                 i2s_value |= KIRKWOOD_I2S_CTL_SIZE_24;
147                 value |= KIRKWOOD_PLAYCTL_SIZE_24;
148                 break;
149         case SNDRV_PCM_FORMAT_S32_LE:
150                 i2s_value |= KIRKWOOD_I2S_CTL_SIZE_32;
151                 value |= KIRKWOOD_PLAYCTL_SIZE_32;
152                 break;
153         default:
154                 return -EINVAL;
155         }
156
157         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
158                 value &= ~KIRKWOOD_PLAYCTL_MONO_MASK;
159                 if (params_channels(params) == 1)
160                         value |= KIRKWOOD_PLAYCTL_MONO_BOTH;
161                 else
162                         value |= KIRKWOOD_PLAYCTL_MONO_OFF;
163         }
164
165         writel(i2s_value, priv->io+i2s_reg);
166         writel(value, priv->io+reg);
167
168         return 0;
169 }
170
171 static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream,
172                                 int cmd, struct snd_soc_dai *dai)
173 {
174         unsigned long value;
175
176         /*
177          * specs says KIRKWOOD_PLAYCTL must be read 2 times before
178          * changing it. So read 1 time here and 1 later.
179          */
180         value = readl(priv->io + KIRKWOOD_PLAYCTL);
181
182         switch (cmd) {
183         case SNDRV_PCM_TRIGGER_START:
184                 /* stop audio, enable interrupts */
185                 value = readl(priv->io + KIRKWOOD_PLAYCTL);
186                 value |= KIRKWOOD_PLAYCTL_PAUSE;
187                 writel(value, priv->io + KIRKWOOD_PLAYCTL);
188
189                 value = readl(priv->io + KIRKWOOD_INT_MASK);
190                 value |= KIRKWOOD_INT_CAUSE_PLAY_BYTES;
191                 writel(value, priv->io + KIRKWOOD_INT_MASK);
192
193                 /* configure audio & enable i2s playback */
194                 value = readl(priv->io + KIRKWOOD_PLAYCTL);
195                 value &= ~KIRKWOOD_PLAYCTL_BURST_MASK;
196                 value &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE
197                                 | KIRKWOOD_PLAYCTL_SPDIF_EN);
198
199                 if (priv->burst == 32)
200                         value |= KIRKWOOD_PLAYCTL_BURST_32;
201                 else
202                         value |= KIRKWOOD_PLAYCTL_BURST_128;
203                 value |= KIRKWOOD_PLAYCTL_I2S_EN;
204                 writel(value, priv->io + KIRKWOOD_PLAYCTL);
205                 break;
206
207         case SNDRV_PCM_TRIGGER_STOP:
208                 /* stop audio, disable interrupts */
209                 value = readl(priv->io + KIRKWOOD_PLAYCTL);
210                 value |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE;
211                 writel(value, priv->io + KIRKWOOD_PLAYCTL);
212
213                 value = readl(priv->io + KIRKWOOD_INT_MASK);
214                 value &= ~KIRKWOOD_INT_CAUSE_PLAY_BYTES;
215                 writel(value, priv->io + KIRKWOOD_INT_MASK);
216
217                 /* disable all playbacks */
218                 value = readl(priv->io + KIRKWOOD_PLAYCTL);
219                 value &= ~(KIRKWOOD_PLAYCTL_I2S_EN | KIRKWOOD_PLAYCTL_SPDIF_EN);
220                 writel(value, priv->io + KIRKWOOD_PLAYCTL);
221                 break;
222
223         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
224         case SNDRV_PCM_TRIGGER_SUSPEND:
225                 value = readl(priv->io + KIRKWOOD_PLAYCTL);
226                 value |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE;
227                 writel(value, priv->io + KIRKWOOD_PLAYCTL);
228                 break;
229
230         case SNDRV_PCM_TRIGGER_RESUME:
231         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
232                 value = readl(priv->io + KIRKWOOD_PLAYCTL);
233                 value &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE);
234                 writel(value, priv->io + KIRKWOOD_PLAYCTL);
235                 break;
236
237         default:
238                 return -EINVAL;
239         }
240
241         return 0;
242 }
243
244 static int kirkwood_i2s_rec_trigger(struct snd_pcm_substream *substream,
245                                 int cmd, struct snd_soc_dai *dai)
246 {
247         unsigned long value;
248
249         value = readl(priv->io + KIRKWOOD_RECCTL);
250
251         switch (cmd) {
252         case SNDRV_PCM_TRIGGER_START:
253                 /* stop audio, enable interrupts */
254                 value = readl(priv->io + KIRKWOOD_RECCTL);
255                 value |= KIRKWOOD_RECCTL_PAUSE;
256                 writel(value, priv->io + KIRKWOOD_RECCTL);
257
258                 value = readl(priv->io + KIRKWOOD_INT_MASK);
259                 value |= KIRKWOOD_INT_CAUSE_REC_BYTES;
260                 writel(value, priv->io + KIRKWOOD_INT_MASK);
261
262                 /* configure audio & enable i2s record */
263                 value = readl(priv->io + KIRKWOOD_RECCTL);
264                 value &= ~KIRKWOOD_RECCTL_BURST_MASK;
265                 value &= ~KIRKWOOD_RECCTL_MONO;
266                 value &= ~(KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE
267                         | KIRKWOOD_RECCTL_SPDIF_EN);
268
269                 if (priv->burst == 32)
270                         value |= KIRKWOOD_RECCTL_BURST_32;
271                 else
272                         value |= KIRKWOOD_RECCTL_BURST_128;
273                 value |= KIRKWOOD_RECCTL_I2S_EN;
274
275                 writel(value, priv->io + KIRKWOOD_RECCTL);
276                 break;
277
278         case SNDRV_PCM_TRIGGER_STOP:
279                 /* stop audio, disable interrupts */
280                 value = readl(priv->io + KIRKWOOD_RECCTL);
281                 value |= KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE;
282                 writel(value, priv->io + KIRKWOOD_RECCTL);
283
284                 value = readl(priv->io + KIRKWOOD_INT_MASK);
285                 value &= ~KIRKWOOD_INT_CAUSE_REC_BYTES;
286                 writel(value, priv->io + KIRKWOOD_INT_MASK);
287
288                 /* disable all records */
289                 value = readl(priv->io + KIRKWOOD_RECCTL);
290                 value &= ~(KIRKWOOD_RECCTL_I2S_EN | KIRKWOOD_RECCTL_SPDIF_EN);
291                 writel(value, priv->io + KIRKWOOD_RECCTL);
292                 break;
293
294         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
295         case SNDRV_PCM_TRIGGER_SUSPEND:
296                 value = readl(priv->io + KIRKWOOD_RECCTL);
297                 value |= KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE;
298                 writel(value, priv->io + KIRKWOOD_RECCTL);
299                 break;
300
301         case SNDRV_PCM_TRIGGER_RESUME:
302         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
303                 value = readl(priv->io + KIRKWOOD_RECCTL);
304                 value &= ~(KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE);
305                 writel(value, priv->io + KIRKWOOD_RECCTL);
306                 break;
307
308         default:
309                 return -EINVAL;
310         }
311
312         return 0;
313 }
314
315 static int kirkwood_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
316                                struct snd_soc_dai *dai)
317 {
318         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
319                 return kirkwood_i2s_play_trigger(substream, cmd, dai);
320         else
321                 return kirkwood_i2s_rec_trigger(substream, cmd, dai);
322
323         return 0;
324 }
325
326 static int kirkwood_i2s_probe(struct platform_device *pdev,
327                              struct snd_soc_dai *dai)
328 {
329         unsigned long value;
330         unsigned int reg_data;
331
332         /* put system in a "safe" state : */
333         /* disable audio interrupts */
334         writel(0xffffffff, priv->io + KIRKWOOD_INT_CAUSE);
335         writel(0, priv->io + KIRKWOOD_INT_MASK);
336
337         reg_data = readl(priv->io + 0x1200);
338         reg_data &= (~(0x333FF8));
339         reg_data |= 0x111D18;
340         writel(reg_data, priv->io + 0x1200);
341
342         msleep(500);
343
344         reg_data = readl(priv->io + 0x1200);
345         reg_data &= (~(0x333FF8));
346         reg_data |= 0x111D18;
347         writel(reg_data, priv->io + 0x1200);
348
349         /* disable playback/record */
350         value = readl(priv->io + KIRKWOOD_PLAYCTL);
351         value &= ~(KIRKWOOD_PLAYCTL_I2S_EN|KIRKWOOD_PLAYCTL_SPDIF_EN);
352         writel(value, priv->io + KIRKWOOD_PLAYCTL);
353
354         value = readl(priv->io + KIRKWOOD_RECCTL);
355         value &= ~(KIRKWOOD_RECCTL_I2S_EN | KIRKWOOD_RECCTL_SPDIF_EN);
356         writel(value, priv->io + KIRKWOOD_RECCTL);
357
358         return 0;
359
360 }
361
362 static void kirkwood_i2s_remove(struct platform_device *pdev,
363                                 struct snd_soc_dai *dai)
364 {
365 }
366
367 static struct snd_soc_dai_ops kirkwood_i2s_dai_ops = {
368         .trigger        = kirkwood_i2s_trigger,
369         .hw_params      = kirkwood_i2s_hw_params,
370         .set_fmt        = kirkwood_i2s_set_fmt,
371 };
372
373
374 struct snd_soc_dai kirkwood_i2s_dai = {
375         .name = DRV_NAME,
376         .id = 0,
377         .probe = kirkwood_i2s_probe,
378         .remove = kirkwood_i2s_remove,
379         .playback = {
380                 .channels_min = 1,
381                 .channels_max = 2,
382                 .rates = KIRKWOOD_I2S_RATES,
383                 .formats = KIRKWOOD_I2S_FORMATS,},
384         .capture = {
385                 .channels_min = 1,
386                 .channels_max = 2,
387                 .rates = KIRKWOOD_I2S_RATES,
388                 .formats = KIRKWOOD_I2S_FORMATS,},
389         .ops = &kirkwood_i2s_dai_ops,
390 };
391 EXPORT_SYMBOL_GPL(kirkwood_i2s_dai);
392
393 static __devinit int kirkwood_i2s_dev_probe(struct platform_device *pdev)
394 {
395         struct resource *mem;
396         struct kirkwood_asoc_platform_data *data =
397                 pdev->dev.platform_data;
398         int err;
399
400         priv = kzalloc(sizeof(struct kirkwood_dma_data), GFP_KERNEL);
401         if (!priv) {
402                 dev_err(&pdev->dev, "allocation failed\n");
403                 err = -ENOMEM;
404                 goto error;
405         }
406
407         mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
408         if (!mem) {
409                 dev_err(&pdev->dev, "platform_get_resource failed\n");
410                 err = -ENXIO;
411                 goto err_alloc;
412         }
413
414         priv->mem = request_mem_region(mem->start, SZ_16K, DRV_NAME);
415         if (!priv->mem) {
416                 dev_err(&pdev->dev, "request_mem_region failed\n");
417                 err = -EBUSY;
418                 goto error;
419         }
420
421         priv->io = ioremap(priv->mem->start, SZ_16K);
422         if (!priv->io) {
423                 dev_err(&pdev->dev, "ioremap failed\n");
424                 err = -ENOMEM;
425                 goto err_iomem;
426         }
427
428         priv->irq = platform_get_irq(pdev, 0);
429         if (priv->irq <= 0) {
430                 dev_err(&pdev->dev, "platform_get_irq failed\n");
431                 err = -ENXIO;
432                 goto err_ioremap;
433         }
434
435         if (!data || !data->dram) {
436                 dev_err(&pdev->dev, "no platform data ?!\n");
437                 err = -EINVAL;
438                 goto err_ioremap;
439         }
440
441         priv->dram = data->dram;
442         priv->burst = data->burst;
443
444         kirkwood_i2s_dai.capture.dma_data = priv;
445         kirkwood_i2s_dai.playback.dma_data = priv;
446
447         return snd_soc_register_dai(&kirkwood_i2s_dai);
448
449 err_ioremap:
450         iounmap(priv->io);
451 err_iomem:
452         release_mem_region(priv->mem->start, SZ_16K);
453 err_alloc:
454         kfree(priv);
455 error:
456         return err;
457 }
458
459 static __devexit int kirkwood_i2s_dev_remove(struct platform_device *pdev)
460 {
461         if (priv) {
462                 iounmap(priv->io);
463                 release_mem_region(priv->mem->start, SZ_16K);
464                 kfree(priv);
465         }
466         snd_soc_unregister_dai(&kirkwood_i2s_dai);
467         return 0;
468 }
469
470 static struct platform_driver kirkwood_i2s_driver = {
471         .probe  = kirkwood_i2s_dev_probe,
472         .remove = kirkwood_i2s_dev_remove,
473         .driver = {
474                 .name = DRV_NAME,
475                 .owner = THIS_MODULE,
476         },
477 };
478
479 static int __init kirkwood_i2s_init(void)
480 {
481         return platform_driver_register(&kirkwood_i2s_driver);
482 }
483 module_init(kirkwood_i2s_init);
484
485 static void __exit kirkwood_i2s_exit(void)
486 {
487         platform_driver_unregister(&kirkwood_i2s_driver);
488 }
489 module_exit(kirkwood_i2s_exit);
490
491 /* Module information */
492 MODULE_AUTHOR("Arnaud Patard, <apatard@mandriva.com>");
493 MODULE_DESCRIPTION("Kirkwood I2S SoC Interface");
494 MODULE_LICENSE("GPL");
495 MODULE_ALIAS("platform:kirkwood-i2s");