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"); |