kirkwood-i2s.c (e199e6136ce6b151e6638ae93dca60748424d900) kirkwood-i2s.c (697378972d075e1b26ed2935bf44fb828c6191f5)
1/*
2 * kirkwood-i2s.c
3 *
4 * (c) 2010 Arnaud Patard <apatard@mandriva.com>
1/*
2 * kirkwood-i2s.c
3 *
4 * (c) 2010 Arnaud Patard <apatard@mandriva.com>
5 * (c) 2010 Arnaud Patard <arnaud.patard@rtp-net.org>
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>
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 <sound/pcm.h>
21#include <sound/pcm_params.h>
22#include <sound/soc.h>
23#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
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
37struct snd_soc_dai kirkwood_i2s_dai;
38static struct kirkwood_dma_data *priv;
39
40static int kirkwood_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
41 unsigned int fmt)
42{
36static int kirkwood_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
37 unsigned int fmt)
38{
39 struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(cpu_dai);
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:

--- 45 unchanged lines hidden (view full) ---

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
40 unsigned long mask;
41 unsigned long value;
42
43 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
44 case SND_SOC_DAIFMT_RIGHT_J:
45 mask = KIRKWOOD_I2S_CTL_RJ;
46 break;
47 case SND_SOC_DAIFMT_LEFT_J:

--- 45 unchanged lines hidden (view full) ---

93 /* wait for dco locked */
94 do {
95 cpu_relax();
96 value = readl(io + KIRKWOOD_DCO_SPCR_STATUS);
97 value &= KIRKWOOD_DCO_SPCR_STATUS;
98 } while (value == 0);
99}
100
101static int kirkwood_i2s_startup(struct snd_pcm_substream *substream,
102 struct snd_soc_dai *dai)
103{
104 struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
105
106 snd_soc_dai_set_dma_data(dai, substream, priv);
107 return 0;
108}
109
104static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream,
105 struct snd_pcm_hw_params *params,
106 struct snd_soc_dai *dai)
107{
110static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream,
111 struct snd_pcm_hw_params *params,
112 struct snd_soc_dai *dai)
113{
114 struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
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;

--- 50 unchanged lines hidden (view full) ---

166 writel(value, priv->io+reg);
167
168 return 0;
169}
170
171static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream,
172 int cmd, struct snd_soc_dai *dai)
173{
115 unsigned int i2s_reg, reg;
116 unsigned long i2s_value, value;
117
118 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
119 i2s_reg = KIRKWOOD_I2S_PLAYCTL;
120 reg = KIRKWOOD_PLAYCTL;
121 } else {
122 i2s_reg = KIRKWOOD_I2S_RECCTL;

--- 50 unchanged lines hidden (view full) ---

173 writel(value, priv->io+reg);
174
175 return 0;
176}
177
178static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream,
179 int cmd, struct snd_soc_dai *dai)
180{
181 struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
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

--- 57 unchanged lines hidden (view full) ---

239 }
240
241 return 0;
242}
243
244static int kirkwood_i2s_rec_trigger(struct snd_pcm_substream *substream,
245 int cmd, struct snd_soc_dai *dai)
246{
182 unsigned long value;
183
184 /*
185 * specs says KIRKWOOD_PLAYCTL must be read 2 times before
186 * changing it. So read 1 time here and 1 later.
187 */
188 value = readl(priv->io + KIRKWOOD_PLAYCTL);
189

--- 57 unchanged lines hidden (view full) ---

247 }
248
249 return 0;
250}
251
252static int kirkwood_i2s_rec_trigger(struct snd_pcm_substream *substream,
253 int cmd, struct snd_soc_dai *dai)
254{
255 struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
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);

