]> git.karo-electronics.de Git - karo-tx-linux.git/blob - sound/soc/kirkwood/kirkwood-i2s.c
ASoC: kirkwood: provide KIRKWOOD_PLAYCTL_ENABLE_MASK
[karo-tx-linux.git] / sound / soc / kirkwood / kirkwood-i2s.c
1 /*
2  * kirkwood-i2s.c
3  *
4  * (c) 2010 Arnaud Patard <apatard@mandriva.com>
5  * (c) 2010 Arnaud Patard <arnaud.patard@rtp-net.org>
6  *
7  *  This program is free software; you can redistribute  it and/or modify it
8  *  under  the terms of  the GNU General  Public License as published by the
9  *  Free Software Foundation;  either version 2 of the  License, or (at your
10  *  option) any later version.
11  */
12
13 #include <linux/init.h>
14 #include <linux/module.h>
15 #include <linux/platform_device.h>
16 #include <linux/io.h>
17 #include <linux/slab.h>
18 #include <linux/mbus.h>
19 #include <linux/delay.h>
20 #include <linux/clk.h>
21 #include <sound/pcm.h>
22 #include <sound/pcm_params.h>
23 #include <sound/soc.h>
24 #include <linux/platform_data/asoc-kirkwood.h>
25 #include "kirkwood.h"
26
27 #define DRV_NAME        "kirkwood-i2s"
28
29 #define KIRKWOOD_I2S_FORMATS \
30         (SNDRV_PCM_FMTBIT_S16_LE | \
31          SNDRV_PCM_FMTBIT_S24_LE | \
32          SNDRV_PCM_FMTBIT_S32_LE)
33
34 static int kirkwood_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
35                 unsigned int fmt)
36 {
37         struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(cpu_dai);
38         unsigned long mask;
39         unsigned long value;
40
41         switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
42         case SND_SOC_DAIFMT_RIGHT_J:
43                 mask = KIRKWOOD_I2S_CTL_RJ;
44                 break;
45         case SND_SOC_DAIFMT_LEFT_J:
46                 mask = KIRKWOOD_I2S_CTL_LJ;
47                 break;
48         case SND_SOC_DAIFMT_I2S:
49                 mask = KIRKWOOD_I2S_CTL_I2S;
50                 break;
51         default:
52                 return -EINVAL;
53         }
54
55         /*
56          * Set same format for playback and record
57          * This avoids some troubles.
58          */
59         value = readl(priv->io+KIRKWOOD_I2S_PLAYCTL);
60         value &= ~KIRKWOOD_I2S_CTL_JUST_MASK;
61         value |= mask;
62         writel(value, priv->io+KIRKWOOD_I2S_PLAYCTL);
63
64         value = readl(priv->io+KIRKWOOD_I2S_RECCTL);
65         value &= ~KIRKWOOD_I2S_CTL_JUST_MASK;
66         value |= mask;
67         writel(value, priv->io+KIRKWOOD_I2S_RECCTL);
68
69         return 0;
70 }
71
72 static inline void kirkwood_set_dco(void __iomem *io, unsigned long rate)
73 {
74         unsigned long value;
75
76         value = KIRKWOOD_DCO_CTL_OFFSET_0;
77         switch (rate) {
78         default:
79         case 44100:
80                 value |= KIRKWOOD_DCO_CTL_FREQ_11;
81                 break;
82         case 48000:
83                 value |= KIRKWOOD_DCO_CTL_FREQ_12;
84                 break;
85         case 96000:
86                 value |= KIRKWOOD_DCO_CTL_FREQ_24;
87                 break;
88         }
89         writel(value, io + KIRKWOOD_DCO_CTL);
90
91         /* wait for dco locked */
92         do {
93                 cpu_relax();
94                 value = readl(io + KIRKWOOD_DCO_SPCR_STATUS);
95                 value &= KIRKWOOD_DCO_SPCR_STATUS_DCO_LOCK;
96         } while (value == 0);
97 }
98
99 static void kirkwood_set_rate(struct snd_soc_dai *dai,
100         struct kirkwood_dma_data *priv, unsigned long rate)
101 {
102         uint32_t clks_ctrl;
103
104         if (rate == 44100 || rate == 48000 || rate == 96000) {
105                 /* use internal dco for the supported rates
106                  * defined in kirkwood_i2s_dai */
107                 dev_dbg(dai->dev, "%s: dco set rate = %lu\n",
108                         __func__, rate);
109                 kirkwood_set_dco(priv->io, rate);
110
111                 clks_ctrl = KIRKWOOD_MCLK_SOURCE_DCO;
112         } else {
113                 /* use the external clock for the other rates
114                  * defined in kirkwood_i2s_dai_extclk */
115                 dev_dbg(dai->dev, "%s: extclk set rate = %lu -> %lu\n",
116                         __func__, rate, 256 * rate);
117                 clk_set_rate(priv->extclk, 256 * rate);
118
119                 clks_ctrl = KIRKWOOD_MCLK_SOURCE_EXTCLK;
120         }
121         writel(clks_ctrl, priv->io + KIRKWOOD_CLOCKS_CTRL);
122 }
123
124 static int kirkwood_i2s_startup(struct snd_pcm_substream *substream,
125                 struct snd_soc_dai *dai)
126 {
127         struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
128
129         snd_soc_dai_set_dma_data(dai, substream, priv);
130         return 0;
131 }
132
133 static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream,
134                                  struct snd_pcm_hw_params *params,
135                                  struct snd_soc_dai *dai)
136 {
137         struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
138         uint32_t ctl_play, ctl_rec;
139         unsigned int i2s_reg;
140         unsigned long i2s_value;
141
142         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
143                 i2s_reg = KIRKWOOD_I2S_PLAYCTL;
144         } else {
145                 i2s_reg = KIRKWOOD_I2S_RECCTL;
146         }
147
148         kirkwood_set_rate(dai, priv, params_rate(params));
149
150         i2s_value = readl(priv->io+i2s_reg);
151         i2s_value &= ~KIRKWOOD_I2S_CTL_SIZE_MASK;
152
153         /*
154          * Size settings in play/rec i2s control regs and play/rec control
155          * regs must be the same.
156          */
157         switch (params_format(params)) {
158         case SNDRV_PCM_FORMAT_S16_LE:
159                 i2s_value |= KIRKWOOD_I2S_CTL_SIZE_16;
160                 ctl_play = KIRKWOOD_PLAYCTL_SIZE_16_C |
161                            KIRKWOOD_PLAYCTL_I2S_EN;
162                 ctl_rec = KIRKWOOD_RECCTL_SIZE_16_C |
163                           KIRKWOOD_RECCTL_I2S_EN;
164                 break;
165         /*
166          * doesn't work... S20_3LE != kirkwood 20bit format ?
167          *
168         case SNDRV_PCM_FORMAT_S20_3LE:
169                 i2s_value |= KIRKWOOD_I2S_CTL_SIZE_20;
170                 ctl_play = KIRKWOOD_PLAYCTL_SIZE_20 |
171                            KIRKWOOD_PLAYCTL_I2S_EN;
172                 ctl_rec = KIRKWOOD_RECCTL_SIZE_20 |
173                           KIRKWOOD_RECCTL_I2S_EN;
174                 break;
175         */
176         case SNDRV_PCM_FORMAT_S24_LE:
177                 i2s_value |= KIRKWOOD_I2S_CTL_SIZE_24;
178                 ctl_play = KIRKWOOD_PLAYCTL_SIZE_24 |
179                            KIRKWOOD_PLAYCTL_I2S_EN;
180                 ctl_rec = KIRKWOOD_RECCTL_SIZE_24 |
181                           KIRKWOOD_RECCTL_I2S_EN;
182                 break;
183         case SNDRV_PCM_FORMAT_S32_LE:
184                 i2s_value |= KIRKWOOD_I2S_CTL_SIZE_32;
185                 ctl_play = KIRKWOOD_PLAYCTL_SIZE_32 |
186                            KIRKWOOD_PLAYCTL_I2S_EN;
187                 ctl_rec = KIRKWOOD_RECCTL_SIZE_32 |
188                           KIRKWOOD_RECCTL_I2S_EN;
189                 break;
190         default:
191                 return -EINVAL;
192         }
193
194         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
195                 if (params_channels(params) == 1)
196                         ctl_play |= KIRKWOOD_PLAYCTL_MONO_BOTH;
197                 else
198                         ctl_play |= KIRKWOOD_PLAYCTL_MONO_OFF;
199
200                 priv->ctl_play &= ~(KIRKWOOD_PLAYCTL_MONO_MASK |
201                                     KIRKWOOD_PLAYCTL_ENABLE_MASK |
202                                     KIRKWOOD_PLAYCTL_SIZE_MASK);
203                 priv->ctl_play |= ctl_play;
204         } else {
205                 priv->ctl_rec &= ~KIRKWOOD_RECCTL_SIZE_MASK;
206                 priv->ctl_rec |= ctl_rec;
207         }
208
209         writel(i2s_value, priv->io+i2s_reg);
210
211         return 0;
212 }
213
214 static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream,
215                                 int cmd, struct snd_soc_dai *dai)
216 {
217         struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
218         uint32_t ctl, value;
219
220         ctl = readl(priv->io + KIRKWOOD_PLAYCTL);
221         if (ctl & KIRKWOOD_PLAYCTL_PAUSE) {
222                 unsigned timeout = 5000;
223                 /*
224                  * The Armada510 spec says that if we enter pause mode, the
225                  * busy bit must be read back as clear _twice_.  Make sure
226                  * we respect that otherwise we get DMA underruns.
227                  */
228                 do {
229                         value = ctl;
230                         ctl = readl(priv->io + KIRKWOOD_PLAYCTL);
231                         if (!((ctl | value) & KIRKWOOD_PLAYCTL_PLAY_BUSY))
232                                 break;
233                         udelay(1);
234                 } while (timeout--);
235
236                 if ((ctl | value) & KIRKWOOD_PLAYCTL_PLAY_BUSY)
237                         dev_notice(dai->dev, "timed out waiting for busy to deassert: %08x\n",
238                                    ctl);
239         }
240
241         switch (cmd) {
242         case SNDRV_PCM_TRIGGER_START:
243                 /* configure */
244                 ctl = priv->ctl_play;
245                 value = ctl & ~KIRKWOOD_PLAYCTL_ENABLE_MASK;
246                 writel(value, priv->io + KIRKWOOD_PLAYCTL);
247
248                 /* enable interrupts */
249                 value = readl(priv->io + KIRKWOOD_INT_MASK);
250                 value |= KIRKWOOD_INT_CAUSE_PLAY_BYTES;
251                 writel(value, priv->io + KIRKWOOD_INT_MASK);
252
253                 /* enable playback */
254                 writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
255                 break;
256
257         case SNDRV_PCM_TRIGGER_STOP:
258                 /* stop audio, disable interrupts */
259                 ctl |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE;
260                 writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
261
262                 value = readl(priv->io + KIRKWOOD_INT_MASK);
263                 value &= ~KIRKWOOD_INT_CAUSE_PLAY_BYTES;
264                 writel(value, priv->io + KIRKWOOD_INT_MASK);
265
266                 /* disable all playbacks */
267                 ctl &= ~KIRKWOOD_PLAYCTL_ENABLE_MASK;
268                 writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
269                 break;
270
271         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
272         case SNDRV_PCM_TRIGGER_SUSPEND:
273                 ctl |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE;
274                 writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
275                 break;
276
277         case SNDRV_PCM_TRIGGER_RESUME:
278         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
279                 ctl &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE);
280                 writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
281                 break;
282
283         default:
284                 return -EINVAL;
285         }
286
287         return 0;
288 }
289
290 static int kirkwood_i2s_rec_trigger(struct snd_pcm_substream *substream,
291                                 int cmd, struct snd_soc_dai *dai)
292 {
293         struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
294         uint32_t ctl, value;
295
296         value = readl(priv->io + KIRKWOOD_RECCTL);
297
298         switch (cmd) {
299         case SNDRV_PCM_TRIGGER_START:
300                 /* configure */
301                 ctl = priv->ctl_rec;
302                 value = ctl & ~KIRKWOOD_RECCTL_I2S_EN;
303                 writel(value, priv->io + KIRKWOOD_RECCTL);
304
305                 /* enable interrupts */
306                 value = readl(priv->io + KIRKWOOD_INT_MASK);
307                 value |= KIRKWOOD_INT_CAUSE_REC_BYTES;
308                 writel(value, priv->io + KIRKWOOD_INT_MASK);
309
310                 /* enable record */
311                 writel(ctl, priv->io + KIRKWOOD_RECCTL);
312                 break;
313
314         case SNDRV_PCM_TRIGGER_STOP:
315                 /* stop audio, disable interrupts */
316                 value = readl(priv->io + KIRKWOOD_RECCTL);
317                 value |= KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE;
318                 writel(value, priv->io + KIRKWOOD_RECCTL);
319
320                 value = readl(priv->io + KIRKWOOD_INT_MASK);
321                 value &= ~KIRKWOOD_INT_CAUSE_REC_BYTES;
322                 writel(value, priv->io + KIRKWOOD_INT_MASK);
323
324                 /* disable all records */
325                 value = readl(priv->io + KIRKWOOD_RECCTL);
326                 value &= ~(KIRKWOOD_RECCTL_I2S_EN | KIRKWOOD_RECCTL_SPDIF_EN);
327                 writel(value, priv->io + KIRKWOOD_RECCTL);
328                 break;
329
330         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
331         case SNDRV_PCM_TRIGGER_SUSPEND:
332                 value = readl(priv->io + KIRKWOOD_RECCTL);
333                 value |= KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE;
334                 writel(value, priv->io + KIRKWOOD_RECCTL);
335                 break;
336
337         case SNDRV_PCM_TRIGGER_RESUME:
338         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
339                 value = readl(priv->io + KIRKWOOD_RECCTL);
340                 value &= ~(KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE);
341                 writel(value, priv->io + KIRKWOOD_RECCTL);
342                 break;
343
344         default:
345                 return -EINVAL;
346         }
347
348         return 0;
349 }
350
351 static int kirkwood_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
352                                struct snd_soc_dai *dai)
353 {
354         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
355                 return kirkwood_i2s_play_trigger(substream, cmd, dai);
356         else
357                 return kirkwood_i2s_rec_trigger(substream, cmd, dai);
358
359         return 0;
360 }
361
362 static int kirkwood_i2s_probe(struct snd_soc_dai *dai)
363 {
364         struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
365         unsigned long value;
366         unsigned int reg_data;
367
368         /* put system in a "safe" state : */
369         /* disable audio interrupts */
370         writel(0xffffffff, priv->io + KIRKWOOD_INT_CAUSE);
371         writel(0, priv->io + KIRKWOOD_INT_MASK);
372
373         reg_data = readl(priv->io + 0x1200);
374         reg_data &= (~(0x333FF8));
375         reg_data |= 0x111D18;
376         writel(reg_data, priv->io + 0x1200);
377
378         msleep(500);
379
380         reg_data = readl(priv->io + 0x1200);
381         reg_data &= (~(0x333FF8));
382         reg_data |= 0x111D18;
383         writel(reg_data, priv->io + 0x1200);
384
385         /* disable playback/record */
386         value = readl(priv->io + KIRKWOOD_PLAYCTL);
387         value &= ~KIRKWOOD_PLAYCTL_ENABLE_MASK;
388         writel(value, priv->io + KIRKWOOD_PLAYCTL);
389
390         value = readl(priv->io + KIRKWOOD_RECCTL);
391         value &= ~(KIRKWOOD_RECCTL_I2S_EN | KIRKWOOD_RECCTL_SPDIF_EN);
392         writel(value, priv->io + KIRKWOOD_RECCTL);
393
394         return 0;
395
396 }
397
398 static const struct snd_soc_dai_ops kirkwood_i2s_dai_ops = {
399         .startup        = kirkwood_i2s_startup,
400         .trigger        = kirkwood_i2s_trigger,
401         .hw_params      = kirkwood_i2s_hw_params,
402         .set_fmt        = kirkwood_i2s_set_fmt,
403 };
404
405
406 static struct snd_soc_dai_driver kirkwood_i2s_dai = {
407         .probe = kirkwood_i2s_probe,
408         .playback = {
409                 .channels_min = 1,
410                 .channels_max = 2,
411                 .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
412                                 SNDRV_PCM_RATE_96000,
413                 .formats = KIRKWOOD_I2S_FORMATS,
414         },
415         .capture = {
416                 .channels_min = 1,
417                 .channels_max = 2,
418                 .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
419                                 SNDRV_PCM_RATE_96000,
420                 .formats = KIRKWOOD_I2S_FORMATS,
421         },
422         .ops = &kirkwood_i2s_dai_ops,
423 };
424
425 static struct snd_soc_dai_driver kirkwood_i2s_dai_extclk = {
426         .probe = kirkwood_i2s_probe,
427         .playback = {
428                 .channels_min = 1,
429                 .channels_max = 2,
430                 .rates = SNDRV_PCM_RATE_8000_192000 |
431                          SNDRV_PCM_RATE_CONTINUOUS |
432                          SNDRV_PCM_RATE_KNOT,
433                 .formats = KIRKWOOD_I2S_FORMATS,
434         },
435         .capture = {
436                 .channels_min = 1,
437                 .channels_max = 2,
438                 .rates = SNDRV_PCM_RATE_8000_192000 |
439                          SNDRV_PCM_RATE_CONTINUOUS |
440                          SNDRV_PCM_RATE_KNOT,
441                 .formats = KIRKWOOD_I2S_FORMATS,
442         },
443         .ops = &kirkwood_i2s_dai_ops,
444 };
445
446 static const struct snd_soc_component_driver kirkwood_i2s_component = {
447         .name           = DRV_NAME,
448 };
449
450 static int kirkwood_i2s_dev_probe(struct platform_device *pdev)
451 {
452         struct kirkwood_asoc_platform_data *data = pdev->dev.platform_data;
453         struct snd_soc_dai_driver *soc_dai = &kirkwood_i2s_dai;
454         struct kirkwood_dma_data *priv;
455         struct resource *mem;
456         int err;
457
458         priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
459         if (!priv) {
460                 dev_err(&pdev->dev, "allocation failed\n");
461                 return -ENOMEM;
462         }
463         dev_set_drvdata(&pdev->dev, priv);
464
465         mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
466         priv->io = devm_ioremap_resource(&pdev->dev, mem);
467         if (IS_ERR(priv->io))
468                 return PTR_ERR(priv->io);
469
470         priv->irq = platform_get_irq(pdev, 0);
471         if (priv->irq <= 0) {
472                 dev_err(&pdev->dev, "platform_get_irq failed\n");
473                 return -ENXIO;
474         }
475
476         if (!data) {
477                 dev_err(&pdev->dev, "no platform data ?!\n");
478                 return -EINVAL;
479         }
480
481         priv->burst = data->burst;
482
483         priv->clk = devm_clk_get(&pdev->dev, NULL);
484         if (IS_ERR(priv->clk)) {
485                 dev_err(&pdev->dev, "no clock\n");
486                 return PTR_ERR(priv->clk);
487         }
488
489         err = clk_prepare_enable(priv->clk);
490         if (err < 0)
491                 return err;
492
493         priv->extclk = devm_clk_get(&pdev->dev, "extclk");
494         if (!IS_ERR(priv->extclk)) {
495                 if (priv->extclk == priv->clk) {
496                         devm_clk_put(&pdev->dev, priv->extclk);
497                         priv->extclk = ERR_PTR(-EINVAL);
498                 } else {
499                         dev_info(&pdev->dev, "found external clock\n");
500                         clk_prepare_enable(priv->extclk);
501                         soc_dai = &kirkwood_i2s_dai_extclk;
502                 }
503         }
504
505         /* Some sensible defaults - this reflects the powerup values */
506         priv->ctl_play = KIRKWOOD_PLAYCTL_SIZE_24;
507         priv->ctl_rec = KIRKWOOD_RECCTL_SIZE_24;
508
509         /* Select the burst size */
510         if (data->burst == 32) {
511                 priv->ctl_play |= KIRKWOOD_PLAYCTL_BURST_32;
512                 priv->ctl_rec |= KIRKWOOD_RECCTL_BURST_32;
513         } else {
514                 priv->ctl_play |= KIRKWOOD_PLAYCTL_BURST_128;
515                 priv->ctl_rec |= KIRKWOOD_RECCTL_BURST_128;
516         }
517
518         err = snd_soc_register_component(&pdev->dev, &kirkwood_i2s_component,
519                                          soc_dai, 1);
520         if (!err)
521                 return 0;
522         dev_err(&pdev->dev, "snd_soc_register_component failed\n");
523
524         if (!IS_ERR(priv->extclk))
525                 clk_disable_unprepare(priv->extclk);
526         clk_disable_unprepare(priv->clk);
527
528         return err;
529 }
530
531 static int kirkwood_i2s_dev_remove(struct platform_device *pdev)
532 {
533         struct kirkwood_dma_data *priv = dev_get_drvdata(&pdev->dev);
534
535         snd_soc_unregister_component(&pdev->dev);
536
537         if (!IS_ERR(priv->extclk))
538                 clk_disable_unprepare(priv->extclk);
539         clk_disable_unprepare(priv->clk);
540
541         return 0;
542 }
543
544 static struct platform_driver kirkwood_i2s_driver = {
545         .probe  = kirkwood_i2s_dev_probe,
546         .remove = kirkwood_i2s_dev_remove,
547         .driver = {
548                 .name = DRV_NAME,
549                 .owner = THIS_MODULE,
550         },
551 };
552
553 module_platform_driver(kirkwood_i2s_driver);
554
555 /* Module information */
556 MODULE_AUTHOR("Arnaud Patard, <arnaud.patard@rtp-net.org>");
557 MODULE_DESCRIPTION("Kirkwood I2S SoC Interface");
558 MODULE_LICENSE("GPL");
559 MODULE_ALIAS("platform:kirkwood-i2s");