--- 63 unchanged lines hidden (view full) ---

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
256 unsigned long value;
257
258 value = readl(priv->io + KIRKWOOD_RECCTL);
259
260 switch (cmd) {
261 case SNDRV_PCM_TRIGGER_START:
262 /* stop audio, enable interrupts */
263 value = readl(priv->io + KIRKWOOD_RECCTL);

--- 63 unchanged lines hidden (view full) ---

327 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
328 return kirkwood_i2s_play_trigger(substream, cmd, dai);
329 else
330 return kirkwood_i2s_rec_trigger(substream, cmd, dai);
331
332 return 0;
333}
334
326static int kirkwood_i2s_probe(struct platform_device *pdev,
327 struct snd_soc_dai *dai)
335static int kirkwood_i2s_probe(struct snd_soc_dai *dai)
328{
336{
337 struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
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

--- 17 unchanged lines hidden (view full) ---

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
338 unsigned long value;
339 unsigned int reg_data;
340
341 /* put system in a "safe" state : */
342 /* disable audio interrupts */
343 writel(0xffffffff, priv->io + KIRKWOOD_INT_CAUSE);
344 writel(0, priv->io + KIRKWOOD_INT_MASK);
345

--- 17 unchanged lines hidden (view full) ---

363 value = readl(priv->io + KIRKWOOD_RECCTL);
364 value &= ~(KIRKWOOD_RECCTL_I2S_EN | KIRKWOOD_RECCTL_SPDIF_EN);
365 writel(value, priv->io + KIRKWOOD_RECCTL);
366
367 return 0;
368
369}
370
362static void kirkwood_i2s_remove(struct platform_device *pdev,
363 struct snd_soc_dai *dai)
371static int kirkwood_i2s_remove(struct snd_soc_dai *dai)
364{
372{
373 return 0;
365}
366
367static struct snd_soc_dai_ops kirkwood_i2s_dai_ops = {
374}
375
376static struct snd_soc_dai_ops kirkwood_i2s_dai_ops = {
377 .startup = kirkwood_i2s_startup,
368 .trigger = kirkwood_i2s_trigger,
369 .hw_params = kirkwood_i2s_hw_params,
370 .set_fmt = kirkwood_i2s_set_fmt,
371};
372
373
378 .trigger = kirkwood_i2s_trigger,
379 .hw_params = kirkwood_i2s_hw_params,
380 .set_fmt = kirkwood_i2s_set_fmt,
381};
382
383
374struct snd_soc_dai kirkwood_i2s_dai = {
375 .name = DRV_NAME,
376 .id = 0,
384static struct snd_soc_dai_driver kirkwood_i2s_dai = {
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};
385 .probe = kirkwood_i2s_probe,
386 .remove = kirkwood_i2s_remove,
387 .playback = {
388 .channels_min = 1,
389 .channels_max = 2,
390 .rates = KIRKWOOD_I2S_RATES,
391 .formats = KIRKWOOD_I2S_FORMATS,},
392 .capture = {
393 .channels_min = 1,
394 .channels_max = 2,
395 .rates = KIRKWOOD_I2S_RATES,
396 .formats = KIRKWOOD_I2S_FORMATS,},
397 .ops = &kirkwood_i2s_dai_ops,
398};
391EXPORT_SYMBOL_GPL(kirkwood_i2s_dai);
392
393static __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;
399
400static __devinit int kirkwood_i2s_dev_probe(struct platform_device *pdev)
401{
402 struct resource *mem;
403 struct kirkwood_asoc_platform_data *data =
404 pdev->dev.platform_data;
405 struct kirkwood_dma_data *priv;
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 int err;
407
408 priv = kzalloc(sizeof(struct kirkwood_dma_data), GFP_KERNEL);
409 if (!priv) {
410 dev_err(&pdev->dev, "allocation failed\n");
411 err = -ENOMEM;
412 goto error;
413 }
414 dev_set_drvdata(&pdev->dev, priv);
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

--- 22 unchanged lines hidden (view full) ---

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
415
416 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
417 if (!mem) {
418 dev_err(&pdev->dev, "platform_get_resource failed\n");
419 err = -ENXIO;
420 goto err_alloc;
421 }
422

--- 22 unchanged lines hidden (view full) ---

445 dev_err(&pdev->dev, "no platform data ?!\n");
446 err = -EINVAL;
447 goto err_ioremap;
448 }
449
450 priv->dram = data->dram;
451 priv->burst = data->burst;
452
444 kirkwood_i2s_dai.capture.dma_data = priv;
445 kirkwood_i2s_dai.playback.dma_data = priv;
453 return snd_soc_register_dai(&pdev->dev, &kirkwood_i2s_dai);
446
454
447 return snd_soc_register_dai(&kirkwood_i2s_dai);
448
449err_ioremap:
450 iounmap(priv->io);
451err_iomem:
452 release_mem_region(priv->mem->start, SZ_16K);
453err_alloc:
454 kfree(priv);
455error:
456 return err;
457}
458
459static __devexit int kirkwood_i2s_dev_remove(struct platform_device *pdev)
460{
455err_ioremap:
456 iounmap(priv->io);
457err_iomem:
458 release_mem_region(priv->mem->start, SZ_16K);
459err_alloc:
460 kfree(priv);
461error:
462 return err;
463}
464
465static __devexit int kirkwood_i2s_dev_remove(struct platform_device *pdev)
466{
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 struct kirkwood_dma_data *priv = dev_get_drvdata(&pdev->dev);
468
469 snd_soc_unregister_dai(&pdev->dev);
470 iounmap(priv->io);
471 release_mem_region(priv->mem->start, SZ_16K);
472 kfree(priv);
473
467 return 0;
468}
469
470static struct platform_driver kirkwood_i2s_driver = {
471 .probe = kirkwood_i2s_dev_probe,
472 .remove = kirkwood_i2s_dev_remove,
473 .driver = {
474 .name = DRV_NAME,

--- 9 unchanged lines hidden (view full) ---

484
485static void __exit kirkwood_i2s_exit(void)
486{
487 platform_driver_unregister(&kirkwood_i2s_driver);
488}
489module_exit(kirkwood_i2s_exit);
490
491/* Module information */
474 return 0;
475}
476
477static struct platform_driver kirkwood_i2s_driver = {
478 .probe = kirkwood_i2s_dev_probe,
479 .remove = kirkwood_i2s_dev_remove,
480 .driver = {
481 .name = DRV_NAME,

--- 9 unchanged lines hidden (view full) ---

491
492static void __exit kirkwood_i2s_exit(void)
493{
494 platform_driver_unregister(&kirkwood_i2s_driver);
495}
496module_exit(kirkwood_i2s_exit);
497
498/* Module information */
492MODULE_AUTHOR("Arnaud Patard, <apatard@mandriva.com>");
499MODULE_AUTHOR("Arnaud Patard, <arnaud.patard@rtp-net.org>");
493MODULE_DESCRIPTION("Kirkwood I2S SoC Interface");
494MODULE_LICENSE("GPL");
495MODULE_ALIAS("platform:kirkwood-i2s");
500MODULE_DESCRIPTION("Kirkwood I2S SoC Interface");
501MODULE_LICENSE("GPL");
502MODULE_ALIAS("platform:kirkwood-i2s");