aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2010-08-05 05:17:01 -0400
committerTakashi Iwai <tiwai@suse.de>2010-08-05 05:17:01 -0400
commite71981343ad29b5d929f82ac56c0b27b8ea0e540 (patch)
tree47135be4252faecbc0e5508658a58f8afd197fff /sound
parent2603798070a80d76e7e6d2992ba4ec74addcec90 (diff)
parentbda7d2a862e6b788bca2d02d38a07966a9c92e48 (diff)
Merge branch 'topic/asoc' into for-linus
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/Kconfig4
-rw-r--r--sound/soc/Makefile4
-rw-r--r--sound/soc/atmel/atmel-pcm.c1
-rw-r--r--sound/soc/atmel/atmel_ssc_dai.c1
-rw-r--r--sound/soc/au1x/psc-ac97.c13
-rw-r--r--sound/soc/au1x/psc-i2s.c13
-rw-r--r--sound/soc/au1x/psc.h1
-rw-r--r--sound/soc/blackfin/bf5xx-ac97.c6
-rw-r--r--sound/soc/blackfin/bf5xx-tdm.c6
-rw-r--r--sound/soc/codecs/Kconfig20
-rw-r--r--sound/soc/codecs/Makefile6
-rw-r--r--sound/soc/codecs/ad1836.c1
-rw-r--r--sound/soc/codecs/ad193x.c41
-rw-r--r--sound/soc/codecs/ad193x.h5
-rw-r--r--sound/soc/codecs/ak4642.c36
-rw-r--r--sound/soc/codecs/cs42l51.c763
-rw-r--r--sound/soc/codecs/cs42l51.h163
-rw-r--r--sound/soc/codecs/da7210.c48
-rw-r--r--sound/soc/codecs/jz4740.c511
-rw-r--r--sound/soc/codecs/jz4740.h20
-rw-r--r--sound/soc/codecs/spdif_transciever.c94
-rw-r--r--sound/soc/codecs/spdif_transciever.h1
-rw-r--r--sound/soc/codecs/tlv320aic23.c7
-rw-r--r--sound/soc/codecs/tlv320dac33.c180
-rw-r--r--sound/soc/codecs/twl4030.c388
-rw-r--r--sound/soc/codecs/twl4030.h4
-rw-r--r--sound/soc/codecs/twl6040.c58
-rw-r--r--sound/soc/codecs/uda134x.c64
-rw-r--r--sound/soc/codecs/uda134x.h5
-rw-r--r--sound/soc/codecs/wm2000.c2
-rw-r--r--sound/soc/codecs/wm8523.c10
-rw-r--r--sound/soc/codecs/wm8711.c3
-rw-r--r--sound/soc/codecs/wm8741.c579
-rw-r--r--sound/soc/codecs/wm8741.h214
-rw-r--r--sound/soc/codecs/wm8750.c11
-rw-r--r--sound/soc/codecs/wm8904.c13
-rw-r--r--sound/soc/codecs/wm8940.c7
-rw-r--r--sound/soc/codecs/wm8955.c10
-rw-r--r--sound/soc/codecs/wm8960.c99
-rw-r--r--sound/soc/codecs/wm8961.c9
-rw-r--r--sound/soc/codecs/wm8974.c3
-rw-r--r--sound/soc/codecs/wm8978.c10
-rw-r--r--sound/soc/codecs/wm8990.c4
-rw-r--r--sound/soc/codecs/wm8994.c75
-rw-r--r--sound/soc/codecs/wm8994.h3
-rw-r--r--sound/soc/codecs/wm9081.c11
-rw-r--r--sound/soc/codecs/wm_hubs.c2
-rw-r--r--sound/soc/davinci/davinci-i2s.c163
-rw-r--r--sound/soc/davinci/davinci-i2s.h5
-rw-r--r--sound/soc/davinci/davinci-mcasp.c6
-rw-r--r--sound/soc/davinci/davinci-pcm.c7
-rw-r--r--sound/soc/davinci/davinci-pcm.h3
-rw-r--r--sound/soc/davinci/davinci-vcif.c2
-rw-r--r--sound/soc/ep93xx/Kconfig18
-rw-r--r--sound/soc/ep93xx/Makefile11
-rw-r--r--sound/soc/ep93xx/ep93xx-i2s.c487
-rw-r--r--sound/soc/ep93xx/ep93xx-i2s.h18
-rw-r--r--sound/soc/ep93xx/ep93xx-pcm.c319
-rw-r--r--sound/soc/ep93xx/ep93xx-pcm.h22
-rw-r--r--sound/soc/ep93xx/snappercl15.c150
-rw-r--r--sound/soc/fsl/mpc5200_psc_i2s.c1
-rw-r--r--sound/soc/fsl/mpc5200_psc_i2s.h12
-rw-r--r--sound/soc/imx/Kconfig19
-rw-r--r--sound/soc/imx/Makefile2
-rw-r--r--sound/soc/imx/eukrea-tlv320.c137
-rw-r--r--sound/soc/imx/imx-pcm-dma-mx2.c6
-rw-r--r--sound/soc/imx/imx-pcm-fiq.c6
-rw-r--r--sound/soc/imx/imx-ssi.c11
-rw-r--r--sound/soc/jz4740/Kconfig23
-rw-r--r--sound/soc/jz4740/Makefile13
-rw-r--r--sound/soc/jz4740/jz4740-i2s.c540
-rw-r--r--sound/soc/jz4740/jz4740-i2s.h18
-rw-r--r--sound/soc/jz4740/jz4740-pcm.c373
-rw-r--r--sound/soc/jz4740/jz4740-pcm.h22
-rw-r--r--sound/soc/jz4740/qi_lb60.c166
-rw-r--r--sound/soc/kirkwood/Kconfig20
-rw-r--r--sound/soc/kirkwood/Makefile9
-rw-r--r--sound/soc/kirkwood/kirkwood-dma.c383
-rw-r--r--sound/soc/kirkwood/kirkwood-dma.h17
-rw-r--r--sound/soc/kirkwood/kirkwood-i2s.c495
-rw-r--r--sound/soc/kirkwood/kirkwood-i2s.h17
-rw-r--r--sound/soc/kirkwood/kirkwood-openrd.c126
-rw-r--r--sound/soc/kirkwood/kirkwood.h129
-rw-r--r--sound/soc/nuc900/Kconfig27
-rw-r--r--sound/soc/nuc900/Makefile11
-rw-r--r--sound/soc/nuc900/nuc900-ac97.c430
-rw-r--r--sound/soc/nuc900/nuc900-audio.c81
-rw-r--r--sound/soc/nuc900/nuc900-audio.h117
-rw-r--r--sound/soc/nuc900/nuc900-pcm.c354
-rw-r--r--sound/soc/omap/omap-mcbsp.c175
-rw-r--r--sound/soc/omap/omap3pandora.c36
-rw-r--r--sound/soc/omap/rx51.c73
-rw-r--r--sound/soc/s3c24xx/Kconfig10
-rw-r--r--sound/soc/s3c24xx/Makefile2
-rw-r--r--sound/soc/s3c24xx/s3c-ac97.c1
-rw-r--r--sound/soc/s3c24xx/s3c-i2s-v2.c3
-rw-r--r--sound/soc/s3c24xx/smartq_wm8987.c295
-rw-r--r--sound/soc/s3c24xx/smdk_wm9713.c3
-rw-r--r--sound/soc/s6000/s6000-i2s.c38
-rw-r--r--sound/soc/sh/Kconfig4
-rw-r--r--sound/soc/sh/fsi-ak4642.c13
-rw-r--r--sound/soc/sh/fsi-da7210.c13
-rw-r--r--sound/soc/sh/fsi.c257
-rw-r--r--sound/soc/soc-core.c115
104 files changed, 8717 insertions, 626 deletions
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index b1749bc67979..3e598e756e54 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -28,9 +28,13 @@ source "sound/soc/atmel/Kconfig"
28source "sound/soc/au1x/Kconfig" 28source "sound/soc/au1x/Kconfig"
29source "sound/soc/blackfin/Kconfig" 29source "sound/soc/blackfin/Kconfig"
30source "sound/soc/davinci/Kconfig" 30source "sound/soc/davinci/Kconfig"
31source "sound/soc/ep93xx/Kconfig"
31source "sound/soc/fsl/Kconfig" 32source "sound/soc/fsl/Kconfig"
32source "sound/soc/imx/Kconfig" 33source "sound/soc/imx/Kconfig"
34source "sound/soc/jz4740/Kconfig"
35source "sound/soc/nuc900/Kconfig"
33source "sound/soc/omap/Kconfig" 36source "sound/soc/omap/Kconfig"
37source "sound/soc/kirkwood/Kconfig"
34source "sound/soc/pxa/Kconfig" 38source "sound/soc/pxa/Kconfig"
35source "sound/soc/s3c24xx/Kconfig" 39source "sound/soc/s3c24xx/Kconfig"
36source "sound/soc/s6000/Kconfig" 40source "sound/soc/s6000/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 1470141d4167..eb183443eee4 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -6,9 +6,13 @@ obj-$(CONFIG_SND_SOC) += atmel/
6obj-$(CONFIG_SND_SOC) += au1x/ 6obj-$(CONFIG_SND_SOC) += au1x/
7obj-$(CONFIG_SND_SOC) += blackfin/ 7obj-$(CONFIG_SND_SOC) += blackfin/
8obj-$(CONFIG_SND_SOC) += davinci/ 8obj-$(CONFIG_SND_SOC) += davinci/
9obj-$(CONFIG_SND_SOC) += ep93xx/
9obj-$(CONFIG_SND_SOC) += fsl/ 10obj-$(CONFIG_SND_SOC) += fsl/
10obj-$(CONFIG_SND_SOC) += imx/ 11obj-$(CONFIG_SND_SOC) += imx/
12obj-$(CONFIG_SND_SOC) += jz4740/
13obj-$(CONFIG_SND_SOC) += nuc900/
11obj-$(CONFIG_SND_SOC) += omap/ 14obj-$(CONFIG_SND_SOC) += omap/
15obj-$(CONFIG_SND_SOC) += kirkwood/
12obj-$(CONFIG_SND_SOC) += pxa/ 16obj-$(CONFIG_SND_SOC) += pxa/
13obj-$(CONFIG_SND_SOC) += s3c24xx/ 17obj-$(CONFIG_SND_SOC) += s3c24xx/
14obj-$(CONFIG_SND_SOC) += s6000/ 18obj-$(CONFIG_SND_SOC) += s6000/
diff --git a/sound/soc/atmel/atmel-pcm.c b/sound/soc/atmel/atmel-pcm.c
index f6b3cc04b34b..dc5249fba85c 100644
--- a/sound/soc/atmel/atmel-pcm.c
+++ b/sound/soc/atmel/atmel-pcm.c
@@ -77,7 +77,6 @@ struct atmel_runtime_data {
77 size_t period_size; 77 size_t period_size;
78 78
79 dma_addr_t period_ptr; /* physical address of next period */ 79 dma_addr_t period_ptr; /* physical address of next period */
80 int periods; /* period index of period_ptr */
81 80
82 /* PDC register save */ 81 /* PDC register save */
83 u32 pdc_xpr_save; 82 u32 pdc_xpr_save;
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c
index 0b59806905d1..c85844d4845b 100644
--- a/sound/soc/atmel/atmel_ssc_dai.c
+++ b/sound/soc/atmel/atmel_ssc_dai.c
@@ -549,7 +549,6 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
549 printk(KERN_WARNING "atmel_ssc_dai: unsupported DAI format 0x%x\n", 549 printk(KERN_WARNING "atmel_ssc_dai: unsupported DAI format 0x%x\n",
550 ssc_p->daifmt); 550 ssc_p->daifmt);
551 return -EINVAL; 551 return -EINVAL;
552 break;
553 } 552 }
554 pr_debug("atmel_ssc_hw_params: " 553 pr_debug("atmel_ssc_hw_params: "
555 "RCMR=%08x RFMR=%08x TCMR=%08x TFMR=%08x\n", 554 "RCMR=%08x RFMR=%08x TCMR=%08x TFMR=%08x\n",
diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c
index a61ccd2d505f..d14a5a91a465 100644
--- a/sound/soc/au1x/psc-ac97.c
+++ b/sound/soc/au1x/psc-ac97.c
@@ -375,12 +375,10 @@ static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev)
375 } 375 }
376 376
377 ret = -EBUSY; 377 ret = -EBUSY;
378 wd->ioarea = request_mem_region(r->start, r->end - r->start + 1, 378 if (!request_mem_region(r->start, resource_size(r), pdev->name))
379 "au1xpsc_ac97");
380 if (!wd->ioarea)
381 goto out0; 379 goto out0;
382 380
383 wd->mmio = ioremap(r->start, 0xffff); 381 wd->mmio = ioremap(r->start, resource_size(r));
384 if (!wd->mmio) 382 if (!wd->mmio)
385 goto out1; 383 goto out1;
386 384
@@ -410,8 +408,7 @@ static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev)
410 408
411 snd_soc_unregister_dai(&au1xpsc_ac97_dai); 409 snd_soc_unregister_dai(&au1xpsc_ac97_dai);
412out1: 410out1:
413 release_resource(wd->ioarea); 411 release_mem_region(r->start, resource_size(r));
414 kfree(wd->ioarea);
415out0: 412out0:
416 kfree(wd); 413 kfree(wd);
417 return ret; 414 return ret;
@@ -420,6 +417,7 @@ out0:
420static int __devexit au1xpsc_ac97_drvremove(struct platform_device *pdev) 417static int __devexit au1xpsc_ac97_drvremove(struct platform_device *pdev)
421{ 418{
422 struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev); 419 struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev);
420 struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
423 421
424 if (wd->dmapd) 422 if (wd->dmapd)
425 au1xpsc_pcm_destroy(wd->dmapd); 423 au1xpsc_pcm_destroy(wd->dmapd);
@@ -433,8 +431,7 @@ static int __devexit au1xpsc_ac97_drvremove(struct platform_device *pdev)
433 au_sync(); 431 au_sync();
434 432
435 iounmap(wd->mmio); 433 iounmap(wd->mmio);
436 release_resource(wd->ioarea); 434 release_mem_region(r->start, resource_size(r));
437 kfree(wd->ioarea);
438 kfree(wd); 435 kfree(wd);
439 436
440 au1xpsc_ac97_workdata = NULL; /* MDEV */ 437 au1xpsc_ac97_workdata = NULL; /* MDEV */
diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c
index 24454c98d0ee..6083fe7799fa 100644
--- a/sound/soc/au1x/psc-i2s.c
+++ b/sound/soc/au1x/psc-i2s.c
@@ -321,12 +321,10 @@ static int __devinit au1xpsc_i2s_drvprobe(struct platform_device *pdev)
321 } 321 }
322 322
323 ret = -EBUSY; 323 ret = -EBUSY;
324 wd->ioarea = request_mem_region(r->start, r->end - r->start + 1, 324 if (!request_mem_region(r->start, resource_size(r), pdev->name))
325 "au1xpsc_i2s");
326 if (!wd->ioarea)
327 goto out0; 325 goto out0;
328 326
329 wd->mmio = ioremap(r->start, 0xffff); 327 wd->mmio = ioremap(r->start, resource_size(r));
330 if (!wd->mmio) 328 if (!wd->mmio)
331 goto out1; 329 goto out1;
332 330
@@ -362,8 +360,7 @@ static int __devinit au1xpsc_i2s_drvprobe(struct platform_device *pdev)
362 360
363 snd_soc_unregister_dai(&au1xpsc_i2s_dai); 361 snd_soc_unregister_dai(&au1xpsc_i2s_dai);
364out1: 362out1:
365 release_resource(wd->ioarea); 363 release_mem_region(r->start, resource_size(r));
366 kfree(wd->ioarea);
367out0: 364out0:
368 kfree(wd); 365 kfree(wd);
369 return ret; 366 return ret;
@@ -372,6 +369,7 @@ out0:
372static int __devexit au1xpsc_i2s_drvremove(struct platform_device *pdev) 369static int __devexit au1xpsc_i2s_drvremove(struct platform_device *pdev)
373{ 370{
374 struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev); 371 struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev);
372 struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
375 373
376 if (wd->dmapd) 374 if (wd->dmapd)
377 au1xpsc_pcm_destroy(wd->dmapd); 375 au1xpsc_pcm_destroy(wd->dmapd);
@@ -384,8 +382,7 @@ static int __devexit au1xpsc_i2s_drvremove(struct platform_device *pdev)
384 au_sync(); 382 au_sync();
385 383
386 iounmap(wd->mmio); 384 iounmap(wd->mmio);
387 release_resource(wd->ioarea); 385 release_mem_region(r->start, resource_size(r));
388 kfree(wd->ioarea);
389 kfree(wd); 386 kfree(wd);
390 387
391 au1xpsc_i2s_workdata = NULL; /* MDEV */ 388 au1xpsc_i2s_workdata = NULL; /* MDEV */
diff --git a/sound/soc/au1x/psc.h b/sound/soc/au1x/psc.h
index 32d3807d3f5a..093775d4dc3e 100644
--- a/sound/soc/au1x/psc.h
+++ b/sound/soc/au1x/psc.h
@@ -32,7 +32,6 @@ struct au1xpsc_audio_data {
32 unsigned long rate; 32 unsigned long rate;
33 33
34 unsigned long pm[2]; 34 unsigned long pm[2];
35 struct resource *ioarea;
36 struct mutex lock; 35 struct mutex lock;
37 struct platform_device *dmapd; 36 struct platform_device *dmapd;
38}; 37};
diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c
index 523b7fc33f4e..c0eba5109980 100644
--- a/sound/soc/blackfin/bf5xx-ac97.c
+++ b/sound/soc/blackfin/bf5xx-ac97.c
@@ -255,8 +255,7 @@ EXPORT_SYMBOL_GPL(soc_ac97_ops);
255#ifdef CONFIG_PM 255#ifdef CONFIG_PM
256static int bf5xx_ac97_suspend(struct snd_soc_dai *dai) 256static int bf5xx_ac97_suspend(struct snd_soc_dai *dai)
257{ 257{
258 struct sport_device *sport = 258 struct sport_device *sport = dai->private_data;
259 (struct sport_device *)dai->private_data;
260 259
261 pr_debug("%s : sport %d\n", __func__, dai->id); 260 pr_debug("%s : sport %d\n", __func__, dai->id);
262 if (!dai->active) 261 if (!dai->active)
@@ -271,8 +270,7 @@ static int bf5xx_ac97_suspend(struct snd_soc_dai *dai)
271static int bf5xx_ac97_resume(struct snd_soc_dai *dai) 270static int bf5xx_ac97_resume(struct snd_soc_dai *dai)
272{ 271{
273 int ret; 272 int ret;
274 struct sport_device *sport = 273 struct sport_device *sport = dai->private_data;
275 (struct sport_device *)dai->private_data;
276 274
277 pr_debug("%s : sport %d\n", __func__, dai->id); 275 pr_debug("%s : sport %d\n", __func__, dai->id);
278 if (!dai->active) 276 if (!dai->active)
diff --git a/sound/soc/blackfin/bf5xx-tdm.c b/sound/soc/blackfin/bf5xx-tdm.c
index 4b360124083e..24c14269f4bc 100644
--- a/sound/soc/blackfin/bf5xx-tdm.c
+++ b/sound/soc/blackfin/bf5xx-tdm.c
@@ -210,8 +210,7 @@ static int bf5xx_tdm_set_channel_map(struct snd_soc_dai *dai,
210#ifdef CONFIG_PM 210#ifdef CONFIG_PM
211static int bf5xx_tdm_suspend(struct snd_soc_dai *dai) 211static int bf5xx_tdm_suspend(struct snd_soc_dai *dai)
212{ 212{
213 struct sport_device *sport = 213 struct sport_device *sport = dai->private_data;
214 (struct sport_device *)dai->private_data;
215 214
216 if (!dai->active) 215 if (!dai->active)
217 return 0; 216 return 0;
@@ -225,8 +224,7 @@ static int bf5xx_tdm_suspend(struct snd_soc_dai *dai)
225static int bf5xx_tdm_resume(struct snd_soc_dai *dai) 224static int bf5xx_tdm_resume(struct snd_soc_dai *dai)
226{ 225{
227 int ret; 226 int ret;
228 struct sport_device *sport = 227 struct sport_device *sport = dai->private_data;
229 (struct sport_device *)dai->private_data;
230 228
231 if (!dai->active) 229 if (!dai->active)
232 return 0; 230 return 0;
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 5da30eb6ad00..83f5c67d3c41 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -22,9 +22,11 @@ config SND_SOC_ALL_CODECS
22 select SND_SOC_AK4642 if I2C 22 select SND_SOC_AK4642 if I2C
23 select SND_SOC_AK4671 if I2C 23 select SND_SOC_AK4671 if I2C
24 select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC 24 select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC
25 select SND_SOC_CS42L51 if I2C
25 select SND_SOC_CS4270 if I2C 26 select SND_SOC_CS4270 if I2C
26 select SND_SOC_MAX9877 if I2C
27 select SND_SOC_DA7210 if I2C 27 select SND_SOC_DA7210 if I2C
28 select SND_SOC_JZ4740 if SOC_JZ4740
29 select SND_SOC_MAX9877 if I2C
28 select SND_SOC_PCM3008 30 select SND_SOC_PCM3008
29 select SND_SOC_SPDIF 31 select SND_SOC_SPDIF
30 select SND_SOC_SSM2602 if I2C 32 select SND_SOC_SSM2602 if I2C
@@ -48,6 +50,7 @@ config SND_SOC_ALL_CODECS
48 select SND_SOC_WM8727 50 select SND_SOC_WM8727
49 select SND_SOC_WM8728 if SND_SOC_I2C_AND_SPI 51 select SND_SOC_WM8728 if SND_SOC_I2C_AND_SPI
50 select SND_SOC_WM8731 if SND_SOC_I2C_AND_SPI 52 select SND_SOC_WM8731 if SND_SOC_I2C_AND_SPI
53 select SND_SOC_WM8741 if SND_SOC_I2C_AND_SPI
51 select SND_SOC_WM8750 if SND_SOC_I2C_AND_SPI 54 select SND_SOC_WM8750 if SND_SOC_I2C_AND_SPI
52 select SND_SOC_WM8753 if SND_SOC_I2C_AND_SPI 55 select SND_SOC_WM8753 if SND_SOC_I2C_AND_SPI
53 select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI 56 select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI
@@ -120,13 +123,13 @@ config SND_SOC_AK4671
120config SND_SOC_CQ0093VC 123config SND_SOC_CQ0093VC
121 tristate 124 tristate
122 125
126config SND_SOC_CS42L51
127 tristate
128
123# Cirrus Logic CS4270 Codec 129# Cirrus Logic CS4270 Codec
124config SND_SOC_CS4270 130config SND_SOC_CS4270
125 tristate 131 tristate
126 132
127config SND_SOC_DA7210
128 tristate
129
130# Cirrus Logic CS4270 Codec VD = 3.3V Errata 133# Cirrus Logic CS4270 Codec VD = 3.3V Errata
131# Select if you are affected by the errata where the part will not function 134# Select if you are affected by the errata where the part will not function
132# if MCLK divide-by-1.5 is selected and VD is set to 3.3V. The driver will 135# if MCLK divide-by-1.5 is selected and VD is set to 3.3V. The driver will
@@ -138,9 +141,15 @@ config SND_SOC_CS4270_VD33_ERRATA
138config SND_SOC_CX20442 141config SND_SOC_CX20442
139 tristate 142 tristate
140 143
144config SND_SOC_JZ4740_CODEC
145 tristate
146
141config SND_SOC_L3 147config SND_SOC_L3
142 tristate 148 tristate
143 149
150config SND_SOC_DA7210
151 tristate
152
144config SND_SOC_PCM3008 153config SND_SOC_PCM3008
145 tristate 154 tristate
146 155
@@ -206,6 +215,9 @@ config SND_SOC_WM8728
206config SND_SOC_WM8731 215config SND_SOC_WM8731
207 tristate 216 tristate
208 217
218config SND_SOC_WM8741
219 tristate
220
209config SND_SOC_WM8750 221config SND_SOC_WM8750
210 tristate 222 tristate
211 223
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 91429eab0707..53524095759c 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -9,6 +9,7 @@ snd-soc-ak4535-objs := ak4535.o
9snd-soc-ak4642-objs := ak4642.o 9snd-soc-ak4642-objs := ak4642.o
10snd-soc-ak4671-objs := ak4671.o 10snd-soc-ak4671-objs := ak4671.o
11snd-soc-cq93vc-objs := cq93vc.o 11snd-soc-cq93vc-objs := cq93vc.o
12snd-soc-cs42l51-objs := cs42l51.o
12snd-soc-cs4270-objs := cs4270.o 13snd-soc-cs4270-objs := cs4270.o
13snd-soc-cx20442-objs := cx20442.o 14snd-soc-cx20442-objs := cx20442.o
14snd-soc-da7210-objs := da7210.o 15snd-soc-da7210-objs := da7210.o
@@ -34,6 +35,7 @@ snd-soc-wm8711-objs := wm8711.o
34snd-soc-wm8727-objs := wm8727.o 35snd-soc-wm8727-objs := wm8727.o
35snd-soc-wm8728-objs := wm8728.o 36snd-soc-wm8728-objs := wm8728.o
36snd-soc-wm8731-objs := wm8731.o 37snd-soc-wm8731-objs := wm8731.o
38snd-soc-wm8741-objs := wm8741.o
37snd-soc-wm8750-objs := wm8750.o 39snd-soc-wm8750-objs := wm8750.o
38snd-soc-wm8753-objs := wm8753.o 40snd-soc-wm8753-objs := wm8753.o
39snd-soc-wm8776-objs := wm8776.o 41snd-soc-wm8776-objs := wm8776.o
@@ -56,6 +58,7 @@ snd-soc-wm9705-objs := wm9705.o
56snd-soc-wm9712-objs := wm9712.o 58snd-soc-wm9712-objs := wm9712.o
57snd-soc-wm9713-objs := wm9713.o 59snd-soc-wm9713-objs := wm9713.o
58snd-soc-wm-hubs-objs := wm_hubs.o 60snd-soc-wm-hubs-objs := wm_hubs.o
61snd-soc-jz4740-codec-objs := jz4740.o
59 62
60# Amp 63# Amp
61snd-soc-max9877-objs := max9877.o 64snd-soc-max9877-objs := max9877.o
@@ -74,10 +77,12 @@ obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o
74obj-$(CONFIG_SND_SOC_AK4642) += snd-soc-ak4642.o 77obj-$(CONFIG_SND_SOC_AK4642) += snd-soc-ak4642.o
75obj-$(CONFIG_SND_SOC_AK4671) += snd-soc-ak4671.o 78obj-$(CONFIG_SND_SOC_AK4671) += snd-soc-ak4671.o
76obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o 79obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o
80obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o
77obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o 81obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o
78obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o 82obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o
79obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o 83obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o
80obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o 84obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o
85obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o
81obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o 86obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o
82obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o 87obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o
83obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o 88obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o
@@ -99,6 +104,7 @@ obj-$(CONFIG_SND_SOC_WM8711) += snd-soc-wm8711.o
99obj-$(CONFIG_SND_SOC_WM8727) += snd-soc-wm8727.o 104obj-$(CONFIG_SND_SOC_WM8727) += snd-soc-wm8727.o
100obj-$(CONFIG_SND_SOC_WM8728) += snd-soc-wm8728.o 105obj-$(CONFIG_SND_SOC_WM8728) += snd-soc-wm8728.o
101obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o 106obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o
107obj-$(CONFIG_SND_SOC_WM8741) += snd-soc-wm8741.o
102obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o 108obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o
103obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o 109obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o
104obj-$(CONFIG_SND_SOC_WM8776) += snd-soc-wm8776.o 110obj-$(CONFIG_SND_SOC_WM8776) += snd-soc-wm8776.o
diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c
index 217538423225..a01006c8c606 100644
--- a/sound/soc/codecs/ad1836.c
+++ b/sound/soc/codecs/ad1836.c
@@ -272,6 +272,7 @@ static int ad1836_register(struct ad1836_priv *ad1836)
272 272
273 if (ad1836_codec) { 273 if (ad1836_codec) {
274 dev_err(codec->dev, "Another ad1836 is registered\n"); 274 dev_err(codec->dev, "Another ad1836 is registered\n");
275 kfree(ad1836);
275 return -EINVAL; 276 return -EINVAL;
276 } 277 }
277 278
diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c
index c8ca1142b2f4..1def75e4862f 100644
--- a/sound/soc/codecs/ad193x.c
+++ b/sound/soc/codecs/ad193x.c
@@ -24,6 +24,7 @@
24 24
25/* codec private data */ 25/* codec private data */
26struct ad193x_priv { 26struct ad193x_priv {
27 unsigned int sysclk;
27 struct snd_soc_codec codec; 28 struct snd_soc_codec codec;
28 u8 reg_cache[AD193X_NUM_REGS]; 29 u8 reg_cache[AD193X_NUM_REGS];
29}; 30};
@@ -251,15 +252,32 @@ static int ad193x_set_dai_fmt(struct snd_soc_dai *codec_dai,
251 return 0; 252 return 0;
252} 253}
253 254
255static int ad193x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
256 int clk_id, unsigned int freq, int dir)
257{
258 struct snd_soc_codec *codec = codec_dai->codec;
259 struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec);
260 switch (freq) {
261 case 12288000:
262 case 18432000:
263 case 24576000:
264 case 36864000:
265 ad193x->sysclk = freq;
266 return 0;
267 }
268 return -EINVAL;
269}
270
254static int ad193x_hw_params(struct snd_pcm_substream *substream, 271static int ad193x_hw_params(struct snd_pcm_substream *substream,
255 struct snd_pcm_hw_params *params, 272 struct snd_pcm_hw_params *params,
256 struct snd_soc_dai *dai) 273 struct snd_soc_dai *dai)
257{ 274{
258 int word_len = 0, reg = 0; 275 int word_len = 0, reg = 0, master_rate = 0;
259 276
260 struct snd_soc_pcm_runtime *rtd = substream->private_data; 277 struct snd_soc_pcm_runtime *rtd = substream->private_data;
261 struct snd_soc_device *socdev = rtd->socdev; 278 struct snd_soc_device *socdev = rtd->socdev;
262 struct snd_soc_codec *codec = socdev->card->codec; 279 struct snd_soc_codec *codec = socdev->card->codec;
280 struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec);
263 281
264 /* bit size */ 282 /* bit size */
265 switch (params_format(params)) { 283 switch (params_format(params)) {
@@ -275,6 +293,25 @@ static int ad193x_hw_params(struct snd_pcm_substream *substream,
275 break; 293 break;
276 } 294 }
277 295
296 switch (ad193x->sysclk) {
297 case 12288000:
298 master_rate = AD193X_PLL_INPUT_256;
299 break;
300 case 18432000:
301 master_rate = AD193X_PLL_INPUT_384;
302 break;
303 case 24576000:
304 master_rate = AD193X_PLL_INPUT_512;
305 break;
306 case 36864000:
307 master_rate = AD193X_PLL_INPUT_768;
308 break;
309 }
310
311 reg = snd_soc_read(codec, AD193X_PLL_CLK_CTRL0);
312 reg = (reg & AD193X_PLL_INPUT_MASK) | master_rate;
313 snd_soc_write(codec, AD193X_PLL_CLK_CTRL0, reg);
314
278 reg = snd_soc_read(codec, AD193X_DAC_CTRL2); 315 reg = snd_soc_read(codec, AD193X_DAC_CTRL2);
279 reg = (reg & (~AD193X_DAC_WORD_LEN_MASK)) | word_len; 316 reg = (reg & (~AD193X_DAC_WORD_LEN_MASK)) | word_len;
280 snd_soc_write(codec, AD193X_DAC_CTRL2, reg); 317 snd_soc_write(codec, AD193X_DAC_CTRL2, reg);
@@ -348,6 +385,7 @@ static int ad193x_bus_probe(struct device *dev, void *ctrl_data, int bus_type)
348 /* pll input: mclki/xi */ 385 /* pll input: mclki/xi */
349 snd_soc_write(codec, AD193X_PLL_CLK_CTRL0, 0x99); /* mclk=24.576Mhz: 0x9D; mclk=12.288Mhz: 0x99 */ 386 snd_soc_write(codec, AD193X_PLL_CLK_CTRL0, 0x99); /* mclk=24.576Mhz: 0x9D; mclk=12.288Mhz: 0x99 */
350 snd_soc_write(codec, AD193X_PLL_CLK_CTRL1, 0x04); 387 snd_soc_write(codec, AD193X_PLL_CLK_CTRL1, 0x04);
388 ad193x->sysclk = 12288000;
351 389
352 ret = snd_soc_register_codec(codec); 390 ret = snd_soc_register_codec(codec);
353 if (ret != 0) { 391 if (ret != 0) {
@@ -383,6 +421,7 @@ static struct snd_soc_dai_ops ad193x_dai_ops = {
383 .hw_params = ad193x_hw_params, 421 .hw_params = ad193x_hw_params,
384 .digital_mute = ad193x_mute, 422 .digital_mute = ad193x_mute,
385 .set_tdm_slot = ad193x_set_tdm_slot, 423 .set_tdm_slot = ad193x_set_tdm_slot,
424 .set_sysclk = ad193x_set_dai_sysclk,
386 .set_fmt = ad193x_set_dai_fmt, 425 .set_fmt = ad193x_set_dai_fmt,
387}; 426};
388 427
diff --git a/sound/soc/codecs/ad193x.h b/sound/soc/codecs/ad193x.h
index a03c880d52f9..654ba64ae04c 100644
--- a/sound/soc/codecs/ad193x.h
+++ b/sound/soc/codecs/ad193x.h
@@ -11,6 +11,11 @@
11 11
12#define AD193X_PLL_CLK_CTRL0 0x800 12#define AD193X_PLL_CLK_CTRL0 0x800
13#define AD193X_PLL_POWERDOWN 0x01 13#define AD193X_PLL_POWERDOWN 0x01
14#define AD193X_PLL_INPUT_MASK (~0x6)
15#define AD193X_PLL_INPUT_256 (0 << 1)
16#define AD193X_PLL_INPUT_384 (1 << 1)
17#define AD193X_PLL_INPUT_512 (2 << 1)
18#define AD193X_PLL_INPUT_768 (3 << 1)
14#define AD193X_PLL_CLK_CTRL1 0x801 19#define AD193X_PLL_CLK_CTRL1 0x801
15#define AD193X_DAC_CTRL0 0x802 20#define AD193X_DAC_CTRL0 0x802
16#define AD193X_DAC_POWERDOWN 0x01 21#define AD193X_DAC_POWERDOWN 0x01
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c
index 7528a54102b5..3d7dc55305ec 100644
--- a/sound/soc/codecs/ak4642.c
+++ b/sound/soc/codecs/ak4642.c
@@ -22,20 +22,13 @@
22 * AK4643 is tested. 22 * AK4643 is tested.
23 */ 23 */
24 24
25#include <linux/module.h>
26#include <linux/moduleparam.h>
27#include <linux/init.h>
28#include <linux/delay.h> 25#include <linux/delay.h>
29#include <linux/pm.h>
30#include <linux/i2c.h> 26#include <linux/i2c.h>
31#include <linux/platform_device.h> 27#include <linux/platform_device.h>
32#include <linux/slab.h> 28#include <linux/slab.h>
33#include <sound/core.h>
34#include <sound/pcm.h>
35#include <sound/pcm_params.h>
36#include <sound/soc.h>
37#include <sound/soc-dapm.h> 29#include <sound/soc-dapm.h>
38#include <sound/initval.h> 30#include <sound/initval.h>
31#include <sound/tlv.h>
39 32
40#include "ak4642.h" 33#include "ak4642.h"
41 34
@@ -111,6 +104,23 @@
111 104
112struct snd_soc_codec_device soc_codec_dev_ak4642; 105struct snd_soc_codec_device soc_codec_dev_ak4642;
113 106
107/*
108 * Playback Volume (table 39)
109 *
110 * max : 0x00 : +12.0 dB
111 * ( 0.5 dB step )
112 * min : 0xFE : -115.0 dB
113 * mute: 0xFF
114 */
115static const DECLARE_TLV_DB_SCALE(out_tlv, -11500, 50, 1);
116
117static const struct snd_kcontrol_new ak4642_snd_controls[] = {
118
119 SOC_DOUBLE_R_TLV("Digital Playback Volume", L_DVC, R_DVC,
120 0, 0xFF, 1, out_tlv),
121};
122
123
114/* codec private data */ 124/* codec private data */
115struct ak4642_priv { 125struct ak4642_priv {
116 struct snd_soc_codec codec; 126 struct snd_soc_codec codec;
@@ -204,7 +214,6 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream,
204 * 214 *
205 * PLL, Master Mode 215 * PLL, Master Mode
206 * Audio I/F Format :MSB justified (ADC & DAC) 216 * Audio I/F Format :MSB justified (ADC & DAC)
207 * Digital Volume: -8dB
208 * Bass Boost Level : Middle 217 * Bass Boost Level : Middle
209 * 218 *
210 * This operation came from example code of 219 * This operation came from example code of
@@ -214,8 +223,6 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream,
214 ak4642_write(codec, 0x0e, 0x19); 223 ak4642_write(codec, 0x0e, 0x19);
215 ak4642_write(codec, 0x09, 0x91); 224 ak4642_write(codec, 0x09, 0x91);
216 ak4642_write(codec, 0x0c, 0x91); 225 ak4642_write(codec, 0x0c, 0x91);
217 ak4642_write(codec, 0x0a, 0x28);
218 ak4642_write(codec, 0x0d, 0x28);
219 ak4642_write(codec, 0x00, 0x64); 226 ak4642_write(codec, 0x00, 0x64);
220 snd_soc_update_bits(codec, PW_MGMT2, PMHP_MASK, PMHP); 227 snd_soc_update_bits(codec, PW_MGMT2, PMHP_MASK, PMHP);
221 snd_soc_update_bits(codec, PW_MGMT2, HPMTN, HPMTN); 228 snd_soc_update_bits(codec, PW_MGMT2, HPMTN, HPMTN);
@@ -491,8 +498,10 @@ static int ak4642_i2c_probe(struct i2c_client *i2c,
491 codec->control_data = i2c; 498 codec->control_data = i2c;
492 499
493 ret = ak4642_init(ak4642); 500 ret = ak4642_init(ak4642);
494 if (ret < 0) 501 if (ret < 0) {
495 printk(KERN_ERR "failed to initialise AK4642\n"); 502 printk(KERN_ERR "failed to initialise AK4642\n");
503 kfree(ak4642);
504 }
496 505
497 return ret; 506 return ret;
498} 507}
@@ -548,6 +557,9 @@ static int ak4642_probe(struct platform_device *pdev)
548 goto pcm_err; 557 goto pcm_err;
549 } 558 }
550 559
560 snd_soc_add_controls(ak4642_codec, ak4642_snd_controls,
561 ARRAY_SIZE(ak4642_snd_controls));
562
551 dev_info(&pdev->dev, "AK4642 Audio Codec %s", AK4642_VERSION); 563 dev_info(&pdev->dev, "AK4642 Audio Codec %s", AK4642_VERSION);
552 return ret; 564 return ret;
553 565
diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c
new file mode 100644
index 000000000000..dd9b8550c402
--- /dev/null
+++ b/sound/soc/codecs/cs42l51.c
@@ -0,0 +1,763 @@
1/*
2 * cs42l51.c
3 *
4 * ASoC Driver for Cirrus Logic CS42L51 codecs
5 *
6 * Copyright (c) 2010 Arnaud Patard <apatard@mandriva.com>
7 *
8 * Based on cs4270.c - Copyright (c) Freescale Semiconductor
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * For now:
20 * - Only I2C is support. Not SPI
21 * - master mode *NOT* supported
22 */
23
24#include <linux/module.h>
25#include <linux/platform_device.h>
26#include <linux/slab.h>
27#include <sound/core.h>
28#include <sound/soc.h>
29#include <sound/soc-dapm.h>
30#include <sound/tlv.h>
31#include <sound/initval.h>
32#include <sound/pcm_params.h>
33#include <sound/pcm.h>
34#include <linux/i2c.h>
35
36#include "cs42l51.h"
37
38enum master_slave_mode {
39 MODE_SLAVE,
40 MODE_SLAVE_AUTO,
41 MODE_MASTER,
42};
43
44struct cs42l51_private {
45 unsigned int mclk;
46 unsigned int audio_mode; /* The mode (I2S or left-justified) */
47 enum master_slave_mode func;
48 struct snd_soc_codec codec;
49 u8 reg_cache[CS42L51_NUMREGS];
50};
51
52static struct snd_soc_codec *cs42l51_codec;
53
54#define CS42L51_FORMATS ( \
55 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \
56 SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \
57 SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \
58 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE)
59
60static int cs42l51_fill_cache(struct snd_soc_codec *codec)
61{
62 u8 *cache = codec->reg_cache + 1;
63 struct i2c_client *i2c_client = codec->control_data;
64 s32 length;
65
66 length = i2c_smbus_read_i2c_block_data(i2c_client,
67 CS42L51_FIRSTREG | 0x80, CS42L51_NUMREGS, cache);
68 if (length != CS42L51_NUMREGS) {
69 dev_err(&i2c_client->dev,
70 "I2C read failure, addr=0x%x (ret=%d vs %d)\n",
71 i2c_client->addr, length, CS42L51_NUMREGS);
72 return -EIO;
73 }
74
75 return 0;
76}
77
78static int cs42l51_i2c_probe(struct i2c_client *i2c_client,
79 const struct i2c_device_id *id)
80{
81 struct snd_soc_codec *codec;
82 struct cs42l51_private *cs42l51;
83 int ret = 0;
84 int reg;
85
86 if (cs42l51_codec)
87 return -EBUSY;
88
89 /* Verify that we have a CS42L51 */
90 ret = i2c_smbus_read_byte_data(i2c_client, CS42L51_CHIP_REV_ID);
91 if (ret < 0) {
92 dev_err(&i2c_client->dev, "failed to read I2C\n");
93 goto error;
94 }
95
96 if ((ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_A)) &&
97 (ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_B))) {
98 dev_err(&i2c_client->dev, "Invalid chip id\n");
99 ret = -ENODEV;
100 goto error;
101 }
102
103 dev_info(&i2c_client->dev, "found device cs42l51 rev %d\n",
104 ret & 7);
105
106 cs42l51 = kzalloc(sizeof(struct cs42l51_private), GFP_KERNEL);
107 if (!cs42l51) {
108 dev_err(&i2c_client->dev, "could not allocate codec\n");
109 return -ENOMEM;
110 }
111 codec = &cs42l51->codec;
112
113 mutex_init(&codec->mutex);
114 INIT_LIST_HEAD(&codec->dapm_widgets);
115 INIT_LIST_HEAD(&codec->dapm_paths);
116
117 codec->dev = &i2c_client->dev;
118 codec->name = "CS42L51";
119 codec->owner = THIS_MODULE;
120 codec->dai = &cs42l51_dai;
121 codec->num_dai = 1;
122 snd_soc_codec_set_drvdata(codec, cs42l51);
123
124 codec->control_data = i2c_client;
125 codec->reg_cache = cs42l51->reg_cache;
126 codec->reg_cache_size = CS42L51_NUMREGS;
127 i2c_set_clientdata(i2c_client, codec);
128
129 ret = cs42l51_fill_cache(codec);
130 if (ret < 0) {
131 dev_err(&i2c_client->dev, "failed to fill register cache\n");
132 goto error_alloc;
133 }
134
135 ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
136 if (ret < 0) {
137 dev_err(&i2c_client->dev, "Failed to set cache I/O: %d\n", ret);
138 goto error_alloc;
139 }
140
141 /*
142 * DAC configuration
143 * - Use signal processor
144 * - auto mute
145 * - vol changes immediate
146 * - no de-emphasize
147 */
148 reg = CS42L51_DAC_CTL_DATA_SEL(1)
149 | CS42L51_DAC_CTL_AMUTE | CS42L51_DAC_CTL_DACSZ(0);
150 ret = snd_soc_write(codec, CS42L51_DAC_CTL, reg);
151 if (ret < 0)
152 goto error_alloc;
153
154 cs42l51_dai.dev = codec->dev;
155 cs42l51_codec = codec;
156
157 ret = snd_soc_register_codec(codec);
158 if (ret != 0) {
159 dev_err(codec->dev, "Failed to register codec: %d\n", ret);
160 goto error_alloc;
161 }
162
163 ret = snd_soc_register_dai(&cs42l51_dai);
164 if (ret < 0) {
165 dev_err(&i2c_client->dev, "failed to register DAIe\n");
166 goto error_reg;
167 }
168
169 return 0;
170
171error_reg:
172 snd_soc_unregister_codec(codec);
173error_alloc:
174 kfree(cs42l51);
175error:
176 return ret;
177}
178
179static int cs42l51_i2c_remove(struct i2c_client *client)
180{
181 struct cs42l51_private *cs42l51 = i2c_get_clientdata(client);
182 snd_soc_unregister_dai(&cs42l51_dai);
183 snd_soc_unregister_codec(cs42l51_codec);
184 cs42l51_codec = NULL;
185 kfree(cs42l51);
186 return 0;
187}
188
189
190static const struct i2c_device_id cs42l51_id[] = {
191 {"cs42l51", 0},
192 {}
193};
194MODULE_DEVICE_TABLE(i2c, cs42l51_id);
195
196static struct i2c_driver cs42l51_i2c_driver = {
197 .driver = {
198 .name = "CS42L51 I2C",
199 .owner = THIS_MODULE,
200 },
201 .id_table = cs42l51_id,
202 .probe = cs42l51_i2c_probe,
203 .remove = cs42l51_i2c_remove,
204};
205
206static int cs42l51_get_chan_mix(struct snd_kcontrol *kcontrol,
207 struct snd_ctl_elem_value *ucontrol)
208{
209 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
210 unsigned long value = snd_soc_read(codec, CS42L51_PCM_MIXER)&3;
211
212 switch (value) {
213 default:
214 case 0:
215 ucontrol->value.integer.value[0] = 0;
216 break;
217 /* same value : (L+R)/2 and (R+L)/2 */
218 case 1:
219 case 2:
220 ucontrol->value.integer.value[0] = 1;
221 break;
222 case 3:
223 ucontrol->value.integer.value[0] = 2;
224 break;
225 }
226
227 return 0;
228}
229
230#define CHAN_MIX_NORMAL 0x00
231#define CHAN_MIX_BOTH 0x55
232#define CHAN_MIX_SWAP 0xFF
233
234static int cs42l51_set_chan_mix(struct snd_kcontrol *kcontrol,
235 struct snd_ctl_elem_value *ucontrol)
236{
237 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
238 unsigned char val;
239
240 switch (ucontrol->value.integer.value[0]) {
241 default:
242 case 0:
243 val = CHAN_MIX_NORMAL;
244 break;
245 case 1:
246 val = CHAN_MIX_BOTH;
247 break;
248 case 2:
249 val = CHAN_MIX_SWAP;
250 break;
251 }
252
253 snd_soc_write(codec, CS42L51_PCM_MIXER, val);
254
255 return 1;
256}
257
258static const DECLARE_TLV_DB_SCALE(adc_pcm_tlv, -5150, 50, 0);
259static const DECLARE_TLV_DB_SCALE(tone_tlv, -1050, 150, 0);
260/* This is a lie. after -102 db, it stays at -102 */
261/* maybe a range would be better */
262static const DECLARE_TLV_DB_SCALE(aout_tlv, -11550, 50, 0);
263
264static const DECLARE_TLV_DB_SCALE(boost_tlv, 1600, 1600, 0);
265static const char *chan_mix[] = {
266 "L R",
267 "L+R",
268 "R L",
269};
270
271static const struct soc_enum cs42l51_chan_mix =
272 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(chan_mix), chan_mix);
273
274static const struct snd_kcontrol_new cs42l51_snd_controls[] = {
275 SOC_DOUBLE_R_SX_TLV("PCM Playback Volume",
276 CS42L51_PCMA_VOL, CS42L51_PCMB_VOL,
277 7, 0xffffff99, 0x18, adc_pcm_tlv),
278 SOC_DOUBLE_R("PCM Playback Switch",
279 CS42L51_PCMA_VOL, CS42L51_PCMB_VOL, 7, 1, 1),
280 SOC_DOUBLE_R_SX_TLV("Analog Playback Volume",
281 CS42L51_AOUTA_VOL, CS42L51_AOUTB_VOL,
282 8, 0xffffff19, 0x18, aout_tlv),
283 SOC_DOUBLE_R_SX_TLV("ADC Mixer Volume",
284 CS42L51_ADCA_VOL, CS42L51_ADCB_VOL,
285 7, 0xffffff99, 0x18, adc_pcm_tlv),
286 SOC_DOUBLE_R("ADC Mixer Switch",
287 CS42L51_ADCA_VOL, CS42L51_ADCB_VOL, 7, 1, 1),
288 SOC_SINGLE("Playback Deemphasis Switch", CS42L51_DAC_CTL, 3, 1, 0),
289 SOC_SINGLE("Auto-Mute Switch", CS42L51_DAC_CTL, 2, 1, 0),
290 SOC_SINGLE("Soft Ramp Switch", CS42L51_DAC_CTL, 1, 1, 0),
291 SOC_SINGLE("Zero Cross Switch", CS42L51_DAC_CTL, 0, 0, 0),
292 SOC_DOUBLE_TLV("Mic Boost Volume",
293 CS42L51_MIC_CTL, 0, 1, 1, 0, boost_tlv),
294 SOC_SINGLE_TLV("Bass Volume", CS42L51_TONE_CTL, 0, 0xf, 1, tone_tlv),
295 SOC_SINGLE_TLV("Treble Volume", CS42L51_TONE_CTL, 4, 0xf, 1, tone_tlv),
296 SOC_ENUM_EXT("PCM channel mixer",
297 cs42l51_chan_mix,
298 cs42l51_get_chan_mix, cs42l51_set_chan_mix),
299};
300
301/*
302 * to power down, one must:
303 * 1.) Enable the PDN bit
304 * 2.) enable power-down for the select channels
305 * 3.) disable the PDN bit.
306 */
307static int cs42l51_pdn_event(struct snd_soc_dapm_widget *w,
308 struct snd_kcontrol *kcontrol, int event)
309{
310 unsigned long value;
311
312 value = snd_soc_read(w->codec, CS42L51_POWER_CTL1);
313 value &= ~CS42L51_POWER_CTL1_PDN;
314
315 switch (event) {
316 case SND_SOC_DAPM_PRE_PMD:
317 value |= CS42L51_POWER_CTL1_PDN;
318 break;
319 default:
320 case SND_SOC_DAPM_POST_PMD:
321 break;
322 }
323 snd_soc_update_bits(w->codec, CS42L51_POWER_CTL1,
324 CS42L51_POWER_CTL1_PDN, value);
325
326 return 0;
327}
328
329static const char *cs42l51_dac_names[] = {"Direct PCM",
330 "DSP PCM", "ADC"};
331static const struct soc_enum cs42l51_dac_mux_enum =
332 SOC_ENUM_SINGLE(CS42L51_DAC_CTL, 6, 3, cs42l51_dac_names);
333static const struct snd_kcontrol_new cs42l51_dac_mux_controls =
334 SOC_DAPM_ENUM("Route", cs42l51_dac_mux_enum);
335
336static const char *cs42l51_adcl_names[] = {"AIN1 Left", "AIN2 Left",
337 "MIC Left", "MIC+preamp Left"};
338static const struct soc_enum cs42l51_adcl_mux_enum =
339 SOC_ENUM_SINGLE(CS42L51_ADC_INPUT, 4, 4, cs42l51_adcl_names);
340static const struct snd_kcontrol_new cs42l51_adcl_mux_controls =
341 SOC_DAPM_ENUM("Route", cs42l51_adcl_mux_enum);
342
343static const char *cs42l51_adcr_names[] = {"AIN1 Right", "AIN2 Right",
344 "MIC Right", "MIC+preamp Right"};
345static const struct soc_enum cs42l51_adcr_mux_enum =
346 SOC_ENUM_SINGLE(CS42L51_ADC_INPUT, 6, 4, cs42l51_adcr_names);
347static const struct snd_kcontrol_new cs42l51_adcr_mux_controls =
348 SOC_DAPM_ENUM("Route", cs42l51_adcr_mux_enum);
349
350static const struct snd_soc_dapm_widget cs42l51_dapm_widgets[] = {
351 SND_SOC_DAPM_MICBIAS("Mic Bias", CS42L51_MIC_POWER_CTL, 1, 1),
352 SND_SOC_DAPM_PGA_E("Left PGA", CS42L51_POWER_CTL1, 3, 1, NULL, 0,
353 cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
354 SND_SOC_DAPM_PGA_E("Right PGA", CS42L51_POWER_CTL1, 4, 1, NULL, 0,
355 cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
356 SND_SOC_DAPM_ADC_E("Left ADC", "Left HiFi Capture",
357 CS42L51_POWER_CTL1, 1, 1,
358 cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
359 SND_SOC_DAPM_ADC_E("Right ADC", "Right HiFi Capture",
360 CS42L51_POWER_CTL1, 2, 1,
361 cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
362 SND_SOC_DAPM_DAC_E("Left DAC", "Left HiFi Playback",
363 CS42L51_POWER_CTL1, 5, 1,
364 cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
365 SND_SOC_DAPM_DAC_E("Right DAC", "Right HiFi Playback",
366 CS42L51_POWER_CTL1, 6, 1,
367 cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
368
369 /* analog/mic */
370 SND_SOC_DAPM_INPUT("AIN1L"),
371 SND_SOC_DAPM_INPUT("AIN1R"),
372 SND_SOC_DAPM_INPUT("AIN2L"),
373 SND_SOC_DAPM_INPUT("AIN2R"),
374 SND_SOC_DAPM_INPUT("MICL"),
375 SND_SOC_DAPM_INPUT("MICR"),
376
377 SND_SOC_DAPM_MIXER("Mic Preamp Left",
378 CS42L51_MIC_POWER_CTL, 2, 1, NULL, 0),
379 SND_SOC_DAPM_MIXER("Mic Preamp Right",
380 CS42L51_MIC_POWER_CTL, 3, 1, NULL, 0),
381
382 /* HP */
383 SND_SOC_DAPM_OUTPUT("HPL"),
384 SND_SOC_DAPM_OUTPUT("HPR"),
385
386 /* mux */
387 SND_SOC_DAPM_MUX("DAC Mux", SND_SOC_NOPM, 0, 0,
388 &cs42l51_dac_mux_controls),
389 SND_SOC_DAPM_MUX("PGA-ADC Mux Left", SND_SOC_NOPM, 0, 0,
390 &cs42l51_adcl_mux_controls),
391 SND_SOC_DAPM_MUX("PGA-ADC Mux Right", SND_SOC_NOPM, 0, 0,
392 &cs42l51_adcr_mux_controls),
393};
394
395static const struct snd_soc_dapm_route cs42l51_routes[] = {
396 {"HPL", NULL, "Left DAC"},
397 {"HPR", NULL, "Right DAC"},
398
399 {"Left ADC", NULL, "Left PGA"},
400 {"Right ADC", NULL, "Right PGA"},
401
402 {"Mic Preamp Left", NULL, "MICL"},
403 {"Mic Preamp Right", NULL, "MICR"},
404
405 {"PGA-ADC Mux Left", "AIN1 Left", "AIN1L" },
406 {"PGA-ADC Mux Left", "AIN2 Left", "AIN2L" },
407 {"PGA-ADC Mux Left", "MIC Left", "MICL" },
408 {"PGA-ADC Mux Left", "MIC+preamp Left", "Mic Preamp Left" },
409 {"PGA-ADC Mux Right", "AIN1 Right", "AIN1R" },
410 {"PGA-ADC Mux Right", "AIN2 Right", "AIN2R" },
411 {"PGA-ADC Mux Right", "MIC Right", "MICR" },
412 {"PGA-ADC Mux Right", "MIC+preamp Right", "Mic Preamp Right" },
413
414 {"Left PGA", NULL, "PGA-ADC Mux Left"},
415 {"Right PGA", NULL, "PGA-ADC Mux Right"},
416};
417
418static int cs42l51_set_dai_fmt(struct snd_soc_dai *codec_dai,
419 unsigned int format)
420{
421 struct snd_soc_codec *codec = codec_dai->codec;
422 struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
423 int ret = 0;
424
425 switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
426 case SND_SOC_DAIFMT_I2S:
427 case SND_SOC_DAIFMT_LEFT_J:
428 case SND_SOC_DAIFMT_RIGHT_J:
429 cs42l51->audio_mode = format & SND_SOC_DAIFMT_FORMAT_MASK;
430 break;
431 default:
432 dev_err(codec->dev, "invalid DAI format\n");
433 ret = -EINVAL;
434 }
435
436 switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
437 case SND_SOC_DAIFMT_CBM_CFM:
438 cs42l51->func = MODE_MASTER;
439 break;
440 case SND_SOC_DAIFMT_CBS_CFS:
441 cs42l51->func = MODE_SLAVE_AUTO;
442 break;
443 default:
444 ret = -EINVAL;
445 break;
446 }
447
448 return ret;
449}
450
451struct cs42l51_ratios {
452 unsigned int ratio;
453 unsigned char speed_mode;
454 unsigned char mclk;
455};
456
457static struct cs42l51_ratios slave_ratios[] = {
458 { 512, CS42L51_QSM_MODE, 0 }, { 768, CS42L51_QSM_MODE, 0 },
459 { 1024, CS42L51_QSM_MODE, 0 }, { 1536, CS42L51_QSM_MODE, 0 },
460 { 2048, CS42L51_QSM_MODE, 0 }, { 3072, CS42L51_QSM_MODE, 0 },
461 { 256, CS42L51_HSM_MODE, 0 }, { 384, CS42L51_HSM_MODE, 0 },
462 { 512, CS42L51_HSM_MODE, 0 }, { 768, CS42L51_HSM_MODE, 0 },
463 { 1024, CS42L51_HSM_MODE, 0 }, { 1536, CS42L51_HSM_MODE, 0 },
464 { 128, CS42L51_SSM_MODE, 0 }, { 192, CS42L51_SSM_MODE, 0 },
465 { 256, CS42L51_SSM_MODE, 0 }, { 384, CS42L51_SSM_MODE, 0 },
466 { 512, CS42L51_SSM_MODE, 0 }, { 768, CS42L51_SSM_MODE, 0 },
467 { 128, CS42L51_DSM_MODE, 0 }, { 192, CS42L51_DSM_MODE, 0 },
468 { 256, CS42L51_DSM_MODE, 0 }, { 384, CS42L51_DSM_MODE, 0 },
469};
470
471static struct cs42l51_ratios slave_auto_ratios[] = {
472 { 1024, CS42L51_QSM_MODE, 0 }, { 1536, CS42L51_QSM_MODE, 0 },
473 { 2048, CS42L51_QSM_MODE, 1 }, { 3072, CS42L51_QSM_MODE, 1 },
474 { 512, CS42L51_HSM_MODE, 0 }, { 768, CS42L51_HSM_MODE, 0 },
475 { 1024, CS42L51_HSM_MODE, 1 }, { 1536, CS42L51_HSM_MODE, 1 },
476 { 256, CS42L51_SSM_MODE, 0 }, { 384, CS42L51_SSM_MODE, 0 },
477 { 512, CS42L51_SSM_MODE, 1 }, { 768, CS42L51_SSM_MODE, 1 },
478 { 128, CS42L51_DSM_MODE, 0 }, { 192, CS42L51_DSM_MODE, 0 },
479 { 256, CS42L51_DSM_MODE, 1 }, { 384, CS42L51_DSM_MODE, 1 },
480};
481
482static int cs42l51_set_dai_sysclk(struct snd_soc_dai *codec_dai,
483 int clk_id, unsigned int freq, int dir)
484{
485 struct snd_soc_codec *codec = codec_dai->codec;
486 struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
487 struct cs42l51_ratios *ratios = NULL;
488 int nr_ratios = 0;
489 unsigned int rates = 0;
490 unsigned int rate_min = -1;
491 unsigned int rate_max = 0;
492 int i;
493
494 cs42l51->mclk = freq;
495
496 switch (cs42l51->func) {
497 case MODE_MASTER:
498 return -EINVAL;
499 case MODE_SLAVE:
500 ratios = slave_ratios;
501 nr_ratios = ARRAY_SIZE(slave_ratios);
502 break;
503 case MODE_SLAVE_AUTO:
504 ratios = slave_auto_ratios;
505 nr_ratios = ARRAY_SIZE(slave_auto_ratios);
506 break;
507 }
508
509 for (i = 0; i < nr_ratios; i++) {
510 unsigned int rate = freq / ratios[i].ratio;
511 rates |= snd_pcm_rate_to_rate_bit(rate);
512 if (rate < rate_min)
513 rate_min = rate;
514 if (rate > rate_max)
515 rate_max = rate;
516 }
517 rates &= ~SNDRV_PCM_RATE_KNOT;
518
519 if (!rates) {
520 dev_err(codec->dev, "could not find a valid sample rate\n");
521 return -EINVAL;
522 }
523
524 codec_dai->playback.rates = rates;
525 codec_dai->playback.rate_min = rate_min;
526 codec_dai->playback.rate_max = rate_max;
527
528 codec_dai->capture.rates = rates;
529 codec_dai->capture.rate_min = rate_min;
530 codec_dai->capture.rate_max = rate_max;
531
532 return 0;
533}
534
535static int cs42l51_hw_params(struct snd_pcm_substream *substream,
536 struct snd_pcm_hw_params *params,
537 struct snd_soc_dai *dai)
538{
539 struct snd_soc_pcm_runtime *rtd = substream->private_data;
540 struct snd_soc_device *socdev = rtd->socdev;
541 struct snd_soc_codec *codec = socdev->card->codec;
542 struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
543 int ret;
544 unsigned int i;
545 unsigned int rate;
546 unsigned int ratio;
547 struct cs42l51_ratios *ratios = NULL;
548 int nr_ratios = 0;
549 int intf_ctl, power_ctl, fmt;
550
551 switch (cs42l51->func) {
552 case MODE_MASTER:
553 return -EINVAL;
554 case MODE_SLAVE:
555 ratios = slave_ratios;
556 nr_ratios = ARRAY_SIZE(slave_ratios);
557 break;
558 case MODE_SLAVE_AUTO:
559 ratios = slave_auto_ratios;
560 nr_ratios = ARRAY_SIZE(slave_auto_ratios);
561 break;
562 }
563
564 /* Figure out which MCLK/LRCK ratio to use */
565 rate = params_rate(params); /* Sampling rate, in Hz */
566 ratio = cs42l51->mclk / rate; /* MCLK/LRCK ratio */
567 for (i = 0; i < nr_ratios; i++) {
568 if (ratios[i].ratio == ratio)
569 break;
570 }
571
572 if (i == nr_ratios) {
573 /* We did not find a matching ratio */
574 dev_err(codec->dev, "could not find matching ratio\n");
575 return -EINVAL;
576 }
577
578 intf_ctl = snd_soc_read(codec, CS42L51_INTF_CTL);
579 power_ctl = snd_soc_read(codec, CS42L51_MIC_POWER_CTL);
580
581 intf_ctl &= ~(CS42L51_INTF_CTL_MASTER | CS42L51_INTF_CTL_ADC_I2S
582 | CS42L51_INTF_CTL_DAC_FORMAT(7));
583 power_ctl &= ~(CS42L51_MIC_POWER_CTL_SPEED(3)
584 | CS42L51_MIC_POWER_CTL_MCLK_DIV2);
585
586 switch (cs42l51->func) {
587 case MODE_MASTER:
588 intf_ctl |= CS42L51_INTF_CTL_MASTER;
589 power_ctl |= CS42L51_MIC_POWER_CTL_SPEED(ratios[i].speed_mode);
590 break;
591 case MODE_SLAVE:
592 power_ctl |= CS42L51_MIC_POWER_CTL_SPEED(ratios[i].speed_mode);
593 break;
594 case MODE_SLAVE_AUTO:
595 power_ctl |= CS42L51_MIC_POWER_CTL_AUTO;
596 break;
597 }
598
599 switch (cs42l51->audio_mode) {
600 case SND_SOC_DAIFMT_I2S:
601 intf_ctl |= CS42L51_INTF_CTL_ADC_I2S;
602 intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(CS42L51_DAC_DIF_I2S);
603 break;
604 case SND_SOC_DAIFMT_LEFT_J:
605 intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(CS42L51_DAC_DIF_LJ24);
606 break;
607 case SND_SOC_DAIFMT_RIGHT_J:
608 switch (params_format(params)) {
609 case SNDRV_PCM_FORMAT_S16_LE:
610 case SNDRV_PCM_FORMAT_S16_BE:
611 fmt = CS42L51_DAC_DIF_RJ16;
612 break;
613 case SNDRV_PCM_FORMAT_S18_3LE:
614 case SNDRV_PCM_FORMAT_S18_3BE:
615 fmt = CS42L51_DAC_DIF_RJ18;
616 break;
617 case SNDRV_PCM_FORMAT_S20_3LE:
618 case SNDRV_PCM_FORMAT_S20_3BE:
619 fmt = CS42L51_DAC_DIF_RJ20;
620 break;
621 case SNDRV_PCM_FORMAT_S24_LE:
622 case SNDRV_PCM_FORMAT_S24_BE:
623 fmt = CS42L51_DAC_DIF_RJ24;
624 break;
625 default:
626 dev_err(codec->dev, "unknown format\n");
627 return -EINVAL;
628 }
629 intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(fmt);
630 break;
631 default:
632 dev_err(codec->dev, "unknown format\n");
633 return -EINVAL;
634 }
635
636 if (ratios[i].mclk)
637 power_ctl |= CS42L51_MIC_POWER_CTL_MCLK_DIV2;
638
639 ret = snd_soc_write(codec, CS42L51_INTF_CTL, intf_ctl);
640 if (ret < 0)
641 return ret;
642
643 ret = snd_soc_write(codec, CS42L51_MIC_POWER_CTL, power_ctl);
644 if (ret < 0)
645 return ret;
646
647 return 0;
648}
649
650static int cs42l51_dai_mute(struct snd_soc_dai *dai, int mute)
651{
652 struct snd_soc_codec *codec = dai->codec;
653 int reg;
654 int mask = CS42L51_DAC_OUT_CTL_DACA_MUTE|CS42L51_DAC_OUT_CTL_DACB_MUTE;
655
656 reg = snd_soc_read(codec, CS42L51_DAC_OUT_CTL);
657
658 if (mute)
659 reg |= mask;
660 else
661 reg &= ~mask;
662
663 return snd_soc_write(codec, CS42L51_DAC_OUT_CTL, reg);
664}
665
666static struct snd_soc_dai_ops cs42l51_dai_ops = {
667 .hw_params = cs42l51_hw_params,
668 .set_sysclk = cs42l51_set_dai_sysclk,
669 .set_fmt = cs42l51_set_dai_fmt,
670 .digital_mute = cs42l51_dai_mute,
671};
672
673struct snd_soc_dai cs42l51_dai = {
674 .name = "CS42L51 HiFi",
675 .playback = {
676 .stream_name = "Playback",
677 .channels_min = 1,
678 .channels_max = 2,
679 .rates = SNDRV_PCM_RATE_8000_96000,
680 .formats = CS42L51_FORMATS,
681 },
682 .capture = {
683 .stream_name = "Capture",
684 .channels_min = 1,
685 .channels_max = 2,
686 .rates = SNDRV_PCM_RATE_8000_96000,
687 .formats = CS42L51_FORMATS,
688 },
689 .ops = &cs42l51_dai_ops,
690};
691EXPORT_SYMBOL_GPL(cs42l51_dai);
692
693
694static int cs42l51_probe(struct platform_device *pdev)
695{
696 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
697 struct snd_soc_codec *codec;
698 int ret = 0;
699
700 if (!cs42l51_codec) {
701 dev_err(&pdev->dev, "CS42L51 codec not yet registered\n");
702 return -EINVAL;
703 }
704
705 socdev->card->codec = cs42l51_codec;
706 codec = socdev->card->codec;
707
708 /* Register PCMs */
709 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
710 if (ret < 0) {
711 dev_err(&pdev->dev, "failed to create PCMs\n");
712 return ret;
713 }
714
715 snd_soc_add_controls(codec, cs42l51_snd_controls,
716 ARRAY_SIZE(cs42l51_snd_controls));
717 snd_soc_dapm_new_controls(codec, cs42l51_dapm_widgets,
718 ARRAY_SIZE(cs42l51_dapm_widgets));
719 snd_soc_dapm_add_routes(codec, cs42l51_routes,
720 ARRAY_SIZE(cs42l51_routes));
721
722 return 0;
723}
724
725
726static int cs42l51_remove(struct platform_device *pdev)
727{
728 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
729
730 snd_soc_free_pcms(socdev);
731 snd_soc_dapm_free(socdev);
732
733 return 0;
734}
735
736struct snd_soc_codec_device soc_codec_device_cs42l51 = {
737 .probe = cs42l51_probe,
738 .remove = cs42l51_remove
739};
740EXPORT_SYMBOL_GPL(soc_codec_device_cs42l51);
741
742static int __init cs42l51_init(void)
743{
744 int ret;
745
746 ret = i2c_add_driver(&cs42l51_i2c_driver);
747 if (ret != 0) {
748 printk(KERN_ERR "%s: can't add i2c driver\n", __func__);
749 return ret;
750 }
751 return 0;
752}
753module_init(cs42l51_init);
754
755static void __exit cs42l51_exit(void)
756{
757 i2c_del_driver(&cs42l51_i2c_driver);
758}
759module_exit(cs42l51_exit);
760
761MODULE_AUTHOR("Arnaud Patard <apatard@mandriva.com>");
762MODULE_DESCRIPTION("Cirrus Logic CS42L51 ALSA SoC Codec Driver");
763MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs42l51.h b/sound/soc/codecs/cs42l51.h
new file mode 100644
index 000000000000..8f0bd9786ad2
--- /dev/null
+++ b/sound/soc/codecs/cs42l51.h
@@ -0,0 +1,163 @@
1/*
2 * cs42l51.h
3 *
4 * ASoC Driver for Cirrus Logic CS42L51 codecs
5 *
6 * Copyright (c) 2010 Arnaud Patard <apatard@mandriva.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 */
18#ifndef _CS42L51_H
19#define _CS42L51_H
20
21#define CS42L51_CHIP_ID 0x1B
22#define CS42L51_CHIP_REV_A 0x00
23#define CS42L51_CHIP_REV_B 0x01
24
25#define CS42L51_CHIP_REV_ID 0x01
26#define CS42L51_MK_CHIP_REV(a, b) ((a)<<3|(b))
27
28#define CS42L51_POWER_CTL1 0x02
29#define CS42L51_POWER_CTL1_PDN_DACB (1<<6)
30#define CS42L51_POWER_CTL1_PDN_DACA (1<<5)
31#define CS42L51_POWER_CTL1_PDN_PGAB (1<<4)
32#define CS42L51_POWER_CTL1_PDN_PGAA (1<<3)
33#define CS42L51_POWER_CTL1_PDN_ADCB (1<<2)
34#define CS42L51_POWER_CTL1_PDN_ADCA (1<<1)
35#define CS42L51_POWER_CTL1_PDN (1<<0)
36
37#define CS42L51_MIC_POWER_CTL 0x03
38#define CS42L51_MIC_POWER_CTL_AUTO (1<<7)
39#define CS42L51_MIC_POWER_CTL_SPEED(x) (((x)&3)<<5)
40#define CS42L51_QSM_MODE 3
41#define CS42L51_HSM_MODE 2
42#define CS42L51_SSM_MODE 1
43#define CS42L51_DSM_MODE 0
44#define CS42L51_MIC_POWER_CTL_3ST_SP (1<<4)
45#define CS42L51_MIC_POWER_CTL_PDN_MICB (1<<3)
46#define CS42L51_MIC_POWER_CTL_PDN_MICA (1<<2)
47#define CS42L51_MIC_POWER_CTL_PDN_BIAS (1<<1)
48#define CS42L51_MIC_POWER_CTL_MCLK_DIV2 (1<<0)
49
50#define CS42L51_INTF_CTL 0x04
51#define CS42L51_INTF_CTL_LOOPBACK (1<<7)
52#define CS42L51_INTF_CTL_MASTER (1<<6)
53#define CS42L51_INTF_CTL_DAC_FORMAT(x) (((x)&7)<<3)
54#define CS42L51_DAC_DIF_LJ24 0x00
55#define CS42L51_DAC_DIF_I2S 0x01
56#define CS42L51_DAC_DIF_RJ24 0x02
57#define CS42L51_DAC_DIF_RJ20 0x03
58#define CS42L51_DAC_DIF_RJ18 0x04
59#define CS42L51_DAC_DIF_RJ16 0x05
60#define CS42L51_INTF_CTL_ADC_I2S (1<<2)
61#define CS42L51_INTF_CTL_DIGMIX (1<<1)
62#define CS42L51_INTF_CTL_MICMIX (1<<0)
63
64#define CS42L51_MIC_CTL 0x05
65#define CS42L51_MIC_CTL_ADC_SNGVOL (1<<7)
66#define CS42L51_MIC_CTL_ADCD_DBOOST (1<<6)
67#define CS42L51_MIC_CTL_ADCA_DBOOST (1<<5)
68#define CS42L51_MIC_CTL_MICBIAS_SEL (1<<4)
69#define CS42L51_MIC_CTL_MICBIAS_LVL(x) (((x)&3)<<2)
70#define CS42L51_MIC_CTL_MICB_BOOST (1<<1)
71#define CS42L51_MIC_CTL_MICA_BOOST (1<<0)
72
73#define CS42L51_ADC_CTL 0x06
74#define CS42L51_ADC_CTL_ADCB_HPFEN (1<<7)
75#define CS42L51_ADC_CTL_ADCB_HPFRZ (1<<6)
76#define CS42L51_ADC_CTL_ADCA_HPFEN (1<<5)
77#define CS42L51_ADC_CTL_ADCA_HPFRZ (1<<4)
78#define CS42L51_ADC_CTL_SOFTB (1<<3)
79#define CS42L51_ADC_CTL_ZCROSSB (1<<2)
80#define CS42L51_ADC_CTL_SOFTA (1<<1)
81#define CS42L51_ADC_CTL_ZCROSSA (1<<0)
82
83#define CS42L51_ADC_INPUT 0x07
84#define CS42L51_ADC_INPUT_AINB_MUX(x) (((x)&3)<<6)
85#define CS42L51_ADC_INPUT_AINA_MUX(x) (((x)&3)<<4)
86#define CS42L51_ADC_INPUT_INV_ADCB (1<<3)
87#define CS42L51_ADC_INPUT_INV_ADCA (1<<2)
88#define CS42L51_ADC_INPUT_ADCB_MUTE (1<<1)
89#define CS42L51_ADC_INPUT_ADCA_MUTE (1<<0)
90
91#define CS42L51_DAC_OUT_CTL 0x08
92#define CS42L51_DAC_OUT_CTL_HP_GAIN(x) (((x)&7)<<5)
93#define CS42L51_DAC_OUT_CTL_DAC_SNGVOL (1<<4)
94#define CS42L51_DAC_OUT_CTL_INV_PCMB (1<<3)
95#define CS42L51_DAC_OUT_CTL_INV_PCMA (1<<2)
96#define CS42L51_DAC_OUT_CTL_DACB_MUTE (1<<1)
97#define CS42L51_DAC_OUT_CTL_DACA_MUTE (1<<0)
98
99#define CS42L51_DAC_CTL 0x09
100#define CS42L51_DAC_CTL_DATA_SEL(x) (((x)&3)<<6)
101#define CS42L51_DAC_CTL_FREEZE (1<<5)
102#define CS42L51_DAC_CTL_DEEMPH (1<<3)
103#define CS42L51_DAC_CTL_AMUTE (1<<2)
104#define CS42L51_DAC_CTL_DACSZ(x) (((x)&3)<<0)
105
106#define CS42L51_ALC_PGA_CTL 0x0A
107#define CS42L51_ALC_PGB_CTL 0x0B
108#define CS42L51_ALC_PGX_ALCX_SRDIS (1<<7)
109#define CS42L51_ALC_PGX_ALCX_ZCDIS (1<<6)
110#define CS42L51_ALC_PGX_PGX_VOL(x) (((x)&0x1f)<<0)
111
112#define CS42L51_ADCA_ATT 0x0C
113#define CS42L51_ADCB_ATT 0x0D
114
115#define CS42L51_ADCA_VOL 0x0E
116#define CS42L51_ADCB_VOL 0x0F
117#define CS42L51_PCMA_VOL 0x10
118#define CS42L51_PCMB_VOL 0x11
119#define CS42L51_MIX_MUTE_ADCMIX (1<<7)
120#define CS42L51_MIX_VOLUME(x) (((x)&0x7f)<<0)
121
122#define CS42L51_BEEP_FREQ 0x12
123#define CS42L51_BEEP_VOL 0x13
124#define CS42L51_BEEP_CONF 0x14
125
126#define CS42L51_TONE_CTL 0x15
127#define CS42L51_TONE_CTL_TREB(x) (((x)&0xf)<<4)
128#define CS42L51_TONE_CTL_BASS(x) (((x)&0xf)<<0)
129
130#define CS42L51_AOUTA_VOL 0x16
131#define CS42L51_AOUTB_VOL 0x17
132#define CS42L51_PCM_MIXER 0x18
133#define CS42L51_LIMIT_THRES_DIS 0x19
134#define CS42L51_LIMIT_REL 0x1A
135#define CS42L51_LIMIT_ATT 0x1B
136#define CS42L51_ALC_EN 0x1C
137#define CS42L51_ALC_REL 0x1D
138#define CS42L51_ALC_THRES 0x1E
139#define CS42L51_NOISE_CONF 0x1F
140
141#define CS42L51_STATUS 0x20
142#define CS42L51_STATUS_SP_CLKERR (1<<6)
143#define CS42L51_STATUS_SPEA_OVFL (1<<5)
144#define CS42L51_STATUS_SPEB_OVFL (1<<4)
145#define CS42L51_STATUS_PCMA_OVFL (1<<3)
146#define CS42L51_STATUS_PCMB_OVFL (1<<2)
147#define CS42L51_STATUS_ADCA_OVFL (1<<1)
148#define CS42L51_STATUS_ADCB_OVFL (1<<0)
149
150#define CS42L51_CHARGE_FREQ 0x21
151
152#define CS42L51_FIRSTREG 0x01
153/*
154 * Hack: with register 0x21, it makes 33 registers. Looks like someone in the
155 * i2c layer doesn't like i2c smbus block read of 33 regs. Workaround by using
156 * 32 regs
157 */
158#define CS42L51_LASTREG 0x20
159#define CS42L51_NUMREGS (CS42L51_LASTREG - CS42L51_FIRSTREG + 1)
160
161extern struct snd_soc_dai cs42l51_dai;
162extern struct snd_soc_codec_device soc_codec_device_cs42l51;
163#endif
diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c
index 75af2d6e0e78..3c51d6a57523 100644
--- a/sound/soc/codecs/da7210.c
+++ b/sound/soc/codecs/da7210.c
@@ -15,23 +15,15 @@
15 * option) any later version. 15 * option) any later version.
16 */ 16 */
17 17
18#include <linux/module.h>
19#include <linux/moduleparam.h>
20#include <linux/kernel.h>
21#include <linux/init.h>
22#include <linux/delay.h> 18#include <linux/delay.h>
23#include <linux/pm.h>
24#include <linux/i2c.h> 19#include <linux/i2c.h>
25#include <linux/platform_device.h> 20#include <linux/platform_device.h>
26#include <linux/slab.h> 21#include <linux/slab.h>
27#include <sound/core.h>
28#include <sound/pcm.h> 22#include <sound/pcm.h>
29#include <sound/pcm_params.h> 23#include <sound/pcm_params.h>
30#include <sound/soc.h>
31#include <sound/soc-dapm.h> 24#include <sound/soc-dapm.h>
32#include <sound/tlv.h>
33#include <sound/initval.h> 25#include <sound/initval.h>
34#include <asm/div64.h> 26#include <sound/tlv.h>
35 27
36#include "da7210.h" 28#include "da7210.h"
37 29
@@ -145,6 +137,29 @@
145 137
146#define DA7210_VERSION "0.0.1" 138#define DA7210_VERSION "0.0.1"
147 139
140/*
141 * Playback Volume
142 *
143 * max : 0x3F (+15.0 dB)
144 * (1.5 dB step)
145 * min : 0x11 (-54.0 dB)
146 * mute : 0x10
147 * reserved : 0x00 - 0x0F
148 *
149 * ** FIXME **
150 *
151 * Reserved area are considered as "mute".
152 * -> min = -79.5 dB
153 */
154static const DECLARE_TLV_DB_SCALE(hp_out_tlv, -7950, 150, 1);
155
156static const struct snd_kcontrol_new da7210_snd_controls[] = {
157
158 SOC_DOUBLE_R_TLV("HeadPhone Playback Volume",
159 DA7210_HP_L_VOL, DA7210_HP_R_VOL,
160 0, 0x3F, 0, hp_out_tlv),
161};
162
148/* Codec private data */ 163/* Codec private data */
149struct da7210_priv { 164struct da7210_priv {
150 struct snd_soc_codec codec; 165 struct snd_soc_codec codec;
@@ -227,10 +242,6 @@ static int da7210_startup(struct snd_pcm_substream *substream,
227 struct snd_soc_codec *codec = dai->codec; 242 struct snd_soc_codec *codec = dai->codec;
228 243
229 if (is_play) { 244 if (is_play) {
230 /* PlayBack Volume 40 */
231 snd_soc_update_bits(codec, DA7210_HP_L_VOL, 0x3F, 40);
232 snd_soc_update_bits(codec, DA7210_HP_R_VOL, 0x3F, 40);
233
234 /* Enable Out */ 245 /* Enable Out */
235 snd_soc_update_bits(codec, DA7210_OUTMIX_L, 0x1F, 0x10); 246 snd_soc_update_bits(codec, DA7210_OUTMIX_L, 0x1F, 0x10);
236 snd_soc_update_bits(codec, DA7210_OUTMIX_R, 0x1F, 0x10); 247 snd_soc_update_bits(codec, DA7210_OUTMIX_R, 0x1F, 0x10);
@@ -488,7 +499,7 @@ static int da7210_init(struct da7210_priv *da7210)
488 ret = snd_soc_register_dai(&da7210_dai); 499 ret = snd_soc_register_dai(&da7210_dai);
489 if (ret) { 500 if (ret) {
490 dev_err(codec->dev, "Failed to register DAI: %d\n", ret); 501 dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
491 goto init_err; 502 goto codec_err;
492 } 503 }
493 504
494 /* FIXME 505 /* FIXME
@@ -574,6 +585,8 @@ static int da7210_init(struct da7210_priv *da7210)
574 585
575 return ret; 586 return ret;
576 587
588codec_err:
589 snd_soc_unregister_codec(codec);
577init_err: 590init_err:
578 kfree(codec->reg_cache); 591 kfree(codec->reg_cache);
579 codec->reg_cache = NULL; 592 codec->reg_cache = NULL;
@@ -601,8 +614,10 @@ static int __devinit da7210_i2c_probe(struct i2c_client *i2c,
601 codec->control_data = i2c; 614 codec->control_data = i2c;
602 615
603 ret = da7210_init(da7210); 616 ret = da7210_init(da7210);
604 if (ret < 0) 617 if (ret < 0) {
605 pr_err("Failed to initialise da7210 audio codec\n"); 618 pr_err("Failed to initialise da7210 audio codec\n");
619 kfree(da7210);
620 }
606 621
607 return ret; 622 return ret;
608} 623}
@@ -656,6 +671,9 @@ static int da7210_probe(struct platform_device *pdev)
656 if (ret < 0) 671 if (ret < 0)
657 goto pcm_err; 672 goto pcm_err;
658 673
674 snd_soc_add_controls(da7210_codec, da7210_snd_controls,
675 ARRAY_SIZE(da7210_snd_controls));
676
659 dev_info(&pdev->dev, "DA7210 Audio Codec %s\n", DA7210_VERSION); 677 dev_info(&pdev->dev, "DA7210 Audio Codec %s\n", DA7210_VERSION);
660 678
661pcm_err: 679pcm_err:
diff --git a/sound/soc/codecs/jz4740.c b/sound/soc/codecs/jz4740.c
new file mode 100644
index 000000000000..66557de1e4fe
--- /dev/null
+++ b/sound/soc/codecs/jz4740.c
@@ -0,0 +1,511 @@
1/*
2 * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * You should have received a copy of the GNU General Public License along
9 * with this program; if not, write to the Free Software Foundation, Inc.,
10 * 675 Mass Ave, Cambridge, MA 02139, USA.
11 *
12 */
13
14#include <linux/kernel.h>
15#include <linux/module.h>
16#include <linux/platform_device.h>
17#include <linux/slab.h>
18
19#include <linux/delay.h>
20
21#include <sound/core.h>
22#include <sound/pcm.h>
23#include <sound/pcm_params.h>
24#include <sound/initval.h>
25#include <sound/soc-dapm.h>
26#include <sound/soc.h>
27
28#define JZ4740_REG_CODEC_1 0x0
29#define JZ4740_REG_CODEC_2 0x1
30
31#define JZ4740_CODEC_1_LINE_ENABLE BIT(29)
32#define JZ4740_CODEC_1_MIC_ENABLE BIT(28)
33#define JZ4740_CODEC_1_SW1_ENABLE BIT(27)
34#define JZ4740_CODEC_1_ADC_ENABLE BIT(26)
35#define JZ4740_CODEC_1_SW2_ENABLE BIT(25)
36#define JZ4740_CODEC_1_DAC_ENABLE BIT(24)
37#define JZ4740_CODEC_1_VREF_DISABLE BIT(20)
38#define JZ4740_CODEC_1_VREF_AMP_DISABLE BIT(19)
39#define JZ4740_CODEC_1_VREF_PULLDOWN BIT(18)
40#define JZ4740_CODEC_1_VREF_LOW_CURRENT BIT(17)
41#define JZ4740_CODEC_1_VREF_HIGH_CURRENT BIT(16)
42#define JZ4740_CODEC_1_HEADPHONE_DISABLE BIT(14)
43#define JZ4740_CODEC_1_HEADPHONE_AMP_CHANGE_ANY BIT(13)
44#define JZ4740_CODEC_1_HEADPHONE_CHARGE BIT(12)
45#define JZ4740_CODEC_1_HEADPHONE_PULLDOWN (BIT(11) | BIT(10))
46#define JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M BIT(9)
47#define JZ4740_CODEC_1_HEADPHONE_POWERDOWN BIT(8)
48#define JZ4740_CODEC_1_SUSPEND BIT(1)
49#define JZ4740_CODEC_1_RESET BIT(0)
50
51#define JZ4740_CODEC_1_LINE_ENABLE_OFFSET 29
52#define JZ4740_CODEC_1_MIC_ENABLE_OFFSET 28
53#define JZ4740_CODEC_1_SW1_ENABLE_OFFSET 27
54#define JZ4740_CODEC_1_ADC_ENABLE_OFFSET 26
55#define JZ4740_CODEC_1_SW2_ENABLE_OFFSET 25
56#define JZ4740_CODEC_1_DAC_ENABLE_OFFSET 24
57#define JZ4740_CODEC_1_HEADPHONE_DISABLE_OFFSET 14
58#define JZ4740_CODEC_1_HEADPHONE_POWERDOWN_OFFSET 8
59
60#define JZ4740_CODEC_2_INPUT_VOLUME_MASK 0x1f0000
61#define JZ4740_CODEC_2_SAMPLE_RATE_MASK 0x000f00
62#define JZ4740_CODEC_2_MIC_BOOST_GAIN_MASK 0x000030
63#define JZ4740_CODEC_2_HEADPHONE_VOLUME_MASK 0x000003
64
65#define JZ4740_CODEC_2_INPUT_VOLUME_OFFSET 16
66#define JZ4740_CODEC_2_SAMPLE_RATE_OFFSET 8
67#define JZ4740_CODEC_2_MIC_BOOST_GAIN_OFFSET 4
68#define JZ4740_CODEC_2_HEADPHONE_VOLUME_OFFSET 0
69
70static const uint32_t jz4740_codec_regs[] = {
71 0x021b2302, 0x00170803,
72};
73
74struct jz4740_codec {
75 void __iomem *base;
76 struct resource *mem;
77
78 uint32_t reg_cache[2];
79 struct snd_soc_codec codec;
80};
81
82static inline struct jz4740_codec *codec_to_jz4740(struct snd_soc_codec *codec)
83{
84 return container_of(codec, struct jz4740_codec, codec);
85}
86
87static unsigned int jz4740_codec_read(struct snd_soc_codec *codec,
88 unsigned int reg)
89{
90 struct jz4740_codec *jz4740_codec = codec_to_jz4740(codec);
91 return readl(jz4740_codec->base + (reg << 2));
92}
93
94static int jz4740_codec_write(struct snd_soc_codec *codec, unsigned int reg,
95 unsigned int val)
96{
97 struct jz4740_codec *jz4740_codec = codec_to_jz4740(codec);
98
99 jz4740_codec->reg_cache[reg] = val;
100 writel(val, jz4740_codec->base + (reg << 2));
101
102 return 0;
103}
104
105static const struct snd_kcontrol_new jz4740_codec_controls[] = {
106 SOC_SINGLE("Master Playback Volume", JZ4740_REG_CODEC_2,
107 JZ4740_CODEC_2_HEADPHONE_VOLUME_OFFSET, 3, 0),
108 SOC_SINGLE("Master Capture Volume", JZ4740_REG_CODEC_2,
109 JZ4740_CODEC_2_INPUT_VOLUME_OFFSET, 31, 0),
110 SOC_SINGLE("Master Playback Switch", JZ4740_REG_CODEC_1,
111 JZ4740_CODEC_1_HEADPHONE_DISABLE_OFFSET, 1, 1),
112 SOC_SINGLE("Mic Capture Volume", JZ4740_REG_CODEC_2,
113 JZ4740_CODEC_2_MIC_BOOST_GAIN_OFFSET, 3, 0),
114};
115
116static const struct snd_kcontrol_new jz4740_codec_output_controls[] = {
117 SOC_DAPM_SINGLE("Bypass Switch", JZ4740_REG_CODEC_1,
118 JZ4740_CODEC_1_SW1_ENABLE_OFFSET, 1, 0),
119 SOC_DAPM_SINGLE("DAC Switch", JZ4740_REG_CODEC_1,
120 JZ4740_CODEC_1_SW2_ENABLE_OFFSET, 1, 0),
121};
122
123static const struct snd_kcontrol_new jz4740_codec_input_controls[] = {
124 SOC_DAPM_SINGLE("Line Capture Switch", JZ4740_REG_CODEC_1,
125 JZ4740_CODEC_1_LINE_ENABLE_OFFSET, 1, 0),
126 SOC_DAPM_SINGLE("Mic Capture Switch", JZ4740_REG_CODEC_1,
127 JZ4740_CODEC_1_MIC_ENABLE_OFFSET, 1, 0),
128};
129
130static const struct snd_soc_dapm_widget jz4740_codec_dapm_widgets[] = {
131 SND_SOC_DAPM_ADC("ADC", "Capture", JZ4740_REG_CODEC_1,
132 JZ4740_CODEC_1_ADC_ENABLE_OFFSET, 0),
133 SND_SOC_DAPM_DAC("DAC", "Playback", JZ4740_REG_CODEC_1,
134 JZ4740_CODEC_1_DAC_ENABLE_OFFSET, 0),
135
136 SND_SOC_DAPM_MIXER("Output Mixer", JZ4740_REG_CODEC_1,
137 JZ4740_CODEC_1_HEADPHONE_POWERDOWN_OFFSET, 1,
138 jz4740_codec_output_controls,
139 ARRAY_SIZE(jz4740_codec_output_controls)),
140
141 SND_SOC_DAPM_MIXER_NAMED_CTL("Input Mixer", SND_SOC_NOPM, 0, 0,
142 jz4740_codec_input_controls,
143 ARRAY_SIZE(jz4740_codec_input_controls)),
144 SND_SOC_DAPM_MIXER("Line Input", SND_SOC_NOPM, 0, 0, NULL, 0),
145
146 SND_SOC_DAPM_OUTPUT("LOUT"),
147 SND_SOC_DAPM_OUTPUT("ROUT"),
148
149 SND_SOC_DAPM_INPUT("MIC"),
150 SND_SOC_DAPM_INPUT("LIN"),
151 SND_SOC_DAPM_INPUT("RIN"),
152};
153
154static const struct snd_soc_dapm_route jz4740_codec_dapm_routes[] = {
155 {"Line Input", NULL, "LIN"},
156 {"Line Input", NULL, "RIN"},
157
158 {"Input Mixer", "Line Capture Switch", "Line Input"},
159 {"Input Mixer", "Mic Capture Switch", "MIC"},
160
161 {"ADC", NULL, "Input Mixer"},
162
163 {"Output Mixer", "Bypass Switch", "Input Mixer"},
164 {"Output Mixer", "DAC Switch", "DAC"},
165
166 {"LOUT", NULL, "Output Mixer"},
167 {"ROUT", NULL, "Output Mixer"},
168};
169
170static int jz4740_codec_hw_params(struct snd_pcm_substream *substream,
171 struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
172{
173 uint32_t val;
174 struct snd_soc_pcm_runtime *rtd = substream->private_data;
175 struct snd_soc_device *socdev = rtd->socdev;
176 struct snd_soc_codec *codec = socdev->card->codec;
177
178 switch (params_rate(params)) {
179 case 8000:
180 val = 0;
181 break;
182 case 11025:
183 val = 1;
184 break;
185 case 12000:
186 val = 2;
187 break;
188 case 16000:
189 val = 3;
190 break;
191 case 22050:
192 val = 4;
193 break;
194 case 24000:
195 val = 5;
196 break;
197 case 32000:
198 val = 6;
199 break;
200 case 44100:
201 val = 7;
202 break;
203 case 48000:
204 val = 8;
205 break;
206 default:
207 return -EINVAL;
208 }
209
210 val <<= JZ4740_CODEC_2_SAMPLE_RATE_OFFSET;
211
212 snd_soc_update_bits(codec, JZ4740_REG_CODEC_2,
213 JZ4740_CODEC_2_SAMPLE_RATE_MASK, val);
214
215 return 0;
216}
217
218static struct snd_soc_dai_ops jz4740_codec_dai_ops = {
219 .hw_params = jz4740_codec_hw_params,
220};
221
222struct snd_soc_dai jz4740_codec_dai = {
223 .name = "jz4740",
224 .playback = {
225 .stream_name = "Playback",
226 .channels_min = 2,
227 .channels_max = 2,
228 .rates = SNDRV_PCM_RATE_8000_48000,
229 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8,
230 },
231 .capture = {
232 .stream_name = "Capture",
233 .channels_min = 2,
234 .channels_max = 2,
235 .rates = SNDRV_PCM_RATE_8000_48000,
236 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8,
237 },
238 .ops = &jz4740_codec_dai_ops,
239 .symmetric_rates = 1,
240};
241EXPORT_SYMBOL_GPL(jz4740_codec_dai);
242
243static void jz4740_codec_wakeup(struct snd_soc_codec *codec)
244{
245 int i;
246 uint32_t *cache = codec->reg_cache;
247
248 snd_soc_update_bits(codec, JZ4740_REG_CODEC_1,
249 JZ4740_CODEC_1_RESET, JZ4740_CODEC_1_RESET);
250 udelay(2);
251
252 snd_soc_update_bits(codec, JZ4740_REG_CODEC_1,
253 JZ4740_CODEC_1_SUSPEND | JZ4740_CODEC_1_RESET, 0);
254
255 for (i = 0; i < ARRAY_SIZE(jz4740_codec_regs); ++i)
256 jz4740_codec_write(codec, i, cache[i]);
257}
258
259static int jz4740_codec_set_bias_level(struct snd_soc_codec *codec,
260 enum snd_soc_bias_level level)
261{
262 unsigned int mask;
263 unsigned int value;
264
265 switch (level) {
266 case SND_SOC_BIAS_ON:
267 break;
268 case SND_SOC_BIAS_PREPARE:
269 mask = JZ4740_CODEC_1_VREF_DISABLE |
270 JZ4740_CODEC_1_VREF_AMP_DISABLE |
271 JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M;
272 value = 0;
273
274 snd_soc_update_bits(codec, JZ4740_REG_CODEC_1, mask, value);
275 break;
276 case SND_SOC_BIAS_STANDBY:
277 /* The only way to clear the suspend flag is to reset the codec */
278 if (codec->bias_level == SND_SOC_BIAS_OFF)
279 jz4740_codec_wakeup(codec);
280
281 mask = JZ4740_CODEC_1_VREF_DISABLE |
282 JZ4740_CODEC_1_VREF_AMP_DISABLE |
283 JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M;
284 value = JZ4740_CODEC_1_VREF_DISABLE |
285 JZ4740_CODEC_1_VREF_AMP_DISABLE |
286 JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M;
287
288 snd_soc_update_bits(codec, JZ4740_REG_CODEC_1, mask, value);
289 break;
290 case SND_SOC_BIAS_OFF:
291 mask = JZ4740_CODEC_1_SUSPEND;
292 value = JZ4740_CODEC_1_SUSPEND;
293
294 snd_soc_update_bits(codec, JZ4740_REG_CODEC_1, mask, value);
295 break;
296 default:
297 break;
298 }
299
300 codec->bias_level = level;
301
302 return 0;
303}
304
305static struct snd_soc_codec *jz4740_codec_codec;
306
307static int jz4740_codec_dev_probe(struct platform_device *pdev)
308{
309 int ret;
310 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
311 struct snd_soc_codec *codec = jz4740_codec_codec;
312
313 BUG_ON(!codec);
314
315 socdev->card->codec = codec;
316
317 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
318 if (ret) {
319 dev_err(&pdev->dev, "Failed to create pcms: %d\n", ret);
320 return ret;
321 }
322
323 snd_soc_add_controls(codec, jz4740_codec_controls,
324 ARRAY_SIZE(jz4740_codec_controls));
325
326 snd_soc_dapm_new_controls(codec, jz4740_codec_dapm_widgets,
327 ARRAY_SIZE(jz4740_codec_dapm_widgets));
328
329 snd_soc_dapm_add_routes(codec, jz4740_codec_dapm_routes,
330 ARRAY_SIZE(jz4740_codec_dapm_routes));
331
332 snd_soc_dapm_new_widgets(codec);
333
334 return 0;
335}
336
337static int jz4740_codec_dev_remove(struct platform_device *pdev)
338{
339 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
340
341 snd_soc_free_pcms(socdev);
342 snd_soc_dapm_free(socdev);
343
344 return 0;
345}
346
347#ifdef CONFIG_PM_SLEEP
348
349static int jz4740_codec_suspend(struct platform_device *pdev, pm_message_t state)
350{
351 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
352 struct snd_soc_codec *codec = socdev->card->codec;
353
354 return jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_OFF);
355}
356
357static int jz4740_codec_resume(struct platform_device *pdev)
358{
359 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
360 struct snd_soc_codec *codec = socdev->card->codec;
361
362 return jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
363}
364
365#else
366#define jz4740_codec_suspend NULL
367#define jz4740_codec_resume NULL
368#endif
369
370struct snd_soc_codec_device soc_codec_dev_jz4740_codec = {
371 .probe = jz4740_codec_dev_probe,
372 .remove = jz4740_codec_dev_remove,
373 .suspend = jz4740_codec_suspend,
374 .resume = jz4740_codec_resume,
375};
376EXPORT_SYMBOL_GPL(soc_codec_dev_jz4740_codec);
377
378static int __devinit jz4740_codec_probe(struct platform_device *pdev)
379{
380 int ret;
381 struct jz4740_codec *jz4740_codec;
382 struct snd_soc_codec *codec;
383 struct resource *mem;
384
385 jz4740_codec = kzalloc(sizeof(*jz4740_codec), GFP_KERNEL);
386 if (!jz4740_codec)
387 return -ENOMEM;
388
389 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
390 if (!mem) {
391 dev_err(&pdev->dev, "Failed to get mmio memory resource\n");
392 ret = -ENOENT;
393 goto err_free_codec;
394 }
395
396 mem = request_mem_region(mem->start, resource_size(mem), pdev->name);
397 if (!mem) {
398 dev_err(&pdev->dev, "Failed to request mmio memory region\n");
399 ret = -EBUSY;
400 goto err_free_codec;
401 }
402
403 jz4740_codec->base = ioremap(mem->start, resource_size(mem));
404 if (!jz4740_codec->base) {
405 dev_err(&pdev->dev, "Failed to ioremap mmio memory\n");
406 ret = -EBUSY;
407 goto err_release_mem_region;
408 }
409 jz4740_codec->mem = mem;
410
411 jz4740_codec_dai.dev = &pdev->dev;
412
413 codec = &jz4740_codec->codec;
414
415 codec->dev = &pdev->dev;
416 codec->name = "jz4740";
417 codec->owner = THIS_MODULE;
418
419 codec->read = jz4740_codec_read;
420 codec->write = jz4740_codec_write;
421 codec->set_bias_level = jz4740_codec_set_bias_level;
422 codec->bias_level = SND_SOC_BIAS_OFF;
423
424 codec->dai = &jz4740_codec_dai;
425 codec->num_dai = 1;
426
427 codec->reg_cache = jz4740_codec->reg_cache;
428 codec->reg_cache_size = 2;
429 memcpy(codec->reg_cache, jz4740_codec_regs, sizeof(jz4740_codec_regs));
430
431 mutex_init(&codec->mutex);
432 INIT_LIST_HEAD(&codec->dapm_widgets);
433 INIT_LIST_HEAD(&codec->dapm_paths);
434
435 jz4740_codec_codec = codec;
436
437 snd_soc_update_bits(codec, JZ4740_REG_CODEC_1,
438 JZ4740_CODEC_1_SW2_ENABLE, JZ4740_CODEC_1_SW2_ENABLE);
439
440 platform_set_drvdata(pdev, jz4740_codec);
441
442 ret = snd_soc_register_codec(codec);
443 if (ret) {
444 dev_err(&pdev->dev, "Failed to register codec\n");
445 goto err_iounmap;
446 }
447
448 ret = snd_soc_register_dai(&jz4740_codec_dai);
449 if (ret) {
450 dev_err(&pdev->dev, "Failed to register codec dai\n");
451 goto err_unregister_codec;
452 }
453
454 jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
455
456 return 0;
457
458err_unregister_codec:
459 snd_soc_unregister_codec(codec);
460err_iounmap:
461 iounmap(jz4740_codec->base);
462err_release_mem_region:
463 release_mem_region(mem->start, resource_size(mem));
464err_free_codec:
465 kfree(jz4740_codec);
466
467 return ret;
468}
469
470static int __devexit jz4740_codec_remove(struct platform_device *pdev)
471{
472 struct jz4740_codec *jz4740_codec = platform_get_drvdata(pdev);
473 struct resource *mem = jz4740_codec->mem;
474
475 snd_soc_unregister_dai(&jz4740_codec_dai);
476 snd_soc_unregister_codec(&jz4740_codec->codec);
477
478 iounmap(jz4740_codec->base);
479 release_mem_region(mem->start, resource_size(mem));
480
481 platform_set_drvdata(pdev, NULL);
482 kfree(jz4740_codec);
483
484 return 0;
485}
486
487static struct platform_driver jz4740_codec_driver = {
488 .probe = jz4740_codec_probe,
489 .remove = __devexit_p(jz4740_codec_remove),
490 .driver = {
491 .name = "jz4740-codec",
492 .owner = THIS_MODULE,
493 },
494};
495
496static int __init jz4740_codec_init(void)
497{
498 return platform_driver_register(&jz4740_codec_driver);
499}
500module_init(jz4740_codec_init);
501
502static void __exit jz4740_codec_exit(void)
503{
504 platform_driver_unregister(&jz4740_codec_driver);
505}
506module_exit(jz4740_codec_exit);
507
508MODULE_DESCRIPTION("JZ4740 SoC internal codec driver");
509MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
510MODULE_LICENSE("GPL v2");
511MODULE_ALIAS("platform:jz4740-codec");
diff --git a/sound/soc/codecs/jz4740.h b/sound/soc/codecs/jz4740.h
new file mode 100644
index 000000000000..b5a0691be763
--- /dev/null
+++ b/sound/soc/codecs/jz4740.h
@@ -0,0 +1,20 @@
1/*
2 * Copyright (C) 2009, Lars-Peter Clausen <lars@metafoo.de>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * You should have received a copy of the GNU General Public License along
9 * with this program; if not, write to the Free Software Foundation, Inc.,
10 * 675 Mass Ave, Cambridge, MA 02139, USA.
11 *
12 */
13
14#ifndef __SND_SOC_CODECS_JZ4740_CODEC_H__
15#define __SND_SOC_CODECS_JZ4740_CODEC_H__
16
17extern struct snd_soc_dai jz4740_codec_dai;
18extern struct snd_soc_codec_device soc_codec_dev_jz4740_codec;
19
20#endif
diff --git a/sound/soc/codecs/spdif_transciever.c b/sound/soc/codecs/spdif_transciever.c
index a63191141052..9119836051a4 100644
--- a/sound/soc/codecs/spdif_transciever.c
+++ b/sound/soc/codecs/spdif_transciever.c
@@ -16,8 +16,10 @@
16 16
17#include <linux/module.h> 17#include <linux/module.h>
18#include <linux/moduleparam.h> 18#include <linux/moduleparam.h>
19#include <linux/slab.h>
19#include <sound/soc.h> 20#include <sound/soc.h>
20#include <sound/pcm.h> 21#include <sound/pcm.h>
22#include <sound/initval.h>
21 23
22#include "spdif_transciever.h" 24#include "spdif_transciever.h"
23 25
@@ -26,6 +28,48 @@ MODULE_LICENSE("GPL");
26#define STUB_RATES SNDRV_PCM_RATE_8000_96000 28#define STUB_RATES SNDRV_PCM_RATE_8000_96000
27#define STUB_FORMATS SNDRV_PCM_FMTBIT_S16_LE 29#define STUB_FORMATS SNDRV_PCM_FMTBIT_S16_LE
28 30
31static struct snd_soc_codec *spdif_dit_codec;
32
33static int spdif_dit_codec_probe(struct platform_device *pdev)
34{
35 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
36 struct snd_soc_codec *codec;
37 int ret;
38
39 if (spdif_dit_codec == NULL) {
40 dev_err(&pdev->dev, "Codec device not registered\n");
41 return -ENODEV;
42 }
43
44 socdev->card->codec = spdif_dit_codec;
45 codec = spdif_dit_codec;
46
47 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
48 if (ret < 0) {
49 dev_err(codec->dev, "failed to create pcms: %d\n", ret);
50 goto err_create_pcms;
51 }
52
53 return 0;
54
55err_create_pcms:
56 return ret;
57}
58
59static int spdif_dit_codec_remove(struct platform_device *pdev)
60{
61 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
62
63 snd_soc_free_pcms(socdev);
64
65 return 0;
66}
67
68struct snd_soc_codec_device soc_codec_dev_spdif_dit = {
69 .probe = spdif_dit_codec_probe,
70 .remove = spdif_dit_codec_remove,
71}; EXPORT_SYMBOL_GPL(soc_codec_dev_spdif_dit);
72
29struct snd_soc_dai dit_stub_dai = { 73struct snd_soc_dai dit_stub_dai = {
30 .name = "DIT", 74 .name = "DIT",
31 .playback = { 75 .playback = {
@@ -40,13 +84,61 @@ EXPORT_SYMBOL_GPL(dit_stub_dai);
40 84
41static int spdif_dit_probe(struct platform_device *pdev) 85static int spdif_dit_probe(struct platform_device *pdev)
42{ 86{
87 struct snd_soc_codec *codec;
88 int ret;
89
90 if (spdif_dit_codec) {
91 dev_err(&pdev->dev, "Another Codec is registered\n");
92 ret = -EINVAL;
93 goto err_reg_codec;
94 }
95
96 codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
97 if (codec == NULL)
98 return -ENOMEM;
99
100 codec->dev = &pdev->dev;
101
102 mutex_init(&codec->mutex);
103
104 INIT_LIST_HEAD(&codec->dapm_widgets);
105 INIT_LIST_HEAD(&codec->dapm_paths);
106
107 codec->name = "spdif-dit";
108 codec->owner = THIS_MODULE;
109 codec->dai = &dit_stub_dai;
110 codec->num_dai = 1;
111
112 spdif_dit_codec = codec;
113
114 ret = snd_soc_register_codec(codec);
115 if (ret < 0) {
116 dev_err(codec->dev, "Failed to register codec: %d\n", ret);
117 goto err_reg_codec;
118 }
119
43 dit_stub_dai.dev = &pdev->dev; 120 dit_stub_dai.dev = &pdev->dev;
44 return snd_soc_register_dai(&dit_stub_dai); 121 ret = snd_soc_register_dai(&dit_stub_dai);
122 if (ret < 0) {
123 dev_err(codec->dev, "Failed to register dai: %d\n", ret);
124 goto err_reg_dai;
125 }
126
127 return 0;
128
129err_reg_dai:
130 snd_soc_unregister_codec(codec);
131err_reg_codec:
132 kfree(spdif_dit_codec);
133 return ret;
45} 134}
46 135
47static int spdif_dit_remove(struct platform_device *pdev) 136static int spdif_dit_remove(struct platform_device *pdev)
48{ 137{
49 snd_soc_unregister_dai(&dit_stub_dai); 138 snd_soc_unregister_dai(&dit_stub_dai);
139 snd_soc_unregister_codec(spdif_dit_codec);
140 kfree(spdif_dit_codec);
141 spdif_dit_codec = NULL;
50 return 0; 142 return 0;
51} 143}
52 144
diff --git a/sound/soc/codecs/spdif_transciever.h b/sound/soc/codecs/spdif_transciever.h
index 296f2eb6c4ef..1e102124f546 100644
--- a/sound/soc/codecs/spdif_transciever.h
+++ b/sound/soc/codecs/spdif_transciever.h
@@ -12,6 +12,7 @@
12#ifndef CODEC_STUBS_H 12#ifndef CODEC_STUBS_H
13#define CODEC_STUBS_H 13#define CODEC_STUBS_H
14 14
15extern struct snd_soc_codec_device soc_codec_dev_spdif_dit;
15extern struct snd_soc_dai dit_stub_dai; 16extern struct snd_soc_dai dit_stub_dai;
16 17
17#endif /* CODEC_STUBS_H */ 18#endif /* CODEC_STUBS_H */
diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c
index b0bae3508b29..0a4b0fef3355 100644
--- a/sound/soc/codecs/tlv320aic23.c
+++ b/sound/soc/codecs/tlv320aic23.c
@@ -560,13 +560,16 @@ static int tlv320aic23_set_bias_level(struct snd_soc_codec *codec,
560 switch (level) { 560 switch (level) {
561 case SND_SOC_BIAS_ON: 561 case SND_SOC_BIAS_ON:
562 /* vref/mid, osc on, dac unmute */ 562 /* vref/mid, osc on, dac unmute */
563 reg &= ~(TLV320AIC23_DEVICE_PWR_OFF | TLV320AIC23_OSC_OFF | \
564 TLV320AIC23_DAC_OFF);
563 tlv320aic23_write(codec, TLV320AIC23_PWR, reg); 565 tlv320aic23_write(codec, TLV320AIC23_PWR, reg);
564 break; 566 break;
565 case SND_SOC_BIAS_PREPARE: 567 case SND_SOC_BIAS_PREPARE:
566 break; 568 break;
567 case SND_SOC_BIAS_STANDBY: 569 case SND_SOC_BIAS_STANDBY:
568 /* everything off except vref/vmid, */ 570 /* everything off except vref/vmid, */
569 tlv320aic23_write(codec, TLV320AIC23_PWR, reg | 0x0040); 571 tlv320aic23_write(codec, TLV320AIC23_PWR, reg | \
572 TLV320AIC23_CLK_OFF);
570 break; 573 break;
571 case SND_SOC_BIAS_OFF: 574 case SND_SOC_BIAS_OFF:
572 /* everything off, dac mute, inactive */ 575 /* everything off, dac mute, inactive */
@@ -615,7 +618,6 @@ static int tlv320aic23_suspend(struct platform_device *pdev,
615 struct snd_soc_device *socdev = platform_get_drvdata(pdev); 618 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
616 struct snd_soc_codec *codec = socdev->card->codec; 619 struct snd_soc_codec *codec = socdev->card->codec;
617 620
618 tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0);
619 tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF); 621 tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF);
620 622
621 return 0; 623 return 0;
@@ -632,7 +634,6 @@ static int tlv320aic23_resume(struct platform_device *pdev)
632 u16 val = tlv320aic23_read_reg_cache(codec, reg); 634 u16 val = tlv320aic23_read_reg_cache(codec, reg);
633 tlv320aic23_write(codec, reg, val); 635 tlv320aic23_write(codec, reg, val);
634 } 636 }
635
636 tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY); 637 tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
637 638
638 return 0; 639 return 0;
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
index 65adc77eada1..8651b01ed223 100644
--- a/sound/soc/codecs/tlv320dac33.c
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -49,8 +49,6 @@
49 49
50#define NSAMPLE_MAX 5700 50#define NSAMPLE_MAX 5700
51 51
52#define LATENCY_TIME_MS 20
53
54#define MODE7_LTHR 10 52#define MODE7_LTHR 10
55#define MODE7_UTHR (DAC33_BUFFER_SIZE_SAMPLES - 10) 53#define MODE7_UTHR (DAC33_BUFFER_SIZE_SAMPLES - 10)
56 54
@@ -62,6 +60,9 @@
62#define US_TO_SAMPLES(rate, us) \ 60#define US_TO_SAMPLES(rate, us) \
63 (rate / (1000000 / us)) 61 (rate / (1000000 / us))
64 62
63#define UTHR_FROM_PERIOD_SIZE(samples, playrate, burstrate) \
64 ((samples * 5000) / ((burstrate * 5000) / (burstrate - playrate)))
65
65static void dac33_calculate_times(struct snd_pcm_substream *substream); 66static void dac33_calculate_times(struct snd_pcm_substream *substream);
66static int dac33_prepare_chip(struct snd_pcm_substream *substream); 67static int dac33_prepare_chip(struct snd_pcm_substream *substream);
67 68
@@ -107,6 +108,10 @@ struct tlv320dac33_priv {
107 * this */ 108 * this */
108 enum dac33_fifo_modes fifo_mode;/* FIFO mode selection */ 109 enum dac33_fifo_modes fifo_mode;/* FIFO mode selection */
109 unsigned int nsample; /* burst read amount from host */ 110 unsigned int nsample; /* burst read amount from host */
111 int mode1_latency; /* latency caused by the i2c writes in
112 * us */
113 int auto_fifo_config; /* Configure the FIFO based on the
114 * period size */
110 u8 burst_bclkdiv; /* BCLK divider value in burst mode */ 115 u8 burst_bclkdiv; /* BCLK divider value in burst mode */
111 unsigned int burst_rate; /* Interface speed in Burst modes */ 116 unsigned int burst_rate; /* Interface speed in Burst modes */
112 117
@@ -120,6 +125,8 @@ struct tlv320dac33_priv {
120 * samples */ 125 * samples */
121 unsigned int mode7_us_to_lthr; /* Time to reach lthr from uthr */ 126 unsigned int mode7_us_to_lthr; /* Time to reach lthr from uthr */
122 127
128 unsigned int uthr;
129
123 enum dac33_state state; 130 enum dac33_state state;
124}; 131};
125 132
@@ -442,6 +449,39 @@ static int dac33_set_nsample(struct snd_kcontrol *kcontrol,
442 return ret; 449 return ret;
443} 450}
444 451
452static int dac33_get_uthr(struct snd_kcontrol *kcontrol,
453 struct snd_ctl_elem_value *ucontrol)
454{
455 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
456 struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
457
458 ucontrol->value.integer.value[0] = dac33->uthr;
459
460 return 0;
461}
462
463static int dac33_set_uthr(struct snd_kcontrol *kcontrol,
464 struct snd_ctl_elem_value *ucontrol)
465{
466 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
467 struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
468 int ret = 0;
469
470 if (dac33->substream)
471 return -EBUSY;
472
473 if (dac33->uthr == ucontrol->value.integer.value[0])
474 return 0;
475
476 if (ucontrol->value.integer.value[0] < (MODE7_LTHR + 10) ||
477 ucontrol->value.integer.value[0] > MODE7_UTHR)
478 ret = -EINVAL;
479 else
480 dac33->uthr = ucontrol->value.integer.value[0];
481
482 return ret;
483}
484
445static int dac33_get_fifo_mode(struct snd_kcontrol *kcontrol, 485static int dac33_get_fifo_mode(struct snd_kcontrol *kcontrol,
446 struct snd_ctl_elem_value *ucontrol) 486 struct snd_ctl_elem_value *ucontrol)
447{ 487{
@@ -503,13 +543,18 @@ static const struct snd_kcontrol_new dac33_snd_controls[] = {
503 DAC33_LINEL_TO_LLO_VOL, DAC33_LINER_TO_RLO_VOL, 0, 127, 1), 543 DAC33_LINEL_TO_LLO_VOL, DAC33_LINER_TO_RLO_VOL, 0, 127, 1),
504}; 544};
505 545
506static const struct snd_kcontrol_new dac33_nsample_snd_controls[] = { 546static const struct snd_kcontrol_new dac33_mode_snd_controls[] = {
507 SOC_SINGLE_EXT("nSample", 0, 0, 5900, 0,
508 dac33_get_nsample, dac33_set_nsample),
509 SOC_ENUM_EXT("FIFO Mode", dac33_fifo_mode_enum, 547 SOC_ENUM_EXT("FIFO Mode", dac33_fifo_mode_enum,
510 dac33_get_fifo_mode, dac33_set_fifo_mode), 548 dac33_get_fifo_mode, dac33_set_fifo_mode),
511}; 549};
512 550
551static const struct snd_kcontrol_new dac33_fifo_snd_controls[] = {
552 SOC_SINGLE_EXT("nSample", 0, 0, 5900, 0,
553 dac33_get_nsample, dac33_set_nsample),
554 SOC_SINGLE_EXT("UTHR", 0, 0, MODE7_UTHR, 0,
555 dac33_get_uthr, dac33_set_uthr),
556};
557
513/* Analog bypass */ 558/* Analog bypass */
514static const struct snd_kcontrol_new dac33_dapm_abypassl_control = 559static const struct snd_kcontrol_new dac33_dapm_abypassl_control =
515 SOC_DAPM_SINGLE("Switch", DAC33_LINEL_TO_LLO_VOL, 7, 1, 1); 560 SOC_DAPM_SINGLE("Switch", DAC33_LINEL_TO_LLO_VOL, 7, 1, 1);
@@ -612,7 +657,7 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33)
612 switch (dac33->fifo_mode) { 657 switch (dac33->fifo_mode) {
613 case DAC33_FIFO_MODE1: 658 case DAC33_FIFO_MODE1:
614 dac33_write16(codec, DAC33_NSAMPLE_MSB, 659 dac33_write16(codec, DAC33_NSAMPLE_MSB,
615 DAC33_THRREG(dac33->nsample + dac33->alarm_threshold)); 660 DAC33_THRREG(dac33->nsample));
616 661
617 /* Take the timestamps */ 662 /* Take the timestamps */
618 spin_lock_irq(&dac33->lock); 663 spin_lock_irq(&dac33->lock);
@@ -761,6 +806,10 @@ static void dac33_shutdown(struct snd_pcm_substream *substream,
761 struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); 806 struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
762 807
763 dac33->substream = NULL; 808 dac33->substream = NULL;
809
810 /* Reset the nSample restrictions */
811 dac33->nsample_min = 0;
812 dac33->nsample_max = NSAMPLE_MAX;
764} 813}
765 814
766static int dac33_hw_params(struct snd_pcm_substream *substream, 815static int dac33_hw_params(struct snd_pcm_substream *substream,
@@ -985,7 +1034,7 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream)
985 * Configure the threshold levels, and leave 10 sample space 1034 * Configure the threshold levels, and leave 10 sample space
986 * at the bottom, and also at the top of the FIFO 1035 * at the bottom, and also at the top of the FIFO
987 */ 1036 */
988 dac33_write16(codec, DAC33_UTHR_MSB, DAC33_THRREG(MODE7_UTHR)); 1037 dac33_write16(codec, DAC33_UTHR_MSB, DAC33_THRREG(dac33->uthr));
989 dac33_write16(codec, DAC33_LTHR_MSB, DAC33_THRREG(MODE7_LTHR)); 1038 dac33_write16(codec, DAC33_LTHR_MSB, DAC33_THRREG(MODE7_LTHR));
990 break; 1039 break;
991 default: 1040 default:
@@ -1003,57 +1052,71 @@ static void dac33_calculate_times(struct snd_pcm_substream *substream)
1003 struct snd_soc_device *socdev = rtd->socdev; 1052 struct snd_soc_device *socdev = rtd->socdev;
1004 struct snd_soc_codec *codec = socdev->card->codec; 1053 struct snd_soc_codec *codec = socdev->card->codec;
1005 struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); 1054 struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
1055 unsigned int period_size = substream->runtime->period_size;
1056 unsigned int rate = substream->runtime->rate;
1006 unsigned int nsample_limit; 1057 unsigned int nsample_limit;
1007 1058
1008 /* In bypass mode we don't need to calculate */ 1059 /* In bypass mode we don't need to calculate */
1009 if (!dac33->fifo_mode) 1060 if (!dac33->fifo_mode)
1010 return; 1061 return;
1011 1062
1012 /* Number of samples (16bit, stereo) in one period */
1013 dac33->nsample_min = snd_pcm_lib_period_bytes(substream) / 4;
1014
1015 /* Number of samples (16bit, stereo) in ALSA buffer */
1016 dac33->nsample_max = snd_pcm_lib_buffer_bytes(substream) / 4;
1017 /* Subtract one period from the total */
1018 dac33->nsample_max -= dac33->nsample_min;
1019
1020 /* Number of samples for LATENCY_TIME_MS / 2 */
1021 dac33->alarm_threshold = substream->runtime->rate /
1022 (1000 / (LATENCY_TIME_MS / 2));
1023
1024 /* Find and fix up the lowest nsmaple limit */
1025 nsample_limit = substream->runtime->rate / (1000 / LATENCY_TIME_MS);
1026
1027 if (dac33->nsample_min < nsample_limit)
1028 dac33->nsample_min = nsample_limit;
1029
1030 if (dac33->nsample < dac33->nsample_min)
1031 dac33->nsample = dac33->nsample_min;
1032
1033 /*
1034 * Find and fix up the highest nsmaple limit
1035 * In order to not overflow the DAC33 buffer substract the
1036 * alarm_threshold value from the size of the DAC33 buffer
1037 */
1038 nsample_limit = DAC33_BUFFER_SIZE_SAMPLES - dac33->alarm_threshold;
1039
1040 if (dac33->nsample_max > nsample_limit)
1041 dac33->nsample_max = nsample_limit;
1042
1043 if (dac33->nsample > dac33->nsample_max)
1044 dac33->nsample = dac33->nsample_max;
1045
1046 switch (dac33->fifo_mode) { 1063 switch (dac33->fifo_mode) {
1047 case DAC33_FIFO_MODE1: 1064 case DAC33_FIFO_MODE1:
1065 /* Number of samples under i2c latency */
1066 dac33->alarm_threshold = US_TO_SAMPLES(rate,
1067 dac33->mode1_latency);
1068 if (dac33->auto_fifo_config) {
1069 if (period_size <= dac33->alarm_threshold)
1070 /*
1071 * Configure nSamaple to number of periods,
1072 * which covers the latency requironment.
1073 */
1074 dac33->nsample = period_size *
1075 ((dac33->alarm_threshold / period_size) +
1076 (dac33->alarm_threshold % period_size ?
1077 1 : 0));
1078 else
1079 dac33->nsample = period_size;
1080 } else {
1081 /* nSample time shall not be shorter than i2c latency */
1082 dac33->nsample_min = dac33->alarm_threshold;
1083 /*
1084 * nSample should not be bigger than alsa buffer minus
1085 * size of one period to avoid overruns
1086 */
1087 dac33->nsample_max = substream->runtime->buffer_size -
1088 period_size;
1089 nsample_limit = DAC33_BUFFER_SIZE_SAMPLES -
1090 dac33->alarm_threshold;
1091 if (dac33->nsample_max > nsample_limit)
1092 dac33->nsample_max = nsample_limit;
1093
1094 /* Correct the nSample if it is outside of the ranges */
1095 if (dac33->nsample < dac33->nsample_min)
1096 dac33->nsample = dac33->nsample_min;
1097 if (dac33->nsample > dac33->nsample_max)
1098 dac33->nsample = dac33->nsample_max;
1099 }
1100
1048 dac33->mode1_us_burst = SAMPLES_TO_US(dac33->burst_rate, 1101 dac33->mode1_us_burst = SAMPLES_TO_US(dac33->burst_rate,
1049 dac33->nsample); 1102 dac33->nsample);
1050 dac33->t_stamp1 = 0; 1103 dac33->t_stamp1 = 0;
1051 dac33->t_stamp2 = 0; 1104 dac33->t_stamp2 = 0;
1052 break; 1105 break;
1053 case DAC33_FIFO_MODE7: 1106 case DAC33_FIFO_MODE7:
1107 if (dac33->auto_fifo_config) {
1108 dac33->uthr = UTHR_FROM_PERIOD_SIZE(
1109 period_size,
1110 rate,
1111 dac33->burst_rate) + 9;
1112 if (dac33->uthr > MODE7_UTHR)
1113 dac33->uthr = MODE7_UTHR;
1114 if (dac33->uthr < (MODE7_LTHR + 10))
1115 dac33->uthr = (MODE7_LTHR + 10);
1116 }
1054 dac33->mode7_us_to_lthr = 1117 dac33->mode7_us_to_lthr =
1055 SAMPLES_TO_US(substream->runtime->rate, 1118 SAMPLES_TO_US(substream->runtime->rate,
1056 MODE7_UTHR - MODE7_LTHR + 1); 1119 dac33->uthr - MODE7_LTHR + 1);
1057 dac33->t_stamp1 = 0; 1120 dac33->t_stamp1 = 0;
1058 break; 1121 break;
1059 default: 1122 default:
@@ -1104,7 +1167,7 @@ static snd_pcm_sframes_t dac33_dai_delay(
1104 struct snd_soc_codec *codec = socdev->card->codec; 1167 struct snd_soc_codec *codec = socdev->card->codec;
1105 struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); 1168 struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
1106 unsigned long long t0, t1, t_now; 1169 unsigned long long t0, t1, t_now;
1107 unsigned int time_delta; 1170 unsigned int time_delta, uthr;
1108 int samples_out, samples_in, samples; 1171 int samples_out, samples_in, samples;
1109 snd_pcm_sframes_t delay = 0; 1172 snd_pcm_sframes_t delay = 0;
1110 1173
@@ -1182,6 +1245,7 @@ static snd_pcm_sframes_t dac33_dai_delay(
1182 case DAC33_FIFO_MODE7: 1245 case DAC33_FIFO_MODE7:
1183 spin_lock(&dac33->lock); 1246 spin_lock(&dac33->lock);
1184 t0 = dac33->t_stamp1; 1247 t0 = dac33->t_stamp1;
1248 uthr = dac33->uthr;
1185 spin_unlock(&dac33->lock); 1249 spin_unlock(&dac33->lock);
1186 t_now = ktime_to_us(ktime_get()); 1250 t_now = ktime_to_us(ktime_get());
1187 1251
@@ -1194,7 +1258,7 @@ static snd_pcm_sframes_t dac33_dai_delay(
1194 * Either the timestamps are messed or equal. Report 1258 * Either the timestamps are messed or equal. Report
1195 * maximum delay 1259 * maximum delay
1196 */ 1260 */
1197 delay = MODE7_UTHR; 1261 delay = uthr;
1198 goto out; 1262 goto out;
1199 } 1263 }
1200 1264
@@ -1208,8 +1272,8 @@ static snd_pcm_sframes_t dac33_dai_delay(
1208 substream->runtime->rate, 1272 substream->runtime->rate,
1209 time_delta); 1273 time_delta);
1210 1274
1211 if (likely(MODE7_UTHR > samples_out)) 1275 if (likely(uthr > samples_out))
1212 delay = MODE7_UTHR - samples_out; 1276 delay = uthr - samples_out;
1213 else 1277 else
1214 delay = 0; 1278 delay = 0;
1215 } else { 1279 } else {
@@ -1227,8 +1291,8 @@ static snd_pcm_sframes_t dac33_dai_delay(
1227 time_delta); 1291 time_delta);
1228 delay = MODE7_LTHR + samples_in - samples_out; 1292 delay = MODE7_LTHR + samples_in - samples_out;
1229 1293
1230 if (unlikely(delay > MODE7_UTHR)) 1294 if (unlikely(delay > uthr))
1231 delay = MODE7_UTHR; 1295 delay = uthr;
1232 } 1296 }
1233 break; 1297 break;
1234 default: 1298 default:
@@ -1347,10 +1411,15 @@ static int dac33_soc_probe(struct platform_device *pdev)
1347 1411
1348 snd_soc_add_controls(codec, dac33_snd_controls, 1412 snd_soc_add_controls(codec, dac33_snd_controls,
1349 ARRAY_SIZE(dac33_snd_controls)); 1413 ARRAY_SIZE(dac33_snd_controls));
1350 /* Only add the nSample controls, if we have valid IRQ number */ 1414 /* Only add the FIFO controls, if we have valid IRQ number */
1351 if (dac33->irq >= 0) 1415 if (dac33->irq >= 0) {
1352 snd_soc_add_controls(codec, dac33_nsample_snd_controls, 1416 snd_soc_add_controls(codec, dac33_mode_snd_controls,
1353 ARRAY_SIZE(dac33_nsample_snd_controls)); 1417 ARRAY_SIZE(dac33_mode_snd_controls));
1418 /* FIFO usage controls only, if autoio config is not selected */
1419 if (!dac33->auto_fifo_config)
1420 snd_soc_add_controls(codec, dac33_fifo_snd_controls,
1421 ARRAY_SIZE(dac33_fifo_snd_controls));
1422 }
1354 1423
1355 dac33_add_widgets(codec); 1424 dac33_add_widgets(codec);
1356 1425
@@ -1481,9 +1550,14 @@ static int __devinit dac33_i2c_probe(struct i2c_client *client,
1481 /* Pre calculate the burst rate */ 1550 /* Pre calculate the burst rate */
1482 dac33->burst_rate = BURST_BASEFREQ_HZ / dac33->burst_bclkdiv / 32; 1551 dac33->burst_rate = BURST_BASEFREQ_HZ / dac33->burst_bclkdiv / 32;
1483 dac33->keep_bclk = pdata->keep_bclk; 1552 dac33->keep_bclk = pdata->keep_bclk;
1553 dac33->auto_fifo_config = pdata->auto_fifo_config;
1554 dac33->mode1_latency = pdata->mode1_latency;
1555 if (!dac33->mode1_latency)
1556 dac33->mode1_latency = 10000; /* 10ms */
1484 dac33->irq = client->irq; 1557 dac33->irq = client->irq;
1485 dac33->nsample = NSAMPLE_MAX; 1558 dac33->nsample = NSAMPLE_MAX;
1486 dac33->nsample_max = NSAMPLE_MAX; 1559 dac33->nsample_max = NSAMPLE_MAX;
1560 dac33->uthr = MODE7_UTHR;
1487 /* Disable FIFO use by default */ 1561 /* Disable FIFO use by default */
1488 dac33->fifo_mode = DAC33_FIFO_BYPASS; 1562 dac33->fifo_mode = DAC33_FIFO_BYPASS;
1489 1563
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index b4fcdb01fc49..7b618bbff884 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -43,37 +43,37 @@
43 */ 43 */
44static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = { 44static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = {
45 0x00, /* this register not used */ 45 0x00, /* this register not used */
46 0x91, /* REG_CODEC_MODE (0x1) */ 46 0x00, /* REG_CODEC_MODE (0x1) */
47 0xc3, /* REG_OPTION (0x2) */ 47 0x00, /* REG_OPTION (0x2) */
48 0x00, /* REG_UNKNOWN (0x3) */ 48 0x00, /* REG_UNKNOWN (0x3) */
49 0x00, /* REG_MICBIAS_CTL (0x4) */ 49 0x00, /* REG_MICBIAS_CTL (0x4) */
50 0x20, /* REG_ANAMICL (0x5) */ 50 0x00, /* REG_ANAMICL (0x5) */
51 0x00, /* REG_ANAMICR (0x6) */ 51 0x00, /* REG_ANAMICR (0x6) */
52 0x00, /* REG_AVADC_CTL (0x7) */ 52 0x00, /* REG_AVADC_CTL (0x7) */
53 0x00, /* REG_ADCMICSEL (0x8) */ 53 0x00, /* REG_ADCMICSEL (0x8) */
54 0x00, /* REG_DIGMIXING (0x9) */ 54 0x00, /* REG_DIGMIXING (0x9) */
55 0x0c, /* REG_ATXL1PGA (0xA) */ 55 0x0f, /* REG_ATXL1PGA (0xA) */
56 0x0c, /* REG_ATXR1PGA (0xB) */ 56 0x0f, /* REG_ATXR1PGA (0xB) */
57 0x00, /* REG_AVTXL2PGA (0xC) */ 57 0x0f, /* REG_AVTXL2PGA (0xC) */
58 0x00, /* REG_AVTXR2PGA (0xD) */ 58 0x0f, /* REG_AVTXR2PGA (0xD) */
59 0x00, /* REG_AUDIO_IF (0xE) */ 59 0x00, /* REG_AUDIO_IF (0xE) */
60 0x00, /* REG_VOICE_IF (0xF) */ 60 0x00, /* REG_VOICE_IF (0xF) */
61 0x00, /* REG_ARXR1PGA (0x10) */ 61 0x3f, /* REG_ARXR1PGA (0x10) */
62 0x00, /* REG_ARXL1PGA (0x11) */ 62 0x3f, /* REG_ARXL1PGA (0x11) */
63 0x6c, /* REG_ARXR2PGA (0x12) */ 63 0x3f, /* REG_ARXR2PGA (0x12) */
64 0x6c, /* REG_ARXL2PGA (0x13) */ 64 0x3f, /* REG_ARXL2PGA (0x13) */
65 0x00, /* REG_VRXPGA (0x14) */ 65 0x25, /* REG_VRXPGA (0x14) */
66 0x00, /* REG_VSTPGA (0x15) */ 66 0x00, /* REG_VSTPGA (0x15) */
67 0x00, /* REG_VRX2ARXPGA (0x16) */ 67 0x00, /* REG_VRX2ARXPGA (0x16) */
68 0x00, /* REG_AVDAC_CTL (0x17) */ 68 0x00, /* REG_AVDAC_CTL (0x17) */
69 0x00, /* REG_ARX2VTXPGA (0x18) */ 69 0x00, /* REG_ARX2VTXPGA (0x18) */
70 0x00, /* REG_ARXL1_APGA_CTL (0x19) */ 70 0x32, /* REG_ARXL1_APGA_CTL (0x19) */
71 0x00, /* REG_ARXR1_APGA_CTL (0x1A) */ 71 0x32, /* REG_ARXR1_APGA_CTL (0x1A) */
72 0x4a, /* REG_ARXL2_APGA_CTL (0x1B) */ 72 0x32, /* REG_ARXL2_APGA_CTL (0x1B) */
73 0x4a, /* REG_ARXR2_APGA_CTL (0x1C) */ 73 0x32, /* REG_ARXR2_APGA_CTL (0x1C) */
74 0x00, /* REG_ATX2ARXPGA (0x1D) */ 74 0x00, /* REG_ATX2ARXPGA (0x1D) */
75 0x00, /* REG_BT_IF (0x1E) */ 75 0x00, /* REG_BT_IF (0x1E) */
76 0x00, /* REG_BTPGA (0x1F) */ 76 0x55, /* REG_BTPGA (0x1F) */
77 0x00, /* REG_BTSTPGA (0x20) */ 77 0x00, /* REG_BTSTPGA (0x20) */
78 0x00, /* REG_EAR_CTL (0x21) */ 78 0x00, /* REG_EAR_CTL (0x21) */
79 0x00, /* REG_HS_SEL (0x22) */ 79 0x00, /* REG_HS_SEL (0x22) */
@@ -85,32 +85,32 @@ static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = {
85 0x00, /* REG_PRECKR_CTL (0x28) */ 85 0x00, /* REG_PRECKR_CTL (0x28) */
86 0x00, /* REG_HFL_CTL (0x29) */ 86 0x00, /* REG_HFL_CTL (0x29) */
87 0x00, /* REG_HFR_CTL (0x2A) */ 87 0x00, /* REG_HFR_CTL (0x2A) */
88 0x00, /* REG_ALC_CTL (0x2B) */ 88 0x05, /* REG_ALC_CTL (0x2B) */
89 0x00, /* REG_ALC_SET1 (0x2C) */ 89 0x00, /* REG_ALC_SET1 (0x2C) */
90 0x00, /* REG_ALC_SET2 (0x2D) */ 90 0x00, /* REG_ALC_SET2 (0x2D) */
91 0x00, /* REG_BOOST_CTL (0x2E) */ 91 0x00, /* REG_BOOST_CTL (0x2E) */
92 0x00, /* REG_SOFTVOL_CTL (0x2F) */ 92 0x00, /* REG_SOFTVOL_CTL (0x2F) */
93 0x00, /* REG_DTMF_FREQSEL (0x30) */ 93 0x13, /* REG_DTMF_FREQSEL (0x30) */
94 0x00, /* REG_DTMF_TONEXT1H (0x31) */ 94 0x00, /* REG_DTMF_TONEXT1H (0x31) */
95 0x00, /* REG_DTMF_TONEXT1L (0x32) */ 95 0x00, /* REG_DTMF_TONEXT1L (0x32) */
96 0x00, /* REG_DTMF_TONEXT2H (0x33) */ 96 0x00, /* REG_DTMF_TONEXT2H (0x33) */
97 0x00, /* REG_DTMF_TONEXT2L (0x34) */ 97 0x00, /* REG_DTMF_TONEXT2L (0x34) */
98 0x00, /* REG_DTMF_TONOFF (0x35) */ 98 0x79, /* REG_DTMF_TONOFF (0x35) */
99 0x00, /* REG_DTMF_WANONOFF (0x36) */ 99 0x11, /* REG_DTMF_WANONOFF (0x36) */
100 0x00, /* REG_I2S_RX_SCRAMBLE_H (0x37) */ 100 0x00, /* REG_I2S_RX_SCRAMBLE_H (0x37) */
101 0x00, /* REG_I2S_RX_SCRAMBLE_M (0x38) */ 101 0x00, /* REG_I2S_RX_SCRAMBLE_M (0x38) */
102 0x00, /* REG_I2S_RX_SCRAMBLE_L (0x39) */ 102 0x00, /* REG_I2S_RX_SCRAMBLE_L (0x39) */
103 0x06, /* REG_APLL_CTL (0x3A) */ 103 0x06, /* REG_APLL_CTL (0x3A) */
104 0x00, /* REG_DTMF_CTL (0x3B) */ 104 0x00, /* REG_DTMF_CTL (0x3B) */
105 0x00, /* REG_DTMF_PGA_CTL2 (0x3C) */ 105 0x44, /* REG_DTMF_PGA_CTL2 (0x3C) */
106 0x00, /* REG_DTMF_PGA_CTL1 (0x3D) */ 106 0x69, /* REG_DTMF_PGA_CTL1 (0x3D) */
107 0x00, /* REG_MISC_SET_1 (0x3E) */ 107 0x00, /* REG_MISC_SET_1 (0x3E) */
108 0x00, /* REG_PCMBTMUX (0x3F) */ 108 0x00, /* REG_PCMBTMUX (0x3F) */
109 0x00, /* not used (0x40) */ 109 0x00, /* not used (0x40) */
110 0x00, /* not used (0x41) */ 110 0x00, /* not used (0x41) */
111 0x00, /* not used (0x42) */ 111 0x00, /* not used (0x42) */
112 0x00, /* REG_RX_PATH_SEL (0x43) */ 112 0x00, /* REG_RX_PATH_SEL (0x43) */
113 0x00, /* REG_VDL_APGA_CTL (0x44) */ 113 0x32, /* REG_VDL_APGA_CTL (0x44) */
114 0x00, /* REG_VIBRA_CTL (0x45) */ 114 0x00, /* REG_VIBRA_CTL (0x45) */
115 0x00, /* REG_VIBRA_SET (0x46) */ 115 0x00, /* REG_VIBRA_SET (0x46) */
116 0x00, /* REG_VIBRA_PWM_SET (0x47) */ 116 0x00, /* REG_VIBRA_PWM_SET (0x47) */
@@ -143,6 +143,9 @@ struct twl4030_priv {
143 u8 earpiece_enabled; 143 u8 earpiece_enabled;
144 u8 predrivel_enabled, predriver_enabled; 144 u8 predrivel_enabled, predriver_enabled;
145 u8 carkitl_enabled, carkitr_enabled; 145 u8 carkitl_enabled, carkitr_enabled;
146
147 /* Delay needed after enabling the digimic interface */
148 unsigned int digimic_delay;
146}; 149};
147 150
148/* 151/*
@@ -244,58 +247,95 @@ static void twl4030_codec_enable(struct snd_soc_codec *codec, int enable)
244 udelay(10); 247 udelay(10);
245} 248}
246 249
247static void twl4030_init_chip(struct snd_soc_codec *codec) 250static inline void twl4030_check_defaults(struct snd_soc_codec *codec)
248{ 251{
249 u8 *cache = codec->reg_cache; 252 int i, difference = 0;
250 int i; 253 u8 val;
254
255 dev_dbg(codec->dev, "Checking TWL audio default configuration\n");
256 for (i = 1; i <= TWL4030_REG_MISC_SET_2; i++) {
257 twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &val, i);
258 if (val != twl4030_reg[i]) {
259 difference++;
260 dev_dbg(codec->dev,
261 "Reg 0x%02x: chip: 0x%02x driver: 0x%02x\n",
262 i, val, twl4030_reg[i]);
263 }
264 }
265 dev_dbg(codec->dev, "Found %d non maching registers. %s\n",
266 difference, difference ? "Not OK" : "OK");
267}
251 268
252 /* clear CODECPDZ prior to setting register defaults */ 269static inline void twl4030_reset_registers(struct snd_soc_codec *codec)
253 twl4030_codec_enable(codec, 0); 270{
271 int i;
254 272
255 /* set all audio section registers to reasonable defaults */ 273 /* set all audio section registers to reasonable defaults */
256 for (i = TWL4030_REG_OPTION; i <= TWL4030_REG_MISC_SET_2; i++) 274 for (i = TWL4030_REG_OPTION; i <= TWL4030_REG_MISC_SET_2; i++)
257 if (i != TWL4030_REG_APLL_CTL) 275 if (i != TWL4030_REG_APLL_CTL)
258 twl4030_write(codec, i, cache[i]); 276 twl4030_write(codec, i, twl4030_reg[i]);
259 277
260} 278}
261 279
262static void twl4030_apll_enable(struct snd_soc_codec *codec, int enable) 280static void twl4030_init_chip(struct platform_device *pdev)
263{ 281{
282 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
283 struct twl4030_setup_data *setup = socdev->codec_data;
284 struct snd_soc_codec *codec = socdev->card->codec;
264 struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); 285 struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
265 int status = -1; 286 u8 reg, byte;
287 int i = 0;
266 288
267 if (enable) { 289 /* Check defaults, if instructed before anything else */
268 twl4030->apll_enabled++; 290 if (setup && setup->check_defaults)
269 if (twl4030->apll_enabled == 1) 291 twl4030_check_defaults(codec);
270 status = twl4030_codec_enable_resource(
271 TWL4030_CODEC_RES_APLL);
272 } else {
273 twl4030->apll_enabled--;
274 if (!twl4030->apll_enabled)
275 status = twl4030_codec_disable_resource(
276 TWL4030_CODEC_RES_APLL);
277 }
278 292
279 if (status >= 0) 293 /* Reset registers, if no setup data or if instructed to do so */
280 twl4030_write_reg_cache(codec, TWL4030_REG_APLL_CTL, status); 294 if (!setup || (setup && setup->reset_registers))
281} 295 twl4030_reset_registers(codec);
282 296
283static void twl4030_power_up(struct snd_soc_codec *codec) 297 /* Refresh APLL_CTL register from HW */
284{ 298 twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &byte,
285 struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); 299 TWL4030_REG_APLL_CTL);
286 u8 anamicl, regmisc1, byte; 300 twl4030_write_reg_cache(codec, TWL4030_REG_APLL_CTL, byte);
287 int i = 0; 301
302 /* anti-pop when changing analog gain */
303 reg = twl4030_read_reg_cache(codec, TWL4030_REG_MISC_SET_1);
304 twl4030_write(codec, TWL4030_REG_MISC_SET_1,
305 reg | TWL4030_SMOOTH_ANAVOL_EN);
288 306
289 if (twl4030->codec_powered) 307 twl4030_write(codec, TWL4030_REG_OPTION,
308 TWL4030_ATXL1_EN | TWL4030_ATXR1_EN |
309 TWL4030_ARXL2_EN | TWL4030_ARXR2_EN);
310
311 /* REG_ARXR2_APGA_CTL reset according to the TRM: 0dB, DA_EN */
312 twl4030_write(codec, TWL4030_REG_ARXR2_APGA_CTL, 0x32);
313
314 /* Machine dependent setup */
315 if (!setup)
290 return; 316 return;
291 317
292 /* set CODECPDZ to turn on codec */ 318 twl4030->digimic_delay = setup->digimic_delay;
293 twl4030_codec_enable(codec, 1); 319
320 /* Configuration for headset ramp delay from setup data */
321 if (setup->sysclk != twl4030->sysclk)
322 dev_warn(codec->dev,
323 "Mismatch in APLL mclk: %u (configured: %u)\n",
324 setup->sysclk, twl4030->sysclk);
325
326 reg = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET);
327 reg &= ~TWL4030_RAMP_DELAY;
328 reg |= (setup->ramp_delay_value << 2);
329 twl4030_write_reg_cache(codec, TWL4030_REG_HS_POPN_SET, reg);
294 330
295 /* initiate offset cancellation */ 331 /* initiate offset cancellation */
296 anamicl = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL); 332 twl4030_codec_enable(codec, 1);
333
334 reg = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL);
335 reg &= ~TWL4030_OFFSET_CNCL_SEL;
336 reg |= setup->offset_cncl_path;
297 twl4030_write(codec, TWL4030_REG_ANAMICL, 337 twl4030_write(codec, TWL4030_REG_ANAMICL,
298 anamicl | TWL4030_CNCL_OFFSET_START); 338 reg | TWL4030_CNCL_OFFSET_START);
299 339
300 /* wait for offset cancellation to complete */ 340 /* wait for offset cancellation to complete */
301 do { 341 do {
@@ -310,23 +350,28 @@ static void twl4030_power_up(struct snd_soc_codec *codec)
310 /* Make sure that the reg_cache has the same value as the HW */ 350 /* Make sure that the reg_cache has the same value as the HW */
311 twl4030_write_reg_cache(codec, TWL4030_REG_ANAMICL, byte); 351 twl4030_write_reg_cache(codec, TWL4030_REG_ANAMICL, byte);
312 352
313 /* anti-pop when changing analog gain */
314 regmisc1 = twl4030_read_reg_cache(codec, TWL4030_REG_MISC_SET_1);
315 twl4030_write(codec, TWL4030_REG_MISC_SET_1,
316 regmisc1 | TWL4030_SMOOTH_ANAVOL_EN);
317
318 /* toggle CODECPDZ as per TRM */
319 twl4030_codec_enable(codec, 0); 353 twl4030_codec_enable(codec, 0);
320 twl4030_codec_enable(codec, 1);
321} 354}
322 355
323/* 356static void twl4030_apll_enable(struct snd_soc_codec *codec, int enable)
324 * Unconditional power down
325 */
326static void twl4030_power_down(struct snd_soc_codec *codec)
327{ 357{
328 /* power down */ 358 struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
329 twl4030_codec_enable(codec, 0); 359 int status = -1;
360
361 if (enable) {
362 twl4030->apll_enabled++;
363 if (twl4030->apll_enabled == 1)
364 status = twl4030_codec_enable_resource(
365 TWL4030_CODEC_RES_APLL);
366 } else {
367 twl4030->apll_enabled--;
368 if (!twl4030->apll_enabled)
369 status = twl4030_codec_disable_resource(
370 TWL4030_CODEC_RES_APLL);
371 }
372
373 if (status >= 0)
374 twl4030_write_reg_cache(codec, TWL4030_REG_APLL_CTL, status);
330} 375}
331 376
332/* Earpiece */ 377/* Earpiece */
@@ -500,10 +545,11 @@ static const struct snd_kcontrol_new twl4030_dapm_abypassl2_control =
500static const struct snd_kcontrol_new twl4030_dapm_abypassv_control = 545static const struct snd_kcontrol_new twl4030_dapm_abypassv_control =
501 SOC_DAPM_SINGLE("Switch", TWL4030_REG_VDL_APGA_CTL, 2, 1, 0); 546 SOC_DAPM_SINGLE("Switch", TWL4030_REG_VDL_APGA_CTL, 2, 1, 0);
502 547
503/* Digital bypass gain, 0 mutes the bypass */ 548/* Digital bypass gain, mute instead of -30dB */
504static const unsigned int twl4030_dapm_dbypass_tlv[] = { 549static const unsigned int twl4030_dapm_dbypass_tlv[] = {
505 TLV_DB_RANGE_HEAD(2), 550 TLV_DB_RANGE_HEAD(3),
506 0, 3, TLV_DB_SCALE_ITEM(-2400, 0, 1), 551 0, 1, TLV_DB_SCALE_ITEM(-3000, 600, 1),
552 2, 3, TLV_DB_SCALE_ITEM(-2400, 0, 0),
507 4, 7, TLV_DB_SCALE_ITEM(-1800, 600, 0), 553 4, 7, TLV_DB_SCALE_ITEM(-1800, 600, 0),
508}; 554};
509 555
@@ -531,36 +577,6 @@ static const struct snd_kcontrol_new twl4030_dapm_dbypassv_control =
531 TWL4030_REG_VSTPGA, 0, 0x29, 0, 577 TWL4030_REG_VSTPGA, 0, 0x29, 0,
532 twl4030_dapm_dbypassv_tlv); 578 twl4030_dapm_dbypassv_tlv);
533 579
534static int micpath_event(struct snd_soc_dapm_widget *w,
535 struct snd_kcontrol *kcontrol, int event)
536{
537 struct soc_enum *e = (struct soc_enum *)w->kcontrols->private_value;
538 unsigned char adcmicsel, micbias_ctl;
539
540 adcmicsel = twl4030_read_reg_cache(w->codec, TWL4030_REG_ADCMICSEL);
541 micbias_ctl = twl4030_read_reg_cache(w->codec, TWL4030_REG_MICBIAS_CTL);
542 /* Prepare the bits for the given TX path:
543 * shift_l == 0: TX1 microphone path
544 * shift_l == 2: TX2 microphone path */
545 if (e->shift_l) {
546 /* TX2 microphone path */
547 if (adcmicsel & TWL4030_TX2IN_SEL)
548 micbias_ctl |= TWL4030_MICBIAS2_CTL; /* digimic */
549 else
550 micbias_ctl &= ~TWL4030_MICBIAS2_CTL;
551 } else {
552 /* TX1 microphone path */
553 if (adcmicsel & TWL4030_TX1IN_SEL)
554 micbias_ctl |= TWL4030_MICBIAS1_CTL; /* digimic */
555 else
556 micbias_ctl &= ~TWL4030_MICBIAS1_CTL;
557 }
558
559 twl4030_write(w->codec, TWL4030_REG_MICBIAS_CTL, micbias_ctl);
560
561 return 0;
562}
563
564/* 580/*
565 * Output PGA builder: 581 * Output PGA builder:
566 * Handle the muting and unmuting of the given output (turning off the 582 * Handle the muting and unmuting of the given output (turning off the
@@ -814,6 +830,16 @@ static int headsetrpga_event(struct snd_soc_dapm_widget *w,
814 return 0; 830 return 0;
815} 831}
816 832
833static int digimic_event(struct snd_soc_dapm_widget *w,
834 struct snd_kcontrol *kcontrol, int event)
835{
836 struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(w->codec);
837
838 if (twl4030->digimic_delay)
839 mdelay(twl4030->digimic_delay);
840 return 0;
841}
842
817/* 843/*
818 * Some of the gain controls in TWL (mostly those which are associated with 844 * Some of the gain controls in TWL (mostly those which are associated with
819 * the outputs) are implemented in an interesting way: 845 * the outputs) are implemented in an interesting way:
@@ -1374,14 +1400,10 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
1374 /* Analog/Digital mic path selection. 1400 /* Analog/Digital mic path selection.
1375 TX1 Left/Right: either analog Left/Right or Digimic0 1401 TX1 Left/Right: either analog Left/Right or Digimic0
1376 TX2 Left/Right: either analog Left/Right or Digimic1 */ 1402 TX2 Left/Right: either analog Left/Right or Digimic1 */
1377 SND_SOC_DAPM_MUX_E("TX1 Capture Route", SND_SOC_NOPM, 0, 0, 1403 SND_SOC_DAPM_MUX("TX1 Capture Route", SND_SOC_NOPM, 0, 0,
1378 &twl4030_dapm_micpathtx1_control, micpath_event, 1404 &twl4030_dapm_micpathtx1_control),
1379 SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD| 1405 SND_SOC_DAPM_MUX("TX2 Capture Route", SND_SOC_NOPM, 0, 0,
1380 SND_SOC_DAPM_POST_REG), 1406 &twl4030_dapm_micpathtx2_control),
1381 SND_SOC_DAPM_MUX_E("TX2 Capture Route", SND_SOC_NOPM, 0, 0,
1382 &twl4030_dapm_micpathtx2_control, micpath_event,
1383 SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD|
1384 SND_SOC_DAPM_POST_REG),
1385 1407
1386 /* Analog input mixers for the capture amplifiers */ 1408 /* Analog input mixers for the capture amplifiers */
1387 SND_SOC_DAPM_MIXER("Analog Left", 1409 SND_SOC_DAPM_MIXER("Analog Left",
@@ -1398,10 +1420,17 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
1398 SND_SOC_DAPM_PGA("ADC Physical Right", 1420 SND_SOC_DAPM_PGA("ADC Physical Right",
1399 TWL4030_REG_AVADC_CTL, 1, 0, NULL, 0), 1421 TWL4030_REG_AVADC_CTL, 1, 0, NULL, 0),
1400 1422
1401 SND_SOC_DAPM_PGA("Digimic0 Enable", 1423 SND_SOC_DAPM_PGA_E("Digimic0 Enable",
1402 TWL4030_REG_ADCMICSEL, 1, 0, NULL, 0), 1424 TWL4030_REG_ADCMICSEL, 1, 0, NULL, 0,
1403 SND_SOC_DAPM_PGA("Digimic1 Enable", 1425 digimic_event, SND_SOC_DAPM_POST_PMU),
1404 TWL4030_REG_ADCMICSEL, 3, 0, NULL, 0), 1426 SND_SOC_DAPM_PGA_E("Digimic1 Enable",
1427 TWL4030_REG_ADCMICSEL, 3, 0, NULL, 0,
1428 digimic_event, SND_SOC_DAPM_POST_PMU),
1429
1430 SND_SOC_DAPM_SUPPLY("micbias1 select", TWL4030_REG_MICBIAS_CTL, 5, 0,
1431 NULL, 0),
1432 SND_SOC_DAPM_SUPPLY("micbias2 select", TWL4030_REG_MICBIAS_CTL, 6, 0,
1433 NULL, 0),
1405 1434
1406 SND_SOC_DAPM_MICBIAS("Mic Bias 1", TWL4030_REG_MICBIAS_CTL, 0, 0), 1435 SND_SOC_DAPM_MICBIAS("Mic Bias 1", TWL4030_REG_MICBIAS_CTL, 0, 0),
1407 SND_SOC_DAPM_MICBIAS("Mic Bias 2", TWL4030_REG_MICBIAS_CTL, 1, 0), 1436 SND_SOC_DAPM_MICBIAS("Mic Bias 2", TWL4030_REG_MICBIAS_CTL, 1, 0),
@@ -1419,8 +1448,11 @@ static const struct snd_soc_dapm_route intercon[] = {
1419 /* Supply for the digital part (APLL) */ 1448 /* Supply for the digital part (APLL) */
1420 {"Digital Voice Playback Mixer", NULL, "APLL Enable"}, 1449 {"Digital Voice Playback Mixer", NULL, "APLL Enable"},
1421 1450
1422 {"Digital R1 Playback Mixer", NULL, "AIF Enable"}, 1451 {"DAC Left1", NULL, "AIF Enable"},
1423 {"Digital L1 Playback Mixer", NULL, "AIF Enable"}, 1452 {"DAC Right1", NULL, "AIF Enable"},
1453 {"DAC Left2", NULL, "AIF Enable"},
1454 {"DAC Right1", NULL, "AIF Enable"},
1455
1424 {"Digital R2 Playback Mixer", NULL, "AIF Enable"}, 1456 {"Digital R2 Playback Mixer", NULL, "AIF Enable"},
1425 {"Digital L2 Playback Mixer", NULL, "AIF Enable"}, 1457 {"Digital L2 Playback Mixer", NULL, "AIF Enable"},
1426 1458
@@ -1491,10 +1523,10 @@ static const struct snd_soc_dapm_route intercon[] = {
1491 1523
1492 /* outputs */ 1524 /* outputs */
1493 /* Must be always connected (for AIF and APLL) */ 1525 /* Must be always connected (for AIF and APLL) */
1494 {"Virtual HiFi OUT", NULL, "Digital L1 Playback Mixer"}, 1526 {"Virtual HiFi OUT", NULL, "DAC Left1"},
1495 {"Virtual HiFi OUT", NULL, "Digital R1 Playback Mixer"}, 1527 {"Virtual HiFi OUT", NULL, "DAC Right1"},
1496 {"Virtual HiFi OUT", NULL, "Digital L2 Playback Mixer"}, 1528 {"Virtual HiFi OUT", NULL, "DAC Left2"},
1497 {"Virtual HiFi OUT", NULL, "Digital R2 Playback Mixer"}, 1529 {"Virtual HiFi OUT", NULL, "DAC Right2"},
1498 /* Must be always connected (for APLL) */ 1530 /* Must be always connected (for APLL) */
1499 {"Virtual Voice OUT", NULL, "Digital Voice Playback Mixer"}, 1531 {"Virtual Voice OUT", NULL, "Digital Voice Playback Mixer"},
1500 /* Physical outputs */ 1532 /* Physical outputs */
@@ -1531,6 +1563,9 @@ static const struct snd_soc_dapm_route intercon[] = {
1531 {"Digimic0 Enable", NULL, "DIGIMIC0"}, 1563 {"Digimic0 Enable", NULL, "DIGIMIC0"},
1532 {"Digimic1 Enable", NULL, "DIGIMIC1"}, 1564 {"Digimic1 Enable", NULL, "DIGIMIC1"},
1533 1565
1566 {"DIGIMIC0", NULL, "micbias1 select"},
1567 {"DIGIMIC1", NULL, "micbias2 select"},
1568
1534 /* TX1 Left capture path */ 1569 /* TX1 Left capture path */
1535 {"TX1 Capture Route", "Analog", "ADC Physical Left"}, 1570 {"TX1 Capture Route", "Analog", "ADC Physical Left"},
1536 {"TX1 Capture Route", "Digimic0", "Digimic0 Enable"}, 1571 {"TX1 Capture Route", "Digimic0", "Digimic0 Enable"},
@@ -1605,10 +1640,10 @@ static int twl4030_set_bias_level(struct snd_soc_codec *codec,
1605 break; 1640 break;
1606 case SND_SOC_BIAS_STANDBY: 1641 case SND_SOC_BIAS_STANDBY:
1607 if (codec->bias_level == SND_SOC_BIAS_OFF) 1642 if (codec->bias_level == SND_SOC_BIAS_OFF)
1608 twl4030_power_up(codec); 1643 twl4030_codec_enable(codec, 1);
1609 break; 1644 break;
1610 case SND_SOC_BIAS_OFF: 1645 case SND_SOC_BIAS_OFF:
1611 twl4030_power_down(codec); 1646 twl4030_codec_enable(codec, 0);
1612 break; 1647 break;
1613 } 1648 }
1614 codec->bias_level = level; 1649 codec->bias_level = level;
@@ -1794,13 +1829,6 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
1794 return -EINVAL; 1829 return -EINVAL;
1795 } 1830 }
1796 1831
1797 if (mode != old_mode) {
1798 /* change rate and set CODECPDZ */
1799 twl4030_codec_enable(codec, 0);
1800 twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode);
1801 twl4030_codec_enable(codec, 1);
1802 }
1803
1804 /* sample size */ 1832 /* sample size */
1805 old_format = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF); 1833 old_format = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF);
1806 format = old_format; 1834 format = old_format;
@@ -1818,16 +1846,20 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
1818 return -EINVAL; 1846 return -EINVAL;
1819 } 1847 }
1820 1848
1821 if (format != old_format) { 1849 if (format != old_format || mode != old_mode) {
1822 1850 if (twl4030->codec_powered) {
1823 /* clear CODECPDZ before changing format (codec requirement) */ 1851 /*
1824 twl4030_codec_enable(codec, 0); 1852 * If the codec is powered, than we need to toggle the
1825 1853 * codec power.
1826 /* change format */ 1854 */
1827 twl4030_write(codec, TWL4030_REG_AUDIO_IF, format); 1855 twl4030_codec_enable(codec, 0);
1828 1856 twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode);
1829 /* set CODECPDZ afterwards */ 1857 twl4030_write(codec, TWL4030_REG_AUDIO_IF, format);
1830 twl4030_codec_enable(codec, 1); 1858 twl4030_codec_enable(codec, 1);
1859 } else {
1860 twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode);
1861 twl4030_write(codec, TWL4030_REG_AUDIO_IF, format);
1862 }
1831 } 1863 }
1832 1864
1833 /* Store the important parameters for the DAI configuration and set 1865 /* Store the important parameters for the DAI configuration and set
@@ -1877,6 +1909,7 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai,
1877 unsigned int fmt) 1909 unsigned int fmt)
1878{ 1910{
1879 struct snd_soc_codec *codec = codec_dai->codec; 1911 struct snd_soc_codec *codec = codec_dai->codec;
1912 struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
1880 u8 old_format, format; 1913 u8 old_format, format;
1881 1914
1882 /* get format */ 1915 /* get format */
@@ -1911,15 +1944,17 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai,
1911 } 1944 }
1912 1945
1913 if (format != old_format) { 1946 if (format != old_format) {
1914 1947 if (twl4030->codec_powered) {
1915 /* clear CODECPDZ before changing format (codec requirement) */ 1948 /*
1916 twl4030_codec_enable(codec, 0); 1949 * If the codec is powered, than we need to toggle the
1917 1950 * codec power.
1918 /* change format */ 1951 */
1919 twl4030_write(codec, TWL4030_REG_AUDIO_IF, format); 1952 twl4030_codec_enable(codec, 0);
1920 1953 twl4030_write(codec, TWL4030_REG_AUDIO_IF, format);
1921 /* set CODECPDZ afterwards */ 1954 twl4030_codec_enable(codec, 1);
1922 twl4030_codec_enable(codec, 1); 1955 } else {
1956 twl4030_write(codec, TWL4030_REG_AUDIO_IF, format);
1957 }
1923 } 1958 }
1924 1959
1925 return 0; 1960 return 0;
@@ -2011,6 +2046,7 @@ static int twl4030_voice_hw_params(struct snd_pcm_substream *substream,
2011 struct snd_soc_pcm_runtime *rtd = substream->private_data; 2046 struct snd_soc_pcm_runtime *rtd = substream->private_data;
2012 struct snd_soc_device *socdev = rtd->socdev; 2047 struct snd_soc_device *socdev = rtd->socdev;
2013 struct snd_soc_codec *codec = socdev->card->codec; 2048 struct snd_soc_codec *codec = socdev->card->codec;
2049 struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
2014 u8 old_mode, mode; 2050 u8 old_mode, mode;
2015 2051
2016 /* Enable voice digital filters */ 2052 /* Enable voice digital filters */
@@ -2035,10 +2071,17 @@ static int twl4030_voice_hw_params(struct snd_pcm_substream *substream,
2035 } 2071 }
2036 2072
2037 if (mode != old_mode) { 2073 if (mode != old_mode) {
2038 /* change rate and set CODECPDZ */ 2074 if (twl4030->codec_powered) {
2039 twl4030_codec_enable(codec, 0); 2075 /*
2040 twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode); 2076 * If the codec is powered, than we need to toggle the
2041 twl4030_codec_enable(codec, 1); 2077 * codec power.
2078 */
2079 twl4030_codec_enable(codec, 0);
2080 twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode);
2081 twl4030_codec_enable(codec, 1);
2082 } else {
2083 twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode);
2084 }
2042 } 2085 }
2043 2086
2044 return 0; 2087 return 0;
@@ -2068,6 +2111,7 @@ static int twl4030_voice_set_dai_fmt(struct snd_soc_dai *codec_dai,
2068 unsigned int fmt) 2111 unsigned int fmt)
2069{ 2112{
2070 struct snd_soc_codec *codec = codec_dai->codec; 2113 struct snd_soc_codec *codec = codec_dai->codec;
2114 struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
2071 u8 old_format, format; 2115 u8 old_format, format;
2072 2116
2073 /* get format */ 2117 /* get format */
@@ -2099,10 +2143,17 @@ static int twl4030_voice_set_dai_fmt(struct snd_soc_dai *codec_dai,
2099 } 2143 }
2100 2144
2101 if (format != old_format) { 2145 if (format != old_format) {
2102 /* change format and set CODECPDZ */ 2146 if (twl4030->codec_powered) {
2103 twl4030_codec_enable(codec, 0); 2147 /*
2104 twl4030_write(codec, TWL4030_REG_VOICE_IF, format); 2148 * If the codec is powered, than we need to toggle the
2105 twl4030_codec_enable(codec, 1); 2149 * codec power.
2150 */
2151 twl4030_codec_enable(codec, 0);
2152 twl4030_write(codec, TWL4030_REG_VOICE_IF, format);
2153 twl4030_codec_enable(codec, 1);
2154 } else {
2155 twl4030_write(codec, TWL4030_REG_VOICE_IF, format);
2156 }
2106 } 2157 }
2107 2158
2108 return 0; 2159 return 0;
@@ -2202,31 +2253,15 @@ static struct snd_soc_codec *twl4030_codec;
2202static int twl4030_soc_probe(struct platform_device *pdev) 2253static int twl4030_soc_probe(struct platform_device *pdev)
2203{ 2254{
2204 struct snd_soc_device *socdev = platform_get_drvdata(pdev); 2255 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
2205 struct twl4030_setup_data *setup = socdev->codec_data;
2206 struct snd_soc_codec *codec; 2256 struct snd_soc_codec *codec;
2207 struct twl4030_priv *twl4030;
2208 int ret; 2257 int ret;
2209 2258
2210 BUG_ON(!twl4030_codec); 2259 BUG_ON(!twl4030_codec);
2211 2260
2212 codec = twl4030_codec; 2261 codec = twl4030_codec;
2213 twl4030 = snd_soc_codec_get_drvdata(codec);
2214 socdev->card->codec = codec; 2262 socdev->card->codec = codec;
2215 2263
2216 /* Configuration for headset ramp delay from setup data */ 2264 twl4030_init_chip(pdev);
2217 if (setup) {
2218 unsigned char hs_pop;
2219
2220 if (setup->sysclk != twl4030->sysclk)
2221 dev_warn(&pdev->dev,
2222 "Mismatch in APLL mclk: %u (configured: %u)\n",
2223 setup->sysclk, twl4030->sysclk);
2224
2225 hs_pop = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET);
2226 hs_pop &= ~TWL4030_RAMP_DELAY;
2227 hs_pop |= (setup->ramp_delay_value << 2);
2228 twl4030_write_reg_cache(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
2229 }
2230 2265
2231 /* register pcms */ 2266 /* register pcms */
2232 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); 2267 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
@@ -2247,6 +2282,8 @@ static int twl4030_soc_remove(struct platform_device *pdev)
2247 struct snd_soc_device *socdev = platform_get_drvdata(pdev); 2282 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
2248 struct snd_soc_codec *codec = socdev->card->codec; 2283 struct snd_soc_codec *codec = socdev->card->codec;
2249 2284
2285 /* Reset registers to their chip default before leaving */
2286 twl4030_reset_registers(codec);
2250 twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF); 2287 twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF);
2251 snd_soc_free_pcms(socdev); 2288 snd_soc_free_pcms(socdev);
2252 snd_soc_dapm_free(socdev); 2289 snd_soc_dapm_free(socdev);
@@ -2287,6 +2324,7 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev)
2287 codec->read = twl4030_read_reg_cache; 2324 codec->read = twl4030_read_reg_cache;
2288 codec->write = twl4030_write; 2325 codec->write = twl4030_write;
2289 codec->set_bias_level = twl4030_set_bias_level; 2326 codec->set_bias_level = twl4030_set_bias_level;
2327 codec->idle_bias_off = 1;
2290 codec->dai = twl4030_dai; 2328 codec->dai = twl4030_dai;
2291 codec->num_dai = ARRAY_SIZE(twl4030_dai); 2329 codec->num_dai = ARRAY_SIZE(twl4030_dai);
2292 codec->reg_cache_size = sizeof(twl4030_reg); 2330 codec->reg_cache_size = sizeof(twl4030_reg);
@@ -2302,9 +2340,7 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev)
2302 2340
2303 /* Set the defaults, and power up the codec */ 2341 /* Set the defaults, and power up the codec */
2304 twl4030->sysclk = twl4030_codec_get_mclk() / 1000; 2342 twl4030->sysclk = twl4030_codec_get_mclk() / 1000;
2305 twl4030_init_chip(codec);
2306 codec->bias_level = SND_SOC_BIAS_OFF; 2343 codec->bias_level = SND_SOC_BIAS_OFF;
2307 twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
2308 2344
2309 ret = snd_soc_register_codec(codec); 2345 ret = snd_soc_register_codec(codec);
2310 if (ret != 0) { 2346 if (ret != 0) {
@@ -2322,7 +2358,7 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev)
2322 return 0; 2358 return 0;
2323 2359
2324error_codec: 2360error_codec:
2325 twl4030_power_down(codec); 2361 twl4030_codec_enable(codec, 0);
2326 kfree(codec->reg_cache); 2362 kfree(codec->reg_cache);
2327error_cache: 2363error_cache:
2328 kfree(twl4030); 2364 kfree(twl4030);
diff --git a/sound/soc/codecs/twl4030.h b/sound/soc/codecs/twl4030.h
index f206d242ca31..6c57430f6e24 100644
--- a/sound/soc/codecs/twl4030.h
+++ b/sound/soc/codecs/twl4030.h
@@ -41,7 +41,11 @@ extern struct snd_soc_codec_device soc_codec_dev_twl4030;
41 41
42struct twl4030_setup_data { 42struct twl4030_setup_data {
43 unsigned int ramp_delay_value; 43 unsigned int ramp_delay_value;
44 unsigned int digimic_delay; /* in ms */
44 unsigned int sysclk; 45 unsigned int sysclk;
46 unsigned int offset_cncl_path;
47 unsigned int check_defaults:1;
48 unsigned int reset_registers:1;
45 unsigned int hs_extmute:1; 49 unsigned int hs_extmute:1;
46 void (*set_hs_extmute)(int mute); 50 void (*set_hs_extmute)(int mute);
47}; 51};
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c
index af36346ff336..64a807f1a8a1 100644
--- a/sound/soc/codecs/twl6040.c
+++ b/sound/soc/codecs/twl6040.c
@@ -360,6 +360,13 @@ static int headset_power_mode(struct snd_soc_codec *codec, int high_perf)
360 return 0; 360 return 0;
361} 361}
362 362
363static int twl6040_hs_dac_event(struct snd_soc_dapm_widget *w,
364 struct snd_kcontrol *kcontrol, int event)
365{
366 msleep(1);
367 return 0;
368}
369
363static int twl6040_power_mode_event(struct snd_soc_dapm_widget *w, 370static int twl6040_power_mode_event(struct snd_soc_dapm_widget *w,
364 struct snd_kcontrol *kcontrol, int event) 371 struct snd_kcontrol *kcontrol, int event)
365{ 372{
@@ -371,6 +378,8 @@ static int twl6040_power_mode_event(struct snd_soc_dapm_widget *w,
371 else 378 else
372 priv->non_lp--; 379 priv->non_lp--;
373 380
381 msleep(1);
382
374 return 0; 383 return 0;
375} 384}
376 385
@@ -471,20 +480,6 @@ static const struct snd_kcontrol_new hfdacl_switch_controls =
471static const struct snd_kcontrol_new hfdacr_switch_controls = 480static const struct snd_kcontrol_new hfdacr_switch_controls =
472 SOC_DAPM_SINGLE("Switch", TWL6040_REG_HFRCTL, 2, 1, 0); 481 SOC_DAPM_SINGLE("Switch", TWL6040_REG_HFRCTL, 2, 1, 0);
473 482
474/* Headset driver switches */
475static const struct snd_kcontrol_new hsl_driver_switch_controls =
476 SOC_DAPM_SINGLE("Switch", TWL6040_REG_HSLCTL, 2, 1, 0);
477
478static const struct snd_kcontrol_new hsr_driver_switch_controls =
479 SOC_DAPM_SINGLE("Switch", TWL6040_REG_HSRCTL, 2, 1, 0);
480
481/* Handsfree driver switches */
482static const struct snd_kcontrol_new hfl_driver_switch_controls =
483 SOC_DAPM_SINGLE("Switch", TWL6040_REG_HFLCTL, 4, 1, 0);
484
485static const struct snd_kcontrol_new hfr_driver_switch_controls =
486 SOC_DAPM_SINGLE("Switch", TWL6040_REG_HFRCTL, 4, 1, 0);
487
488static const struct snd_kcontrol_new ep_driver_switch_controls = 483static const struct snd_kcontrol_new ep_driver_switch_controls =
489 SOC_DAPM_SINGLE("Switch", TWL6040_REG_EARCTL, 0, 1, 0); 484 SOC_DAPM_SINGLE("Switch", TWL6040_REG_EARCTL, 0, 1, 0);
490 485
@@ -548,10 +543,14 @@ static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = {
548 TWL6040_REG_DMICBCTL, 4, 0), 543 TWL6040_REG_DMICBCTL, 4, 0),
549 544
550 /* DACs */ 545 /* DACs */
551 SND_SOC_DAPM_DAC("HSDAC Left", "Headset Playback", 546 SND_SOC_DAPM_DAC_E("HSDAC Left", "Headset Playback",
552 TWL6040_REG_HSLCTL, 0, 0), 547 TWL6040_REG_HSLCTL, 0, 0,
553 SND_SOC_DAPM_DAC("HSDAC Right", "Headset Playback", 548 twl6040_hs_dac_event,
554 TWL6040_REG_HSRCTL, 0, 0), 549 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
550 SND_SOC_DAPM_DAC_E("HSDAC Right", "Headset Playback",
551 TWL6040_REG_HSRCTL, 0, 0,
552 twl6040_hs_dac_event,
553 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
555 SND_SOC_DAPM_DAC_E("HFDAC Left", "Handsfree Playback", 554 SND_SOC_DAPM_DAC_E("HFDAC Left", "Handsfree Playback",
556 TWL6040_REG_HFLCTL, 0, 0, 555 TWL6040_REG_HFLCTL, 0, 0,
557 twl6040_power_mode_event, 556 twl6040_power_mode_event,
@@ -571,18 +570,19 @@ static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = {
571 SND_SOC_DAPM_SWITCH("HFDAC Right Playback", 570 SND_SOC_DAPM_SWITCH("HFDAC Right Playback",
572 SND_SOC_NOPM, 0, 0, &hfdacr_switch_controls), 571 SND_SOC_NOPM, 0, 0, &hfdacr_switch_controls),
573 572
574 SND_SOC_DAPM_SWITCH("Headset Left Driver", 573 /* Analog playback drivers */
575 SND_SOC_NOPM, 0, 0, &hsl_driver_switch_controls), 574 SND_SOC_DAPM_PGA_E("Handsfree Left Driver",
576 SND_SOC_DAPM_SWITCH("Headset Right Driver", 575 TWL6040_REG_HFLCTL, 4, 0, NULL, 0,
577 SND_SOC_NOPM, 0, 0, &hsr_driver_switch_controls),
578 SND_SOC_DAPM_SWITCH_E("Handsfree Left Driver",
579 SND_SOC_NOPM, 0, 0, &hfl_driver_switch_controls,
580 twl6040_power_mode_event, 576 twl6040_power_mode_event,
581 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), 577 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
582 SND_SOC_DAPM_SWITCH_E("Handsfree Right Driver", 578 SND_SOC_DAPM_PGA_E("Handsfree Right Driver",
583 SND_SOC_NOPM, 0, 0, &hfr_driver_switch_controls, 579 TWL6040_REG_HFRCTL, 4, 0, NULL, 0,
584 twl6040_power_mode_event, 580 twl6040_power_mode_event,
585 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), 581 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
582 SND_SOC_DAPM_PGA("Headset Left Driver",
583 TWL6040_REG_HSLCTL, 2, 0, NULL, 0),
584 SND_SOC_DAPM_PGA("Headset Right Driver",
585 TWL6040_REG_HSRCTL, 2, 0, NULL, 0),
586 SND_SOC_DAPM_SWITCH_E("Earphone Driver", 586 SND_SOC_DAPM_SWITCH_E("Earphone Driver",
587 SND_SOC_NOPM, 0, 0, &ep_driver_switch_controls, 587 SND_SOC_NOPM, 0, 0, &ep_driver_switch_controls,
588 twl6040_power_mode_event, 588 twl6040_power_mode_event,
@@ -616,8 +616,8 @@ static const struct snd_soc_dapm_route intercon[] = {
616 {"HSDAC Left Playback", "Switch", "HSDAC Left"}, 616 {"HSDAC Left Playback", "Switch", "HSDAC Left"},
617 {"HSDAC Right Playback", "Switch", "HSDAC Right"}, 617 {"HSDAC Right Playback", "Switch", "HSDAC Right"},
618 618
619 {"Headset Left Driver", "Switch", "HSDAC Left Playback"}, 619 {"Headset Left Driver", NULL, "HSDAC Left Playback"},
620 {"Headset Right Driver", "Switch", "HSDAC Right Playback"}, 620 {"Headset Right Driver", NULL, "HSDAC Right Playback"},
621 621
622 {"HSOL", NULL, "Headset Left Driver"}, 622 {"HSOL", NULL, "Headset Left Driver"},
623 {"HSOR", NULL, "Headset Right Driver"}, 623 {"HSOR", NULL, "Headset Right Driver"},
@@ -928,7 +928,7 @@ static int twl6040_set_dai_sysclk(struct snd_soc_dai *codec_dai,
928 case 19200000: 928 case 19200000:
929 /* mclk input, pll disabled */ 929 /* mclk input, pll disabled */
930 hppllctl |= TWL6040_MCLK_19200KHZ | 930 hppllctl |= TWL6040_MCLK_19200KHZ |
931 TWL6040_HPLLSQRBP | 931 TWL6040_HPLLSQRENA |
932 TWL6040_HPLLBP; 932 TWL6040_HPLLBP;
933 break; 933 break;
934 case 26000000: 934 case 26000000:
diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c
index 28aac53c97bb..f3b4c1d6a82d 100644
--- a/sound/soc/codecs/uda134x.c
+++ b/sound/soc/codecs/uda134x.c
@@ -28,19 +28,6 @@
28#include "uda134x.h" 28#include "uda134x.h"
29 29
30 30
31#define POWER_OFF_ON_STANDBY 1
32/*
33 ALSA SOC usually puts the device in standby mode when it's not used
34 for sometime. If you define POWER_OFF_ON_STANDBY the driver will
35 turn off the ADC/DAC when this callback is invoked and turn it back
36 on when needed. Unfortunately this will result in a very light bump
37 (it can be audible only with good earphones). If this bothers you
38 just comment this line, you will have slightly higher power
39 consumption . Please note that sending the L3 command for ADC is
40 enough to make the bump, so it doesn't make difference if you
41 completely take off power from the codec.
42 */
43
44#define UDA134X_RATES SNDRV_PCM_RATE_8000_48000 31#define UDA134X_RATES SNDRV_PCM_RATE_8000_48000
45#define UDA134X_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \ 32#define UDA134X_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \
46 SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S20_3LE) 33 SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S20_3LE)
@@ -58,7 +45,7 @@ static const char uda134x_reg[UDA134X_REGS_NUM] = {
58 /* Extended address registers */ 45 /* Extended address registers */
59 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 46 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
60 /* Status, data regs */ 47 /* Status, data regs */
61 0x00, 0x83, 0x00, 0x40, 0x80, 0x00, 48 0x00, 0x83, 0x00, 0x40, 0x80, 0xC0, 0x00,
62}; 49};
63 50
64/* 51/*
@@ -117,6 +104,7 @@ static int uda134x_write(struct snd_soc_codec *codec, unsigned int reg,
117 case UDA134X_DATA000: 104 case UDA134X_DATA000:
118 case UDA134X_DATA001: 105 case UDA134X_DATA001:
119 case UDA134X_DATA010: 106 case UDA134X_DATA010:
107 case UDA134X_DATA011:
120 addr = UDA134X_DATA0_ADDR; 108 addr = UDA134X_DATA0_ADDR;
121 break; 109 break;
122 case UDA134X_DATA1: 110 case UDA134X_DATA1:
@@ -353,8 +341,22 @@ static int uda134x_set_bias_level(struct snd_soc_codec *codec,
353 switch (level) { 341 switch (level) {
354 case SND_SOC_BIAS_ON: 342 case SND_SOC_BIAS_ON:
355 /* ADC, DAC on */ 343 /* ADC, DAC on */
356 reg = uda134x_read_reg_cache(codec, UDA134X_STATUS1); 344 switch (pd->model) {
357 uda134x_write(codec, UDA134X_STATUS1, reg | 0x03); 345 case UDA134X_UDA1340:
346 case UDA134X_UDA1344:
347 case UDA134X_UDA1345:
348 reg = uda134x_read_reg_cache(codec, UDA134X_DATA011);
349 uda134x_write(codec, UDA134X_DATA011, reg | 0x03);
350 break;
351 case UDA134X_UDA1341:
352 reg = uda134x_read_reg_cache(codec, UDA134X_STATUS1);
353 uda134x_write(codec, UDA134X_STATUS1, reg | 0x03);
354 break;
355 default:
356 printk(KERN_ERR "UDA134X SoC codec: "
357 "unsupported model %d\n", pd->model);
358 return -EINVAL;
359 }
358 break; 360 break;
359 case SND_SOC_BIAS_PREPARE: 361 case SND_SOC_BIAS_PREPARE:
360 /* power on */ 362 /* power on */
@@ -367,8 +369,22 @@ static int uda134x_set_bias_level(struct snd_soc_codec *codec,
367 break; 369 break;
368 case SND_SOC_BIAS_STANDBY: 370 case SND_SOC_BIAS_STANDBY:
369 /* ADC, DAC power off */ 371 /* ADC, DAC power off */
370 reg = uda134x_read_reg_cache(codec, UDA134X_STATUS1); 372 switch (pd->model) {
371 uda134x_write(codec, UDA134X_STATUS1, reg & ~(0x03)); 373 case UDA134X_UDA1340:
374 case UDA134X_UDA1344:
375 case UDA134X_UDA1345:
376 reg = uda134x_read_reg_cache(codec, UDA134X_DATA011);
377 uda134x_write(codec, UDA134X_DATA011, reg & ~(0x03));
378 break;
379 case UDA134X_UDA1341:
380 reg = uda134x_read_reg_cache(codec, UDA134X_STATUS1);
381 uda134x_write(codec, UDA134X_STATUS1, reg & ~(0x03));
382 break;
383 default:
384 printk(KERN_ERR "UDA134X SoC codec: "
385 "unsupported model %d\n", pd->model);
386 return -EINVAL;
387 }
372 break; 388 break;
373 case SND_SOC_BIAS_OFF: 389 case SND_SOC_BIAS_OFF:
374 /* power off */ 390 /* power off */
@@ -531,9 +547,7 @@ static int uda134x_soc_probe(struct platform_device *pdev)
531 codec->num_dai = 1; 547 codec->num_dai = 1;
532 codec->read = uda134x_read_reg_cache; 548 codec->read = uda134x_read_reg_cache;
533 codec->write = uda134x_write; 549 codec->write = uda134x_write;
534#ifdef POWER_OFF_ON_STANDBY 550
535 codec->set_bias_level = uda134x_set_bias_level;
536#endif
537 INIT_LIST_HEAD(&codec->dapm_widgets); 551 INIT_LIST_HEAD(&codec->dapm_widgets);
538 INIT_LIST_HEAD(&codec->dapm_paths); 552 INIT_LIST_HEAD(&codec->dapm_paths);
539 553
@@ -544,6 +558,14 @@ static int uda134x_soc_probe(struct platform_device *pdev)
544 558
545 uda134x_reset(codec); 559 uda134x_reset(codec);
546 560
561 if (pd->is_powered_on_standby) {
562 codec->set_bias_level = NULL;
563 uda134x_set_bias_level(codec, SND_SOC_BIAS_ON);
564 } else {
565 codec->set_bias_level = uda134x_set_bias_level;
566 uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
567 }
568
547 /* register pcms */ 569 /* register pcms */
548 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); 570 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
549 if (ret < 0) { 571 if (ret < 0) {
diff --git a/sound/soc/codecs/uda134x.h b/sound/soc/codecs/uda134x.h
index 94f440490b31..205f03b3eaf8 100644
--- a/sound/soc/codecs/uda134x.h
+++ b/sound/soc/codecs/uda134x.h
@@ -23,9 +23,10 @@
23#define UDA134X_DATA000 10 23#define UDA134X_DATA000 10
24#define UDA134X_DATA001 11 24#define UDA134X_DATA001 11
25#define UDA134X_DATA010 12 25#define UDA134X_DATA010 12
26#define UDA134X_DATA1 13 26#define UDA134X_DATA011 13
27#define UDA134X_DATA1 14
27 28
28#define UDA134X_REGS_NUM 14 29#define UDA134X_REGS_NUM 15
29 30
30#define STATUS0_DAIFMT_MASK (~(7<<1)) 31#define STATUS0_DAIFMT_MASK (~(7<<1))
31#define STATUS0_SYSCLK_MASK (~(3<<4)) 32#define STATUS0_SYSCLK_MASK (~(3<<4))
diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c
index 002e289d1255..4bcd168794e1 100644
--- a/sound/soc/codecs/wm2000.c
+++ b/sound/soc/codecs/wm2000.c
@@ -795,6 +795,8 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,
795 795
796 dev_set_drvdata(&i2c->dev, wm2000); 796 dev_set_drvdata(&i2c->dev, wm2000);
797 wm2000->anc_eng_ena = 1; 797 wm2000->anc_eng_ena = 1;
798 wm2000->anc_active = 1;
799 wm2000->spk_ena = 1;
798 wm2000->i2c = i2c; 800 wm2000->i2c = i2c;
799 801
800 wm2000_reset(wm2000); 802 wm2000_reset(wm2000);
diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c
index 37242a7d3077..0ad039b4adf5 100644
--- a/sound/soc/codecs/wm8523.c
+++ b/sound/soc/codecs/wm8523.c
@@ -482,7 +482,8 @@ static int wm8523_register(struct wm8523_priv *wm8523,
482 482
483 if (wm8523_codec) { 483 if (wm8523_codec) {
484 dev_err(codec->dev, "Another WM8523 is registered\n"); 484 dev_err(codec->dev, "Another WM8523 is registered\n");
485 return -EINVAL; 485 ret = -EINVAL;
486 goto err;
486 } 487 }
487 488
488 mutex_init(&codec->mutex); 489 mutex_init(&codec->mutex);
@@ -570,18 +571,19 @@ static int wm8523_register(struct wm8523_priv *wm8523,
570 ret = snd_soc_register_codec(codec); 571 ret = snd_soc_register_codec(codec);
571 if (ret != 0) { 572 if (ret != 0) {
572 dev_err(codec->dev, "Failed to register codec: %d\n", ret); 573 dev_err(codec->dev, "Failed to register codec: %d\n", ret);
573 return ret; 574 goto err_enable;
574 } 575 }
575 576
576 ret = snd_soc_register_dai(&wm8523_dai); 577 ret = snd_soc_register_dai(&wm8523_dai);
577 if (ret != 0) { 578 if (ret != 0) {
578 dev_err(codec->dev, "Failed to register DAI: %d\n", ret); 579 dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
579 snd_soc_unregister_codec(codec); 580 goto err_codec;
580 return ret;
581 } 581 }
582 582
583 return 0; 583 return 0;
584 584
585err_codec:
586 snd_soc_unregister_codec(codec);
585err_enable: 587err_enable:
586 regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), wm8523->supplies); 588 regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), wm8523->supplies);
587err_get: 589err_get:
diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c
index effb14eee7d4..e2dba07f0260 100644
--- a/sound/soc/codecs/wm8711.c
+++ b/sound/soc/codecs/wm8711.c
@@ -439,7 +439,8 @@ static int wm8711_register(struct wm8711_priv *wm8711,
439 439
440 if (wm8711_codec) { 440 if (wm8711_codec) {
441 dev_err(codec->dev, "Another WM8711 is registered\n"); 441 dev_err(codec->dev, "Another WM8711 is registered\n");
442 return -EINVAL; 442 ret = -EINVAL;
443 goto err;
443 } 444 }
444 445
445 mutex_init(&codec->mutex); 446 mutex_init(&codec->mutex);
diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c
new file mode 100644
index 000000000000..b9ea8904ad4b
--- /dev/null
+++ b/sound/soc/codecs/wm8741.c
@@ -0,0 +1,579 @@
1/*
2 * wm8741.c -- WM8741 ALSA SoC Audio driver
3 *
4 * Copyright 2010 Wolfson Microelectronics plc
5 *
6 * Author: Ian Lartey <ian@opensource.wolfsonmicro.com>
7 *
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#include <linux/module.h>
15#include <linux/moduleparam.h>
16#include <linux/init.h>
17#include <linux/delay.h>
18#include <linux/pm.h>
19#include <linux/i2c.h>
20#include <linux/platform_device.h>
21#include <linux/regulator/consumer.h>
22#include <linux/slab.h>
23#include <sound/core.h>
24#include <sound/pcm.h>
25#include <sound/pcm_params.h>
26#include <sound/soc.h>
27#include <sound/soc-dapm.h>
28#include <sound/initval.h>
29#include <sound/tlv.h>
30
31#include "wm8741.h"
32
33static struct snd_soc_codec *wm8741_codec;
34struct snd_soc_codec_device soc_codec_dev_wm8741;
35
36#define WM8741_NUM_SUPPLIES 2
37static const char *wm8741_supply_names[WM8741_NUM_SUPPLIES] = {
38 "AVDD",
39 "DVDD",
40};
41
42#define WM8741_NUM_RATES 4
43
44/* codec private data */
45struct wm8741_priv {
46 struct snd_soc_codec codec;
47 u16 reg_cache[WM8741_REGISTER_COUNT];
48 struct regulator_bulk_data supplies[WM8741_NUM_SUPPLIES];
49 unsigned int sysclk;
50 unsigned int rate_constraint_list[WM8741_NUM_RATES];
51 struct snd_pcm_hw_constraint_list rate_constraint;
52};
53
54static const u16 wm8741_reg_defaults[WM8741_REGISTER_COUNT] = {
55 0x0000, /* R0 - DACLLSB Attenuation */
56 0x0000, /* R1 - DACLMSB Attenuation */
57 0x0000, /* R2 - DACRLSB Attenuation */
58 0x0000, /* R3 - DACRMSB Attenuation */
59 0x0000, /* R4 - Volume Control */
60 0x000A, /* R5 - Format Control */
61 0x0000, /* R6 - Filter Control */
62 0x0000, /* R7 - Mode Control 1 */
63 0x0002, /* R8 - Mode Control 2 */
64 0x0000, /* R9 - Reset */
65 0x0002, /* R32 - ADDITONAL_CONTROL_1 */
66};
67
68
69static int wm8741_reset(struct snd_soc_codec *codec)
70{
71 return snd_soc_write(codec, WM8741_RESET, 0);
72}
73
74static const DECLARE_TLV_DB_SCALE(dac_tlv_fine, -12700, 13, 0);
75static const DECLARE_TLV_DB_SCALE(dac_tlv, -12700, 400, 0);
76
77static const struct snd_kcontrol_new wm8741_snd_controls[] = {
78SOC_DOUBLE_R_TLV("Fine Playback Volume", WM8741_DACLLSB_ATTENUATION,
79 WM8741_DACRLSB_ATTENUATION, 1, 255, 1, dac_tlv_fine),
80SOC_DOUBLE_R_TLV("Playback Volume", WM8741_DACLMSB_ATTENUATION,
81 WM8741_DACRMSB_ATTENUATION, 0, 511, 1, dac_tlv),
82};
83
84static const struct snd_soc_dapm_widget wm8741_dapm_widgets[] = {
85SND_SOC_DAPM_DAC("DACL", "Playback", SND_SOC_NOPM, 0, 0),
86SND_SOC_DAPM_DAC("DACR", "Playback", SND_SOC_NOPM, 0, 0),
87SND_SOC_DAPM_OUTPUT("VOUTLP"),
88SND_SOC_DAPM_OUTPUT("VOUTLN"),
89SND_SOC_DAPM_OUTPUT("VOUTRP"),
90SND_SOC_DAPM_OUTPUT("VOUTRN"),
91};
92
93static const struct snd_soc_dapm_route intercon[] = {
94 { "VOUTLP", NULL, "DACL" },
95 { "VOUTLN", NULL, "DACL" },
96 { "VOUTRP", NULL, "DACR" },
97 { "VOUTRN", NULL, "DACR" },
98};
99
100static int wm8741_add_widgets(struct snd_soc_codec *codec)
101{
102 snd_soc_dapm_new_controls(codec, wm8741_dapm_widgets,
103 ARRAY_SIZE(wm8741_dapm_widgets));
104
105 snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
106
107 return 0;
108}
109
110static struct {
111 int value;
112 int ratio;
113} lrclk_ratios[WM8741_NUM_RATES] = {
114 { 1, 256 },
115 { 2, 384 },
116 { 3, 512 },
117 { 4, 768 },
118};
119
120
121static int wm8741_startup(struct snd_pcm_substream *substream,
122 struct snd_soc_dai *dai)
123{
124 struct snd_soc_codec *codec = dai->codec;
125 struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
126
127 /* The set of sample rates that can be supported depends on the
128 * MCLK supplied to the CODEC - enforce this.
129 */
130 if (!wm8741->sysclk) {
131 dev_err(codec->dev,
132 "No MCLK configured, call set_sysclk() on init\n");
133 return -EINVAL;
134 }
135
136 snd_pcm_hw_constraint_list(substream->runtime, 0,
137 SNDRV_PCM_HW_PARAM_RATE,
138 &wm8741->rate_constraint);
139
140 return 0;
141}
142
143static int wm8741_hw_params(struct snd_pcm_substream *substream,
144 struct snd_pcm_hw_params *params,
145 struct snd_soc_dai *dai)
146{
147 struct snd_soc_pcm_runtime *rtd = substream->private_data;
148 struct snd_soc_device *socdev = rtd->socdev;
149 struct snd_soc_codec *codec = socdev->card->codec;
150 struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
151 u16 iface = snd_soc_read(codec, WM8741_FORMAT_CONTROL) & 0x1FC;
152 int i;
153
154 /* Find a supported LRCLK ratio */
155 for (i = 0; i < ARRAY_SIZE(lrclk_ratios); i++) {
156 if (wm8741->sysclk / params_rate(params) ==
157 lrclk_ratios[i].ratio)
158 break;
159 }
160
161 /* Should never happen, should be handled by constraints */
162 if (i == ARRAY_SIZE(lrclk_ratios)) {
163 dev_err(codec->dev, "MCLK/fs ratio %d unsupported\n",
164 wm8741->sysclk / params_rate(params));
165 return -EINVAL;
166 }
167
168 /* bit size */
169 switch (params_format(params)) {
170 case SNDRV_PCM_FORMAT_S16_LE:
171 break;
172 case SNDRV_PCM_FORMAT_S20_3LE:
173 iface |= 0x0001;
174 break;
175 case SNDRV_PCM_FORMAT_S24_LE:
176 iface |= 0x0002;
177 break;
178 case SNDRV_PCM_FORMAT_S32_LE:
179 iface |= 0x0003;
180 break;
181 default:
182 dev_dbg(codec->dev, "wm8741_hw_params: Unsupported bit size param = %d",
183 params_format(params));
184 return -EINVAL;
185 }
186
187 dev_dbg(codec->dev, "wm8741_hw_params: bit size param = %d",
188 params_format(params));
189
190 snd_soc_write(codec, WM8741_FORMAT_CONTROL, iface);
191 return 0;
192}
193
194static int wm8741_set_dai_sysclk(struct snd_soc_dai *codec_dai,
195 int clk_id, unsigned int freq, int dir)
196{
197 struct snd_soc_codec *codec = codec_dai->codec;
198 struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
199 unsigned int val;
200 int i;
201
202 dev_dbg(codec->dev, "wm8741_set_dai_sysclk info: freq=%dHz\n", freq);
203
204 wm8741->sysclk = freq;
205
206 wm8741->rate_constraint.count = 0;
207
208 for (i = 0; i < ARRAY_SIZE(lrclk_ratios); i++) {
209 dev_dbg(codec->dev, "index = %d, ratio = %d, freq = %d",
210 i, lrclk_ratios[i].ratio, freq);
211
212 val = freq / lrclk_ratios[i].ratio;
213 /* Check that it's a standard rate since core can't
214 * cope with others and having the odd rates confuses
215 * constraint matching.
216 */
217 switch (val) {
218 case 32000:
219 case 44100:
220 case 48000:
221 case 64000:
222 case 88200:
223 case 96000:
224 dev_dbg(codec->dev, "Supported sample rate: %dHz\n",
225 val);
226 wm8741->rate_constraint_list[i] = val;
227 wm8741->rate_constraint.count++;
228 break;
229 default:
230 dev_dbg(codec->dev, "Skipping sample rate: %dHz\n",
231 val);
232 }
233 }
234
235 /* Need at least one supported rate... */
236 if (wm8741->rate_constraint.count == 0)
237 return -EINVAL;
238
239 return 0;
240}
241
242static int wm8741_set_dai_fmt(struct snd_soc_dai *codec_dai,
243 unsigned int fmt)
244{
245 struct snd_soc_codec *codec = codec_dai->codec;
246 u16 iface = snd_soc_read(codec, WM8741_FORMAT_CONTROL) & 0x1C3;
247
248 /* check master/slave audio interface */
249 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
250 case SND_SOC_DAIFMT_CBS_CFS:
251 break;
252 default:
253 return -EINVAL;
254 }
255
256 /* interface format */
257 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
258 case SND_SOC_DAIFMT_I2S:
259 iface |= 0x0008;
260 break;
261 case SND_SOC_DAIFMT_RIGHT_J:
262 break;
263 case SND_SOC_DAIFMT_LEFT_J:
264 iface |= 0x0004;
265 break;
266 case SND_SOC_DAIFMT_DSP_A:
267 iface |= 0x0003;
268 break;
269 case SND_SOC_DAIFMT_DSP_B:
270 iface |= 0x0013;
271 break;
272 default:
273 return -EINVAL;
274 }
275
276 /* clock inversion */
277 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
278 case SND_SOC_DAIFMT_NB_NF:
279 break;
280 case SND_SOC_DAIFMT_IB_IF:
281 iface |= 0x0010;
282 break;
283 case SND_SOC_DAIFMT_IB_NF:
284 iface |= 0x0020;
285 break;
286 case SND_SOC_DAIFMT_NB_IF:
287 iface |= 0x0030;
288 break;
289 default:
290 return -EINVAL;
291 }
292
293
294 dev_dbg(codec->dev, "wm8741_set_dai_fmt: Format=%x, Clock Inv=%x\n",
295 fmt & SND_SOC_DAIFMT_FORMAT_MASK,
296 ((fmt & SND_SOC_DAIFMT_INV_MASK)));
297
298 snd_soc_write(codec, WM8741_FORMAT_CONTROL, iface);
299 return 0;
300}
301
302#define WM8741_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
303 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | \
304 SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | \
305 SNDRV_PCM_RATE_192000)
306
307#define WM8741_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
308 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
309
310static struct snd_soc_dai_ops wm8741_dai_ops = {
311 .startup = wm8741_startup,
312 .hw_params = wm8741_hw_params,
313 .set_sysclk = wm8741_set_dai_sysclk,
314 .set_fmt = wm8741_set_dai_fmt,
315};
316
317struct snd_soc_dai wm8741_dai = {
318 .name = "WM8741",
319 .playback = {
320 .stream_name = "Playback",
321 .channels_min = 2, /* Mono modes not yet supported */
322 .channels_max = 2,
323 .rates = WM8741_RATES,
324 .formats = WM8741_FORMATS,
325 },
326 .ops = &wm8741_dai_ops,
327};
328EXPORT_SYMBOL_GPL(wm8741_dai);
329
330#ifdef CONFIG_PM
331static int wm8741_resume(struct platform_device *pdev)
332{
333 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
334 struct snd_soc_codec *codec = socdev->card->codec;
335 u16 *cache = codec->reg_cache;
336 int i;
337
338 /* RESTORE REG Cache */
339 for (i = 0; i < WM8741_REGISTER_COUNT; i++) {
340 if (cache[i] == wm8741_reg_defaults[i] || WM8741_RESET == i)
341 continue;
342 snd_soc_write(codec, i, cache[i]);
343 }
344 return 0;
345}
346#else
347#define wm8741_suspend NULL
348#define wm8741_resume NULL
349#endif
350
351static int wm8741_probe(struct platform_device *pdev)
352{
353 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
354 struct snd_soc_codec *codec;
355 int ret = 0;
356
357 if (wm8741_codec == NULL) {
358 dev_err(&pdev->dev, "Codec device not registered\n");
359 return -ENODEV;
360 }
361
362 socdev->card->codec = wm8741_codec;
363 codec = wm8741_codec;
364
365 /* register pcms */
366 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
367 if (ret < 0) {
368 dev_err(codec->dev, "failed to create pcms: %d\n", ret);
369 goto pcm_err;
370 }
371
372 snd_soc_add_controls(codec, wm8741_snd_controls,
373 ARRAY_SIZE(wm8741_snd_controls));
374 wm8741_add_widgets(codec);
375
376 return ret;
377
378pcm_err:
379 return ret;
380}
381
382static int wm8741_remove(struct platform_device *pdev)
383{
384 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
385
386 snd_soc_free_pcms(socdev);
387 snd_soc_dapm_free(socdev);
388
389 return 0;
390}
391
392struct snd_soc_codec_device soc_codec_dev_wm8741 = {
393 .probe = wm8741_probe,
394 .remove = wm8741_remove,
395 .resume = wm8741_resume,
396};
397EXPORT_SYMBOL_GPL(soc_codec_dev_wm8741);
398
399static int wm8741_register(struct wm8741_priv *wm8741,
400 enum snd_soc_control_type control)
401{
402 int ret;
403 struct snd_soc_codec *codec = &wm8741->codec;
404 int i;
405
406 if (wm8741_codec) {
407 dev_err(codec->dev, "Another WM8741 is registered\n");
408 return -EINVAL;
409 }
410
411 mutex_init(&codec->mutex);
412 INIT_LIST_HEAD(&codec->dapm_widgets);
413 INIT_LIST_HEAD(&codec->dapm_paths);
414
415 snd_soc_codec_set_drvdata(codec, wm8741);
416 codec->name = "WM8741";
417 codec->owner = THIS_MODULE;
418 codec->bias_level = SND_SOC_BIAS_OFF;
419 codec->set_bias_level = NULL;
420 codec->dai = &wm8741_dai;
421 codec->num_dai = 1;
422 codec->reg_cache_size = WM8741_REGISTER_COUNT;
423 codec->reg_cache = &wm8741->reg_cache;
424
425 wm8741->rate_constraint.list = &wm8741->rate_constraint_list[0];
426 wm8741->rate_constraint.count =
427 ARRAY_SIZE(wm8741->rate_constraint_list);
428
429 memcpy(codec->reg_cache, wm8741_reg_defaults,
430 sizeof(wm8741->reg_cache));
431
432 ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
433 if (ret != 0) {
434 dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
435 goto err;
436 }
437
438 for (i = 0; i < ARRAY_SIZE(wm8741->supplies); i++)
439 wm8741->supplies[i].supply = wm8741_supply_names[i];
440
441 ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8741->supplies),
442 wm8741->supplies);
443 if (ret != 0) {
444 dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
445 goto err;
446 }
447
448 ret = regulator_bulk_enable(ARRAY_SIZE(wm8741->supplies),
449 wm8741->supplies);
450 if (ret != 0) {
451 dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
452 goto err_get;
453 }
454
455 ret = wm8741_reset(codec);
456 if (ret < 0) {
457 dev_err(codec->dev, "Failed to issue reset\n");
458 goto err_enable;
459 }
460
461 wm8741_dai.dev = codec->dev;
462
463 /* Change some default settings - latch VU */
464 wm8741->reg_cache[WM8741_DACLLSB_ATTENUATION] |= WM8741_UPDATELL;
465 wm8741->reg_cache[WM8741_DACLMSB_ATTENUATION] |= WM8741_UPDATELM;
466 wm8741->reg_cache[WM8741_DACRLSB_ATTENUATION] |= WM8741_UPDATERL;
467 wm8741->reg_cache[WM8741_DACRLSB_ATTENUATION] |= WM8741_UPDATERM;
468
469 wm8741_codec = codec;
470
471 ret = snd_soc_register_codec(codec);
472 if (ret != 0) {
473 dev_err(codec->dev, "Failed to register codec: %d\n", ret);
474 return ret;
475 }
476
477 ret = snd_soc_register_dai(&wm8741_dai);
478 if (ret != 0) {
479 dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
480 snd_soc_unregister_codec(codec);
481 return ret;
482 }
483
484 dev_dbg(codec->dev, "Successful registration\n");
485 return 0;
486
487err_enable:
488 regulator_bulk_disable(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
489
490err_get:
491 regulator_bulk_free(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
492
493err:
494 kfree(wm8741);
495 return ret;
496}
497
498static void wm8741_unregister(struct wm8741_priv *wm8741)
499{
500 regulator_bulk_free(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
501
502 snd_soc_unregister_dai(&wm8741_dai);
503 snd_soc_unregister_codec(&wm8741->codec);
504 kfree(wm8741);
505 wm8741_codec = NULL;
506}
507
508#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
509static __devinit int wm8741_i2c_probe(struct i2c_client *i2c,
510 const struct i2c_device_id *id)
511{
512 struct wm8741_priv *wm8741;
513 struct snd_soc_codec *codec;
514
515 wm8741 = kzalloc(sizeof(struct wm8741_priv), GFP_KERNEL);
516 if (wm8741 == NULL)
517 return -ENOMEM;
518
519 codec = &wm8741->codec;
520 codec->hw_write = (hw_write_t)i2c_master_send;
521
522 i2c_set_clientdata(i2c, wm8741);
523 codec->control_data = i2c;
524
525 codec->dev = &i2c->dev;
526
527 return wm8741_register(wm8741, SND_SOC_I2C);
528}
529
530static __devexit int wm8741_i2c_remove(struct i2c_client *client)
531{
532 struct wm8741_priv *wm8741 = i2c_get_clientdata(client);
533 wm8741_unregister(wm8741);
534 return 0;
535}
536
537static const struct i2c_device_id wm8741_i2c_id[] = {
538 { "wm8741", 0 },
539 { }
540};
541MODULE_DEVICE_TABLE(i2c, wm8741_i2c_id);
542
543
544static struct i2c_driver wm8741_i2c_driver = {
545 .driver = {
546 .name = "WM8741",
547 .owner = THIS_MODULE,
548 },
549 .probe = wm8741_i2c_probe,
550 .remove = __devexit_p(wm8741_i2c_remove),
551 .id_table = wm8741_i2c_id,
552};
553#endif
554
555static int __init wm8741_modinit(void)
556{
557 int ret;
558#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
559 ret = i2c_add_driver(&wm8741_i2c_driver);
560 if (ret != 0) {
561 printk(KERN_ERR "Failed to register WM8741 I2C driver: %d\n",
562 ret);
563 }
564#endif
565 return 0;
566}
567module_init(wm8741_modinit);
568
569static void __exit wm8741_exit(void)
570{
571#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
572 i2c_del_driver(&wm8741_i2c_driver);
573#endif
574}
575module_exit(wm8741_exit);
576
577MODULE_DESCRIPTION("ASoC WM8741 driver");
578MODULE_AUTHOR("Ian Lartey <ian@opensource.wolfsonmicro.com>");
579MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/wm8741.h b/sound/soc/codecs/wm8741.h
new file mode 100644
index 000000000000..fdef6ecd1f6f
--- /dev/null
+++ b/sound/soc/codecs/wm8741.h
@@ -0,0 +1,214 @@
1/*
2 * wm8741.h -- WM8423 ASoC driver
3 *
4 * Copyright 2010 Wolfson Microelectronics, plc
5 *
6 * Author: Ian Lartey <ian@opensource.wolfsonmicro.com>
7 *
8 * Based on wm8753.h
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 */
14
15#ifndef _WM8741_H
16#define _WM8741_H
17
18/*
19 * Register values.
20 */
21#define WM8741_DACLLSB_ATTENUATION 0x00
22#define WM8741_DACLMSB_ATTENUATION 0x01
23#define WM8741_DACRLSB_ATTENUATION 0x02
24#define WM8741_DACRMSB_ATTENUATION 0x03
25#define WM8741_VOLUME_CONTROL 0x04
26#define WM8741_FORMAT_CONTROL 0x05
27#define WM8741_FILTER_CONTROL 0x06
28#define WM8741_MODE_CONTROL_1 0x07
29#define WM8741_MODE_CONTROL_2 0x08
30#define WM8741_RESET 0x09
31#define WM8741_ADDITIONAL_CONTROL_1 0x20
32
33#define WM8741_REGISTER_COUNT 11
34#define WM8741_MAX_REGISTER 0x20
35
36/*
37 * Field Definitions.
38 */
39
40/*
41 * R0 (0x00) - DACLLSB_ATTENUATION
42 */
43#define WM8741_UPDATELL 0x0020 /* UPDATELL */
44#define WM8741_UPDATELL_MASK 0x0020 /* UPDATELL */
45#define WM8741_UPDATELL_SHIFT 5 /* UPDATELL */
46#define WM8741_UPDATELL_WIDTH 1 /* UPDATELL */
47#define WM8741_LAT_4_0_MASK 0x001F /* LAT[4:0] - [4:0] */
48#define WM8741_LAT_4_0_SHIFT 0 /* LAT[4:0] - [4:0] */
49#define WM8741_LAT_4_0_WIDTH 5 /* LAT[4:0] - [4:0] */
50
51/*
52 * R1 (0x01) - DACLMSB_ATTENUATION
53 */
54#define WM8741_UPDATELM 0x0020 /* UPDATELM */
55#define WM8741_UPDATELM_MASK 0x0020 /* UPDATELM */
56#define WM8741_UPDATELM_SHIFT 5 /* UPDATELM */
57#define WM8741_UPDATELM_WIDTH 1 /* UPDATELM */
58#define WM8741_LAT_9_5_0_MASK 0x001F /* LAT[9:5] - [4:0] */
59#define WM8741_LAT_9_5_0_SHIFT 0 /* LAT[9:5] - [4:0] */
60#define WM8741_LAT_9_5_0_WIDTH 5 /* LAT[9:5] - [4:0] */
61
62/*
63 * R2 (0x02) - DACRLSB_ATTENUATION
64 */
65#define WM8741_UPDATERL 0x0020 /* UPDATERL */
66#define WM8741_UPDATERL_MASK 0x0020 /* UPDATERL */
67#define WM8741_UPDATERL_SHIFT 5 /* UPDATERL */
68#define WM8741_UPDATERL_WIDTH 1 /* UPDATERL */
69#define WM8741_RAT_4_0_MASK 0x001F /* RAT[4:0] - [4:0] */
70#define WM8741_RAT_4_0_SHIFT 0 /* RAT[4:0] - [4:0] */
71#define WM8741_RAT_4_0_WIDTH 5 /* RAT[4:0] - [4:0] */
72
73/*
74 * R3 (0x03) - DACRMSB_ATTENUATION
75 */
76#define WM8741_UPDATERM 0x0020 /* UPDATERM */
77#define WM8741_UPDATERM_MASK 0x0020 /* UPDATERM */
78#define WM8741_UPDATERM_SHIFT 5 /* UPDATERM */
79#define WM8741_UPDATERM_WIDTH 1 /* UPDATERM */
80#define WM8741_RAT_9_5_0_MASK 0x001F /* RAT[9:5] - [4:0] */
81#define WM8741_RAT_9_5_0_SHIFT 0 /* RAT[9:5] - [4:0] */
82#define WM8741_RAT_9_5_0_WIDTH 5 /* RAT[9:5] - [4:0] */
83
84/*
85 * R4 (0x04) - VOLUME_CONTROL
86 */
87#define WM8741_AMUTE 0x0080 /* AMUTE */
88#define WM8741_AMUTE_MASK 0x0080 /* AMUTE */
89#define WM8741_AMUTE_SHIFT 7 /* AMUTE */
90#define WM8741_AMUTE_WIDTH 1 /* AMUTE */
91#define WM8741_ZFLAG_MASK 0x0060 /* ZFLAG - [6:5] */
92#define WM8741_ZFLAG_SHIFT 5 /* ZFLAG - [6:5] */
93#define WM8741_ZFLAG_WIDTH 2 /* ZFLAG - [6:5] */
94#define WM8741_IZD 0x0010 /* IZD */
95#define WM8741_IZD_MASK 0x0010 /* IZD */
96#define WM8741_IZD_SHIFT 4 /* IZD */
97#define WM8741_IZD_WIDTH 1 /* IZD */
98#define WM8741_SOFT 0x0008 /* SOFT MUTE */
99#define WM8741_SOFT_MASK 0x0008 /* SOFT MUTE */
100#define WM8741_SOFT_SHIFT 3 /* SOFT MUTE */
101#define WM8741_SOFT_WIDTH 1 /* SOFT MUTE */
102#define WM8741_ATC 0x0004 /* ATC */
103#define WM8741_ATC_MASK 0x0004 /* ATC */
104#define WM8741_ATC_SHIFT 2 /* ATC */
105#define WM8741_ATC_WIDTH 1 /* ATC */
106#define WM8741_ATT2DB 0x0002 /* ATT2DB */
107#define WM8741_ATT2DB_MASK 0x0002 /* ATT2DB */
108#define WM8741_ATT2DB_SHIFT 1 /* ATT2DB */
109#define WM8741_ATT2DB_WIDTH 1 /* ATT2DB */
110#define WM8741_VOL_RAMP 0x0001 /* VOL_RAMP */
111#define WM8741_VOL_RAMP_MASK 0x0001 /* VOL_RAMP */
112#define WM8741_VOL_RAMP_SHIFT 0 /* VOL_RAMP */
113#define WM8741_VOL_RAMP_WIDTH 1 /* VOL_RAMP */
114
115/*
116 * R5 (0x05) - FORMAT_CONTROL
117 */
118#define WM8741_PWDN 0x0080 /* PWDN */
119#define WM8741_PWDN_MASK 0x0080 /* PWDN */
120#define WM8741_PWDN_SHIFT 7 /* PWDN */
121#define WM8741_PWDN_WIDTH 1 /* PWDN */
122#define WM8741_REV 0x0040 /* REV */
123#define WM8741_REV_MASK 0x0040 /* REV */
124#define WM8741_REV_SHIFT 6 /* REV */
125#define WM8741_REV_WIDTH 1 /* REV */
126#define WM8741_BCP 0x0020 /* BCP */
127#define WM8741_BCP_MASK 0x0020 /* BCP */
128#define WM8741_BCP_SHIFT 5 /* BCP */
129#define WM8741_BCP_WIDTH 1 /* BCP */
130#define WM8741_LRP 0x0010 /* LRP */
131#define WM8741_LRP_MASK 0x0010 /* LRP */
132#define WM8741_LRP_SHIFT 4 /* LRP */
133#define WM8741_LRP_WIDTH 1 /* LRP */
134#define WM8741_FMT_MASK 0x000C /* FMT - [3:2] */
135#define WM8741_FMT_SHIFT 2 /* FMT - [3:2] */
136#define WM8741_FMT_WIDTH 2 /* FMT - [3:2] */
137#define WM8741_IWL_MASK 0x0003 /* IWL - [1:0] */
138#define WM8741_IWL_SHIFT 0 /* IWL - [1:0] */
139#define WM8741_IWL_WIDTH 2 /* IWL - [1:0] */
140
141/*
142 * R6 (0x06) - FILTER_CONTROL
143 */
144#define WM8741_ZFLAG_HI 0x0080 /* ZFLAG_HI */
145#define WM8741_ZFLAG_HI_MASK 0x0080 /* ZFLAG_HI */
146#define WM8741_ZFLAG_HI_SHIFT 7 /* ZFLAG_HI */
147#define WM8741_ZFLAG_HI_WIDTH 1 /* ZFLAG_HI */
148#define WM8741_DEEMPH_MASK 0x0060 /* DEEMPH - [6:5] */
149#define WM8741_DEEMPH_SHIFT 5 /* DEEMPH - [6:5] */
150#define WM8741_DEEMPH_WIDTH 2 /* DEEMPH - [6:5] */
151#define WM8741_DSDFILT_MASK 0x0018 /* DSDFILT - [4:3] */
152#define WM8741_DSDFILT_SHIFT 3 /* DSDFILT - [4:3] */
153#define WM8741_DSDFILT_WIDTH 2 /* DSDFILT - [4:3] */
154#define WM8741_FIRSEL_MASK 0x0007 /* FIRSEL - [2:0] */
155#define WM8741_FIRSEL_SHIFT 0 /* FIRSEL - [2:0] */
156#define WM8741_FIRSEL_WIDTH 3 /* FIRSEL - [2:0] */
157
158/*
159 * R7 (0x07) - MODE_CONTROL_1
160 */
161#define WM8741_MODE8X 0x0080 /* MODE8X */
162#define WM8741_MODE8X_MASK 0x0080 /* MODE8X */
163#define WM8741_MODE8X_SHIFT 7 /* MODE8X */
164#define WM8741_MODE8X_WIDTH 1 /* MODE8X */
165#define WM8741_OSR_MASK 0x0060 /* OSR - [6:5] */
166#define WM8741_OSR_SHIFT 5 /* OSR - [6:5] */
167#define WM8741_OSR_WIDTH 2 /* OSR - [6:5] */
168#define WM8741_SR_MASK 0x001C /* SR - [4:2] */
169#define WM8741_SR_SHIFT 2 /* SR - [4:2] */
170#define WM8741_SR_WIDTH 3 /* SR - [4:2] */
171#define WM8741_MODESEL_MASK 0x0003 /* MODESEL - [1:0] */
172#define WM8741_MODESEL_SHIFT 0 /* MODESEL - [1:0] */
173#define WM8741_MODESEL_WIDTH 2 /* MODESEL - [1:0] */
174
175/*
176 * R8 (0x08) - MODE_CONTROL_2
177 */
178#define WM8741_DSD_GAIN 0x0040 /* DSD_GAIN */
179#define WM8741_DSD_GAIN_MASK 0x0040 /* DSD_GAIN */
180#define WM8741_DSD_GAIN_SHIFT 6 /* DSD_GAIN */
181#define WM8741_DSD_GAIN_WIDTH 1 /* DSD_GAIN */
182#define WM8741_SDOUT 0x0020 /* SDOUT */
183#define WM8741_SDOUT_MASK 0x0020 /* SDOUT */
184#define WM8741_SDOUT_SHIFT 5 /* SDOUT */
185#define WM8741_SDOUT_WIDTH 1 /* SDOUT */
186#define WM8741_DOUT 0x0010 /* DOUT */
187#define WM8741_DOUT_MASK 0x0010 /* DOUT */
188#define WM8741_DOUT_SHIFT 4 /* DOUT */
189#define WM8741_DOUT_WIDTH 1 /* DOUT */
190#define WM8741_DIFF_MASK 0x000C /* DIFF - [3:2] */
191#define WM8741_DIFF_SHIFT 2 /* DIFF - [3:2] */
192#define WM8741_DIFF_WIDTH 2 /* DIFF - [3:2] */
193#define WM8741_DITHER_MASK 0x0003 /* DITHER - [1:0] */
194#define WM8741_DITHER_SHIFT 0 /* DITHER - [1:0] */
195#define WM8741_DITHER_WIDTH 2 /* DITHER - [1:0] */
196
197/*
198 * R32 (0x20) - ADDITONAL_CONTROL_1
199 */
200#define WM8741_DSD_LEVEL 0x0002 /* DSD_LEVEL */
201#define WM8741_DSD_LEVEL_MASK 0x0002 /* DSD_LEVEL */
202#define WM8741_DSD_LEVEL_SHIFT 1 /* DSD_LEVEL */
203#define WM8741_DSD_LEVEL_WIDTH 1 /* DSD_LEVEL */
204#define WM8741_DSD_NO_NOTCH 0x0001 /* DSD_NO_NOTCH */
205#define WM8741_DSD_NO_NOTCH_MASK 0x0001 /* DSD_NO_NOTCH */
206#define WM8741_DSD_NO_NOTCH_SHIFT 0 /* DSD_NO_NOTCH */
207#define WM8741_DSD_NO_NOTCH_WIDTH 1 /* DSD_NO_NOTCH */
208
209#define WM8741_SYSCLK 0
210
211extern struct snd_soc_dai wm8741_dai;
212extern struct snd_soc_codec_device soc_codec_dev_wm8741;
213
214#endif
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c
index 9407e193fcc3..e2c05e3e323a 100644
--- a/sound/soc/codecs/wm8750.c
+++ b/sound/soc/codecs/wm8750.c
@@ -884,6 +884,7 @@ static int wm8750_i2c_remove(struct i2c_client *client)
884 884
885static const struct i2c_device_id wm8750_i2c_id[] = { 885static const struct i2c_device_id wm8750_i2c_id[] = {
886 { "wm8750", 0 }, 886 { "wm8750", 0 },
887 { "wm8987", 0 }, /* WM8987 is register compatible with WM8750 */
887 { } 888 { }
888}; 889};
889MODULE_DEVICE_TABLE(i2c, wm8750_i2c_id); 890MODULE_DEVICE_TABLE(i2c, wm8750_i2c_id);
@@ -925,14 +926,22 @@ static int __devexit wm8750_spi_remove(struct spi_device *spi)
925 return 0; 926 return 0;
926} 927}
927 928
929static const struct spi_device_id wm8750_spi_id[] = {
930 { "wm8750", 0 },
931 { "wm8987", 0 },
932 { }
933};
934MODULE_DEVICE_TABLE(spi, wm8750_spi_id);
935
928static struct spi_driver wm8750_spi_driver = { 936static struct spi_driver wm8750_spi_driver = {
929 .driver = { 937 .driver = {
930 .name = "wm8750", 938 .name = "WM8750 SPI Codec",
931 .bus = &spi_bus_type, 939 .bus = &spi_bus_type,
932 .owner = THIS_MODULE, 940 .owner = THIS_MODULE,
933 }, 941 },
934 .probe = wm8750_spi_probe, 942 .probe = wm8750_spi_probe,
935 .remove = __devexit_p(wm8750_spi_remove), 943 .remove = __devexit_p(wm8750_spi_remove),
944 .id_table = wm8750_spi_id,
936}; 945};
937#endif 946#endif
938 947
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c
index 87f14f8675fa..f7dcabf6283c 100644
--- a/sound/soc/codecs/wm8904.c
+++ b/sound/soc/codecs/wm8904.c
@@ -2433,7 +2433,8 @@ static int wm8904_register(struct wm8904_priv *wm8904,
2433 2433
2434 if (wm8904_codec) { 2434 if (wm8904_codec) {
2435 dev_err(codec->dev, "Another WM8904 is registered\n"); 2435 dev_err(codec->dev, "Another WM8904 is registered\n");
2436 return -EINVAL; 2436 ret = -EINVAL;
2437 goto err;
2437 } 2438 }
2438 2439
2439 mutex_init(&codec->mutex); 2440 mutex_init(&codec->mutex);
@@ -2462,7 +2463,8 @@ static int wm8904_register(struct wm8904_priv *wm8904,
2462 default: 2463 default:
2463 dev_err(codec->dev, "Unknown device type %d\n", 2464 dev_err(codec->dev, "Unknown device type %d\n",
2464 wm8904->devtype); 2465 wm8904->devtype);
2465 return -EINVAL; 2466 ret = -EINVAL;
2467 goto err;
2466 } 2468 }
2467 2469
2468 memcpy(codec->reg_cache, wm8904_reg, sizeof(wm8904_reg)); 2470 memcpy(codec->reg_cache, wm8904_reg, sizeof(wm8904_reg));
@@ -2566,18 +2568,19 @@ static int wm8904_register(struct wm8904_priv *wm8904,
2566 ret = snd_soc_register_codec(codec); 2568 ret = snd_soc_register_codec(codec);
2567 if (ret != 0) { 2569 if (ret != 0) {
2568 dev_err(codec->dev, "Failed to register codec: %d\n", ret); 2570 dev_err(codec->dev, "Failed to register codec: %d\n", ret);
2569 return ret; 2571 goto err_enable;
2570 } 2572 }
2571 2573
2572 ret = snd_soc_register_dai(&wm8904_dai); 2574 ret = snd_soc_register_dai(&wm8904_dai);
2573 if (ret != 0) { 2575 if (ret != 0) {
2574 dev_err(codec->dev, "Failed to register DAI: %d\n", ret); 2576 dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
2575 snd_soc_unregister_codec(codec); 2577 goto err_codec;
2576 return ret;
2577 } 2578 }
2578 2579
2579 return 0; 2580 return 0;
2580 2581
2582err_codec:
2583 snd_soc_unregister_codec(codec);
2581err_enable: 2584err_enable:
2582 regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), wm8904->supplies); 2585 regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), wm8904->supplies);
2583err_get: 2586err_get:
diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c
index e3c4bbfaae27..f0c11138e610 100644
--- a/sound/soc/codecs/wm8940.c
+++ b/sound/soc/codecs/wm8940.c
@@ -845,6 +845,7 @@ static void wm8940_unregister(struct wm8940_priv *wm8940)
845static int wm8940_i2c_probe(struct i2c_client *i2c, 845static int wm8940_i2c_probe(struct i2c_client *i2c,
846 const struct i2c_device_id *id) 846 const struct i2c_device_id *id)
847{ 847{
848 int ret;
848 struct wm8940_priv *wm8940; 849 struct wm8940_priv *wm8940;
849 struct snd_soc_codec *codec; 850 struct snd_soc_codec *codec;
850 851
@@ -858,7 +859,11 @@ static int wm8940_i2c_probe(struct i2c_client *i2c,
858 codec->control_data = i2c; 859 codec->control_data = i2c;
859 codec->dev = &i2c->dev; 860 codec->dev = &i2c->dev;
860 861
861 return wm8940_register(wm8940, SND_SOC_I2C); 862 ret = wm8940_register(wm8940, SND_SOC_I2C);
863 if (ret < 0)
864 kfree(wm8940);
865
866 return ret;
862} 867}
863 868
864static int __devexit wm8940_i2c_remove(struct i2c_client *client) 869static int __devexit wm8940_i2c_remove(struct i2c_client *client)
diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c
index fedb76452f1b..5f025593d84d 100644
--- a/sound/soc/codecs/wm8955.c
+++ b/sound/soc/codecs/wm8955.c
@@ -964,7 +964,8 @@ static int wm8955_register(struct wm8955_priv *wm8955,
964 964
965 if (wm8955_codec) { 965 if (wm8955_codec) {
966 dev_err(codec->dev, "Another WM8955 is registered\n"); 966 dev_err(codec->dev, "Another WM8955 is registered\n");
967 return -EINVAL; 967 ret = -EINVAL;
968 goto err;
968 } 969 }
969 970
970 mutex_init(&codec->mutex); 971 mutex_init(&codec->mutex);
@@ -1047,18 +1048,19 @@ static int wm8955_register(struct wm8955_priv *wm8955,
1047 ret = snd_soc_register_codec(codec); 1048 ret = snd_soc_register_codec(codec);
1048 if (ret != 0) { 1049 if (ret != 0) {
1049 dev_err(codec->dev, "Failed to register codec: %d\n", ret); 1050 dev_err(codec->dev, "Failed to register codec: %d\n", ret);
1050 return ret; 1051 goto err_enable;
1051 } 1052 }
1052 1053
1053 ret = snd_soc_register_dai(&wm8955_dai); 1054 ret = snd_soc_register_dai(&wm8955_dai);
1054 if (ret != 0) { 1055 if (ret != 0) {
1055 dev_err(codec->dev, "Failed to register DAI: %d\n", ret); 1056 dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
1056 snd_soc_unregister_codec(codec); 1057 goto err_codec;
1057 return ret;
1058 } 1058 }
1059 1059
1060 return 0; 1060 return 0;
1061 1061
1062err_codec:
1063 snd_soc_unregister_codec(codec);
1062err_enable: 1064err_enable:
1063 regulator_bulk_disable(ARRAY_SIZE(wm8955->supplies), wm8955->supplies); 1065 regulator_bulk_disable(ARRAY_SIZE(wm8955->supplies), wm8955->supplies);
1064err_get: 1066err_get:
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
index 7233cc68435a..3c6ee61f6c95 100644
--- a/sound/soc/codecs/wm8960.c
+++ b/sound/soc/codecs/wm8960.c
@@ -79,12 +79,13 @@ struct wm8960_priv {
79 struct snd_soc_dapm_widget *lout1; 79 struct snd_soc_dapm_widget *lout1;
80 struct snd_soc_dapm_widget *rout1; 80 struct snd_soc_dapm_widget *rout1;
81 struct snd_soc_dapm_widget *out3; 81 struct snd_soc_dapm_widget *out3;
82 bool deemph;
83 int playback_fs;
82}; 84};
83 85
84#define wm8960_reset(c) snd_soc_write(c, WM8960_RESET, 0) 86#define wm8960_reset(c) snd_soc_write(c, WM8960_RESET, 0)
85 87
86/* enumerated controls */ 88/* enumerated controls */
87static const char *wm8960_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"};
88static const char *wm8960_polarity[] = {"No Inversion", "Left Inverted", 89static const char *wm8960_polarity[] = {"No Inversion", "Left Inverted",
89 "Right Inverted", "Stereo Inversion"}; 90 "Right Inverted", "Stereo Inversion"};
90static const char *wm8960_3d_upper_cutoff[] = {"High", "Low"}; 91static const char *wm8960_3d_upper_cutoff[] = {"High", "Low"};
@@ -93,7 +94,6 @@ static const char *wm8960_alcfunc[] = {"Off", "Right", "Left", "Stereo"};
93static const char *wm8960_alcmode[] = {"ALC", "Limiter"}; 94static const char *wm8960_alcmode[] = {"ALC", "Limiter"};
94 95
95static const struct soc_enum wm8960_enum[] = { 96static const struct soc_enum wm8960_enum[] = {
96 SOC_ENUM_SINGLE(WM8960_DACCTL1, 1, 4, wm8960_deemph),
97 SOC_ENUM_SINGLE(WM8960_DACCTL1, 5, 4, wm8960_polarity), 97 SOC_ENUM_SINGLE(WM8960_DACCTL1, 5, 4, wm8960_polarity),
98 SOC_ENUM_SINGLE(WM8960_DACCTL2, 5, 4, wm8960_polarity), 98 SOC_ENUM_SINGLE(WM8960_DACCTL2, 5, 4, wm8960_polarity),
99 SOC_ENUM_SINGLE(WM8960_3D, 6, 2, wm8960_3d_upper_cutoff), 99 SOC_ENUM_SINGLE(WM8960_3D, 6, 2, wm8960_3d_upper_cutoff),
@@ -102,6 +102,59 @@ static const struct soc_enum wm8960_enum[] = {
102 SOC_ENUM_SINGLE(WM8960_ALC3, 8, 2, wm8960_alcmode), 102 SOC_ENUM_SINGLE(WM8960_ALC3, 8, 2, wm8960_alcmode),
103}; 103};
104 104
105static const int deemph_settings[] = { 0, 32000, 44100, 48000 };
106
107static int wm8960_set_deemph(struct snd_soc_codec *codec)
108{
109 struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
110 int val, i, best;
111
112 /* If we're using deemphasis select the nearest available sample
113 * rate.
114 */
115 if (wm8960->deemph) {
116 best = 1;
117 for (i = 2; i < ARRAY_SIZE(deemph_settings); i++) {
118 if (abs(deemph_settings[i] - wm8960->playback_fs) <
119 abs(deemph_settings[best] - wm8960->playback_fs))
120 best = i;
121 }
122
123 val = best << 1;
124 } else {
125 val = 0;
126 }
127
128 dev_dbg(codec->dev, "Set deemphasis %d\n", val);
129
130 return snd_soc_update_bits(codec, WM8960_DACCTL1,
131 0x6, val);
132}
133
134static int wm8960_get_deemph(struct snd_kcontrol *kcontrol,
135 struct snd_ctl_elem_value *ucontrol)
136{
137 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
138 struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
139
140 return wm8960->deemph;
141}
142
143static int wm8960_put_deemph(struct snd_kcontrol *kcontrol,
144 struct snd_ctl_elem_value *ucontrol)
145{
146 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
147 struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
148 int deemph = ucontrol->value.enumerated.item[0];
149
150 if (deemph > 1)
151 return -EINVAL;
152
153 wm8960->deemph = deemph;
154
155 return wm8960_set_deemph(codec);
156}
157
105static const DECLARE_TLV_DB_SCALE(adc_tlv, -9700, 50, 0); 158static const DECLARE_TLV_DB_SCALE(adc_tlv, -9700, 50, 0);
106static const DECLARE_TLV_DB_SCALE(dac_tlv, -12700, 50, 1); 159static const DECLARE_TLV_DB_SCALE(dac_tlv, -12700, 50, 1);
107static const DECLARE_TLV_DB_SCALE(bypass_tlv, -2100, 300, 0); 160static const DECLARE_TLV_DB_SCALE(bypass_tlv, -2100, 300, 0);
@@ -131,23 +184,24 @@ SOC_SINGLE("Speaker DC Volume", WM8960_CLASSD3, 3, 5, 0),
131SOC_SINGLE("Speaker AC Volume", WM8960_CLASSD3, 0, 5, 0), 184SOC_SINGLE("Speaker AC Volume", WM8960_CLASSD3, 0, 5, 0),
132 185
133SOC_SINGLE("PCM Playback -6dB Switch", WM8960_DACCTL1, 7, 1, 0), 186SOC_SINGLE("PCM Playback -6dB Switch", WM8960_DACCTL1, 7, 1, 0),
134SOC_ENUM("ADC Polarity", wm8960_enum[1]), 187SOC_ENUM("ADC Polarity", wm8960_enum[0]),
135SOC_ENUM("Playback De-emphasis", wm8960_enum[0]),
136SOC_SINGLE("ADC High Pass Filter Switch", WM8960_DACCTL1, 0, 1, 0), 188SOC_SINGLE("ADC High Pass Filter Switch", WM8960_DACCTL1, 0, 1, 0),
137 189
138SOC_ENUM("DAC Polarity", wm8960_enum[2]), 190SOC_ENUM("DAC Polarity", wm8960_enum[2]),
191SOC_SINGLE_BOOL_EXT("DAC Deemphasis Switch", 0,
192 wm8960_get_deemph, wm8960_put_deemph),
139 193
140SOC_ENUM("3D Filter Upper Cut-Off", wm8960_enum[3]), 194SOC_ENUM("3D Filter Upper Cut-Off", wm8960_enum[2]),
141SOC_ENUM("3D Filter Lower Cut-Off", wm8960_enum[4]), 195SOC_ENUM("3D Filter Lower Cut-Off", wm8960_enum[3]),
142SOC_SINGLE("3D Volume", WM8960_3D, 1, 15, 0), 196SOC_SINGLE("3D Volume", WM8960_3D, 1, 15, 0),
143SOC_SINGLE("3D Switch", WM8960_3D, 0, 1, 0), 197SOC_SINGLE("3D Switch", WM8960_3D, 0, 1, 0),
144 198
145SOC_ENUM("ALC Function", wm8960_enum[5]), 199SOC_ENUM("ALC Function", wm8960_enum[4]),
146SOC_SINGLE("ALC Max Gain", WM8960_ALC1, 4, 7, 0), 200SOC_SINGLE("ALC Max Gain", WM8960_ALC1, 4, 7, 0),
147SOC_SINGLE("ALC Target", WM8960_ALC1, 0, 15, 1), 201SOC_SINGLE("ALC Target", WM8960_ALC1, 0, 15, 1),
148SOC_SINGLE("ALC Min Gain", WM8960_ALC2, 4, 7, 0), 202SOC_SINGLE("ALC Min Gain", WM8960_ALC2, 4, 7, 0),
149SOC_SINGLE("ALC Hold Time", WM8960_ALC2, 0, 15, 0), 203SOC_SINGLE("ALC Hold Time", WM8960_ALC2, 0, 15, 0),
150SOC_ENUM("ALC Mode", wm8960_enum[6]), 204SOC_ENUM("ALC Mode", wm8960_enum[5]),
151SOC_SINGLE("ALC Decay", WM8960_ALC3, 4, 15, 0), 205SOC_SINGLE("ALC Decay", WM8960_ALC3, 4, 15, 0),
152SOC_SINGLE("ALC Attack", WM8960_ALC3, 0, 15, 0), 206SOC_SINGLE("ALC Attack", WM8960_ALC3, 0, 15, 0),
153 207
@@ -433,6 +487,21 @@ static int wm8960_set_dai_fmt(struct snd_soc_dai *codec_dai,
433 return 0; 487 return 0;
434} 488}
435 489
490static struct {
491 int rate;
492 unsigned int val;
493} alc_rates[] = {
494 { 48000, 0 },
495 { 44100, 0 },
496 { 32000, 1 },
497 { 22050, 2 },
498 { 24000, 2 },
499 { 16000, 3 },
500 { 11250, 4 },
501 { 12000, 4 },
502 { 8000, 5 },
503};
504
436static int wm8960_hw_params(struct snd_pcm_substream *substream, 505static int wm8960_hw_params(struct snd_pcm_substream *substream,
437 struct snd_pcm_hw_params *params, 506 struct snd_pcm_hw_params *params,
438 struct snd_soc_dai *dai) 507 struct snd_soc_dai *dai)
@@ -440,7 +509,9 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream,
440 struct snd_soc_pcm_runtime *rtd = substream->private_data; 509 struct snd_soc_pcm_runtime *rtd = substream->private_data;
441 struct snd_soc_device *socdev = rtd->socdev; 510 struct snd_soc_device *socdev = rtd->socdev;
442 struct snd_soc_codec *codec = socdev->card->codec; 511 struct snd_soc_codec *codec = socdev->card->codec;
512 struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
443 u16 iface = snd_soc_read(codec, WM8960_IFACE1) & 0xfff3; 513 u16 iface = snd_soc_read(codec, WM8960_IFACE1) & 0xfff3;
514 int i;
444 515
445 /* bit size */ 516 /* bit size */
446 switch (params_format(params)) { 517 switch (params_format(params)) {
@@ -454,6 +525,18 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream,
454 break; 525 break;
455 } 526 }
456 527
528 /* Update filters for the new rate */
529 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
530 wm8960->playback_fs = params_rate(params);
531 wm8960_set_deemph(codec);
532 } else {
533 for (i = 0; i < ARRAY_SIZE(alc_rates); i++)
534 if (alc_rates[i].rate == params_rate(params))
535 snd_soc_update_bits(codec,
536 WM8960_ADDCTL3, 0x7,
537 alc_rates[i].val);
538 }
539
457 /* set iface */ 540 /* set iface */
458 snd_soc_write(codec, WM8960_IFACE1, iface); 541 snd_soc_write(codec, WM8960_IFACE1, iface);
459 return 0; 542 return 0;
diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c
index 5b9a756242f1..2549d3a297ab 100644
--- a/sound/soc/codecs/wm8961.c
+++ b/sound/soc/codecs/wm8961.c
@@ -1102,7 +1102,7 @@ static int wm8961_register(struct wm8961_priv *wm8961)
1102 ret = wm8961_reset(codec); 1102 ret = wm8961_reset(codec);
1103 if (ret < 0) { 1103 if (ret < 0) {
1104 dev_err(codec->dev, "Failed to issue reset\n"); 1104 dev_err(codec->dev, "Failed to issue reset\n");
1105 return ret; 1105 goto err;
1106 } 1106 }
1107 1107
1108 /* Enable class W */ 1108 /* Enable class W */
@@ -1147,18 +1147,19 @@ static int wm8961_register(struct wm8961_priv *wm8961)
1147 ret = snd_soc_register_codec(codec); 1147 ret = snd_soc_register_codec(codec);
1148 if (ret != 0) { 1148 if (ret != 0) {
1149 dev_err(codec->dev, "Failed to register codec: %d\n", ret); 1149 dev_err(codec->dev, "Failed to register codec: %d\n", ret);
1150 return ret; 1150 goto err;
1151 } 1151 }
1152 1152
1153 ret = snd_soc_register_dai(&wm8961_dai); 1153 ret = snd_soc_register_dai(&wm8961_dai);
1154 if (ret != 0) { 1154 if (ret != 0) {
1155 dev_err(codec->dev, "Failed to register DAI: %d\n", ret); 1155 dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
1156 snd_soc_unregister_codec(codec); 1156 goto err_codec;
1157 return ret;
1158 } 1157 }
1159 1158
1160 return 0; 1159 return 0;
1161 1160
1161err_codec:
1162 snd_soc_unregister_codec(codec);
1162err: 1163err:
1163 kfree(wm8961); 1164 kfree(wm8961);
1164 return ret; 1165 return ret;
diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c
index a2c4b2f37cca..1468fe10cbbe 100644
--- a/sound/soc/codecs/wm8974.c
+++ b/sound/soc/codecs/wm8974.c
@@ -670,7 +670,8 @@ static __devinit int wm8974_register(struct wm8974_priv *wm8974)
670 670
671 if (wm8974_codec) { 671 if (wm8974_codec) {
672 dev_err(codec->dev, "Another WM8974 is registered\n"); 672 dev_err(codec->dev, "Another WM8974 is registered\n");
673 return -EINVAL; 673 ret = -EINVAL;
674 goto err;
674 } 675 }
675 676
676 mutex_init(&codec->mutex); 677 mutex_init(&codec->mutex);
diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c
index 51d5f433215c..8a1ad778e7e3 100644
--- a/sound/soc/codecs/wm8978.c
+++ b/sound/soc/codecs/wm8978.c
@@ -1076,7 +1076,6 @@ static __devinit int wm8978_register(struct wm8978_priv *wm8978)
1076err_codec: 1076err_codec:
1077 snd_soc_unregister_codec(codec); 1077 snd_soc_unregister_codec(codec);
1078err: 1078err:
1079 kfree(wm8978);
1080 return ret; 1079 return ret;
1081} 1080}
1082 1081
@@ -1085,13 +1084,13 @@ static __devexit void wm8978_unregister(struct wm8978_priv *wm8978)
1085 wm8978_set_bias_level(&wm8978->codec, SND_SOC_BIAS_OFF); 1084 wm8978_set_bias_level(&wm8978->codec, SND_SOC_BIAS_OFF);
1086 snd_soc_unregister_dai(&wm8978_dai); 1085 snd_soc_unregister_dai(&wm8978_dai);
1087 snd_soc_unregister_codec(&wm8978->codec); 1086 snd_soc_unregister_codec(&wm8978->codec);
1088 kfree(wm8978);
1089 wm8978_codec = NULL; 1087 wm8978_codec = NULL;
1090} 1088}
1091 1089
1092static __devinit int wm8978_i2c_probe(struct i2c_client *i2c, 1090static __devinit int wm8978_i2c_probe(struct i2c_client *i2c,
1093 const struct i2c_device_id *id) 1091 const struct i2c_device_id *id)
1094{ 1092{
1093 int ret;
1095 struct wm8978_priv *wm8978; 1094 struct wm8978_priv *wm8978;
1096 struct snd_soc_codec *codec; 1095 struct snd_soc_codec *codec;
1097 1096
@@ -1107,13 +1106,18 @@ static __devinit int wm8978_i2c_probe(struct i2c_client *i2c,
1107 1106
1108 codec->dev = &i2c->dev; 1107 codec->dev = &i2c->dev;
1109 1108
1110 return wm8978_register(wm8978); 1109 ret = wm8978_register(wm8978);
1110 if (ret < 0)
1111 kfree(wm8978);
1112
1113 return ret;
1111} 1114}
1112 1115
1113static __devexit int wm8978_i2c_remove(struct i2c_client *client) 1116static __devexit int wm8978_i2c_remove(struct i2c_client *client)
1114{ 1117{
1115 struct wm8978_priv *wm8978 = i2c_get_clientdata(client); 1118 struct wm8978_priv *wm8978 = i2c_get_clientdata(client);
1116 wm8978_unregister(wm8978); 1119 wm8978_unregister(wm8978);
1120 kfree(wm8978);
1117 return 0; 1121 return 0;
1118} 1122}
1119 1123
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c
index c018772cc430..dd8d909788c1 100644
--- a/sound/soc/codecs/wm8990.c
+++ b/sound/soc/codecs/wm8990.c
@@ -30,8 +30,6 @@
30 30
31#include "wm8990.h" 31#include "wm8990.h"
32 32
33#define WM8990_VERSION "0.2"
34
35/* codec private data */ 33/* codec private data */
36struct wm8990_priv { 34struct wm8990_priv {
37 unsigned int sysclk; 35 unsigned int sysclk;
@@ -1511,8 +1509,6 @@ static int wm8990_probe(struct platform_device *pdev)
1511 struct wm8990_priv *wm8990; 1509 struct wm8990_priv *wm8990;
1512 int ret; 1510 int ret;
1513 1511
1514 pr_info("WM8990 Audio Codec %s\n", WM8990_VERSION);
1515
1516 setup = socdev->codec_data; 1512 setup = socdev->codec_data;
1517 codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); 1513 codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
1518 if (codec == NULL) 1514 if (codec == NULL)
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index e84a1177f350..a87046a96f2a 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -1677,6 +1677,26 @@ static struct {
1677 1677
1678static int wm8994_readable(unsigned int reg) 1678static int wm8994_readable(unsigned int reg)
1679{ 1679{
1680 switch (reg) {
1681 case WM8994_GPIO_1:
1682 case WM8994_GPIO_2:
1683 case WM8994_GPIO_3:
1684 case WM8994_GPIO_4:
1685 case WM8994_GPIO_5:
1686 case WM8994_GPIO_6:
1687 case WM8994_GPIO_7:
1688 case WM8994_GPIO_8:
1689 case WM8994_GPIO_9:
1690 case WM8994_GPIO_10:
1691 case WM8994_GPIO_11:
1692 case WM8994_INTERRUPT_STATUS_1:
1693 case WM8994_INTERRUPT_STATUS_2:
1694 case WM8994_INTERRUPT_RAW_STATUS_2:
1695 return 1;
1696 default:
1697 break;
1698 }
1699
1680 if (reg >= ARRAY_SIZE(access_masks)) 1700 if (reg >= ARRAY_SIZE(access_masks))
1681 return 0; 1701 return 0;
1682 return access_masks[reg].readable != 0; 1702 return access_masks[reg].readable != 0;
@@ -2341,6 +2361,20 @@ SOC_DAPM_SINGLE("AIF2 Switch", WM8994_AIF1_ADC1_RIGHT_MIXER_ROUTING,
2341 0, 1, 0), 2361 0, 1, 0),
2342}; 2362};
2343 2363
2364static const struct snd_kcontrol_new aif1adc2l_mix[] = {
2365SOC_DAPM_SINGLE("DMIC Switch", WM8994_AIF1_ADC2_LEFT_MIXER_ROUTING,
2366 1, 1, 0),
2367SOC_DAPM_SINGLE("AIF2 Switch", WM8994_AIF1_ADC2_LEFT_MIXER_ROUTING,
2368 0, 1, 0),
2369};
2370
2371static const struct snd_kcontrol_new aif1adc2r_mix[] = {
2372SOC_DAPM_SINGLE("DMIC Switch", WM8994_AIF1_ADC2_RIGHT_MIXER_ROUTING,
2373 1, 1, 0),
2374SOC_DAPM_SINGLE("AIF2 Switch", WM8994_AIF1_ADC2_RIGHT_MIXER_ROUTING,
2375 0, 1, 0),
2376};
2377
2344static const struct snd_kcontrol_new aif2dac2l_mix[] = { 2378static const struct snd_kcontrol_new aif2dac2l_mix[] = {
2345SOC_DAPM_SINGLE("Right Sidetone Switch", WM8994_DAC2_LEFT_MIXER_ROUTING, 2379SOC_DAPM_SINGLE("Right Sidetone Switch", WM8994_DAC2_LEFT_MIXER_ROUTING,
2346 5, 1, 0), 2380 5, 1, 0),
@@ -2472,6 +2506,7 @@ static const struct snd_kcontrol_new aif3adc_mux =
2472static const struct snd_soc_dapm_widget wm8994_dapm_widgets[] = { 2506static const struct snd_soc_dapm_widget wm8994_dapm_widgets[] = {
2473SND_SOC_DAPM_INPUT("DMIC1DAT"), 2507SND_SOC_DAPM_INPUT("DMIC1DAT"),
2474SND_SOC_DAPM_INPUT("DMIC2DAT"), 2508SND_SOC_DAPM_INPUT("DMIC2DAT"),
2509SND_SOC_DAPM_INPUT("Clock"),
2475 2510
2476SND_SOC_DAPM_SUPPLY("CLK_SYS", SND_SOC_NOPM, 0, 0, clk_sys_event, 2511SND_SOC_DAPM_SUPPLY("CLK_SYS", SND_SOC_NOPM, 0, 0, clk_sys_event,
2477 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), 2512 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
@@ -2506,6 +2541,11 @@ SND_SOC_DAPM_MIXER("AIF1ADC1L Mixer", SND_SOC_NOPM, 0, 0,
2506SND_SOC_DAPM_MIXER("AIF1ADC1R Mixer", SND_SOC_NOPM, 0, 0, 2541SND_SOC_DAPM_MIXER("AIF1ADC1R Mixer", SND_SOC_NOPM, 0, 0,
2507 aif1adc1r_mix, ARRAY_SIZE(aif1adc1r_mix)), 2542 aif1adc1r_mix, ARRAY_SIZE(aif1adc1r_mix)),
2508 2543
2544SND_SOC_DAPM_MIXER("AIF1ADC2L Mixer", SND_SOC_NOPM, 0, 0,
2545 aif1adc2l_mix, ARRAY_SIZE(aif1adc2l_mix)),
2546SND_SOC_DAPM_MIXER("AIF1ADC2R Mixer", SND_SOC_NOPM, 0, 0,
2547 aif1adc2r_mix, ARRAY_SIZE(aif1adc2r_mix)),
2548
2509SND_SOC_DAPM_MIXER("AIF2DAC2L Mixer", SND_SOC_NOPM, 0, 0, 2549SND_SOC_DAPM_MIXER("AIF2DAC2L Mixer", SND_SOC_NOPM, 0, 0,
2510 aif2dac2l_mix, ARRAY_SIZE(aif2dac2l_mix)), 2550 aif2dac2l_mix, ARRAY_SIZE(aif2dac2l_mix)),
2511SND_SOC_DAPM_MIXER("AIF2DAC2R Mixer", SND_SOC_NOPM, 0, 0, 2551SND_SOC_DAPM_MIXER("AIF2DAC2R Mixer", SND_SOC_NOPM, 0, 0,
@@ -2668,6 +2708,14 @@ static const struct snd_soc_dapm_route intercon[] = {
2668 { "AIF1ADC1R Mixer", "ADC/DMIC Switch", "ADCR Mux" }, 2708 { "AIF1ADC1R Mixer", "ADC/DMIC Switch", "ADCR Mux" },
2669 { "AIF1ADC1R Mixer", "AIF2 Switch", "AIF2DACR" }, 2709 { "AIF1ADC1R Mixer", "AIF2 Switch", "AIF2DACR" },
2670 2710
2711 { "AIF1ADC2L", NULL, "AIF1ADC2L Mixer" },
2712 { "AIF1ADC2L Mixer", "DMIC Switch", "DMIC2L" },
2713 { "AIF1ADC2L Mixer", "AIF2 Switch", "AIF2DACL" },
2714
2715 { "AIF1ADC2R", NULL, "AIF1ADC2R Mixer" },
2716 { "AIF1ADC2R Mixer", "DMIC Switch", "DMIC2R" },
2717 { "AIF1ADC2R Mixer", "AIF2 Switch", "AIF2DACR" },
2718
2671 /* Pin level routing for AIF3 */ 2719 /* Pin level routing for AIF3 */
2672 { "AIF1DAC1L", NULL, "AIF1DAC Mux" }, 2720 { "AIF1DAC1L", NULL, "AIF1DAC Mux" },
2673 { "AIF1DAC1R", NULL, "AIF1DAC Mux" }, 2721 { "AIF1DAC1R", NULL, "AIF1DAC Mux" },
@@ -2946,11 +2994,14 @@ static int wm8994_set_fll(struct snd_soc_dai *dai, int id, int src,
2946 return 0; 2994 return 0;
2947} 2995}
2948 2996
2997static int opclk_divs[] = { 10, 20, 30, 40, 55, 60, 80, 120, 160 };
2998
2949static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai, 2999static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai,
2950 int clk_id, unsigned int freq, int dir) 3000 int clk_id, unsigned int freq, int dir)
2951{ 3001{
2952 struct snd_soc_codec *codec = dai->codec; 3002 struct snd_soc_codec *codec = dai->codec;
2953 struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); 3003 struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
3004 int i;
2954 3005
2955 switch (dai->id) { 3006 switch (dai->id) {
2956 case 1: 3007 case 1:
@@ -2988,6 +3039,25 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai,
2988 dev_dbg(dai->dev, "AIF%d using FLL2\n", dai->id); 3039 dev_dbg(dai->dev, "AIF%d using FLL2\n", dai->id);
2989 break; 3040 break;
2990 3041
3042 case WM8994_SYSCLK_OPCLK:
3043 /* Special case - a division (times 10) is given and
3044 * no effect on main clocking.
3045 */
3046 if (freq) {
3047 for (i = 0; i < ARRAY_SIZE(opclk_divs); i++)
3048 if (opclk_divs[i] == freq)
3049 break;
3050 if (i == ARRAY_SIZE(opclk_divs))
3051 return -EINVAL;
3052 snd_soc_update_bits(codec, WM8994_CLOCKING_2,
3053 WM8994_OPCLK_DIV_MASK, i);
3054 snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_2,
3055 WM8994_OPCLK_ENA, WM8994_OPCLK_ENA);
3056 } else {
3057 snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_2,
3058 WM8994_OPCLK_ENA, 0);
3059 }
3060
2991 default: 3061 default:
2992 return -EINVAL; 3062 return -EINVAL;
2993 } 3063 }
@@ -4004,6 +4074,11 @@ static int wm8994_codec_probe(struct platform_device *pdev)
4004 1 << WM8994_AIF2DAC_3D_GAIN_SHIFT, 4074 1 << WM8994_AIF2DAC_3D_GAIN_SHIFT,
4005 1 << WM8994_AIF2DAC_3D_GAIN_SHIFT); 4075 1 << WM8994_AIF2DAC_3D_GAIN_SHIFT);
4006 4076
4077 /* Unconditionally enable AIF1 ADC TDM mode; it only affects
4078 * behaviour on idle TDM clock cycles. */
4079 snd_soc_update_bits(codec, WM8994_AIF1_CONTROL_1,
4080 WM8994_AIF1ADC_TDM, WM8994_AIF1ADC_TDM);
4081
4007 wm8994_update_class_w(codec); 4082 wm8994_update_class_w(codec);
4008 4083
4009 ret = snd_soc_register_codec(codec); 4084 ret = snd_soc_register_codec(codec);
diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h
index 7072dc539354..2e0ca67a8df7 100644
--- a/sound/soc/codecs/wm8994.h
+++ b/sound/soc/codecs/wm8994.h
@@ -20,6 +20,9 @@ extern struct snd_soc_dai wm8994_dai[];
20#define WM8994_SYSCLK_FLL1 3 20#define WM8994_SYSCLK_FLL1 3
21#define WM8994_SYSCLK_FLL2 4 21#define WM8994_SYSCLK_FLL2 4
22 22
23/* OPCLK is also configured with set_dai_sysclk, specify division*10 as rate. */
24#define WM8994_SYSCLK_OPCLK 5
25
23#define WM8994_FLL1 1 26#define WM8994_FLL1 1
24#define WM8994_FLL2 2 27#define WM8994_FLL2 2
25 28
diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c
index 13186fb4dcb4..76b37ff6c264 100644
--- a/sound/soc/codecs/wm9081.c
+++ b/sound/soc/codecs/wm9081.c
@@ -1356,7 +1356,7 @@ static int wm9081_register(struct wm9081_priv *wm9081,
1356 ret = snd_soc_codec_set_cache_io(codec, 8, 16, control); 1356 ret = snd_soc_codec_set_cache_io(codec, 8, 16, control);
1357 if (ret != 0) { 1357 if (ret != 0) {
1358 dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); 1358 dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
1359 return ret; 1359 goto err;
1360 } 1360 }
1361 1361
1362 reg = snd_soc_read(codec, WM9081_SOFTWARE_RESET); 1362 reg = snd_soc_read(codec, WM9081_SOFTWARE_RESET);
@@ -1369,7 +1369,7 @@ static int wm9081_register(struct wm9081_priv *wm9081,
1369 ret = wm9081_reset(codec); 1369 ret = wm9081_reset(codec);
1370 if (ret < 0) { 1370 if (ret < 0) {
1371 dev_err(codec->dev, "Failed to issue reset\n"); 1371 dev_err(codec->dev, "Failed to issue reset\n");
1372 return ret; 1372 goto err;
1373 } 1373 }
1374 1374
1375 wm9081_set_bias_level(codec, SND_SOC_BIAS_STANDBY); 1375 wm9081_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
@@ -1388,18 +1388,19 @@ static int wm9081_register(struct wm9081_priv *wm9081,
1388 ret = snd_soc_register_codec(codec); 1388 ret = snd_soc_register_codec(codec);
1389 if (ret != 0) { 1389 if (ret != 0) {
1390 dev_err(codec->dev, "Failed to register codec: %d\n", ret); 1390 dev_err(codec->dev, "Failed to register codec: %d\n", ret);
1391 return ret; 1391 goto err;
1392 } 1392 }
1393 1393
1394 ret = snd_soc_register_dai(&wm9081_dai); 1394 ret = snd_soc_register_dai(&wm9081_dai);
1395 if (ret != 0) { 1395 if (ret != 0) {
1396 dev_err(codec->dev, "Failed to register DAI: %d\n", ret); 1396 dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
1397 snd_soc_unregister_codec(codec); 1397 goto err_codec;
1398 return ret;
1399 } 1398 }
1400 1399
1401 return 0; 1400 return 0;
1402 1401
1402err_codec:
1403 snd_soc_unregister_codec(codec);
1403err: 1404err:
1404 kfree(wm9081); 1405 kfree(wm9081);
1405 return ret; 1406 return ret;
diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c
index 16f1a57da08a..2cb81538cd91 100644
--- a/sound/soc/codecs/wm_hubs.c
+++ b/sound/soc/codecs/wm_hubs.c
@@ -410,6 +410,8 @@ static int hp_event(struct snd_soc_dapm_widget *w,
410 WM8993_HPOUT1L_DLY | 410 WM8993_HPOUT1L_DLY |
411 WM8993_HPOUT1R_DLY, 0); 411 WM8993_HPOUT1R_DLY, 0);
412 412
413 snd_soc_write(codec, WM8993_DC_SERVO_0, 0);
414
413 snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1, 415 snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1,
414 WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA, 416 WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA,
415 0); 417 0);
diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c
index adadcd3aa1b1..9e8932abf158 100644
--- a/sound/soc/davinci/davinci-i2s.c
+++ b/sound/soc/davinci/davinci-i2s.c
@@ -26,6 +26,7 @@
26#include <mach/asp.h> 26#include <mach/asp.h>
27 27
28#include "davinci-pcm.h" 28#include "davinci-pcm.h"
29#include "davinci-i2s.h"
29 30
30 31
31/* 32/*
@@ -68,16 +69,21 @@
68#define DAVINCI_MCBSP_RCR_RDATDLY(v) ((v) << 16) 69#define DAVINCI_MCBSP_RCR_RDATDLY(v) ((v) << 16)
69#define DAVINCI_MCBSP_RCR_RFIG (1 << 18) 70#define DAVINCI_MCBSP_RCR_RFIG (1 << 18)
70#define DAVINCI_MCBSP_RCR_RWDLEN2(v) ((v) << 21) 71#define DAVINCI_MCBSP_RCR_RWDLEN2(v) ((v) << 21)
72#define DAVINCI_MCBSP_RCR_RFRLEN2(v) ((v) << 24)
73#define DAVINCI_MCBSP_RCR_RPHASE BIT(31)
71 74
72#define DAVINCI_MCBSP_XCR_XWDLEN1(v) ((v) << 5) 75#define DAVINCI_MCBSP_XCR_XWDLEN1(v) ((v) << 5)
73#define DAVINCI_MCBSP_XCR_XFRLEN1(v) ((v) << 8) 76#define DAVINCI_MCBSP_XCR_XFRLEN1(v) ((v) << 8)
74#define DAVINCI_MCBSP_XCR_XDATDLY(v) ((v) << 16) 77#define DAVINCI_MCBSP_XCR_XDATDLY(v) ((v) << 16)
75#define DAVINCI_MCBSP_XCR_XFIG (1 << 18) 78#define DAVINCI_MCBSP_XCR_XFIG (1 << 18)
76#define DAVINCI_MCBSP_XCR_XWDLEN2(v) ((v) << 21) 79#define DAVINCI_MCBSP_XCR_XWDLEN2(v) ((v) << 21)
80#define DAVINCI_MCBSP_XCR_XFRLEN2(v) ((v) << 24)
81#define DAVINCI_MCBSP_XCR_XPHASE BIT(31)
77 82
78#define DAVINCI_MCBSP_SRGR_FWID(v) ((v) << 8) 83#define DAVINCI_MCBSP_SRGR_FWID(v) ((v) << 8)
79#define DAVINCI_MCBSP_SRGR_FPER(v) ((v) << 16) 84#define DAVINCI_MCBSP_SRGR_FPER(v) ((v) << 16)
80#define DAVINCI_MCBSP_SRGR_FSGM (1 << 28) 85#define DAVINCI_MCBSP_SRGR_FSGM (1 << 28)
86#define DAVINCI_MCBSP_SRGR_CLKSM BIT(29)
81 87
82#define DAVINCI_MCBSP_PCR_CLKRP (1 << 0) 88#define DAVINCI_MCBSP_PCR_CLKRP (1 << 0)
83#define DAVINCI_MCBSP_PCR_CLKXP (1 << 1) 89#define DAVINCI_MCBSP_PCR_CLKXP (1 << 1)
@@ -116,6 +122,7 @@ static const unsigned char double_fmt[SNDRV_PCM_FORMAT_S32_LE + 1] = {
116}; 122};
117 123
118struct davinci_mcbsp_dev { 124struct davinci_mcbsp_dev {
125 struct device *dev;
119 struct davinci_pcm_dma_params dma_params[2]; 126 struct davinci_pcm_dma_params dma_params[2];
120 void __iomem *base; 127 void __iomem *base;
121#define MOD_DSP_A 0 128#define MOD_DSP_A 0
@@ -144,6 +151,11 @@ struct davinci_mcbsp_dev {
144 * won't end up being swapped because of the underrun. 151 * won't end up being swapped because of the underrun.
145 */ 152 */
146 unsigned enable_channel_combine:1; 153 unsigned enable_channel_combine:1;
154
155 unsigned int fmt;
156 int clk_div;
157 int clk_input_pin;
158 bool i2s_accurate_sck;
147}; 159};
148 160
149static inline void davinci_mcbsp_write_reg(struct davinci_mcbsp_dev *dev, 161static inline void davinci_mcbsp_write_reg(struct davinci_mcbsp_dev *dev,
@@ -254,10 +266,12 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
254 struct davinci_mcbsp_dev *dev = cpu_dai->private_data; 266 struct davinci_mcbsp_dev *dev = cpu_dai->private_data;
255 unsigned int pcr; 267 unsigned int pcr;
256 unsigned int srgr; 268 unsigned int srgr;
269 /* Attention srgr is updated by hw_params! */
257 srgr = DAVINCI_MCBSP_SRGR_FSGM | 270 srgr = DAVINCI_MCBSP_SRGR_FSGM |
258 DAVINCI_MCBSP_SRGR_FPER(DEFAULT_BITPERSAMPLE * 2 - 1) | 271 DAVINCI_MCBSP_SRGR_FPER(DEFAULT_BITPERSAMPLE * 2 - 1) |
259 DAVINCI_MCBSP_SRGR_FWID(DEFAULT_BITPERSAMPLE - 1); 272 DAVINCI_MCBSP_SRGR_FWID(DEFAULT_BITPERSAMPLE - 1);
260 273
274 dev->fmt = fmt;
261 /* set master/slave audio interface */ 275 /* set master/slave audio interface */
262 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 276 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
263 case SND_SOC_DAIFMT_CBS_CFS: 277 case SND_SOC_DAIFMT_CBS_CFS:
@@ -268,11 +282,26 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
268 DAVINCI_MCBSP_PCR_CLKRM; 282 DAVINCI_MCBSP_PCR_CLKRM;
269 break; 283 break;
270 case SND_SOC_DAIFMT_CBM_CFS: 284 case SND_SOC_DAIFMT_CBM_CFS:
271 /* McBSP CLKR pin is the input for the Sample Rate Generator. 285 pcr = DAVINCI_MCBSP_PCR_FSRM | DAVINCI_MCBSP_PCR_FSXM;
272 * McBSP FSR and FSX are driven by the Sample Rate Generator. */ 286 /*
273 pcr = DAVINCI_MCBSP_PCR_SCLKME | 287 * Selection of the clock input pin that is the
274 DAVINCI_MCBSP_PCR_FSXM | 288 * input for the Sample Rate Generator.
275 DAVINCI_MCBSP_PCR_FSRM; 289 * McBSP FSR and FSX are driven by the Sample Rate
290 * Generator.
291 */
292 switch (dev->clk_input_pin) {
293 case MCBSP_CLKS:
294 pcr |= DAVINCI_MCBSP_PCR_CLKXM |
295 DAVINCI_MCBSP_PCR_CLKRM;
296 break;
297 case MCBSP_CLKR:
298 pcr |= DAVINCI_MCBSP_PCR_SCLKME;
299 break;
300 default:
301 dev_err(dev->dev, "bad clk_input_pin\n");
302 return -EINVAL;
303 }
304
276 break; 305 break;
277 case SND_SOC_DAIFMT_CBM_CFM: 306 case SND_SOC_DAIFMT_CBM_CFM:
278 /* codec is master */ 307 /* codec is master */
@@ -372,6 +401,18 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
372 return 0; 401 return 0;
373} 402}
374 403
404static int davinci_i2s_dai_set_clkdiv(struct snd_soc_dai *cpu_dai,
405 int div_id, int div)
406{
407 struct davinci_mcbsp_dev *dev = cpu_dai->private_data;
408
409 if (div_id != DAVINCI_MCBSP_CLKGDV)
410 return -ENODEV;
411
412 dev->clk_div = div;
413 return 0;
414}
415
375static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, 416static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
376 struct snd_pcm_hw_params *params, 417 struct snd_pcm_hw_params *params,
377 struct snd_soc_dai *dai) 418 struct snd_soc_dai *dai)
@@ -380,8 +421,8 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
380 struct davinci_pcm_dma_params *dma_params = 421 struct davinci_pcm_dma_params *dma_params =
381 &dev->dma_params[substream->stream]; 422 &dev->dma_params[substream->stream];
382 struct snd_interval *i = NULL; 423 struct snd_interval *i = NULL;
383 int mcbsp_word_length; 424 int mcbsp_word_length, master;
384 unsigned int rcr, xcr, srgr; 425 unsigned int rcr, xcr, srgr, clk_div, freq, framesize;
385 u32 spcr; 426 u32 spcr;
386 snd_pcm_format_t fmt; 427 snd_pcm_format_t fmt;
387 unsigned element_cnt = 1; 428 unsigned element_cnt = 1;
@@ -396,12 +437,59 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
396 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); 437 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr);
397 } 438 }
398 439
399 i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); 440 master = dev->fmt & SND_SOC_DAIFMT_MASTER_MASK;
400 srgr = DAVINCI_MCBSP_SRGR_FSGM; 441 fmt = params_format(params);
401 srgr |= DAVINCI_MCBSP_SRGR_FWID(snd_interval_value(i) - 1); 442 mcbsp_word_length = asp_word_length[fmt];
402 443
403 i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_FRAME_BITS); 444 switch (master) {
404 srgr |= DAVINCI_MCBSP_SRGR_FPER(snd_interval_value(i) - 1); 445 case SND_SOC_DAIFMT_CBS_CFS:
446 freq = clk_get_rate(dev->clk);
447 srgr = DAVINCI_MCBSP_SRGR_FSGM |
448 DAVINCI_MCBSP_SRGR_CLKSM;
449 srgr |= DAVINCI_MCBSP_SRGR_FWID(mcbsp_word_length *
450 8 - 1);
451 if (dev->i2s_accurate_sck) {
452 clk_div = 256;
453 do {
454 framesize = (freq / (--clk_div)) /
455 params->rate_num *
456 params->rate_den;
457 } while (((framesize < 33) || (framesize > 4095)) &&
458 (clk_div));
459 clk_div--;
460 srgr |= DAVINCI_MCBSP_SRGR_FPER(framesize - 1);
461 } else {
462 /* symmetric waveforms */
463 clk_div = freq / (mcbsp_word_length * 16) /
464 params->rate_num * params->rate_den;
465 srgr |= DAVINCI_MCBSP_SRGR_FPER(mcbsp_word_length *
466 16 - 1);
467 }
468 clk_div &= 0xFF;
469 srgr |= clk_div;
470 break;
471 case SND_SOC_DAIFMT_CBM_CFS:
472 srgr = DAVINCI_MCBSP_SRGR_FSGM;
473 clk_div = dev->clk_div - 1;
474 srgr |= DAVINCI_MCBSP_SRGR_FWID(mcbsp_word_length * 8 - 1);
475 srgr |= DAVINCI_MCBSP_SRGR_FPER(mcbsp_word_length * 16 - 1);
476 clk_div &= 0xFF;
477 srgr |= clk_div;
478 break;
479 case SND_SOC_DAIFMT_CBM_CFM:
480 /* Clock and frame sync given from external sources */
481 i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS);
482 srgr = DAVINCI_MCBSP_SRGR_FSGM;
483 srgr |= DAVINCI_MCBSP_SRGR_FWID(snd_interval_value(i) - 1);
484 pr_debug("%s - %d FWID set: re-read srgr = %X\n",
485 __func__, __LINE__, snd_interval_value(i) - 1);
486
487 i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_FRAME_BITS);
488 srgr |= DAVINCI_MCBSP_SRGR_FPER(snd_interval_value(i) - 1);
489 break;
490 default:
491 return -EINVAL;
492 }
405 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, srgr); 493 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, srgr);
406 494
407 rcr = DAVINCI_MCBSP_RCR_RFIG; 495 rcr = DAVINCI_MCBSP_RCR_RFIG;
@@ -426,12 +514,41 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
426 element_cnt = 1; 514 element_cnt = 1;
427 fmt = double_fmt[fmt]; 515 fmt = double_fmt[fmt];
428 } 516 }
517 switch (master) {
518 case SND_SOC_DAIFMT_CBS_CFS:
519 case SND_SOC_DAIFMT_CBS_CFM:
520 rcr |= DAVINCI_MCBSP_RCR_RFRLEN2(0);
521 xcr |= DAVINCI_MCBSP_XCR_XFRLEN2(0);
522 rcr |= DAVINCI_MCBSP_RCR_RPHASE;
523 xcr |= DAVINCI_MCBSP_XCR_XPHASE;
524 break;
525 case SND_SOC_DAIFMT_CBM_CFM:
526 case SND_SOC_DAIFMT_CBM_CFS:
527 rcr |= DAVINCI_MCBSP_RCR_RFRLEN2(element_cnt - 1);
528 xcr |= DAVINCI_MCBSP_XCR_XFRLEN2(element_cnt - 1);
529 break;
530 default:
531 return -EINVAL;
532 }
429 } 533 }
430 dma_params->acnt = dma_params->data_type = data_type[fmt]; 534 dma_params->acnt = dma_params->data_type = data_type[fmt];
431 dma_params->fifo_level = 0; 535 dma_params->fifo_level = 0;
432 mcbsp_word_length = asp_word_length[fmt]; 536 mcbsp_word_length = asp_word_length[fmt];
433 rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(element_cnt - 1); 537
434 xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(element_cnt - 1); 538 switch (master) {
539 case SND_SOC_DAIFMT_CBS_CFS:
540 case SND_SOC_DAIFMT_CBS_CFM:
541 rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(0);
542 xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(0);
543 break;
544 case SND_SOC_DAIFMT_CBM_CFM:
545 case SND_SOC_DAIFMT_CBM_CFS:
546 rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(element_cnt - 1);
547 xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(element_cnt - 1);
548 break;
549 default:
550 return -EINVAL;
551 }
435 552
436 rcr |= DAVINCI_MCBSP_RCR_RWDLEN1(mcbsp_word_length) | 553 rcr |= DAVINCI_MCBSP_RCR_RWDLEN1(mcbsp_word_length) |
437 DAVINCI_MCBSP_RCR_RWDLEN2(mcbsp_word_length); 554 DAVINCI_MCBSP_RCR_RWDLEN2(mcbsp_word_length);
@@ -442,6 +559,10 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream,
442 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, xcr); 559 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, xcr);
443 else 560 else
444 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, rcr); 561 davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, rcr);
562
563 pr_debug("%s - %d srgr=%X\n", __func__, __LINE__, srgr);
564 pr_debug("%s - %d xcr=%X\n", __func__, __LINE__, xcr);
565 pr_debug("%s - %d rcr=%X\n", __func__, __LINE__, rcr);
445 return 0; 566 return 0;
446} 567}
447 568
@@ -500,6 +621,7 @@ static struct snd_soc_dai_ops davinci_i2s_dai_ops = {
500 .trigger = davinci_i2s_trigger, 621 .trigger = davinci_i2s_trigger,
501 .hw_params = davinci_i2s_hw_params, 622 .hw_params = davinci_i2s_hw_params,
502 .set_fmt = davinci_i2s_set_dai_fmt, 623 .set_fmt = davinci_i2s_set_dai_fmt,
624 .set_clkdiv = davinci_i2s_dai_set_clkdiv,
503 625
504}; 626};
505 627
@@ -526,6 +648,8 @@ static int davinci_i2s_probe(struct platform_device *pdev)
526 struct snd_platform_data *pdata = pdev->dev.platform_data; 648 struct snd_platform_data *pdata = pdev->dev.platform_data;
527 struct davinci_mcbsp_dev *dev; 649 struct davinci_mcbsp_dev *dev;
528 struct resource *mem, *ioarea, *res; 650 struct resource *mem, *ioarea, *res;
651 enum dma_event_q asp_chan_q = EVENTQ_0;
652 enum dma_event_q ram_chan_q = EVENTQ_1;
529 int ret; 653 int ret;
530 654
531 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 655 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -552,7 +676,17 @@ static int davinci_i2s_probe(struct platform_device *pdev)
552 pdata->sram_size_playback; 676 pdata->sram_size_playback;
553 dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].sram_size = 677 dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].sram_size =
554 pdata->sram_size_capture; 678 pdata->sram_size_capture;
679 dev->clk_input_pin = pdata->clk_input_pin;
680 dev->i2s_accurate_sck = pdata->i2s_accurate_sck;
681 asp_chan_q = pdata->asp_chan_q;
682 ram_chan_q = pdata->ram_chan_q;
555 } 683 }
684
685 dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].asp_chan_q = asp_chan_q;
686 dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].ram_chan_q = ram_chan_q;
687 dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].asp_chan_q = asp_chan_q;
688 dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].ram_chan_q = ram_chan_q;
689
556 dev->clk = clk_get(&pdev->dev, NULL); 690 dev->clk = clk_get(&pdev->dev, NULL);
557 if (IS_ERR(dev->clk)) { 691 if (IS_ERR(dev->clk)) {
558 ret = -ENODEV; 692 ret = -ENODEV;
@@ -584,6 +718,7 @@ static int davinci_i2s_probe(struct platform_device *pdev)
584 goto err_free_mem; 718 goto err_free_mem;
585 } 719 }
586 dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].channel = res->start; 720 dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].channel = res->start;
721 dev->dev = &pdev->dev;
587 722
588 davinci_i2s_dai.private_data = dev; 723 davinci_i2s_dai.private_data = dev;
589 davinci_i2s_dai.capture.dma_data = dev->dma_params; 724 davinci_i2s_dai.capture.dma_data = dev->dma_params;
diff --git a/sound/soc/davinci/davinci-i2s.h b/sound/soc/davinci/davinci-i2s.h
index 241648ce8873..0b1e77b8c279 100644
--- a/sound/soc/davinci/davinci-i2s.h
+++ b/sound/soc/davinci/davinci-i2s.h
@@ -12,6 +12,11 @@
12#ifndef _DAVINCI_I2S_H 12#ifndef _DAVINCI_I2S_H
13#define _DAVINCI_I2S_H 13#define _DAVINCI_I2S_H
14 14
15/* McBSP dividers */
16enum davinci_mcbsp_div {
17 DAVINCI_MCBSP_CLKGDV, /* Sample rate generator divider */
18};
19
15extern struct snd_soc_dai davinci_i2s_dai; 20extern struct snd_soc_dai davinci_i2s_dai;
16 21
17#endif 22#endif
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c
index d3955096d872..b24720894af6 100644
--- a/sound/soc/davinci/davinci-mcasp.c
+++ b/sound/soc/davinci/davinci-mcasp.c
@@ -890,7 +890,8 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
890 dev->rxnumevt = pdata->rxnumevt; 890 dev->rxnumevt = pdata->rxnumevt;
891 891
892 dma_data = &dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK]; 892 dma_data = &dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK];
893 dma_data->eventq_no = pdata->eventq_no; 893 dma_data->asp_chan_q = pdata->asp_chan_q;
894 dma_data->ram_chan_q = pdata->ram_chan_q;
894 dma_data->dma_addr = (dma_addr_t) (pdata->tx_dma_offset + 895 dma_data->dma_addr = (dma_addr_t) (pdata->tx_dma_offset +
895 io_v2p(dev->base)); 896 io_v2p(dev->base));
896 897
@@ -904,7 +905,8 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
904 dma_data->channel = res->start; 905 dma_data->channel = res->start;
905 906
906 dma_data = &dev->dma_params[SNDRV_PCM_STREAM_CAPTURE]; 907 dma_data = &dev->dma_params[SNDRV_PCM_STREAM_CAPTURE];
907 dma_data->eventq_no = pdata->eventq_no; 908 dma_data->asp_chan_q = pdata->asp_chan_q;
909 dma_data->ram_chan_q = pdata->ram_chan_q;
908 dma_data->dma_addr = (dma_addr_t)(pdata->rx_dma_offset + 910 dma_data->dma_addr = (dma_addr_t)(pdata->rx_dma_offset +
909 io_v2p(dev->base)); 911 io_v2p(dev->base));
910 912
diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c
index 2dc406f42fe7..a7124116d2e0 100644
--- a/sound/soc/davinci/davinci-pcm.c
+++ b/sound/soc/davinci/davinci-pcm.c
@@ -381,7 +381,7 @@ static int request_ping_pong(struct snd_pcm_substream *substream,
381 /* Request ram master channel */ 381 /* Request ram master channel */
382 link = prtd->ram_channel = edma_alloc_channel(EDMA_CHANNEL_ANY, 382 link = prtd->ram_channel = edma_alloc_channel(EDMA_CHANNEL_ANY,
383 davinci_pcm_dma_irq, substream, 383 davinci_pcm_dma_irq, substream,
384 EVENTQ_1); 384 prtd->params->ram_chan_q);
385 if (link < 0) 385 if (link < 0)
386 goto exit1; 386 goto exit1;
387 387
@@ -477,7 +477,8 @@ static int davinci_pcm_dma_request(struct snd_pcm_substream *substream)
477 477
478 /* Request asp master DMA channel */ 478 /* Request asp master DMA channel */
479 link = prtd->asp_channel = edma_alloc_channel(params->channel, 479 link = prtd->asp_channel = edma_alloc_channel(params->channel,
480 davinci_pcm_dma_irq, substream, EVENTQ_0); 480 davinci_pcm_dma_irq, substream,
481 prtd->params->asp_chan_q);
481 if (link < 0) 482 if (link < 0)
482 goto exit1; 483 goto exit1;
483 484
@@ -800,7 +801,7 @@ static void davinci_pcm_free(struct snd_pcm *pcm)
800 dma_free_writecombine(pcm->card->dev, buf->bytes, 801 dma_free_writecombine(pcm->card->dev, buf->bytes,
801 buf->area, buf->addr); 802 buf->area, buf->addr);
802 buf->area = NULL; 803 buf->area = NULL;
803 iram_dma = (struct snd_dma_buffer *)buf->private_data; 804 iram_dma = buf->private_data;
804 if (iram_dma) { 805 if (iram_dma) {
805 sram_free(iram_dma->area, iram_dma->bytes); 806 sram_free(iram_dma->area, iram_dma->bytes);
806 kfree(iram_dma); 807 kfree(iram_dma);
diff --git a/sound/soc/davinci/davinci-pcm.h b/sound/soc/davinci/davinci-pcm.h
index 0764944cf10f..b799a02333d8 100644
--- a/sound/soc/davinci/davinci-pcm.h
+++ b/sound/soc/davinci/davinci-pcm.h
@@ -21,7 +21,8 @@ struct davinci_pcm_dma_params {
21 unsigned short acnt; 21 unsigned short acnt;
22 dma_addr_t dma_addr; /* device physical address for DMA */ 22 dma_addr_t dma_addr; /* device physical address for DMA */
23 unsigned sram_size; 23 unsigned sram_size;
24 enum dma_event_q eventq_no; /* event queue number */ 24 enum dma_event_q asp_chan_q; /* event queue number for ASP channel */
25 enum dma_event_q ram_chan_q; /* event queue number for RAM channel */
25 unsigned char data_type; /* xfer data type */ 26 unsigned char data_type; /* xfer data type */
26 unsigned char convert_mono_stereo; 27 unsigned char convert_mono_stereo;
27 unsigned int fifo_level; 28 unsigned int fifo_level;
diff --git a/sound/soc/davinci/davinci-vcif.c b/sound/soc/davinci/davinci-vcif.c
index 9aa980d38231..48678533da7a 100644
--- a/sound/soc/davinci/davinci-vcif.c
+++ b/sound/soc/davinci/davinci-vcif.c
@@ -203,7 +203,7 @@ static int davinci_vcif_probe(struct platform_device *pdev)
203 int ret; 203 int ret;
204 204
205 davinci_vcif_dev = kzalloc(sizeof(struct davinci_vcif_dev), GFP_KERNEL); 205 davinci_vcif_dev = kzalloc(sizeof(struct davinci_vcif_dev), GFP_KERNEL);
206 if (!davinci_vc) { 206 if (!davinci_vcif_dev) {
207 dev_dbg(&pdev->dev, 207 dev_dbg(&pdev->dev,
208 "could not allocate memory for private data\n"); 208 "could not allocate memory for private data\n");
209 return -ENOMEM; 209 return -ENOMEM;
diff --git a/sound/soc/ep93xx/Kconfig b/sound/soc/ep93xx/Kconfig
new file mode 100644
index 000000000000..f617f560f46b
--- /dev/null
+++ b/sound/soc/ep93xx/Kconfig
@@ -0,0 +1,18 @@
1config SND_EP93XX_SOC
2 tristate "SoC Audio support for the Cirrus Logic EP93xx series"
3 depends on ARCH_EP93XX && SND_SOC
4 help
5 Say Y or M if you want to add support for codecs attached to
6 the EP93xx I2S interface.
7
8config SND_EP93XX_SOC_I2S
9 tristate
10
11config SND_EP93XX_SOC_SNAPPERCL15
12 tristate "SoC Audio support for Bluewater Systems Snapper CL15 module"
13 depends on SND_EP93XX_SOC && MACH_SNAPPER_CL15
14 select SND_EP93XX_SOC_I2S
15 select SND_SOC_TLV320AIC23
16 help
17 Say Y or M here if you want to add support for I2S audio on the
18 Bluewater Systems Snapper CL15 module.
diff --git a/sound/soc/ep93xx/Makefile b/sound/soc/ep93xx/Makefile
new file mode 100644
index 000000000000..272e60f57b9a
--- /dev/null
+++ b/sound/soc/ep93xx/Makefile
@@ -0,0 +1,11 @@
1# EP93xx Platform Support
2snd-soc-ep93xx-objs := ep93xx-pcm.o
3snd-soc-ep93xx-i2s-objs := ep93xx-i2s.o
4
5obj-$(CONFIG_SND_EP93XX_SOC) += snd-soc-ep93xx.o
6obj-$(CONFIG_SND_EP93XX_SOC_I2S) += snd-soc-ep93xx-i2s.o
7
8# EP93XX Machine Support
9snd-soc-snappercl15-objs := snappercl15.o
10
11obj-$(CONFIG_SND_EP93XX_SOC_SNAPPERCL15) += snd-soc-snappercl15.o
diff --git a/sound/soc/ep93xx/ep93xx-i2s.c b/sound/soc/ep93xx/ep93xx-i2s.c
new file mode 100644
index 000000000000..00b946632184
--- /dev/null
+++ b/sound/soc/ep93xx/ep93xx-i2s.c
@@ -0,0 +1,487 @@
1/*
2 * linux/sound/soc/ep93xx-i2s.c
3 * EP93xx I2S driver
4 *
5 * Copyright (C) 2010 Ryan Mallon <ryan@bluewatersys.com>
6 *
7 * Based on the original driver by:
8 * Copyright (C) 2007 Chase Douglas <chasedouglas@gmail>
9 * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
14 *
15 */
16
17#include <linux/module.h>
18#include <linux/init.h>
19#include <linux/slab.h>
20#include <linux/clk.h>
21#include <linux/io.h>
22
23#include <sound/core.h>
24#include <sound/pcm.h>
25#include <sound/pcm_params.h>
26#include <sound/initval.h>
27#include <sound/soc.h>
28
29#include <mach/hardware.h>
30#include <mach/ep93xx-regs.h>
31#include <mach/dma.h>
32
33#include "ep93xx-pcm.h"
34#include "ep93xx-i2s.h"
35
36#define EP93XX_I2S_TXCLKCFG 0x00
37#define EP93XX_I2S_RXCLKCFG 0x04
38#define EP93XX_I2S_GLCTRL 0x0C
39
40#define EP93XX_I2S_TXLINCTRLDATA 0x28
41#define EP93XX_I2S_TXCTRL 0x2C
42#define EP93XX_I2S_TXWRDLEN 0x30
43#define EP93XX_I2S_TX0EN 0x34
44
45#define EP93XX_I2S_RXLINCTRLDATA 0x58
46#define EP93XX_I2S_RXCTRL 0x5C
47#define EP93XX_I2S_RXWRDLEN 0x60
48#define EP93XX_I2S_RX0EN 0x64
49
50#define EP93XX_I2S_WRDLEN_16 (0 << 0)
51#define EP93XX_I2S_WRDLEN_24 (1 << 0)
52#define EP93XX_I2S_WRDLEN_32 (2 << 0)
53
54#define EP93XX_I2S_LINCTRLDATA_R_JUST (1 << 2) /* Right justify */
55
56#define EP93XX_I2S_CLKCFG_LRS (1 << 0) /* lrclk polarity */
57#define EP93XX_I2S_CLKCFG_CKP (1 << 1) /* Bit clock polarity */
58#define EP93XX_I2S_CLKCFG_REL (1 << 2) /* First bit transition */
59#define EP93XX_I2S_CLKCFG_MASTER (1 << 3) /* Master mode */
60#define EP93XX_I2S_CLKCFG_NBCG (1 << 4) /* Not bit clock gating */
61
62struct ep93xx_i2s_info {
63 struct clk *mclk;
64 struct clk *sclk;
65 struct clk *lrclk;
66 struct ep93xx_pcm_dma_params *dma_params;
67 struct resource *mem;
68 void __iomem *regs;
69};
70
71struct ep93xx_pcm_dma_params ep93xx_i2s_dma_params[] = {
72 [SNDRV_PCM_STREAM_PLAYBACK] = {
73 .name = "i2s-pcm-out",
74 .dma_port = EP93XX_DMA_M2P_PORT_I2S1,
75 },
76 [SNDRV_PCM_STREAM_CAPTURE] = {
77 .name = "i2s-pcm-in",
78 .dma_port = EP93XX_DMA_M2P_PORT_I2S1,
79 },
80};
81
82static inline void ep93xx_i2s_write_reg(struct ep93xx_i2s_info *info,
83 unsigned reg, unsigned val)
84{
85 __raw_writel(val, info->regs + reg);
86}
87
88static inline unsigned ep93xx_i2s_read_reg(struct ep93xx_i2s_info *info,
89 unsigned reg)
90{
91 return __raw_readl(info->regs + reg);
92}
93
94static void ep93xx_i2s_enable(struct ep93xx_i2s_info *info, int stream)
95{
96 unsigned base_reg;
97 int i;
98
99 if ((ep93xx_i2s_read_reg(info, EP93XX_I2S_TX0EN) & 0x1) == 0 &&
100 (ep93xx_i2s_read_reg(info, EP93XX_I2S_RX0EN) & 0x1) == 0) {
101 /* Enable clocks */
102 clk_enable(info->mclk);
103 clk_enable(info->sclk);
104 clk_enable(info->lrclk);
105
106 /* Enable i2s */
107 ep93xx_i2s_write_reg(info, EP93XX_I2S_GLCTRL, 1);
108 }
109
110 /* Enable fifos */
111 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
112 base_reg = EP93XX_I2S_TX0EN;
113 else
114 base_reg = EP93XX_I2S_RX0EN;
115 for (i = 0; i < 3; i++)
116 ep93xx_i2s_write_reg(info, base_reg + (i * 4), 1);
117}
118
119static void ep93xx_i2s_disable(struct ep93xx_i2s_info *info, int stream)
120{
121 unsigned base_reg;
122 int i;
123
124 /* Disable fifos */
125 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
126 base_reg = EP93XX_I2S_TX0EN;
127 else
128 base_reg = EP93XX_I2S_RX0EN;
129 for (i = 0; i < 3; i++)
130 ep93xx_i2s_write_reg(info, base_reg + (i * 4), 0);
131
132 if ((ep93xx_i2s_read_reg(info, EP93XX_I2S_TX0EN) & 0x1) == 0 &&
133 (ep93xx_i2s_read_reg(info, EP93XX_I2S_RX0EN) & 0x1) == 0) {
134 /* Disable i2s */
135 ep93xx_i2s_write_reg(info, EP93XX_I2S_GLCTRL, 0);
136
137 /* Disable clocks */
138 clk_disable(info->lrclk);
139 clk_disable(info->sclk);
140 clk_disable(info->mclk);
141 }
142}
143
144static int ep93xx_i2s_startup(struct snd_pcm_substream *substream,
145 struct snd_soc_dai *dai)
146{
147 struct snd_soc_pcm_runtime *rtd = substream->private_data;
148 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
149 struct ep93xx_i2s_info *info = rtd->dai->cpu_dai->private_data;
150
151 snd_soc_dai_set_dma_data(cpu_dai, substream,
152 &info->dma_params[substream->stream]);
153 return 0;
154}
155
156static void ep93xx_i2s_shutdown(struct snd_pcm_substream *substream,
157 struct snd_soc_dai *dai)
158{
159 struct snd_soc_pcm_runtime *rtd = substream->private_data;
160 struct ep93xx_i2s_info *info = rtd->dai->cpu_dai->private_data;
161
162 ep93xx_i2s_disable(info, substream->stream);
163}
164
165static int ep93xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
166 unsigned int fmt)
167{
168 struct ep93xx_i2s_info *info = cpu_dai->private_data;
169 unsigned int clk_cfg, lin_ctrl;
170
171 clk_cfg = ep93xx_i2s_read_reg(info, EP93XX_I2S_RXCLKCFG);
172 lin_ctrl = ep93xx_i2s_read_reg(info, EP93XX_I2S_RXLINCTRLDATA);
173
174 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
175 case SND_SOC_DAIFMT_I2S:
176 clk_cfg |= EP93XX_I2S_CLKCFG_REL;
177 lin_ctrl &= ~EP93XX_I2S_LINCTRLDATA_R_JUST;
178 break;
179
180 case SND_SOC_DAIFMT_LEFT_J:
181 clk_cfg &= ~EP93XX_I2S_CLKCFG_REL;
182 lin_ctrl &= ~EP93XX_I2S_LINCTRLDATA_R_JUST;
183 break;
184
185 case SND_SOC_DAIFMT_RIGHT_J:
186 clk_cfg &= ~EP93XX_I2S_CLKCFG_REL;
187 lin_ctrl |= EP93XX_I2S_LINCTRLDATA_R_JUST;
188 break;
189
190 default:
191 return -EINVAL;
192 }
193
194 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
195 case SND_SOC_DAIFMT_CBS_CFS:
196 /* CPU is master */
197 clk_cfg |= EP93XX_I2S_CLKCFG_MASTER;
198 break;
199
200 case SND_SOC_DAIFMT_CBM_CFM:
201 /* Codec is master */
202 clk_cfg &= ~EP93XX_I2S_CLKCFG_MASTER;
203 break;
204
205 default:
206 return -EINVAL;
207 }
208
209 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
210 case SND_SOC_DAIFMT_NB_NF:
211 /* Negative bit clock, lrclk low on left word */
212 clk_cfg &= ~(EP93XX_I2S_CLKCFG_CKP | EP93XX_I2S_CLKCFG_REL);
213 break;
214
215 case SND_SOC_DAIFMT_NB_IF:
216 /* Negative bit clock, lrclk low on right word */
217 clk_cfg &= ~EP93XX_I2S_CLKCFG_CKP;
218 clk_cfg |= EP93XX_I2S_CLKCFG_REL;
219 break;
220
221 case SND_SOC_DAIFMT_IB_NF:
222 /* Positive bit clock, lrclk low on left word */
223 clk_cfg |= EP93XX_I2S_CLKCFG_CKP;
224 clk_cfg &= ~EP93XX_I2S_CLKCFG_REL;
225 break;
226
227 case SND_SOC_DAIFMT_IB_IF:
228 /* Positive bit clock, lrclk low on right word */
229 clk_cfg |= EP93XX_I2S_CLKCFG_CKP | EP93XX_I2S_CLKCFG_REL;
230 break;
231 }
232
233 /* Write new register values */
234 ep93xx_i2s_write_reg(info, EP93XX_I2S_RXCLKCFG, clk_cfg);
235 ep93xx_i2s_write_reg(info, EP93XX_I2S_TXCLKCFG, clk_cfg);
236 ep93xx_i2s_write_reg(info, EP93XX_I2S_RXLINCTRLDATA, lin_ctrl);
237 ep93xx_i2s_write_reg(info, EP93XX_I2S_TXLINCTRLDATA, lin_ctrl);
238 return 0;
239}
240
241static int ep93xx_i2s_hw_params(struct snd_pcm_substream *substream,
242 struct snd_pcm_hw_params *params,
243 struct snd_soc_dai *dai)
244{
245 struct snd_soc_pcm_runtime *rtd = substream->private_data;
246 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
247 struct ep93xx_i2s_info *info = cpu_dai->private_data;
248 unsigned word_len, div, sdiv, lrdiv;
249 int found = 0, err;
250
251 switch (params_format(params)) {
252 case SNDRV_PCM_FORMAT_S16_LE:
253 word_len = EP93XX_I2S_WRDLEN_16;
254 break;
255
256 case SNDRV_PCM_FORMAT_S24_LE:
257 word_len = EP93XX_I2S_WRDLEN_24;
258 break;
259
260 case SNDRV_PCM_FORMAT_S32_LE:
261 word_len = EP93XX_I2S_WRDLEN_32;
262 break;
263
264 default:
265 return -EINVAL;
266 }
267
268 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
269 ep93xx_i2s_write_reg(info, EP93XX_I2S_TXWRDLEN, word_len);
270 else
271 ep93xx_i2s_write_reg(info, EP93XX_I2S_RXWRDLEN, word_len);
272
273 /*
274 * Calculate the sdiv (bit clock) and lrdiv (left/right clock) values.
275 * If the lrclk is pulse length is larger than the word size, then the
276 * bit clock will be gated for the unused bits.
277 */
278 div = (clk_get_rate(info->mclk) / params_rate(params)) *
279 params_channels(params);
280 for (sdiv = 2; sdiv <= 4; sdiv += 2)
281 for (lrdiv = 32; lrdiv <= 128; lrdiv <<= 1)
282 if (sdiv * lrdiv == div) {
283 found = 1;
284 goto out;
285 }
286out:
287 if (!found)
288 return -EINVAL;
289
290 err = clk_set_rate(info->sclk, clk_get_rate(info->mclk) / sdiv);
291 if (err)
292 return err;
293
294 err = clk_set_rate(info->lrclk, clk_get_rate(info->sclk) / lrdiv);
295 if (err)
296 return err;
297
298 ep93xx_i2s_enable(info, substream->stream);
299 return 0;
300}
301
302static int ep93xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id,
303 unsigned int freq, int dir)
304{
305 struct ep93xx_i2s_info *info = cpu_dai->private_data;
306
307 if (dir == SND_SOC_CLOCK_IN || clk_id != 0)
308 return -EINVAL;
309
310 return clk_set_rate(info->mclk, freq);
311}
312
313#ifdef CONFIG_PM
314static int ep93xx_i2s_suspend(struct snd_soc_dai *dai)
315{
316 struct ep93xx_i2s_info *info = dai->private_data;
317
318 if (!dai->active)
319 return;
320
321 ep93xx_i2s_disable(info, SNDRV_PCM_STREAM_PLAYBACK);
322 ep93xx_i2s_disable(info, SNDRV_PCM_STREAM_CAPTURE);
323}
324
325static int ep93xx_i2s_resume(struct snd_soc_dai *dai)
326{
327 struct ep93xx_i2s_info *info = dai->private_data;
328
329 if (!dai->active)
330 return;
331
332 ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_PLAYBACK);
333 ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_CAPTURE);
334}
335#else
336#define ep93xx_i2s_suspend NULL
337#define ep93xx_i2s_resume NULL
338#endif
339
340static struct snd_soc_dai_ops ep93xx_i2s_dai_ops = {
341 .startup = ep93xx_i2s_startup,
342 .shutdown = ep93xx_i2s_shutdown,
343 .hw_params = ep93xx_i2s_hw_params,
344 .set_sysclk = ep93xx_i2s_set_sysclk,
345 .set_fmt = ep93xx_i2s_set_dai_fmt,
346};
347
348#define EP93XX_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
349 SNDRV_PCM_FMTBIT_S24_LE | \
350 SNDRV_PCM_FMTBIT_S32_LE)
351
352struct snd_soc_dai ep93xx_i2s_dai = {
353 .name = "ep93xx-i2s",
354 .id = 0,
355 .symmetric_rates= 1,
356 .suspend = ep93xx_i2s_suspend,
357 .resume = ep93xx_i2s_resume,
358 .playback = {
359 .channels_min = 2,
360 .channels_max = 2,
361 .rates = SNDRV_PCM_RATE_8000_48000,
362 .formats = EP93XX_I2S_FORMATS,
363 },
364 .capture = {
365 .channels_min = 2,
366 .channels_max = 2,
367 .rates = SNDRV_PCM_RATE_8000_48000,
368 .formats = EP93XX_I2S_FORMATS,
369 },
370 .ops = &ep93xx_i2s_dai_ops,
371};
372EXPORT_SYMBOL_GPL(ep93xx_i2s_dai);
373
374static int ep93xx_i2s_probe(struct platform_device *pdev)
375{
376 struct ep93xx_i2s_info *info;
377 struct resource *res;
378 int err;
379
380 info = kzalloc(sizeof(struct ep93xx_i2s_info), GFP_KERNEL);
381 if (!info) {
382 err = -ENOMEM;
383 goto fail;
384 }
385
386 ep93xx_i2s_dai.dev = &pdev->dev;
387 ep93xx_i2s_dai.private_data = info;
388 info->dma_params = ep93xx_i2s_dma_params;
389
390 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
391 if (!res) {
392 err = -ENODEV;
393 goto fail;
394 }
395
396 info->mem = request_mem_region(res->start, resource_size(res),
397 pdev->name);
398 if (!info->mem) {
399 err = -EBUSY;
400 goto fail;
401 }
402
403 info->regs = ioremap(info->mem->start, resource_size(info->mem));
404 if (!info->regs) {
405 err = -ENXIO;
406 goto fail_release_mem;
407 }
408
409 info->mclk = clk_get(&pdev->dev, "mclk");
410 if (IS_ERR(info->mclk)) {
411 err = PTR_ERR(info->mclk);
412 goto fail_unmap_mem;
413 }
414
415 info->sclk = clk_get(&pdev->dev, "sclk");
416 if (IS_ERR(info->sclk)) {
417 err = PTR_ERR(info->sclk);
418 goto fail_put_mclk;
419 }
420
421 info->lrclk = clk_get(&pdev->dev, "lrclk");
422 if (IS_ERR(info->lrclk)) {
423 err = PTR_ERR(info->lrclk);
424 goto fail_put_sclk;
425 }
426
427 err = snd_soc_register_dai(&ep93xx_i2s_dai);
428 if (err)
429 goto fail_put_lrclk;
430
431 return 0;
432
433fail_put_lrclk:
434 clk_put(info->lrclk);
435fail_put_sclk:
436 clk_put(info->sclk);
437fail_put_mclk:
438 clk_put(info->mclk);
439fail_unmap_mem:
440 iounmap(info->regs);
441fail_release_mem:
442 release_mem_region(info->mem->start, resource_size(info->mem));
443 kfree(info);
444fail:
445 return err;
446}
447
448static int __devexit ep93xx_i2s_remove(struct platform_device *pdev)
449{
450 struct ep93xx_i2s_info *info = ep93xx_i2s_dai.private_data;
451
452 snd_soc_unregister_dai(&ep93xx_i2s_dai);
453 clk_put(info->lrclk);
454 clk_put(info->sclk);
455 clk_put(info->mclk);
456 iounmap(info->regs);
457 release_mem_region(info->mem->start, resource_size(info->mem));
458 kfree(info);
459 return 0;
460}
461
462static struct platform_driver ep93xx_i2s_driver = {
463 .probe = ep93xx_i2s_probe,
464 .remove = __devexit_p(ep93xx_i2s_remove),
465 .driver = {
466 .name = "ep93xx-i2s",
467 .owner = THIS_MODULE,
468 },
469};
470
471static int __init ep93xx_i2s_init(void)
472{
473 return platform_driver_register(&ep93xx_i2s_driver);
474}
475
476static void __exit ep93xx_i2s_exit(void)
477{
478 platform_driver_unregister(&ep93xx_i2s_driver);
479}
480
481module_init(ep93xx_i2s_init);
482module_exit(ep93xx_i2s_exit);
483
484MODULE_ALIAS("platform:ep93xx-i2s");
485MODULE_AUTHOR("Ryan Mallon <ryan@bluewatersys.com>");
486MODULE_DESCRIPTION("EP93XX I2S driver");
487MODULE_LICENSE("GPL");
diff --git a/sound/soc/ep93xx/ep93xx-i2s.h b/sound/soc/ep93xx/ep93xx-i2s.h
new file mode 100644
index 000000000000..3bd4ebfaa1de
--- /dev/null
+++ b/sound/soc/ep93xx/ep93xx-i2s.h
@@ -0,0 +1,18 @@
1/*
2 * linux/sound/soc/ep93xx-i2s.h
3 * EP93xx I2S driver
4 *
5 * Copyright (C) 2010 Ryan Mallon <ryan@bluewatersys.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 */
12
13#ifndef _EP93XX_SND_SOC_I2S_H
14#define _EP93XX_SND_SOC_I2S_H
15
16extern struct snd_soc_dai ep93xx_i2s_dai;
17
18#endif /* _EP93XX_SND_SOC_I2S_H */
diff --git a/sound/soc/ep93xx/ep93xx-pcm.c b/sound/soc/ep93xx/ep93xx-pcm.c
new file mode 100644
index 000000000000..4ba938400791
--- /dev/null
+++ b/sound/soc/ep93xx/ep93xx-pcm.c
@@ -0,0 +1,319 @@
1/*
2 * linux/sound/arm/ep93xx-pcm.c - EP93xx ALSA PCM interface
3 *
4 * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
5 * Copyright (C) 2006 Applied Data Systems
6 *
7 * Rewritten for the SoC audio subsystem (Based on PXA2xx code):
8 * Copyright (c) 2008 Ryan Mallon <ryan@bluewatersys.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 */
14
15#include <linux/module.h>
16#include <linux/init.h>
17#include <linux/device.h>
18#include <linux/slab.h>
19#include <linux/dma-mapping.h>
20
21#include <sound/core.h>
22#include <sound/pcm.h>
23#include <sound/pcm_params.h>
24#include <sound/soc.h>
25
26#include <mach/dma.h>
27#include <mach/hardware.h>
28#include <mach/ep93xx-regs.h>
29
30#include "ep93xx-pcm.h"
31
32static const struct snd_pcm_hardware ep93xx_pcm_hardware = {
33 .info = (SNDRV_PCM_INFO_MMAP |
34 SNDRV_PCM_INFO_MMAP_VALID |
35 SNDRV_PCM_INFO_INTERLEAVED |
36 SNDRV_PCM_INFO_BLOCK_TRANSFER),
37
38 .rates = SNDRV_PCM_RATE_8000_48000,
39 .rate_min = SNDRV_PCM_RATE_8000,
40 .rate_max = SNDRV_PCM_RATE_48000,
41
42 .formats = (SNDRV_PCM_FMTBIT_S16_LE |
43 SNDRV_PCM_FMTBIT_S24_LE |
44 SNDRV_PCM_FMTBIT_S32_LE),
45
46 .buffer_bytes_max = 131072,
47 .period_bytes_min = 32,
48 .period_bytes_max = 32768,
49 .periods_min = 1,
50 .periods_max = 32,
51 .fifo_size = 32,
52};
53
54struct ep93xx_runtime_data
55{
56 struct ep93xx_dma_m2p_client cl;
57 struct ep93xx_pcm_dma_params *params;
58 int pointer_bytes;
59 struct tasklet_struct period_tasklet;
60 int periods;
61 struct ep93xx_dma_buffer buf[32];
62};
63
64static void ep93xx_pcm_period_elapsed(unsigned long data)
65{
66 struct snd_pcm_substream *substream = (struct snd_pcm_substream *)data;
67 snd_pcm_period_elapsed(substream);
68}
69
70static void ep93xx_pcm_buffer_started(void *cookie,
71 struct ep93xx_dma_buffer *buf)
72{
73}
74
75static void ep93xx_pcm_buffer_finished(void *cookie,
76 struct ep93xx_dma_buffer *buf,
77 int bytes, int error)
78{
79 struct snd_pcm_substream *substream = cookie;
80 struct ep93xx_runtime_data *rtd = substream->runtime->private_data;
81
82 if (buf == rtd->buf + rtd->periods - 1)
83 rtd->pointer_bytes = 0;
84 else
85 rtd->pointer_bytes += buf->size;
86
87 if (!error) {
88 ep93xx_dma_m2p_submit_recursive(&rtd->cl, buf);
89 tasklet_schedule(&rtd->period_tasklet);
90 } else {
91 snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
92 }
93}
94
95static int ep93xx_pcm_open(struct snd_pcm_substream *substream)
96{
97 struct snd_soc_pcm_runtime *soc_rtd = substream->private_data;
98 struct snd_soc_dai *cpu_dai = soc_rtd->dai->cpu_dai;
99 struct ep93xx_pcm_dma_params *dma_params;
100 struct ep93xx_runtime_data *rtd;
101 int ret;
102
103 dma_params = snd_soc_dai_get_dma_data(cpu_dai, substream);
104 snd_soc_set_runtime_hwparams(substream, &ep93xx_pcm_hardware);
105
106 rtd = kmalloc(sizeof(*rtd), GFP_KERNEL);
107 if (!rtd)
108 return -ENOMEM;
109
110 memset(&rtd->period_tasklet, 0, sizeof(rtd->period_tasklet));
111 rtd->period_tasklet.func = ep93xx_pcm_period_elapsed;
112 rtd->period_tasklet.data = (unsigned long)substream;
113
114 rtd->cl.name = dma_params->name;
115 rtd->cl.flags = dma_params->dma_port | EP93XX_DMA_M2P_IGNORE_ERROR |
116 ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
117 EP93XX_DMA_M2P_TX : EP93XX_DMA_M2P_RX);
118 rtd->cl.cookie = substream;
119 rtd->cl.buffer_started = ep93xx_pcm_buffer_started;
120 rtd->cl.buffer_finished = ep93xx_pcm_buffer_finished;
121 ret = ep93xx_dma_m2p_client_register(&rtd->cl);
122 if (ret < 0) {
123 kfree(rtd);
124 return ret;
125 }
126
127 substream->runtime->private_data = rtd;
128 return 0;
129}
130
131static int ep93xx_pcm_close(struct snd_pcm_substream *substream)
132{
133 struct ep93xx_runtime_data *rtd = substream->runtime->private_data;
134
135 ep93xx_dma_m2p_client_unregister(&rtd->cl);
136 kfree(rtd);
137 return 0;
138}
139
140static int ep93xx_pcm_hw_params(struct snd_pcm_substream *substream,
141 struct snd_pcm_hw_params *params)
142{
143 struct snd_pcm_runtime *runtime = substream->runtime;
144 struct ep93xx_runtime_data *rtd = runtime->private_data;
145 size_t totsize = params_buffer_bytes(params);
146 size_t period = params_period_bytes(params);
147 int i;
148
149 snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
150 runtime->dma_bytes = totsize;
151
152 rtd->periods = (totsize + period - 1) / period;
153 for (i = 0; i < rtd->periods; i++) {
154 rtd->buf[i].bus_addr = runtime->dma_addr + (i * period);
155 rtd->buf[i].size = period;
156 if ((i + 1) * period > totsize)
157 rtd->buf[i].size = totsize - (i * period);
158 }
159
160 return 0;
161}
162
163static int ep93xx_pcm_hw_free(struct snd_pcm_substream *substream)
164{
165 snd_pcm_set_runtime_buffer(substream, NULL);
166 return 0;
167}
168
169static int ep93xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
170{
171 struct ep93xx_runtime_data *rtd = substream->runtime->private_data;
172 int ret;
173 int i;
174
175 ret = 0;
176 switch (cmd) {
177 case SNDRV_PCM_TRIGGER_START:
178 case SNDRV_PCM_TRIGGER_RESUME:
179 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
180 rtd->pointer_bytes = 0;
181 for (i = 0; i < rtd->periods; i++)
182 ep93xx_dma_m2p_submit(&rtd->cl, rtd->buf + i);
183 break;
184
185 case SNDRV_PCM_TRIGGER_STOP:
186 case SNDRV_PCM_TRIGGER_SUSPEND:
187 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
188 ep93xx_dma_m2p_flush(&rtd->cl);
189 break;
190
191 default:
192 ret = -EINVAL;
193 break;
194 }
195
196 return ret;
197}
198
199static snd_pcm_uframes_t ep93xx_pcm_pointer(struct snd_pcm_substream *substream)
200{
201 struct snd_pcm_runtime *runtime = substream->runtime;
202 struct ep93xx_runtime_data *rtd = substream->runtime->private_data;
203
204 /* FIXME: implement this with sub-period granularity */
205 return bytes_to_frames(runtime, rtd->pointer_bytes);
206}
207
208static int ep93xx_pcm_mmap(struct snd_pcm_substream *substream,
209 struct vm_area_struct *vma)
210{
211 struct snd_pcm_runtime *runtime = substream->runtime;
212
213 return dma_mmap_writecombine(substream->pcm->card->dev, vma,
214 runtime->dma_area,
215 runtime->dma_addr,
216 runtime->dma_bytes);
217}
218
219static struct snd_pcm_ops ep93xx_pcm_ops = {
220 .open = ep93xx_pcm_open,
221 .close = ep93xx_pcm_close,
222 .ioctl = snd_pcm_lib_ioctl,
223 .hw_params = ep93xx_pcm_hw_params,
224 .hw_free = ep93xx_pcm_hw_free,
225 .trigger = ep93xx_pcm_trigger,
226 .pointer = ep93xx_pcm_pointer,
227 .mmap = ep93xx_pcm_mmap,
228};
229
230static int ep93xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
231{
232 struct snd_pcm_substream *substream = pcm->streams[stream].substream;
233 struct snd_dma_buffer *buf = &substream->dma_buffer;
234 size_t size = ep93xx_pcm_hardware.buffer_bytes_max;
235
236 buf->dev.type = SNDRV_DMA_TYPE_DEV;
237 buf->dev.dev = pcm->card->dev;
238 buf->private_data = NULL;
239 buf->area = dma_alloc_writecombine(pcm->card->dev, size,
240 &buf->addr, GFP_KERNEL);
241 buf->bytes = size;
242
243 return (buf->area == NULL) ? -ENOMEM : 0;
244}
245
246static void ep93xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
247{
248 struct snd_pcm_substream *substream;
249 struct snd_dma_buffer *buf;
250 int stream;
251
252 for (stream = 0; stream < 2; stream++) {
253 substream = pcm->streams[stream].substream;
254 if (!substream)
255 continue;
256
257 buf = &substream->dma_buffer;
258 if (!buf->area)
259 continue;
260
261 dma_free_writecombine(pcm->card->dev, buf->bytes, buf->area,
262 buf->addr);
263 buf->area = NULL;
264 }
265}
266
267static u64 ep93xx_pcm_dmamask = 0xffffffff;
268
269static int ep93xx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
270 struct snd_pcm *pcm)
271{
272 int ret = 0;
273
274 if (!card->dev->dma_mask)
275 card->dev->dma_mask = &ep93xx_pcm_dmamask;
276 if (!card->dev->coherent_dma_mask)
277 card->dev->coherent_dma_mask = 0xffffffff;
278
279 if (dai->playback.channels_min) {
280 ret = ep93xx_pcm_preallocate_dma_buffer(pcm,
281 SNDRV_PCM_STREAM_PLAYBACK);
282 if (ret)
283 return ret;
284 }
285
286 if (dai->capture.channels_min) {
287 ret = ep93xx_pcm_preallocate_dma_buffer(pcm,
288 SNDRV_PCM_STREAM_CAPTURE);
289 if (ret)
290 return ret;
291 }
292
293 return 0;
294}
295
296struct snd_soc_platform ep93xx_soc_platform = {
297 .name = "ep93xx-audio",
298 .pcm_ops = &ep93xx_pcm_ops,
299 .pcm_new = &ep93xx_pcm_new,
300 .pcm_free = &ep93xx_pcm_free_dma_buffers,
301};
302EXPORT_SYMBOL_GPL(ep93xx_soc_platform);
303
304static int __init ep93xx_soc_platform_init(void)
305{
306 return snd_soc_register_platform(&ep93xx_soc_platform);
307}
308
309static void __exit ep93xx_soc_platform_exit(void)
310{
311 snd_soc_unregister_platform(&ep93xx_soc_platform);
312}
313
314module_init(ep93xx_soc_platform_init);
315module_exit(ep93xx_soc_platform_exit);
316
317MODULE_AUTHOR("Ryan Mallon <ryan@bluewatersys.com>");
318MODULE_DESCRIPTION("EP93xx ALSA PCM interface");
319MODULE_LICENSE("GPL");
diff --git a/sound/soc/ep93xx/ep93xx-pcm.h b/sound/soc/ep93xx/ep93xx-pcm.h
new file mode 100644
index 000000000000..4ffdd3f62fe9
--- /dev/null
+++ b/sound/soc/ep93xx/ep93xx-pcm.h
@@ -0,0 +1,22 @@
1/*
2 * sound/soc/ep93xx/ep93xx-pcm.h - EP93xx ALSA PCM interface
3 *
4 * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
5 * Copyright (C) 2006 Applied Data Systems
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#ifndef _EP93XX_SND_SOC_PCM_H
13#define _EP93XX_SND_SOC_PCM_H
14
15struct ep93xx_pcm_dma_params {
16 char *name;
17 int dma_port;
18};
19
20extern struct snd_soc_platform ep93xx_soc_platform;
21
22#endif /* _EP93XX_SND_SOC_PCM_H */
diff --git a/sound/soc/ep93xx/snappercl15.c b/sound/soc/ep93xx/snappercl15.c
new file mode 100644
index 000000000000..64955340ff75
--- /dev/null
+++ b/sound/soc/ep93xx/snappercl15.c
@@ -0,0 +1,150 @@
1/*
2 * snappercl15.c -- SoC audio for Bluewater Systems Snapper CL15 module
3 *
4 * Copyright (C) 2008 Bluewater Systems Ltd
5 * Author: Ryan Mallon <ryan@bluewatersys.com>
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
14#include <linux/platform_device.h>
15#include <sound/core.h>
16#include <sound/pcm.h>
17#include <sound/soc.h>
18#include <sound/soc-dapm.h>
19
20#include <asm/mach-types.h>
21#include <mach/hardware.h>
22
23#include "../codecs/tlv320aic23.h"
24#include "ep93xx-pcm.h"
25#include "ep93xx-i2s.h"
26
27#define CODEC_CLOCK 5644800
28
29static int snappercl15_hw_params(struct snd_pcm_substream *substream,
30 struct snd_pcm_hw_params *params)
31{
32 struct snd_soc_pcm_runtime *rtd = substream->private_data;
33 struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
34 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
35 int err;
36
37 err = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
38 SND_SOC_DAIFMT_NB_IF |
39 SND_SOC_DAIFMT_CBS_CFS);
40
41 err = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
42 SND_SOC_DAIFMT_NB_IF |
43 SND_SOC_DAIFMT_CBS_CFS);
44 if (err)
45 return err;
46
47 err = snd_soc_dai_set_sysclk(codec_dai, 0, CODEC_CLOCK,
48 SND_SOC_CLOCK_IN);
49 if (err)
50 return err;
51
52 err = snd_soc_dai_set_sysclk(cpu_dai, 0, CODEC_CLOCK,
53 SND_SOC_CLOCK_OUT);
54 if (err)
55 return err;
56
57 return 0;
58}
59
60static struct snd_soc_ops snappercl15_ops = {
61 .hw_params = snappercl15_hw_params,
62};
63
64static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = {
65 SND_SOC_DAPM_HP("Headphone Jack", NULL),
66 SND_SOC_DAPM_LINE("Line In", NULL),
67 SND_SOC_DAPM_MIC("Mic Jack", NULL),
68};
69
70static const struct snd_soc_dapm_route audio_map[] = {
71 {"Headphone Jack", NULL, "LHPOUT"},
72 {"Headphone Jack", NULL, "RHPOUT"},
73
74 {"LLINEIN", NULL, "Line In"},
75 {"RLINEIN", NULL, "Line In"},
76
77 {"MICIN", NULL, "Mic Jack"},
78};
79
80static int snappercl15_tlv320aic23_init(struct snd_soc_codec *codec)
81{
82 snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets,
83 ARRAY_SIZE(tlv320aic23_dapm_widgets));
84
85 snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
86 return 0;
87}
88
89static struct snd_soc_dai_link snappercl15_dai = {
90 .name = "tlv320aic23",
91 .stream_name = "AIC23",
92 .cpu_dai = &ep93xx_i2s_dai,
93 .codec_dai = &tlv320aic23_dai,
94 .init = snappercl15_tlv320aic23_init,
95 .ops = &snappercl15_ops,
96};
97
98static struct snd_soc_card snd_soc_snappercl15 = {
99 .name = "Snapper CL15",
100 .platform = &ep93xx_soc_platform,
101 .dai_link = &snappercl15_dai,
102 .num_links = 1,
103};
104
105static struct snd_soc_device snappercl15_snd_devdata = {
106 .card = &snd_soc_snappercl15,
107 .codec_dev = &soc_codec_dev_tlv320aic23,
108};
109
110static struct platform_device *snappercl15_snd_device;
111
112static int __init snappercl15_init(void)
113{
114 int ret;
115
116 if (!machine_is_snapper_cl15())
117 return -ENODEV;
118
119 ret = ep93xx_i2s_acquire(EP93XX_SYSCON_DEVCFG_I2SONAC97,
120 EP93XX_SYSCON_I2SCLKDIV_ORIDE |
121 EP93XX_SYSCON_I2SCLKDIV_SPOL);
122 if (ret)
123 return ret;
124
125 snappercl15_snd_device = platform_device_alloc("soc-audio", -1);
126 if (!snappercl15_snd_device)
127 return -ENOMEM;
128
129 platform_set_drvdata(snappercl15_snd_device, &snappercl15_snd_devdata);
130 snappercl15_snd_devdata.dev = &snappercl15_snd_device->dev;
131 ret = platform_device_add(snappercl15_snd_device);
132 if (ret)
133 platform_device_put(snappercl15_snd_device);
134
135 return ret;
136}
137
138static void __exit snappercl15_exit(void)
139{
140 platform_device_unregister(snappercl15_snd_device);
141 ep93xx_i2s_release();
142}
143
144module_init(snappercl15_init);
145module_exit(snappercl15_exit);
146
147MODULE_AUTHOR("Ryan Mallon <ryan@bluewatersys.com>");
148MODULE_DESCRIPTION("ALSA SoC Snapper CL15");
149MODULE_LICENSE("GPL");
150
diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c
index 4f455bd6851f..676841cbae98 100644
--- a/sound/soc/fsl/mpc5200_psc_i2s.c
+++ b/sound/soc/fsl/mpc5200_psc_i2s.c
@@ -16,7 +16,6 @@
16 16
17#include <asm/mpc52xx_psc.h> 17#include <asm/mpc52xx_psc.h>
18 18
19#include "mpc5200_psc_i2s.h"
20#include "mpc5200_dma.h" 19#include "mpc5200_dma.h"
21 20
22/** 21/**
diff --git a/sound/soc/fsl/mpc5200_psc_i2s.h b/sound/soc/fsl/mpc5200_psc_i2s.h
deleted file mode 100644
index ce55e070fdf3..000000000000
--- a/sound/soc/fsl/mpc5200_psc_i2s.h
+++ /dev/null
@@ -1,12 +0,0 @@
1/*
2 * Freescale MPC5200 PSC in I2S mode
3 * ALSA SoC Digital Audio Interface (DAI) driver
4 *
5 */
6
7#ifndef __SOUND_SOC_FSL_MPC52xx_PSC_I2S_H__
8#define __SOUND_SOC_FSL_MPC52xx_PSC_I2S_H__
9
10extern struct snd_soc_dai psc_i2s_dai[];
11
12#endif /* __SOUND_SOC_FSL_MPC52xx_PSC_I2S_H__ */
diff --git a/sound/soc/imx/Kconfig b/sound/soc/imx/Kconfig
index 252defea93b5..52dac5e3874c 100644
--- a/sound/soc/imx/Kconfig
+++ b/sound/soc/imx/Kconfig
@@ -1,4 +1,4 @@
1config SND_IMX_SOC 1menuconfig SND_IMX_SOC
2 tristate "SoC Audio for Freescale i.MX CPUs" 2 tristate "SoC Audio for Freescale i.MX CPUs"
3 depends on ARCH_MXC 3 depends on ARCH_MXC
4 select SND_PCM 4 select SND_PCM
@@ -8,14 +8,12 @@ config SND_IMX_SOC
8 Say Y or M if you want to add support for codecs attached to 8 Say Y or M if you want to add support for codecs attached to
9 the i.MX SSI interface. 9 the i.MX SSI interface.
10 10
11config SND_MXC_SOC_SSI 11if SND_IMX_SOC
12 tristate
13 12
14config SND_MXC_SOC_WM1133_EV1 13config SND_MXC_SOC_WM1133_EV1
15 tristate "Audio on the the i.MX31ADS with WM1133-EV1 fitted" 14 tristate "Audio on the the i.MX31ADS with WM1133-EV1 fitted"
16 depends on SND_IMX_SOC && MACH_MX31ADS_WM1133_EV1 && EXPERIMENTAL 15 depends on MACH_MX31ADS_WM1133_EV1 && EXPERIMENTAL
17 select SND_SOC_WM8350 16 select SND_SOC_WM8350
18 select SND_MXC_SOC_SSI
19 help 17 help
20 Enable support for audio on the i.MX31ADS with the WM1133-EV1 18 Enable support for audio on the i.MX31ADS with the WM1133-EV1
21 PMIC board with WM8835x fitted. 19 PMIC board with WM8835x fitted.
@@ -23,8 +21,17 @@ config SND_MXC_SOC_WM1133_EV1
23config SND_SOC_PHYCORE_AC97 21config SND_SOC_PHYCORE_AC97
24 tristate "SoC Audio support for Phytec phyCORE (and phyCARD) boards" 22 tristate "SoC Audio support for Phytec phyCORE (and phyCARD) boards"
25 depends on MACH_PCM043 || MACH_PCA100 23 depends on MACH_PCM043 || MACH_PCA100
26 select SND_MXC_SOC_SSI
27 select SND_SOC_WM9712 24 select SND_SOC_WM9712
28 help 25 help
29 Say Y if you want to add support for SoC audio on Phytec phyCORE 26 Say Y if you want to add support for SoC audio on Phytec phyCORE
30 and phyCARD boards in AC97 mode 27 and phyCARD boards in AC97 mode
28
29config SND_SOC_EUKREA_TLV320
30 tristate "Eukrea TLV320"
31 depends on MACH_EUKREA_MBIMX27_BASEBOARD || MACH_EUKREA_MBIMXSD_BASEBOARD
32 select SND_SOC_TLV320AIC23
33 help
34 Enable I2S based access to the TLV320AIC23B codec attached
35 to the SSI interface
36
37endif # SND_IMX_SOC
diff --git a/sound/soc/imx/Makefile b/sound/soc/imx/Makefile
index 2d203635ac11..7bc57baf2b0e 100644
--- a/sound/soc/imx/Makefile
+++ b/sound/soc/imx/Makefile
@@ -8,8 +8,10 @@ endif
8obj-$(CONFIG_SND_IMX_SOC) += snd-soc-imx.o 8obj-$(CONFIG_SND_IMX_SOC) += snd-soc-imx.o
9 9
10# i.MX Machine Support 10# i.MX Machine Support
11snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o
11snd-soc-phycore-ac97-objs := phycore-ac97.o 12snd-soc-phycore-ac97-objs := phycore-ac97.o
12snd-soc-wm1133-ev1-objs := wm1133-ev1.o 13snd-soc-wm1133-ev1-objs := wm1133-ev1.o
13 14
15obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o
14obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o 16obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o
15obj-$(CONFIG_SND_MXC_SOC_WM1133_EV1) += snd-soc-wm1133-ev1.o 17obj-$(CONFIG_SND_MXC_SOC_WM1133_EV1) += snd-soc-wm1133-ev1.o
diff --git a/sound/soc/imx/eukrea-tlv320.c b/sound/soc/imx/eukrea-tlv320.c
new file mode 100644
index 000000000000..f15dfbdc47ee
--- /dev/null
+++ b/sound/soc/imx/eukrea-tlv320.c
@@ -0,0 +1,137 @@
1/*
2 * eukrea-tlv320.c -- SoC audio for eukrea_cpuimxXX in I2S mode
3 *
4 * Copyright 2010 Eric Bénard, Eukréa Electromatique <eric@eukrea.com>
5 *
6 * based on sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c
7 * which is Copyright 2009 Simtec Electronics
8 * and on sound/soc/imx/phycore-ac97.c which is
9 * Copyright 2009 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
10 *
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by the
13 * Free Software Foundation; either version 2 of the License, or (at your
14 * option) any later version.
15 *
16 */
17
18#include <linux/module.h>
19#include <linux/moduleparam.h>
20#include <linux/device.h>
21#include <linux/i2c.h>
22#include <sound/core.h>
23#include <sound/pcm.h>
24#include <sound/soc.h>
25#include <sound/soc-dapm.h>
26#include <asm/mach-types.h>
27
28#include "../codecs/tlv320aic23.h"
29#include "imx-ssi.h"
30
31#define CODEC_CLOCK 12000000
32
33static int eukrea_tlv320_hw_params(struct snd_pcm_substream *substream,
34 struct snd_pcm_hw_params *params)
35{
36 struct snd_soc_pcm_runtime *rtd = substream->private_data;
37 struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
38 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
39 int ret;
40
41 ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
42 SND_SOC_DAIFMT_NB_NF |
43 SND_SOC_DAIFMT_CBM_CFM);
44 if (ret) {
45 pr_err("%s: failed set cpu dai format\n", __func__);
46 return ret;
47 }
48
49 ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
50 SND_SOC_DAIFMT_NB_NF |
51 SND_SOC_DAIFMT_CBM_CFM);
52 if (ret) {
53 pr_err("%s: failed set codec dai format\n", __func__);
54 return ret;
55 }
56
57 ret = snd_soc_dai_set_sysclk(codec_dai, 0,
58 CODEC_CLOCK, SND_SOC_CLOCK_OUT);
59 if (ret) {
60 pr_err("%s: failed setting codec sysclk\n", __func__);
61 return ret;
62 }
63 snd_soc_dai_set_tdm_slot(cpu_dai, 0xffffffc, 0xffffffc, 2, 0);
64
65 ret = snd_soc_dai_set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 0,
66 SND_SOC_CLOCK_IN);
67 if (ret) {
68 pr_err("can't set CPU system clock IMX_SSP_SYS_CLK\n");
69 return ret;
70 }
71
72 return 0;
73}
74
75static struct snd_soc_ops eukrea_tlv320_snd_ops = {
76 .hw_params = eukrea_tlv320_hw_params,
77};
78
79static struct snd_soc_dai_link eukrea_tlv320_dai = {
80 .name = "tlv320aic23",
81 .stream_name = "TLV320AIC23",
82 .codec_dai = &tlv320aic23_dai,
83 .ops = &eukrea_tlv320_snd_ops,
84};
85
86static struct snd_soc_card eukrea_tlv320 = {
87 .name = "cpuimx-audio",
88 .platform = &imx_soc_platform,
89 .dai_link = &eukrea_tlv320_dai,
90 .num_links = 1,
91};
92
93static struct snd_soc_device eukrea_tlv320_snd_devdata = {
94 .card = &eukrea_tlv320,
95 .codec_dev = &soc_codec_dev_tlv320aic23,
96};
97
98static struct platform_device *eukrea_tlv320_snd_device;
99
100static int __init eukrea_tlv320_init(void)
101{
102 int ret;
103
104 if (!machine_is_eukrea_cpuimx27() && !machine_is_eukrea_cpuimx25sd()
105 && !machine_is_eukrea_cpuimx35sd())
106 /* return happy. We might run on a totally different machine */
107 return 0;
108
109 eukrea_tlv320_snd_device = platform_device_alloc("soc-audio", -1);
110 if (!eukrea_tlv320_snd_device)
111 return -ENOMEM;
112
113 eukrea_tlv320_dai.cpu_dai = &imx_ssi_pcm_dai[0];
114
115 platform_set_drvdata(eukrea_tlv320_snd_device, &eukrea_tlv320_snd_devdata);
116 eukrea_tlv320_snd_devdata.dev = &eukrea_tlv320_snd_device->dev;
117 ret = platform_device_add(eukrea_tlv320_snd_device);
118
119 if (ret) {
120 printk(KERN_ERR "ASoC: Platform device allocation failed\n");
121 platform_device_put(eukrea_tlv320_snd_device);
122 }
123
124 return ret;
125}
126
127static void __exit eukrea_tlv320_exit(void)
128{
129 platform_device_unregister(eukrea_tlv320_snd_device);
130}
131
132module_init(eukrea_tlv320_init);
133module_exit(eukrea_tlv320_exit);
134
135MODULE_AUTHOR("Eric Bénard <eric@eukrea.com>");
136MODULE_DESCRIPTION("CPUIMX ALSA SoC driver");
137MODULE_LICENSE("GPL");
diff --git a/sound/soc/imx/imx-pcm-dma-mx2.c b/sound/soc/imx/imx-pcm-dma-mx2.c
index 05f19c9284f4..0a595da4811d 100644
--- a/sound/soc/imx/imx-pcm-dma-mx2.c
+++ b/sound/soc/imx/imx-pcm-dma-mx2.c
@@ -292,12 +292,16 @@ static int snd_imx_open(struct snd_pcm_substream *substream)
292 int ret; 292 int ret;
293 293
294 iprtd = kzalloc(sizeof(*iprtd), GFP_KERNEL); 294 iprtd = kzalloc(sizeof(*iprtd), GFP_KERNEL);
295 if (iprtd == NULL)
296 return -ENOMEM;
295 runtime->private_data = iprtd; 297 runtime->private_data = iprtd;
296 298
297 ret = snd_pcm_hw_constraint_integer(substream->runtime, 299 ret = snd_pcm_hw_constraint_integer(substream->runtime,
298 SNDRV_PCM_HW_PARAM_PERIODS); 300 SNDRV_PCM_HW_PARAM_PERIODS);
299 if (ret < 0) 301 if (ret < 0) {
302 kfree(iprtd);
300 return ret; 303 return ret;
304 }
301 305
302 snd_soc_set_runtime_hwparams(substream, &snd_imx_hardware); 306 snd_soc_set_runtime_hwparams(substream, &snd_imx_hardware);
303 return 0; 307 return 0;
diff --git a/sound/soc/imx/imx-pcm-fiq.c b/sound/soc/imx/imx-pcm-fiq.c
index 6b518e07eea9..b2bf27282cd2 100644
--- a/sound/soc/imx/imx-pcm-fiq.c
+++ b/sound/soc/imx/imx-pcm-fiq.c
@@ -192,6 +192,8 @@ static int snd_imx_open(struct snd_pcm_substream *substream)
192 int ret; 192 int ret;
193 193
194 iprtd = kzalloc(sizeof(*iprtd), GFP_KERNEL); 194 iprtd = kzalloc(sizeof(*iprtd), GFP_KERNEL);
195 if (iprtd == NULL)
196 return -ENOMEM;
195 runtime->private_data = iprtd; 197 runtime->private_data = iprtd;
196 198
197 iprtd->substream = substream; 199 iprtd->substream = substream;
@@ -202,8 +204,10 @@ static int snd_imx_open(struct snd_pcm_substream *substream)
202 204
203 ret = snd_pcm_hw_constraint_integer(substream->runtime, 205 ret = snd_pcm_hw_constraint_integer(substream->runtime,
204 SNDRV_PCM_HW_PARAM_PERIODS); 206 SNDRV_PCM_HW_PARAM_PERIODS);
205 if (ret < 0) 207 if (ret < 0) {
208 kfree(iprtd);
206 return ret; 209 return ret;
210 }
207 211
208 snd_soc_set_runtime_hwparams(substream, &snd_imx_hardware); 212 snd_soc_set_runtime_hwparams(substream, &snd_imx_hardware);
209 return 0; 213 return 0;
diff --git a/sound/soc/imx/imx-ssi.c b/sound/soc/imx/imx-ssi.c
index 80b4fee2442b..50f51624c535 100644
--- a/sound/soc/imx/imx-ssi.c
+++ b/sound/soc/imx/imx-ssi.c
@@ -83,8 +83,6 @@ static int imx_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
83/* 83/*
84 * SSI DAI format configuration. 84 * SSI DAI format configuration.
85 * Should only be called when port is inactive (i.e. SSIEN = 0). 85 * Should only be called when port is inactive (i.e. SSIEN = 0).
86 * Note: We don't use the I2S modes but instead manually configure the
87 * SSI for I2S because the I2S mode is only a register preset.
88 */ 86 */
89static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) 87static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
90{ 88{
@@ -99,6 +97,10 @@ static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
99 /* data on rising edge of bclk, frame low 1clk before data */ 97 /* data on rising edge of bclk, frame low 1clk before data */
100 strcr |= SSI_STCR_TFSI | SSI_STCR_TEFS | SSI_STCR_TXBIT0; 98 strcr |= SSI_STCR_TFSI | SSI_STCR_TEFS | SSI_STCR_TXBIT0;
101 scr |= SSI_SCR_NET; 99 scr |= SSI_SCR_NET;
100 if (ssi->flags & IMX_SSI_USE_I2S_SLAVE) {
101 scr &= ~SSI_I2S_MODE_MASK;
102 scr |= SSI_SCR_I2S_MODE_SLAVE;
103 }
102 break; 104 break;
103 case SND_SOC_DAIFMT_LEFT_J: 105 case SND_SOC_DAIFMT_LEFT_J:
104 /* data on rising edge of bclk, frame high with data */ 106 /* data on rising edge of bclk, frame high with data */
@@ -143,6 +145,11 @@ static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
143 145
144 strcr |= SSI_STCR_TFEN0; 146 strcr |= SSI_STCR_TFEN0;
145 147
148 if (ssi->flags & IMX_SSI_NET)
149 scr |= SSI_SCR_NET;
150 if (ssi->flags & IMX_SSI_SYN)
151 scr |= SSI_SCR_SYN;
152
146 writel(strcr, ssi->base + SSI_STCR); 153 writel(strcr, ssi->base + SSI_STCR);
147 writel(strcr, ssi->base + SSI_SRCR); 154 writel(strcr, ssi->base + SSI_SRCR);
148 writel(scr, ssi->base + SSI_SCR); 155 writel(scr, ssi->base + SSI_SCR);
diff --git a/sound/soc/jz4740/Kconfig b/sound/soc/jz4740/Kconfig
new file mode 100644
index 000000000000..5351cba66c9e
--- /dev/null
+++ b/sound/soc/jz4740/Kconfig
@@ -0,0 +1,23 @@
1config SND_JZ4740_SOC
2 tristate "SoC Audio for Ingenic JZ4740 SoC"
3 depends on MACH_JZ4740 && SND_SOC
4 help
5 Say Y or M if you want to add support for codecs attached to
6 the JZ4740 I2S interface. You will also need to select the audio
7 interfaces to support below.
8
9config SND_JZ4740_SOC_I2S
10 depends on SND_JZ4740_SOC
11 tristate "SoC Audio (I2S protocol) for Ingenic JZ4740 SoC"
12 help
13 Say Y if you want to use I2S protocol and I2S codec on Ingenic JZ4740
14 based boards.
15
16config SND_JZ4740_SOC_QI_LB60
17 tristate "SoC Audio support for Qi LB60"
18 depends on SND_JZ4740_SOC && JZ4740_QI_LB60
19 select SND_JZ4740_SOC_I2S
20 select SND_SOC_JZ4740_CODEC
21 help
22 Say Y if you want to add support for ASoC audio on the Qi LB60 board
23 a.k.a Qi Ben NanoNote.
diff --git a/sound/soc/jz4740/Makefile b/sound/soc/jz4740/Makefile
new file mode 100644
index 000000000000..be873c1b0c20
--- /dev/null
+++ b/sound/soc/jz4740/Makefile
@@ -0,0 +1,13 @@
1#
2# Jz4740 Platform Support
3#
4snd-soc-jz4740-objs := jz4740-pcm.o
5snd-soc-jz4740-i2s-objs := jz4740-i2s.o
6
7obj-$(CONFIG_SND_JZ4740_SOC) += snd-soc-jz4740.o
8obj-$(CONFIG_SND_JZ4740_SOC_I2S) += snd-soc-jz4740-i2s.o
9
10# Jz4740 Machine Support
11snd-soc-qi-lb60-objs := qi_lb60.o
12
13obj-$(CONFIG_SND_JZ4740_SOC_QI_LB60) += snd-soc-qi-lb60.o
diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c
new file mode 100644
index 000000000000..eb518f0c5e01
--- /dev/null
+++ b/sound/soc/jz4740/jz4740-i2s.c
@@ -0,0 +1,540 @@
1/*
2 * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * You should have received a copy of the GNU General Public License along
10 * with this program; if not, write to the Free Software Foundation, Inc.,
11 * 675 Mass Ave, Cambridge, MA 02139, USA.
12 *
13 */
14
15#include <linux/init.h>
16#include <linux/io.h>
17#include <linux/kernel.h>
18#include <linux/module.h>
19#include <linux/platform_device.h>
20#include <linux/slab.h>
21
22#include <linux/clk.h>
23#include <linux/delay.h>
24
25#include <linux/dma-mapping.h>
26
27#include <sound/core.h>
28#include <sound/pcm.h>
29#include <sound/pcm_params.h>
30#include <sound/soc.h>
31#include <sound/soc-dapm.h>
32#include <sound/initval.h>
33
34#include "jz4740-i2s.h"
35#include "jz4740-pcm.h"
36
37#define JZ_REG_AIC_CONF 0x00
38#define JZ_REG_AIC_CTRL 0x04
39#define JZ_REG_AIC_I2S_FMT 0x10
40#define JZ_REG_AIC_FIFO_STATUS 0x14
41#define JZ_REG_AIC_I2S_STATUS 0x1c
42#define JZ_REG_AIC_CLK_DIV 0x30
43#define JZ_REG_AIC_FIFO 0x34
44
45#define JZ_AIC_CONF_FIFO_RX_THRESHOLD_MASK (0xf << 12)
46#define JZ_AIC_CONF_FIFO_TX_THRESHOLD_MASK (0xf << 8)
47#define JZ_AIC_CONF_OVERFLOW_PLAY_LAST BIT(6)
48#define JZ_AIC_CONF_INTERNAL_CODEC BIT(5)
49#define JZ_AIC_CONF_I2S BIT(4)
50#define JZ_AIC_CONF_RESET BIT(3)
51#define JZ_AIC_CONF_BIT_CLK_MASTER BIT(2)
52#define JZ_AIC_CONF_SYNC_CLK_MASTER BIT(1)
53#define JZ_AIC_CONF_ENABLE BIT(0)
54
55#define JZ_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET 12
56#define JZ_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET 8
57
58#define JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE_MASK (0x7 << 19)
59#define JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_MASK (0x7 << 16)
60#define JZ_AIC_CTRL_ENABLE_RX_DMA BIT(15)
61#define JZ_AIC_CTRL_ENABLE_TX_DMA BIT(14)
62#define JZ_AIC_CTRL_MONO_TO_STEREO BIT(11)
63#define JZ_AIC_CTRL_SWITCH_ENDIANNESS BIT(10)
64#define JZ_AIC_CTRL_SIGNED_TO_UNSIGNED BIT(9)
65#define JZ_AIC_CTRL_FLUSH BIT(8)
66#define JZ_AIC_CTRL_ENABLE_ROR_INT BIT(6)
67#define JZ_AIC_CTRL_ENABLE_TUR_INT BIT(5)
68#define JZ_AIC_CTRL_ENABLE_RFS_INT BIT(4)
69#define JZ_AIC_CTRL_ENABLE_TFS_INT BIT(3)
70#define JZ_AIC_CTRL_ENABLE_LOOPBACK BIT(2)
71#define JZ_AIC_CTRL_ENABLE_PLAYBACK BIT(1)
72#define JZ_AIC_CTRL_ENABLE_CAPTURE BIT(0)
73
74#define JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE_OFFSET 19
75#define JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_OFFSET 16
76
77#define JZ_AIC_I2S_FMT_DISABLE_BIT_CLK BIT(12)
78#define JZ_AIC_I2S_FMT_ENABLE_SYS_CLK BIT(4)
79#define JZ_AIC_I2S_FMT_MSB BIT(0)
80
81#define JZ_AIC_I2S_STATUS_BUSY BIT(2)
82
83#define JZ_AIC_CLK_DIV_MASK 0xf
84
85struct jz4740_i2s {
86 struct resource *mem;
87 void __iomem *base;
88 dma_addr_t phys_base;
89
90 struct clk *clk_aic;
91 struct clk *clk_i2s;
92
93 struct jz4740_pcm_config pcm_config_playback;
94 struct jz4740_pcm_config pcm_config_capture;
95};
96
97static inline uint32_t jz4740_i2s_read(const struct jz4740_i2s *i2s,
98 unsigned int reg)
99{
100 return readl(i2s->base + reg);
101}
102
103static inline void jz4740_i2s_write(const struct jz4740_i2s *i2s,
104 unsigned int reg, uint32_t value)
105{
106 writel(value, i2s->base + reg);
107}
108
109static inline struct jz4740_i2s *jz4740_dai_to_i2s(struct snd_soc_dai *dai)
110{
111 return dai->private_data;
112}
113
114static int jz4740_i2s_startup(struct snd_pcm_substream *substream,
115 struct snd_soc_dai *dai)
116{
117 struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
118 uint32_t conf, ctrl;
119
120 if (dai->active)
121 return 0;
122
123 ctrl = jz4740_i2s_read(i2s, JZ_REG_AIC_CTRL);
124 ctrl |= JZ_AIC_CTRL_FLUSH;
125 jz4740_i2s_write(i2s, JZ_REG_AIC_CTRL, ctrl);
126
127 clk_enable(i2s->clk_i2s);
128
129 conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF);
130 conf |= JZ_AIC_CONF_ENABLE;
131 jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf);
132
133 return 0;
134}
135
136static void jz4740_i2s_shutdown(struct snd_pcm_substream *substream,
137 struct snd_soc_dai *dai)
138{
139 struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
140 uint32_t conf;
141
142 if (!dai->active)
143 return;
144
145 conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF);
146 conf &= ~JZ_AIC_CONF_ENABLE;
147 jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf);
148
149 clk_disable(i2s->clk_i2s);
150}
151
152static int jz4740_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
153 struct snd_soc_dai *dai)
154{
155 struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
156
157 uint32_t ctrl;
158 uint32_t mask;
159
160 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
161 mask = JZ_AIC_CTRL_ENABLE_PLAYBACK | JZ_AIC_CTRL_ENABLE_TX_DMA;
162 else
163 mask = JZ_AIC_CTRL_ENABLE_CAPTURE | JZ_AIC_CTRL_ENABLE_RX_DMA;
164
165 ctrl = jz4740_i2s_read(i2s, JZ_REG_AIC_CTRL);
166
167 switch (cmd) {
168 case SNDRV_PCM_TRIGGER_START:
169 case SNDRV_PCM_TRIGGER_RESUME:
170 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
171 ctrl |= mask;
172 break;
173 case SNDRV_PCM_TRIGGER_STOP:
174 case SNDRV_PCM_TRIGGER_SUSPEND:
175 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
176 ctrl &= ~mask;
177 break;
178 default:
179 return -EINVAL;
180 }
181
182 jz4740_i2s_write(i2s, JZ_REG_AIC_CTRL, ctrl);
183
184 return 0;
185}
186
187static int jz4740_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
188{
189 struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
190
191 uint32_t format = 0;
192 uint32_t conf;
193
194 conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF);
195
196 conf &= ~(JZ_AIC_CONF_BIT_CLK_MASTER | JZ_AIC_CONF_SYNC_CLK_MASTER);
197
198 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
199 case SND_SOC_DAIFMT_CBS_CFS:
200 conf |= JZ_AIC_CONF_BIT_CLK_MASTER | JZ_AIC_CONF_SYNC_CLK_MASTER;
201 format |= JZ_AIC_I2S_FMT_ENABLE_SYS_CLK;
202 break;
203 case SND_SOC_DAIFMT_CBM_CFS:
204 conf |= JZ_AIC_CONF_SYNC_CLK_MASTER;
205 break;
206 case SND_SOC_DAIFMT_CBS_CFM:
207 conf |= JZ_AIC_CONF_BIT_CLK_MASTER;
208 break;
209 case SND_SOC_DAIFMT_CBM_CFM:
210 break;
211 default:
212 return -EINVAL;
213 }
214
215 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
216 case SND_SOC_DAIFMT_MSB:
217 format |= JZ_AIC_I2S_FMT_MSB;
218 break;
219 case SND_SOC_DAIFMT_I2S:
220 break;
221 default:
222 return -EINVAL;
223 }
224
225 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
226 case SND_SOC_DAIFMT_NB_NF:
227 break;
228 default:
229 return -EINVAL;
230 }
231
232 jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf);
233 jz4740_i2s_write(i2s, JZ_REG_AIC_I2S_FMT, format);
234
235 return 0;
236}
237
238static int jz4740_i2s_hw_params(struct snd_pcm_substream *substream,
239 struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
240{
241 struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
242 enum jz4740_dma_width dma_width;
243 struct jz4740_pcm_config *pcm_config;
244 unsigned int sample_size;
245 uint32_t ctrl;
246
247 ctrl = jz4740_i2s_read(i2s, JZ_REG_AIC_CTRL);
248
249 switch (params_format(params)) {
250 case SNDRV_PCM_FORMAT_S8:
251 sample_size = 0;
252 dma_width = JZ4740_DMA_WIDTH_8BIT;
253 break;
254 case SNDRV_PCM_FORMAT_S16:
255 sample_size = 1;
256 dma_width = JZ4740_DMA_WIDTH_16BIT;
257 break;
258 default:
259 return -EINVAL;
260 }
261
262 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
263 ctrl &= ~JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE_MASK;
264 ctrl |= sample_size << JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE_OFFSET;
265 if (params_channels(params) == 1)
266 ctrl |= JZ_AIC_CTRL_MONO_TO_STEREO;
267 else
268 ctrl &= ~JZ_AIC_CTRL_MONO_TO_STEREO;
269
270 pcm_config = &i2s->pcm_config_playback;
271 pcm_config->dma_config.dst_width = dma_width;
272
273 } else {
274 ctrl &= ~JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_MASK;
275 ctrl |= sample_size << JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_OFFSET;
276
277 pcm_config = &i2s->pcm_config_capture;
278 pcm_config->dma_config.src_width = dma_width;
279 }
280
281 jz4740_i2s_write(i2s, JZ_REG_AIC_CTRL, ctrl);
282
283 snd_soc_dai_set_dma_data(dai, substream, pcm_config);
284
285 return 0;
286}
287
288static int jz4740_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id,
289 unsigned int freq, int dir)
290{
291 struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
292 struct clk *parent;
293 int ret = 0;
294
295 switch (clk_id) {
296 case JZ4740_I2S_CLKSRC_EXT:
297 parent = clk_get(NULL, "ext");
298 clk_set_parent(i2s->clk_i2s, parent);
299 break;
300 case JZ4740_I2S_CLKSRC_PLL:
301 parent = clk_get(NULL, "pll half");
302 clk_set_parent(i2s->clk_i2s, parent);
303 ret = clk_set_rate(i2s->clk_i2s, freq);
304 break;
305 default:
306 return -EINVAL;
307 }
308 clk_put(parent);
309
310 return ret;
311}
312
313static int jz4740_i2s_suspend(struct snd_soc_dai *dai)
314{
315 struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
316 uint32_t conf;
317
318 if (dai->active) {
319 conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF);
320 conf &= ~JZ_AIC_CONF_ENABLE;
321 jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf);
322
323 clk_disable(i2s->clk_i2s);
324 }
325
326 clk_disable(i2s->clk_aic);
327
328 return 0;
329}
330
331static int jz4740_i2s_resume(struct snd_soc_dai *dai)
332{
333 struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
334 uint32_t conf;
335
336 clk_enable(i2s->clk_aic);
337
338 if (dai->active) {
339 clk_enable(i2s->clk_i2s);
340
341 conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF);
342 conf |= JZ_AIC_CONF_ENABLE;
343 jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf);
344 }
345
346 return 0;
347}
348
349static int jz4740_i2s_probe(struct platform_device *pdev, struct snd_soc_dai *dai)
350{
351 struct jz4740_i2s *i2s = jz4740_dai_to_i2s(dai);
352 uint32_t conf;
353
354 conf = (7 << JZ_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET) |
355 (8 << JZ_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET) |
356 JZ_AIC_CONF_OVERFLOW_PLAY_LAST |
357 JZ_AIC_CONF_I2S |
358 JZ_AIC_CONF_INTERNAL_CODEC;
359
360 jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, JZ_AIC_CONF_RESET);
361 jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf);
362
363 return 0;
364}
365
366static struct snd_soc_dai_ops jz4740_i2s_dai_ops = {
367 .startup = jz4740_i2s_startup,
368 .shutdown = jz4740_i2s_shutdown,
369 .trigger = jz4740_i2s_trigger,
370 .hw_params = jz4740_i2s_hw_params,
371 .set_fmt = jz4740_i2s_set_fmt,
372 .set_sysclk = jz4740_i2s_set_sysclk,
373};
374
375#define JZ4740_I2S_FMTS (SNDRV_PCM_FMTBIT_S8 | \
376 SNDRV_PCM_FMTBIT_S16_LE)
377
378struct snd_soc_dai jz4740_i2s_dai = {
379 .name = "jz4740-i2s",
380 .probe = jz4740_i2s_probe,
381 .playback = {
382 .channels_min = 1,
383 .channels_max = 2,
384 .rates = SNDRV_PCM_RATE_8000_48000,
385 .formats = JZ4740_I2S_FMTS,
386 },
387 .capture = {
388 .channels_min = 2,
389 .channels_max = 2,
390 .rates = SNDRV_PCM_RATE_8000_48000,
391 .formats = JZ4740_I2S_FMTS,
392 },
393 .symmetric_rates = 1,
394 .ops = &jz4740_i2s_dai_ops,
395 .suspend = jz4740_i2s_suspend,
396 .resume = jz4740_i2s_resume,
397};
398EXPORT_SYMBOL_GPL(jz4740_i2s_dai);
399
400static void __devinit jz4740_i2c_init_pcm_config(struct jz4740_i2s *i2s)
401{
402 struct jz4740_dma_config *dma_config;
403
404 /* Playback */
405 dma_config = &i2s->pcm_config_playback.dma_config;
406 dma_config->src_width = JZ4740_DMA_WIDTH_32BIT,
407 dma_config->transfer_size = JZ4740_DMA_TRANSFER_SIZE_16BYTE;
408 dma_config->request_type = JZ4740_DMA_TYPE_AIC_TRANSMIT;
409 dma_config->flags = JZ4740_DMA_SRC_AUTOINC;
410 dma_config->mode = JZ4740_DMA_MODE_SINGLE;
411 i2s->pcm_config_playback.fifo_addr = i2s->phys_base + JZ_REG_AIC_FIFO;
412
413 /* Capture */
414 dma_config = &i2s->pcm_config_capture.dma_config;
415 dma_config->dst_width = JZ4740_DMA_WIDTH_32BIT,
416 dma_config->transfer_size = JZ4740_DMA_TRANSFER_SIZE_16BYTE;
417 dma_config->request_type = JZ4740_DMA_TYPE_AIC_RECEIVE;
418 dma_config->flags = JZ4740_DMA_DST_AUTOINC;
419 dma_config->mode = JZ4740_DMA_MODE_SINGLE;
420 i2s->pcm_config_capture.fifo_addr = i2s->phys_base + JZ_REG_AIC_FIFO;
421}
422
423static int __devinit jz4740_i2s_dev_probe(struct platform_device *pdev)
424{
425 struct jz4740_i2s *i2s;
426 int ret;
427
428 i2s = kzalloc(sizeof(*i2s), GFP_KERNEL);
429
430 if (!i2s)
431 return -ENOMEM;
432
433 i2s->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
434 if (!i2s->mem) {
435 ret = -ENOENT;
436 goto err_free;
437 }
438
439 i2s->mem = request_mem_region(i2s->mem->start, resource_size(i2s->mem),
440 pdev->name);
441 if (!i2s->mem) {
442 ret = -EBUSY;
443 goto err_free;
444 }
445
446 i2s->base = ioremap_nocache(i2s->mem->start, resource_size(i2s->mem));
447 if (!i2s->base) {
448 ret = -EBUSY;
449 goto err_release_mem_region;
450 }
451
452 i2s->phys_base = i2s->mem->start;
453
454 i2s->clk_aic = clk_get(&pdev->dev, "aic");
455 if (IS_ERR(i2s->clk_aic)) {
456 ret = PTR_ERR(i2s->clk_aic);
457 goto err_iounmap;
458 }
459
460 i2s->clk_i2s = clk_get(&pdev->dev, "i2s");
461 if (IS_ERR(i2s->clk_i2s)) {
462 ret = PTR_ERR(i2s->clk_i2s);
463 goto err_clk_put_aic;
464 }
465
466 clk_enable(i2s->clk_aic);
467
468 jz4740_i2c_init_pcm_config(i2s);
469
470 jz4740_i2s_dai.private_data = i2s;
471 ret = snd_soc_register_dai(&jz4740_i2s_dai);
472
473 if (ret) {
474 dev_err(&pdev->dev, "Failed to register DAI\n");
475 goto err_clk_put_i2s;
476 }
477
478 platform_set_drvdata(pdev, i2s);
479
480 return 0;
481
482err_clk_put_i2s:
483 clk_disable(i2s->clk_aic);
484 clk_put(i2s->clk_i2s);
485err_clk_put_aic:
486 clk_put(i2s->clk_aic);
487err_iounmap:
488 iounmap(i2s->base);
489err_release_mem_region:
490 release_mem_region(i2s->mem->start, resource_size(i2s->mem));
491err_free:
492 kfree(i2s);
493
494 return ret;
495}
496
497static int __devexit jz4740_i2s_dev_remove(struct platform_device *pdev)
498{
499 struct jz4740_i2s *i2s = platform_get_drvdata(pdev);
500
501 snd_soc_unregister_dai(&jz4740_i2s_dai);
502
503 clk_disable(i2s->clk_aic);
504 clk_put(i2s->clk_i2s);
505 clk_put(i2s->clk_aic);
506
507 iounmap(i2s->base);
508 release_mem_region(i2s->mem->start, resource_size(i2s->mem));
509
510 platform_set_drvdata(pdev, NULL);
511 kfree(i2s);
512
513 return 0;
514}
515
516static struct platform_driver jz4740_i2s_driver = {
517 .probe = jz4740_i2s_dev_probe,
518 .remove = __devexit_p(jz4740_i2s_dev_remove),
519 .driver = {
520 .name = "jz4740-i2s",
521 .owner = THIS_MODULE,
522 },
523};
524
525static int __init jz4740_i2s_init(void)
526{
527 return platform_driver_register(&jz4740_i2s_driver);
528}
529module_init(jz4740_i2s_init);
530
531static void __exit jz4740_i2s_exit(void)
532{
533 platform_driver_unregister(&jz4740_i2s_driver);
534}
535module_exit(jz4740_i2s_exit);
536
537MODULE_AUTHOR("Lars-Peter Clausen, <lars@metafoo.de>");
538MODULE_DESCRIPTION("Ingenic JZ4740 SoC I2S driver");
539MODULE_LICENSE("GPL");
540MODULE_ALIAS("platform:jz4740-i2s");
diff --git a/sound/soc/jz4740/jz4740-i2s.h b/sound/soc/jz4740/jz4740-i2s.h
new file mode 100644
index 000000000000..da22ed88a589
--- /dev/null
+++ b/sound/soc/jz4740/jz4740-i2s.h
@@ -0,0 +1,18 @@
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License version 2 as
4 * published by the Free Software Foundation.
5 */
6
7#ifndef _JZ4740_I2S_H
8#define _JZ4740_I2S_H
9
10/* I2S clock source */
11#define JZ4740_I2S_CLKSRC_EXT 0
12#define JZ4740_I2S_CLKSRC_PLL 1
13
14#define JZ4740_I2S_BIT_CLK 0
15
16extern struct snd_soc_dai jz4740_i2s_dai;
17
18#endif
diff --git a/sound/soc/jz4740/jz4740-pcm.c b/sound/soc/jz4740/jz4740-pcm.c
new file mode 100644
index 000000000000..ee68d850c8dd
--- /dev/null
+++ b/sound/soc/jz4740/jz4740-pcm.c
@@ -0,0 +1,373 @@
1/*
2 * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * You should have received a copy of the GNU General Public License along
10 * with this program; if not, write to the Free Software Foundation, Inc.,
11 * 675 Mass Ave, Cambridge, MA 02139, USA.
12 *
13 */
14
15#include <linux/init.h>
16#include <linux/interrupt.h>
17#include <linux/kernel.h>
18#include <linux/module.h>
19#include <linux/platform_device.h>
20#include <linux/slab.h>
21
22#include <linux/dma-mapping.h>
23
24#include <sound/core.h>
25#include <sound/pcm.h>
26#include <sound/pcm_params.h>
27#include <sound/soc.h>
28
29#include <asm/mach-jz4740/dma.h>
30#include "jz4740-pcm.h"
31
32struct jz4740_runtime_data {
33 unsigned long dma_period;
34 dma_addr_t dma_start;
35 dma_addr_t dma_pos;
36 dma_addr_t dma_end;
37
38 struct jz4740_dma_chan *dma;
39
40 dma_addr_t fifo_addr;
41};
42
43/* identify hardware playback capabilities */
44static const struct snd_pcm_hardware jz4740_pcm_hardware = {
45 .info = SNDRV_PCM_INFO_MMAP |
46 SNDRV_PCM_INFO_MMAP_VALID |
47 SNDRV_PCM_INFO_INTERLEAVED |
48 SNDRV_PCM_INFO_BLOCK_TRANSFER,
49 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8,
50
51 .rates = SNDRV_PCM_RATE_8000_48000,
52 .channels_min = 1,
53 .channels_max = 2,
54 .period_bytes_min = 16,
55 .period_bytes_max = 2 * PAGE_SIZE,
56 .periods_min = 2,
57 .periods_max = 128,
58 .buffer_bytes_max = 128 * 2 * PAGE_SIZE,
59 .fifo_size = 32,
60};
61
62static void jz4740_pcm_start_transfer(struct jz4740_runtime_data *prtd,
63 struct snd_pcm_substream *substream)
64{
65 unsigned long count;
66
67 if (prtd->dma_pos == prtd->dma_end)
68 prtd->dma_pos = prtd->dma_start;
69
70 if (prtd->dma_pos + prtd->dma_period > prtd->dma_end)
71 count = prtd->dma_end - prtd->dma_pos;
72 else
73 count = prtd->dma_period;
74
75 jz4740_dma_disable(prtd->dma);
76
77 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
78 jz4740_dma_set_src_addr(prtd->dma, prtd->dma_pos);
79 jz4740_dma_set_dst_addr(prtd->dma, prtd->fifo_addr);
80 } else {
81 jz4740_dma_set_src_addr(prtd->dma, prtd->fifo_addr);
82 jz4740_dma_set_dst_addr(prtd->dma, prtd->dma_pos);
83 }
84
85 jz4740_dma_set_transfer_count(prtd->dma, count);
86
87 prtd->dma_pos += count;
88
89 jz4740_dma_enable(prtd->dma);
90}
91
92static void jz4740_pcm_dma_transfer_done(struct jz4740_dma_chan *dma, int err,
93 void *dev_id)
94{
95 struct snd_pcm_substream *substream = dev_id;
96 struct snd_pcm_runtime *runtime = substream->runtime;
97 struct jz4740_runtime_data *prtd = runtime->private_data;
98
99 snd_pcm_period_elapsed(substream);
100
101 jz4740_pcm_start_transfer(prtd, substream);
102}
103
104static int jz4740_pcm_hw_params(struct snd_pcm_substream *substream,
105 struct snd_pcm_hw_params *params)
106{
107 struct snd_pcm_runtime *runtime = substream->runtime;
108 struct jz4740_runtime_data *prtd = runtime->private_data;
109 struct snd_soc_pcm_runtime *rtd = substream->private_data;
110 struct jz4740_pcm_config *config;
111
112 config = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
113
114 if (!config)
115 return 0;
116
117 if (!prtd->dma) {
118 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
119 prtd->dma = jz4740_dma_request(substream, "PCM Capture");
120 else
121 prtd->dma = jz4740_dma_request(substream, "PCM Playback");
122 }
123
124 if (!prtd->dma)
125 return -EBUSY;
126
127 jz4740_dma_configure(prtd->dma, &config->dma_config);
128 prtd->fifo_addr = config->fifo_addr;
129
130 jz4740_dma_set_complete_cb(prtd->dma, jz4740_pcm_dma_transfer_done);
131
132 snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
133 runtime->dma_bytes = params_buffer_bytes(params);
134
135 prtd->dma_period = params_period_bytes(params);
136 prtd->dma_start = runtime->dma_addr;
137 prtd->dma_pos = prtd->dma_start;
138 prtd->dma_end = prtd->dma_start + runtime->dma_bytes;
139
140 return 0;
141}
142
143static int jz4740_pcm_hw_free(struct snd_pcm_substream *substream)
144{
145 struct jz4740_runtime_data *prtd = substream->runtime->private_data;
146
147 snd_pcm_set_runtime_buffer(substream, NULL);
148 if (prtd->dma) {
149 jz4740_dma_free(prtd->dma);
150 prtd->dma = NULL;
151 }
152
153 return 0;
154}
155
156static int jz4740_pcm_prepare(struct snd_pcm_substream *substream)
157{
158 struct jz4740_runtime_data *prtd = substream->runtime->private_data;
159
160 if (!prtd->dma)
161 return -EBUSY;
162
163 prtd->dma_pos = prtd->dma_start;
164
165 return 0;
166}
167
168static int jz4740_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
169{
170 struct snd_pcm_runtime *runtime = substream->runtime;
171 struct jz4740_runtime_data *prtd = runtime->private_data;
172
173 switch (cmd) {
174 case SNDRV_PCM_TRIGGER_START:
175 case SNDRV_PCM_TRIGGER_RESUME:
176 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
177 jz4740_pcm_start_transfer(prtd, substream);
178 break;
179 case SNDRV_PCM_TRIGGER_STOP:
180 case SNDRV_PCM_TRIGGER_SUSPEND:
181 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
182 jz4740_dma_disable(prtd->dma);
183 break;
184 default:
185 break;
186 }
187
188 return 0;
189}
190
191static snd_pcm_uframes_t jz4740_pcm_pointer(struct snd_pcm_substream *substream)
192{
193 struct snd_pcm_runtime *runtime = substream->runtime;
194 struct jz4740_runtime_data *prtd = runtime->private_data;
195 unsigned long byte_offset;
196 snd_pcm_uframes_t offset;
197 struct jz4740_dma_chan *dma = prtd->dma;
198
199 /* prtd->dma_pos points to the end of the current transfer. So by
200 * subtracting prdt->dma_start we get the offset to the end of the
201 * current period in bytes. By subtracting the residue of the transfer
202 * we get the current offset in bytes. */
203 byte_offset = prtd->dma_pos - prtd->dma_start;
204 byte_offset -= jz4740_dma_get_residue(dma);
205
206 offset = bytes_to_frames(runtime, byte_offset);
207 if (offset >= runtime->buffer_size)
208 offset = 0;
209
210 return offset;
211}
212
213static int jz4740_pcm_open(struct snd_pcm_substream *substream)
214{
215 struct snd_pcm_runtime *runtime = substream->runtime;
216 struct jz4740_runtime_data *prtd;
217
218 prtd = kzalloc(sizeof(*prtd), GFP_KERNEL);
219 if (prtd == NULL)
220 return -ENOMEM;
221
222 snd_soc_set_runtime_hwparams(substream, &jz4740_pcm_hardware);
223
224 runtime->private_data = prtd;
225
226 return 0;
227}
228
229static int jz4740_pcm_close(struct snd_pcm_substream *substream)
230{
231 struct snd_pcm_runtime *runtime = substream->runtime;
232 struct jz4740_runtime_data *prtd = runtime->private_data;
233
234 kfree(prtd);
235
236 return 0;
237}
238
239static int jz4740_pcm_mmap(struct snd_pcm_substream *substream,
240 struct vm_area_struct *vma)
241{
242 return remap_pfn_range(vma, vma->vm_start,
243 substream->dma_buffer.addr >> PAGE_SHIFT,
244 vma->vm_end - vma->vm_start, vma->vm_page_prot);
245}
246
247static struct snd_pcm_ops jz4740_pcm_ops = {
248 .open = jz4740_pcm_open,
249 .close = jz4740_pcm_close,
250 .ioctl = snd_pcm_lib_ioctl,
251 .hw_params = jz4740_pcm_hw_params,
252 .hw_free = jz4740_pcm_hw_free,
253 .prepare = jz4740_pcm_prepare,
254 .trigger = jz4740_pcm_trigger,
255 .pointer = jz4740_pcm_pointer,
256 .mmap = jz4740_pcm_mmap,
257};
258
259static int jz4740_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
260{
261 struct snd_pcm_substream *substream = pcm->streams[stream].substream;
262 struct snd_dma_buffer *buf = &substream->dma_buffer;
263 size_t size = jz4740_pcm_hardware.buffer_bytes_max;
264
265 buf->dev.type = SNDRV_DMA_TYPE_DEV;
266 buf->dev.dev = pcm->card->dev;
267 buf->private_data = NULL;
268
269 buf->area = dma_alloc_noncoherent(pcm->card->dev, size,
270 &buf->addr, GFP_KERNEL);
271 if (!buf->area)
272 return -ENOMEM;
273
274 buf->bytes = size;
275
276 return 0;
277}
278
279static void jz4740_pcm_free(struct snd_pcm *pcm)
280{
281 struct snd_pcm_substream *substream;
282 struct snd_dma_buffer *buf;
283 int stream;
284
285 for (stream = 0; stream < SNDRV_PCM_STREAM_LAST; ++stream) {
286 substream = pcm->streams[stream].substream;
287 if (!substream)
288 continue;
289
290 buf = &substream->dma_buffer;
291 if (!buf->area)
292 continue;
293
294 dma_free_noncoherent(pcm->card->dev, buf->bytes, buf->area,
295 buf->addr);
296 buf->area = NULL;
297 }
298}
299
300static u64 jz4740_pcm_dmamask = DMA_BIT_MASK(32);
301
302int jz4740_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
303 struct snd_pcm *pcm)
304{
305 int ret = 0;
306
307 if (!card->dev->dma_mask)
308 card->dev->dma_mask = &jz4740_pcm_dmamask;
309
310 if (!card->dev->coherent_dma_mask)
311 card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
312
313 if (dai->playback.channels_min) {
314 ret = jz4740_pcm_preallocate_dma_buffer(pcm,
315 SNDRV_PCM_STREAM_PLAYBACK);
316 if (ret)
317 goto err;
318 }
319
320 if (dai->capture.channels_min) {
321 ret = jz4740_pcm_preallocate_dma_buffer(pcm,
322 SNDRV_PCM_STREAM_CAPTURE);
323 if (ret)
324 goto err;
325 }
326
327err:
328 return ret;
329}
330
331struct snd_soc_platform jz4740_soc_platform = {
332 .name = "jz4740-pcm",
333 .pcm_ops = &jz4740_pcm_ops,
334 .pcm_new = jz4740_pcm_new,
335 .pcm_free = jz4740_pcm_free,
336};
337EXPORT_SYMBOL_GPL(jz4740_soc_platform);
338
339static int __devinit jz4740_pcm_probe(struct platform_device *pdev)
340{
341 return snd_soc_register_platform(&jz4740_soc_platform);
342}
343
344static int __devexit jz4740_pcm_remove(struct platform_device *pdev)
345{
346 snd_soc_unregister_platform(&jz4740_soc_platform);
347 return 0;
348}
349
350static struct platform_driver jz4740_pcm_driver = {
351 .probe = jz4740_pcm_probe,
352 .remove = __devexit_p(jz4740_pcm_remove),
353 .driver = {
354 .name = "jz4740-pcm",
355 .owner = THIS_MODULE,
356 },
357};
358
359static int __init jz4740_soc_platform_init(void)
360{
361 return platform_driver_register(&jz4740_pcm_driver);
362}
363module_init(jz4740_soc_platform_init);
364
365static void __exit jz4740_soc_platform_exit(void)
366{
367 return platform_driver_unregister(&jz4740_pcm_driver);
368}
369module_exit(jz4740_soc_platform_exit);
370
371MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
372MODULE_DESCRIPTION("Ingenic SoC JZ4740 PCM driver");
373MODULE_LICENSE("GPL");
diff --git a/sound/soc/jz4740/jz4740-pcm.h b/sound/soc/jz4740/jz4740-pcm.h
new file mode 100644
index 000000000000..e3f221e2779c
--- /dev/null
+++ b/sound/soc/jz4740/jz4740-pcm.h
@@ -0,0 +1,22 @@
1/*
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 as
5 * published by the Free Software Foundation.
6 */
7
8#ifndef _JZ4740_PCM_H
9#define _JZ4740_PCM_H
10
11#include <linux/dma-mapping.h>
12#include <asm/mach-jz4740/dma.h>
13
14/* platform data */
15extern struct snd_soc_platform jz4740_soc_platform;
16
17struct jz4740_pcm_config {
18 struct jz4740_dma_config dma_config;
19 phys_addr_t fifo_addr;
20};
21
22#endif
diff --git a/sound/soc/jz4740/qi_lb60.c b/sound/soc/jz4740/qi_lb60.c
new file mode 100644
index 000000000000..f15f4918f15f
--- /dev/null
+++ b/sound/soc/jz4740/qi_lb60.c
@@ -0,0 +1,166 @@
1/*
2 * Copyright (C) 2009, Lars-Peter Clausen <lars@metafoo.de>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * You should have received a copy of the GNU General Public License along
9 * with this program; if not, write to the Free Software Foundation, Inc.,
10 * 675 Mass Ave, Cambridge, MA 02139, USA.
11 *
12 */
13
14#include <linux/module.h>
15#include <linux/moduleparam.h>
16#include <linux/timer.h>
17#include <linux/interrupt.h>
18#include <linux/platform_device.h>
19#include <sound/core.h>
20#include <sound/pcm.h>
21#include <sound/soc.h>
22#include <sound/soc-dapm.h>
23#include <linux/gpio.h>
24
25#include "../codecs/jz4740.h"
26#include "jz4740-pcm.h"
27#include "jz4740-i2s.h"
28
29
30#define QI_LB60_SND_GPIO JZ_GPIO_PORTB(29)
31#define QI_LB60_AMP_GPIO JZ_GPIO_PORTD(4)
32
33static int qi_lb60_spk_event(struct snd_soc_dapm_widget *widget,
34 struct snd_kcontrol *ctrl, int event)
35{
36 int on = 0;
37 if (event & SND_SOC_DAPM_POST_PMU)
38 on = 1;
39 else if (event & SND_SOC_DAPM_PRE_PMD)
40 on = 0;
41
42 gpio_set_value(QI_LB60_SND_GPIO, on);
43 gpio_set_value(QI_LB60_AMP_GPIO, on);
44
45 return 0;
46}
47
48static const struct snd_soc_dapm_widget qi_lb60_widgets[] = {
49 SND_SOC_DAPM_SPK("Speaker", qi_lb60_spk_event),
50 SND_SOC_DAPM_MIC("Mic", NULL),
51};
52
53static const struct snd_soc_dapm_route qi_lb60_routes[] = {
54 {"Mic", NULL, "MIC"},
55 {"Speaker", NULL, "LOUT"},
56 {"Speaker", NULL, "ROUT"},
57};
58
59#define QI_LB60_DAIFMT (SND_SOC_DAIFMT_I2S | \
60 SND_SOC_DAIFMT_NB_NF | \
61 SND_SOC_DAIFMT_CBM_CFM)
62
63static int qi_lb60_codec_init(struct snd_soc_codec *codec)
64{
65 int ret;
66 struct snd_soc_dai *cpu_dai = codec->socdev->card->dai_link->cpu_dai;
67
68 snd_soc_dapm_nc_pin(codec, "LIN");
69 snd_soc_dapm_nc_pin(codec, "RIN");
70
71 ret = snd_soc_dai_set_fmt(cpu_dai, QI_LB60_DAIFMT);
72 if (ret < 0) {
73 dev_err(codec->dev, "Failed to set cpu dai format: %d\n", ret);
74 return ret;
75 }
76
77 snd_soc_dapm_new_controls(codec, qi_lb60_widgets, ARRAY_SIZE(qi_lb60_widgets));
78 snd_soc_dapm_add_routes(codec, qi_lb60_routes, ARRAY_SIZE(qi_lb60_routes));
79 snd_soc_dapm_sync(codec);
80
81 return 0;
82}
83
84static struct snd_soc_dai_link qi_lb60_dai = {
85 .name = "jz4740",
86 .stream_name = "jz4740",
87 .cpu_dai = &jz4740_i2s_dai,
88 .codec_dai = &jz4740_codec_dai,
89 .init = qi_lb60_codec_init,
90};
91
92static struct snd_soc_card qi_lb60 = {
93 .name = "QI LB60",
94 .dai_link = &qi_lb60_dai,
95 .num_links = 1,
96 .platform = &jz4740_soc_platform,
97};
98
99static struct snd_soc_device qi_lb60_snd_devdata = {
100 .card = &qi_lb60,
101 .codec_dev = &soc_codec_dev_jz4740_codec,
102};
103
104static struct platform_device *qi_lb60_snd_device;
105
106static int __init qi_lb60_init(void)
107{
108 int ret;
109
110 qi_lb60_snd_device = platform_device_alloc("soc-audio", -1);
111
112 if (!qi_lb60_snd_device)
113 return -ENOMEM;
114
115 ret = gpio_request(QI_LB60_SND_GPIO, "SND");
116 if (ret) {
117 pr_err("qi_lb60 snd: Failed to request SND GPIO(%d): %d\n",
118 QI_LB60_SND_GPIO, ret);
119 goto err_device_put;
120 }
121
122 ret = gpio_request(QI_LB60_AMP_GPIO, "AMP");
123 if (ret) {
124 pr_err("qi_lb60 snd: Failed to request AMP GPIO(%d): %d\n",
125 QI_LB60_AMP_GPIO, ret);
126 goto err_gpio_free_snd;
127 }
128
129 gpio_direction_output(QI_LB60_SND_GPIO, 0);
130 gpio_direction_output(QI_LB60_AMP_GPIO, 0);
131
132 platform_set_drvdata(qi_lb60_snd_device, &qi_lb60_snd_devdata);
133 qi_lb60_snd_devdata.dev = &qi_lb60_snd_device->dev;
134
135 ret = platform_device_add(qi_lb60_snd_device);
136 if (ret) {
137 pr_err("qi_lb60 snd: Failed to add snd soc device: %d\n", ret);
138 goto err_unset_pdata;
139 }
140
141 return 0;
142
143err_unset_pdata:
144 platform_set_drvdata(qi_lb60_snd_device, NULL);
145/*err_gpio_free_amp:*/
146 gpio_free(QI_LB60_AMP_GPIO);
147err_gpio_free_snd:
148 gpio_free(QI_LB60_SND_GPIO);
149err_device_put:
150 platform_device_put(qi_lb60_snd_device);
151
152 return ret;
153}
154module_init(qi_lb60_init);
155
156static void __exit qi_lb60_exit(void)
157{
158 gpio_free(QI_LB60_AMP_GPIO);
159 gpio_free(QI_LB60_SND_GPIO);
160 platform_device_unregister(qi_lb60_snd_device);
161}
162module_exit(qi_lb60_exit);
163
164MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
165MODULE_DESCRIPTION("ALSA SoC QI LB60 Audio support");
166MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/kirkwood/Kconfig b/sound/soc/kirkwood/Kconfig
new file mode 100644
index 000000000000..16ec2a2dba4d
--- /dev/null
+++ b/sound/soc/kirkwood/Kconfig
@@ -0,0 +1,20 @@
1config SND_KIRKWOOD_SOC
2 tristate "SoC Audio for the Marvell Kirkwood chip"
3 depends on ARCH_KIRKWOOD
4 help
5 Say Y or M if you want to add support for codecs attached to
6 the Kirkwood I2S interface. You will also need to select the
7 audio interfaces to support below.
8
9config SND_KIRKWOOD_SOC_I2S
10 tristate
11
12config SND_KIRKWOOD_SOC_OPENRD
13 tristate "SoC Audio support for Kirkwood Openrd Client"
14 depends on SND_KIRKWOOD_SOC && MACH_OPENRD_CLIENT
15 select SND_KIRKWOOD_SOC_I2S
16 select SND_SOC_CS42L51
17 help
18 Say Y if you want to add support for SoC audio on
19 Openrd Client.
20
diff --git a/sound/soc/kirkwood/Makefile b/sound/soc/kirkwood/Makefile
new file mode 100644
index 000000000000..33a16dcab5b5
--- /dev/null
+++ b/sound/soc/kirkwood/Makefile
@@ -0,0 +1,9 @@
1snd-soc-kirkwood-objs := kirkwood-dma.o
2snd-soc-kirkwood-i2s-objs := kirkwood-i2s.o
3
4obj-$(CONFIG_SND_KIRKWOOD_SOC) += snd-soc-kirkwood.o
5obj-$(CONFIG_SND_KIRKWOOD_SOC_I2S) += snd-soc-kirkwood-i2s.o
6
7snd-soc-openrd-objs := kirkwood-openrd.o
8
9obj-$(CONFIG_SND_KIRKWOOD_SOC_OPENRD) += snd-soc-openrd.o
diff --git a/sound/soc/kirkwood/kirkwood-dma.c b/sound/soc/kirkwood/kirkwood-dma.c
new file mode 100644
index 000000000000..a30205be3e2b
--- /dev/null
+++ b/sound/soc/kirkwood/kirkwood-dma.c
@@ -0,0 +1,383 @@
1/*
2 * kirkwood-dma.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/device.h>
15#include <linux/io.h>
16#include <linux/slab.h>
17#include <linux/interrupt.h>
18#include <linux/dma-mapping.h>
19#include <linux/mbus.h>
20#include <sound/soc.h>
21#include "kirkwood-dma.h"
22#include "kirkwood.h"
23
24#define KIRKWOOD_RATES \
25 (SNDRV_PCM_RATE_44100 | \
26 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
27#define KIRKWOOD_FORMATS \
28 (SNDRV_PCM_FMTBIT_S16_LE | \
29 SNDRV_PCM_FMTBIT_S24_LE | \
30 SNDRV_PCM_FMTBIT_S32_LE)
31
32struct kirkwood_dma_priv {
33 struct snd_pcm_substream *play_stream;
34 struct snd_pcm_substream *rec_stream;
35 struct kirkwood_dma_data *data;
36};
37
38static struct snd_pcm_hardware kirkwood_dma_snd_hw = {
39 .info = (SNDRV_PCM_INFO_INTERLEAVED |
40 SNDRV_PCM_INFO_MMAP |
41 SNDRV_PCM_INFO_MMAP_VALID |
42 SNDRV_PCM_INFO_BLOCK_TRANSFER |
43 SNDRV_PCM_INFO_PAUSE),
44 .formats = KIRKWOOD_FORMATS,
45 .rates = KIRKWOOD_RATES,
46 .rate_min = 44100,
47 .rate_max = 96000,
48 .channels_min = 1,
49 .channels_max = 2,
50 .buffer_bytes_max = KIRKWOOD_SND_MAX_PERIOD_BYTES * KIRKWOOD_SND_MAX_PERIODS,
51 .period_bytes_min = KIRKWOOD_SND_MIN_PERIOD_BYTES,
52 .period_bytes_max = KIRKWOOD_SND_MAX_PERIOD_BYTES,
53 .periods_min = KIRKWOOD_SND_MIN_PERIODS,
54 .periods_max = KIRKWOOD_SND_MAX_PERIODS,
55 .fifo_size = 0,
56};
57
58static u64 kirkwood_dma_dmamask = 0xFFFFFFFFUL;
59
60static irqreturn_t kirkwood_dma_irq(int irq, void *dev_id)
61{
62 struct kirkwood_dma_priv *prdata = dev_id;
63 struct kirkwood_dma_data *priv = prdata->data;
64 unsigned long mask, status, cause;
65
66 mask = readl(priv->io + KIRKWOOD_INT_MASK);
67 status = readl(priv->io + KIRKWOOD_INT_CAUSE) & mask;
68
69 cause = readl(priv->io + KIRKWOOD_ERR_CAUSE);
70 if (unlikely(cause)) {
71 printk(KERN_WARNING "%s: got err interrupt 0x%lx\n",
72 __func__, cause);
73 writel(cause, priv->io + KIRKWOOD_ERR_CAUSE);
74 return IRQ_HANDLED;
75 }
76
77 /* we've enabled only bytes interrupts ... */
78 if (status & ~(KIRKWOOD_INT_CAUSE_PLAY_BYTES | \
79 KIRKWOOD_INT_CAUSE_REC_BYTES)) {
80 printk(KERN_WARNING "%s: unexpected interrupt %lx\n",
81 __func__, status);
82 return IRQ_NONE;
83 }
84
85 /* ack int */
86 writel(status, priv->io + KIRKWOOD_INT_CAUSE);
87
88 if (status & KIRKWOOD_INT_CAUSE_PLAY_BYTES)
89 snd_pcm_period_elapsed(prdata->play_stream);
90
91 if (status & KIRKWOOD_INT_CAUSE_REC_BYTES)
92 snd_pcm_period_elapsed(prdata->rec_stream);
93
94 return IRQ_HANDLED;
95}
96
97static void kirkwood_dma_conf_mbus_windows(void __iomem *base, int win,
98 unsigned long dma,
99 struct mbus_dram_target_info *dram)
100{
101 int i;
102
103 /* First disable and clear windows */
104 writel(0, base + KIRKWOOD_AUDIO_WIN_CTRL_REG(win));
105 writel(0, base + KIRKWOOD_AUDIO_WIN_BASE_REG(win));
106
107 /* try to find matching cs for current dma address */
108 for (i = 0; i < dram->num_cs; i++) {
109 struct mbus_dram_window *cs = dram->cs + i;
110 if ((cs->base & 0xffff0000) < (dma & 0xffff0000)) {
111 writel(cs->base & 0xffff0000,
112 base + KIRKWOOD_AUDIO_WIN_BASE_REG(win));
113 writel(((cs->size - 1) & 0xffff0000) |
114 (cs->mbus_attr << 8) |
115 (dram->mbus_dram_target_id << 4) | 1,
116 base + KIRKWOOD_AUDIO_WIN_CTRL_REG(win));
117 }
118 }
119}
120
121static int kirkwood_dma_open(struct snd_pcm_substream *substream)
122{
123 int err;
124 struct snd_pcm_runtime *runtime = substream->runtime;
125 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
126 struct snd_soc_dai *cpu_dai = soc_runtime->dai->cpu_dai;
127 struct kirkwood_dma_data *priv;
128 struct kirkwood_dma_priv *prdata = cpu_dai->private_data;
129 unsigned long addr;
130
131 priv = snd_soc_dai_get_dma_data(cpu_dai, substream);
132 snd_soc_set_runtime_hwparams(substream, &kirkwood_dma_snd_hw);
133
134 /* Ensure that all constraints linked to dma burst are fullfilled */
135 err = snd_pcm_hw_constraint_minmax(runtime,
136 SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
137 priv->burst * 2,
138 KIRKWOOD_AUDIO_BUF_MAX-1);
139 if (err < 0)
140 return err;
141
142 err = snd_pcm_hw_constraint_step(runtime, 0,
143 SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
144 priv->burst);
145 if (err < 0)
146 return err;
147
148 err = snd_pcm_hw_constraint_step(substream->runtime, 0,
149 SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
150 priv->burst);
151 if (err < 0)
152 return err;
153
154 if (soc_runtime->dai->cpu_dai->private_data == NULL) {
155 prdata = kzalloc(sizeof(struct kirkwood_dma_priv), GFP_KERNEL);
156 if (prdata == NULL)
157 return -ENOMEM;
158
159 prdata->data = priv;
160
161 err = request_irq(priv->irq, kirkwood_dma_irq, IRQF_SHARED,
162 "kirkwood-i2s", prdata);
163 if (err) {
164 kfree(prdata);
165 return -EBUSY;
166 }
167
168 soc_runtime->dai->cpu_dai->private_data = prdata;
169
170 /*
171 * Enable Error interrupts. We're only ack'ing them but
172 * it's usefull for diagnostics
173 */
174 writel((unsigned long)-1, priv->io + KIRKWOOD_ERR_MASK);
175 }
176
177 addr = virt_to_phys(substream->dma_buffer.area);
178 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
179 prdata->play_stream = substream;
180 kirkwood_dma_conf_mbus_windows(priv->io,
181 KIRKWOOD_PLAYBACK_WIN, addr, priv->dram);
182 } else {
183 prdata->rec_stream = substream;
184 kirkwood_dma_conf_mbus_windows(priv->io,
185 KIRKWOOD_RECORD_WIN, addr, priv->dram);
186 }
187
188 return 0;
189}
190
191static int kirkwood_dma_close(struct snd_pcm_substream *substream)
192{
193 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
194 struct snd_soc_dai *cpu_dai = soc_runtime->dai->cpu_dai;
195 struct kirkwood_dma_priv *prdata = cpu_dai->private_data;
196 struct kirkwood_dma_data *priv;
197
198 priv = snd_soc_dai_get_dma_data(cpu_dai, substream);
199
200 if (!prdata || !priv)
201 return 0;
202
203 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
204 prdata->play_stream = NULL;
205 else
206 prdata->rec_stream = NULL;
207
208 if (!prdata->play_stream && !prdata->rec_stream) {
209 writel(0, priv->io + KIRKWOOD_ERR_MASK);
210 free_irq(priv->irq, prdata);
211 kfree(prdata);
212 soc_runtime->dai->cpu_dai->private_data = NULL;
213 }
214
215 return 0;
216}
217
218static int kirkwood_dma_hw_params(struct snd_pcm_substream *substream,
219 struct snd_pcm_hw_params *params)
220{
221 struct snd_pcm_runtime *runtime = substream->runtime;
222
223 snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
224 runtime->dma_bytes = params_buffer_bytes(params);
225
226 return 0;
227}
228
229static int kirkwood_dma_hw_free(struct snd_pcm_substream *substream)
230{
231 snd_pcm_set_runtime_buffer(substream, NULL);
232 return 0;
233}
234
235static int kirkwood_dma_prepare(struct snd_pcm_substream *substream)
236{
237 struct snd_pcm_runtime *runtime = substream->runtime;
238 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
239 struct snd_soc_dai *cpu_dai = soc_runtime->dai->cpu_dai;
240 struct kirkwood_dma_data *priv;
241 unsigned long size, count;
242
243 priv = snd_soc_dai_get_dma_data(cpu_dai, substream);
244
245 /* compute buffer size in term of "words" as requested in specs */
246 size = frames_to_bytes(runtime, runtime->buffer_size);
247 size = (size>>2)-1;
248 count = snd_pcm_lib_period_bytes(substream);
249
250 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
251 writel(count, priv->io + KIRKWOOD_PLAY_BYTE_INT_COUNT);
252 writel(runtime->dma_addr, priv->io + KIRKWOOD_PLAY_BUF_ADDR);
253 writel(size, priv->io + KIRKWOOD_PLAY_BUF_SIZE);
254 } else {
255 writel(count, priv->io + KIRKWOOD_REC_BYTE_INT_COUNT);
256 writel(runtime->dma_addr, priv->io + KIRKWOOD_REC_BUF_ADDR);
257 writel(size, priv->io + KIRKWOOD_REC_BUF_SIZE);
258 }
259
260
261 return 0;
262}
263
264static snd_pcm_uframes_t kirkwood_dma_pointer(struct snd_pcm_substream
265 *substream)
266{
267 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
268 struct snd_soc_dai *cpu_dai = soc_runtime->dai->cpu_dai;
269 struct kirkwood_dma_data *priv;
270 snd_pcm_uframes_t count;
271
272 priv = snd_soc_dai_get_dma_data(cpu_dai, substream);
273
274 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
275 count = bytes_to_frames(substream->runtime,
276 readl(priv->io + KIRKWOOD_PLAY_BYTE_COUNT));
277 else
278 count = bytes_to_frames(substream->runtime,
279 readl(priv->io + KIRKWOOD_REC_BYTE_COUNT));
280
281 return count;
282}
283
284struct snd_pcm_ops kirkwood_dma_ops = {
285 .open = kirkwood_dma_open,
286 .close = kirkwood_dma_close,
287 .ioctl = snd_pcm_lib_ioctl,
288 .hw_params = kirkwood_dma_hw_params,
289 .hw_free = kirkwood_dma_hw_free,
290 .prepare = kirkwood_dma_prepare,
291 .pointer = kirkwood_dma_pointer,
292};
293
294static int kirkwood_dma_preallocate_dma_buffer(struct snd_pcm *pcm,
295 int stream)
296{
297 struct snd_pcm_substream *substream = pcm->streams[stream].substream;
298 struct snd_dma_buffer *buf = &substream->dma_buffer;
299 size_t size = kirkwood_dma_snd_hw.buffer_bytes_max;
300
301 buf->dev.type = SNDRV_DMA_TYPE_DEV;
302 buf->dev.dev = pcm->card->dev;
303 buf->area = dma_alloc_coherent(pcm->card->dev, size,
304 &buf->addr, GFP_KERNEL);
305 if (!buf->area)
306 return -ENOMEM;
307 buf->bytes = size;
308 buf->private_data = NULL;
309
310 return 0;
311}
312
313static int kirkwood_dma_new(struct snd_card *card,
314 struct snd_soc_dai *dai, struct snd_pcm *pcm)
315{
316 int ret;
317
318 if (!card->dev->dma_mask)
319 card->dev->dma_mask = &kirkwood_dma_dmamask;
320 if (!card->dev->coherent_dma_mask)
321 card->dev->coherent_dma_mask = 0xffffffff;
322
323 if (dai->playback.channels_min) {
324 ret = kirkwood_dma_preallocate_dma_buffer(pcm,
325 SNDRV_PCM_STREAM_PLAYBACK);
326 if (ret)
327 return ret;
328 }
329
330 if (dai->capture.channels_min) {
331 ret = kirkwood_dma_preallocate_dma_buffer(pcm,
332 SNDRV_PCM_STREAM_CAPTURE);
333 if (ret)
334 return ret;
335 }
336
337 return 0;
338}
339
340static void kirkwood_dma_free_dma_buffers(struct snd_pcm *pcm)
341{
342 struct snd_pcm_substream *substream;
343 struct snd_dma_buffer *buf;
344 int stream;
345
346 for (stream = 0; stream < 2; stream++) {
347 substream = pcm->streams[stream].substream;
348 if (!substream)
349 continue;
350 buf = &substream->dma_buffer;
351 if (!buf->area)
352 continue;
353
354 dma_free_coherent(pcm->card->dev, buf->bytes,
355 buf->area, buf->addr);
356 buf->area = NULL;
357 }
358}
359
360struct snd_soc_platform kirkwood_soc_platform = {
361 .name = "kirkwood-dma",
362 .pcm_ops = &kirkwood_dma_ops,
363 .pcm_new = kirkwood_dma_new,
364 .pcm_free = kirkwood_dma_free_dma_buffers,
365};
366EXPORT_SYMBOL_GPL(kirkwood_soc_platform);
367
368static int __init kirkwood_soc_platform_init(void)
369{
370 return snd_soc_register_platform(&kirkwood_soc_platform);
371}
372module_init(kirkwood_soc_platform_init);
373
374static void __exit kirkwood_soc_platform_exit(void)
375{
376 snd_soc_unregister_platform(&kirkwood_soc_platform);
377}
378module_exit(kirkwood_soc_platform_exit);
379
380MODULE_AUTHOR("Arnaud Patard <apatard@mandriva.com>");
381MODULE_DESCRIPTION("Marvell Kirkwood Audio DMA module");
382MODULE_LICENSE("GPL");
383
diff --git a/sound/soc/kirkwood/kirkwood-dma.h b/sound/soc/kirkwood/kirkwood-dma.h
new file mode 100644
index 000000000000..ba4454cd34f1
--- /dev/null
+++ b/sound/soc/kirkwood/kirkwood-dma.h
@@ -0,0 +1,17 @@
1/*
2 * kirkwood-dma.h
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#ifndef _KIRKWOOD_DMA_H
13#define _KIRKWOOD_DMA_H
14
15extern struct snd_soc_platform kirkwood_soc_platform;
16
17#endif
diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c
new file mode 100644
index 000000000000..981ffc2a13c8
--- /dev/null
+++ b/sound/soc/kirkwood/kirkwood-i2s.c
@@ -0,0 +1,495 @@
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
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{
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
77static 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
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{
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
171static 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
244static 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
315static 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
326static 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
362static void kirkwood_i2s_remove(struct platform_device *pdev,
363 struct snd_soc_dai *dai)
364{
365}
366
367static 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
374struct 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};
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;
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
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{
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
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,
475 .owner = THIS_MODULE,
476 },
477};
478
479static int __init kirkwood_i2s_init(void)
480{
481 return platform_driver_register(&kirkwood_i2s_driver);
482}
483module_init(kirkwood_i2s_init);
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 */
492MODULE_AUTHOR("Arnaud Patard, <apatard@mandriva.com>");
493MODULE_DESCRIPTION("Kirkwood I2S SoC Interface");
494MODULE_LICENSE("GPL");
495MODULE_ALIAS("platform:kirkwood-i2s");
diff --git a/sound/soc/kirkwood/kirkwood-i2s.h b/sound/soc/kirkwood/kirkwood-i2s.h
new file mode 100644
index 000000000000..c5595c616d7a
--- /dev/null
+++ b/sound/soc/kirkwood/kirkwood-i2s.h
@@ -0,0 +1,17 @@
1/*
2 * kirkwood-i2s.h
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#ifndef _KIRKWOOD_I2S_H
13#define _KIRKWOOD_I2S_H
14
15extern struct snd_soc_dai kirkwood_i2s_dai;
16
17#endif
diff --git a/sound/soc/kirkwood/kirkwood-openrd.c b/sound/soc/kirkwood/kirkwood-openrd.c
new file mode 100644
index 000000000000..0353d06bc41a
--- /dev/null
+++ b/sound/soc/kirkwood/kirkwood-openrd.c
@@ -0,0 +1,126 @@
1/*
2 * kirkwood-openrd.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/module.h>
13#include <linux/moduleparam.h>
14#include <linux/interrupt.h>
15#include <linux/platform_device.h>
16#include <linux/slab.h>
17#include <sound/soc.h>
18#include <mach/kirkwood.h>
19#include <plat/audio.h>
20#include <asm/mach-types.h>
21#include "kirkwood-i2s.h"
22#include "kirkwood-dma.h"
23#include "../codecs/cs42l51.h"
24
25static int openrd_client_hw_params(struct snd_pcm_substream *substream,
26 struct snd_pcm_hw_params *params)
27{
28 struct snd_soc_pcm_runtime *rtd = substream->private_data;
29 struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
30 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
31 int ret;
32 unsigned int freq, fmt;
33
34 fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS;
35 ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
36 if (ret < 0)
37 return ret;
38
39 ret = snd_soc_dai_set_fmt(codec_dai, fmt);
40 if (ret < 0)
41 return ret;
42
43 switch (params_rate(params)) {
44 default:
45 case 44100:
46 freq = 11289600;
47 break;
48 case 48000:
49 freq = 12288000;
50 break;
51 case 96000:
52 freq = 24576000;
53 break;
54 }
55
56 return snd_soc_dai_set_sysclk(codec_dai, 0, freq, SND_SOC_CLOCK_IN);
57
58}
59
60static struct snd_soc_ops openrd_client_ops = {
61 .hw_params = openrd_client_hw_params,
62};
63
64
65static struct snd_soc_dai_link openrd_client_dai[] = {
66{
67 .name = "CS42L51",
68 .stream_name = "CS42L51 HiFi",
69 .cpu_dai = &kirkwood_i2s_dai,
70 .codec_dai = &cs42l51_dai,
71 .ops = &openrd_client_ops,
72},
73};
74
75
76static struct snd_soc_card openrd_client = {
77 .name = "OpenRD Client",
78 .platform = &kirkwood_soc_platform,
79 .dai_link = openrd_client_dai,
80 .num_links = ARRAY_SIZE(openrd_client_dai),
81};
82
83static struct snd_soc_device openrd_client_snd_devdata = {
84 .card = &openrd_client,
85 .codec_dev = &soc_codec_device_cs42l51,
86};
87
88static struct platform_device *openrd_client_snd_device;
89
90static int __init openrd_client_init(void)
91{
92 int ret;
93
94 if (!machine_is_openrd_client())
95 return 0;
96
97 openrd_client_snd_device = platform_device_alloc("soc-audio", -1);
98 if (!openrd_client_snd_device)
99 return -ENOMEM;
100
101 platform_set_drvdata(openrd_client_snd_device,
102 &openrd_client_snd_devdata);
103 openrd_client_snd_devdata.dev = &openrd_client_snd_device->dev;
104
105 ret = platform_device_add(openrd_client_snd_device);
106 if (ret) {
107 printk(KERN_ERR "%s: platform_device_add failed\n", __func__);
108 platform_device_put(openrd_client_snd_device);
109 }
110
111 return ret;
112}
113
114static void __exit openrd_client_exit(void)
115{
116 platform_device_unregister(openrd_client_snd_device);
117}
118
119module_init(openrd_client_init);
120module_exit(openrd_client_exit);
121
122/* Module information */
123MODULE_AUTHOR("Arnaud Patard <apatard@mandriva.com>");
124MODULE_DESCRIPTION("ALSA SoC OpenRD Client");
125MODULE_LICENSE("GPL");
126MODULE_ALIAS("platform:soc-audio");
diff --git a/sound/soc/kirkwood/kirkwood.h b/sound/soc/kirkwood/kirkwood.h
new file mode 100644
index 000000000000..bb6e6a5648c9
--- /dev/null
+++ b/sound/soc/kirkwood/kirkwood.h
@@ -0,0 +1,129 @@
1/*
2 * kirkwood.h
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#ifndef _KIRKWOOD_AUDIO_H
13#define _KIRKWOOD_AUDIO_H
14
15#define KIRKWOOD_RECORD_WIN 0
16#define KIRKWOOD_PLAYBACK_WIN 1
17#define KIRKWOOD_MAX_AUDIO_WIN 2
18
19#define KIRKWOOD_AUDIO_WIN_BASE_REG(win) (0xA00 + ((win)<<3))
20#define KIRKWOOD_AUDIO_WIN_CTRL_REG(win) (0xA04 + ((win)<<3))
21
22
23#define KIRKWOOD_RECCTL 0x1000
24#define KIRKWOOD_RECCTL_SPDIF_EN (1<<11)
25#define KIRKWOOD_RECCTL_I2S_EN (1<<10)
26#define KIRKWOOD_RECCTL_PAUSE (1<<9)
27#define KIRKWOOD_RECCTL_MUTE (1<<8)
28#define KIRKWOOD_RECCTL_BURST_MASK (3<<5)
29#define KIRKWOOD_RECCTL_BURST_128 (2<<5)
30#define KIRKWOOD_RECCTL_BURST_32 (1<<5)
31#define KIRKWOOD_RECCTL_MONO (1<<4)
32#define KIRKWOOD_RECCTL_MONO_CHAN_RIGHT (1<<3)
33#define KIRKWOOD_RECCTL_MONO_CHAN_LEFT (0<<3)
34#define KIRKWOOD_RECCTL_SIZE_MASK (7<<0)
35#define KIRKWOOD_RECCTL_SIZE_16 (7<<0)
36#define KIRKWOOD_RECCTL_SIZE_16_C (3<<0)
37#define KIRKWOOD_RECCTL_SIZE_20 (2<<0)
38#define KIRKWOOD_RECCTL_SIZE_24 (1<<0)
39#define KIRKWOOD_RECCTL_SIZE_32 (0<<0)
40
41#define KIRKWOOD_REC_BUF_ADDR 0x1004
42#define KIRKWOOD_REC_BUF_SIZE 0x1008
43#define KIRKWOOD_REC_BYTE_COUNT 0x100C
44
45#define KIRKWOOD_PLAYCTL 0x1100
46#define KIRKWOOD_PLAYCTL_PLAY_BUSY (1<<16)
47#define KIRKWOOD_PLAYCTL_BURST_MASK (3<<11)
48#define KIRKWOOD_PLAYCTL_BURST_128 (2<<11)
49#define KIRKWOOD_PLAYCTL_BURST_32 (1<<11)
50#define KIRKWOOD_PLAYCTL_PAUSE (1<<9)
51#define KIRKWOOD_PLAYCTL_SPDIF_MUTE (1<<8)
52#define KIRKWOOD_PLAYCTL_MONO_MASK (3<<5)
53#define KIRKWOOD_PLAYCTL_MONO_BOTH (3<<5)
54#define KIRKWOOD_PLAYCTL_MONO_OFF (0<<5)
55#define KIRKWOOD_PLAYCTL_I2S_MUTE (1<<7)
56#define KIRKWOOD_PLAYCTL_SPDIF_EN (1<<4)
57#define KIRKWOOD_PLAYCTL_I2S_EN (1<<3)
58#define KIRKWOOD_PLAYCTL_SIZE_MASK (7<<0)
59#define KIRKWOOD_PLAYCTL_SIZE_16 (7<<0)
60#define KIRKWOOD_PLAYCTL_SIZE_16_C (3<<0)
61#define KIRKWOOD_PLAYCTL_SIZE_20 (2<<0)
62#define KIRKWOOD_PLAYCTL_SIZE_24 (1<<0)
63#define KIRKWOOD_PLAYCTL_SIZE_32 (0<<0)
64
65#define KIRKWOOD_PLAY_BUF_ADDR 0x1104
66#define KIRKWOOD_PLAY_BUF_SIZE 0x1108
67#define KIRKWOOD_PLAY_BYTE_COUNT 0x110C
68
69#define KIRKWOOD_DCO_CTL 0x1204
70#define KIRKWOOD_DCO_CTL_OFFSET_MASK (0xFFF<<2)
71#define KIRKWOOD_DCO_CTL_OFFSET_0 (0x800<<2)
72#define KIRKWOOD_DCO_CTL_FREQ_MASK (3<<0)
73#define KIRKWOOD_DCO_CTL_FREQ_11 (0<<0)
74#define KIRKWOOD_DCO_CTL_FREQ_12 (1<<0)
75#define KIRKWOOD_DCO_CTL_FREQ_24 (2<<0)
76
77#define KIRKWOOD_DCO_SPCR_STATUS 0x120c
78#define KIRKWOOD_DCO_SPCR_STATUS_DCO_LOCK (1<<16)
79
80#define KIRKWOOD_ERR_CAUSE 0x1300
81#define KIRKWOOD_ERR_MASK 0x1304
82
83#define KIRKWOOD_INT_CAUSE 0x1308
84#define KIRKWOOD_INT_MASK 0x130C
85#define KIRKWOOD_INT_CAUSE_PLAY_BYTES (1<<14)
86#define KIRKWOOD_INT_CAUSE_REC_BYTES (1<<13)
87#define KIRKWOOD_INT_CAUSE_DMA_PLAY_END (1<<7)
88#define KIRKWOOD_INT_CAUSE_DMA_PLAY_3Q (1<<6)
89#define KIRKWOOD_INT_CAUSE_DMA_PLAY_HALF (1<<5)
90#define KIRKWOOD_INT_CAUSE_DMA_PLAY_1Q (1<<4)
91#define KIRKWOOD_INT_CAUSE_DMA_REC_END (1<<3)
92#define KIRKWOOD_INT_CAUSE_DMA_REC_3Q (1<<2)
93#define KIRKWOOD_INT_CAUSE_DMA_REC_HALF (1<<1)
94#define KIRKWOOD_INT_CAUSE_DMA_REC_1Q (1<<0)
95
96#define KIRKWOOD_REC_BYTE_INT_COUNT 0x1310
97#define KIRKWOOD_PLAY_BYTE_INT_COUNT 0x1314
98#define KIRKWOOD_BYTE_INT_COUNT_MASK 0xffffff
99
100#define KIRKWOOD_I2S_PLAYCTL 0x2508
101#define KIRKWOOD_I2S_RECCTL 0x2408
102#define KIRKWOOD_I2S_CTL_JUST_MASK (0xf<<26)
103#define KIRKWOOD_I2S_CTL_LJ (0<<26)
104#define KIRKWOOD_I2S_CTL_I2S (5<<26)
105#define KIRKWOOD_I2S_CTL_RJ (8<<26)
106#define KIRKWOOD_I2S_CTL_SIZE_MASK (3<<30)
107#define KIRKWOOD_I2S_CTL_SIZE_16 (3<<30)
108#define KIRKWOOD_I2S_CTL_SIZE_20 (2<<30)
109#define KIRKWOOD_I2S_CTL_SIZE_24 (1<<30)
110#define KIRKWOOD_I2S_CTL_SIZE_32 (0<<30)
111
112#define KIRKWOOD_AUDIO_BUF_MAX (16*1024*1024)
113
114/* Theses values come from the marvell alsa driver */
115/* need to find where they come from */
116#define KIRKWOOD_SND_MIN_PERIODS 8
117#define KIRKWOOD_SND_MAX_PERIODS 16
118#define KIRKWOOD_SND_MIN_PERIOD_BYTES 0x4000
119#define KIRKWOOD_SND_MAX_PERIOD_BYTES 0x4000
120
121struct kirkwood_dma_data {
122 struct resource *mem;
123 void __iomem *io;
124 int irq;
125 int burst;
126 struct mbus_dram_target_info *dram;
127};
128
129#endif
diff --git a/sound/soc/nuc900/Kconfig b/sound/soc/nuc900/Kconfig
new file mode 100644
index 000000000000..a0ed1c618f60
--- /dev/null
+++ b/sound/soc/nuc900/Kconfig
@@ -0,0 +1,27 @@
1##
2## NUC900 series AC97 API
3##
4config SND_SOC_NUC900
5 tristate "SoC Audio for NUC900 series"
6 depends on ARCH_W90X900
7 help
8 This option enables support for AC97 mode on the NUC900 SoC.
9
10config SND_SOC_NUC900_AC97
11 tristate
12 select AC97_BUS
13 select SND_AC97_CODEC
14 select SND_SOC_AC97_BUS
15
16
17##
18## Boards
19##
20config SND_SOC_NUC900EVB
21 tristate "NUC900 AC97 support for demo board"
22 depends on SND_SOC_NUC900
23 select SND_SOC_NUC900_AC97
24 select SND_SOC_AC97_CODEC
25 help
26 Select this option to enable audio (AC97) on the
27 NUC900 demoboard.
diff --git a/sound/soc/nuc900/Makefile b/sound/soc/nuc900/Makefile
new file mode 100644
index 000000000000..7e46c7150316
--- /dev/null
+++ b/sound/soc/nuc900/Makefile
@@ -0,0 +1,11 @@
1# NUC900 series audio
2snd-soc-nuc900-pcm-objs := nuc900-pcm.o
3snd-soc-nuc900-ac97-objs := nuc900-ac97.o
4
5obj-$(CONFIG_SND_SOC_NUC900) += snd-soc-nuc900-pcm.o
6obj-$(CONFIG_SND_SOC_NUC900_AC97) += snd-soc-nuc900-ac97.o
7
8# Boards
9snd-soc-nuc900-audio-objs := nuc900-audio.o
10
11obj-$(CONFIG_SND_SOC_NUC900EVB) += snd-soc-nuc900-audio.o
diff --git a/sound/soc/nuc900/nuc900-ac97.c b/sound/soc/nuc900/nuc900-ac97.c
new file mode 100644
index 000000000000..caa7c901bc2e
--- /dev/null
+++ b/sound/soc/nuc900/nuc900-ac97.c
@@ -0,0 +1,430 @@
1/*
2 * Copyright (c) 2009-2010 Nuvoton technology corporation.
3 *
4 * Wan ZongShun <mcuos.com@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation;version 2 of the License.
9 *
10 */
11
12#include <linux/init.h>
13#include <linux/module.h>
14#include <linux/slab.h>
15#include <linux/device.h>
16#include <linux/delay.h>
17#include <linux/mutex.h>
18#include <linux/suspend.h>
19#include <sound/core.h>
20#include <sound/pcm.h>
21#include <sound/initval.h>
22#include <sound/soc.h>
23#include <linux/device.h>
24#include <linux/clk.h>
25
26#include <mach/mfp.h>
27
28#include "nuc900-audio.h"
29
30static DEFINE_MUTEX(ac97_mutex);
31struct nuc900_audio *nuc900_ac97_data;
32
33static int nuc900_checkready(void)
34{
35 struct nuc900_audio *nuc900_audio = nuc900_ac97_data;
36
37 if (!(AUDIO_READ(nuc900_audio->mmio + ACTL_ACIS0) & CODEC_READY))
38 return -EPERM;
39
40 return 0;
41}
42
43/* AC97 controller reads codec register */
44static unsigned short nuc900_ac97_read(struct snd_ac97 *ac97,
45 unsigned short reg)
46{
47 struct nuc900_audio *nuc900_audio = nuc900_ac97_data;
48 unsigned long timeout = 0x10000, val;
49
50 mutex_lock(&ac97_mutex);
51
52 val = nuc900_checkready();
53 if (!!val) {
54 dev_err(nuc900_audio->dev, "AC97 codec is not ready\n");
55 goto out;
56 }
57
58 /* set the R_WB bit and write register index */
59 AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS1, R_WB | reg);
60
61 /* set the valid frame bit and valid slots */
62 val = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0);
63 val |= (VALID_FRAME | SLOT1_VALID);
64 AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, val);
65
66 udelay(100);
67
68 /* polling the AC_R_FINISH */
69 while (!(AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON) & AC_R_FINISH)
70 && timeout--)
71 mdelay(1);
72
73 if (!timeout) {
74 dev_err(nuc900_audio->dev, "AC97 read register time out !\n");
75 val = -EPERM;
76 goto out;
77 }
78
79 val = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0) ;
80 val &= ~SLOT1_VALID;
81 AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, val);
82
83 if (AUDIO_READ(nuc900_audio->mmio + ACTL_ACIS1) >> 2 != reg) {
84 dev_err(nuc900_audio->dev,
85 "R_INDEX of REG_ACTL_ACIS1 not match!\n");
86 }
87
88 udelay(100);
89 val = (AUDIO_READ(nuc900_audio->mmio + ACTL_ACIS2) & 0xFFFF);
90
91out:
92 mutex_unlock(&ac97_mutex);
93 return val;
94}
95
96/* AC97 controller writes to codec register */
97static void nuc900_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
98 unsigned short val)
99{
100 struct nuc900_audio *nuc900_audio = nuc900_ac97_data;
101 unsigned long tmp, timeout = 0x10000;
102
103 mutex_lock(&ac97_mutex);
104
105 tmp = nuc900_checkready();
106 if (!!tmp)
107 dev_err(nuc900_audio->dev, "AC97 codec is not ready\n");
108
109 /* clear the R_WB bit and write register index */
110 AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS1, reg);
111
112 /* write register value */
113 AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS2, val);
114
115 /* set the valid frame bit and valid slots */
116 tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0);
117 tmp |= SLOT1_VALID | SLOT2_VALID | VALID_FRAME;
118 AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, tmp);
119
120 udelay(100);
121
122 /* polling the AC_W_FINISH */
123 while ((AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON) & AC_W_FINISH)
124 && timeout--)
125 mdelay(1);
126
127 if (!timeout)
128 dev_err(nuc900_audio->dev, "AC97 write register time out !\n");
129
130 tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0);
131 tmp &= ~(SLOT1_VALID | SLOT2_VALID);
132 AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, tmp);
133
134 mutex_unlock(&ac97_mutex);
135
136}
137
138static void nuc900_ac97_warm_reset(struct snd_ac97 *ac97)
139{
140 struct nuc900_audio *nuc900_audio = nuc900_ac97_data;
141 unsigned long val;
142
143 mutex_lock(&ac97_mutex);
144
145 /* warm reset AC 97 */
146 val = AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON);
147 val |= AC_W_RES;
148 AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACCON, val);
149
150 udelay(100);
151
152 val = nuc900_checkready();
153 if (!!val)
154 dev_err(nuc900_audio->dev, "AC97 codec is not ready\n");
155
156 mutex_unlock(&ac97_mutex);
157}
158
159static void nuc900_ac97_cold_reset(struct snd_ac97 *ac97)
160{
161 struct nuc900_audio *nuc900_audio = nuc900_ac97_data;
162 unsigned long val;
163
164 mutex_lock(&ac97_mutex);
165
166 /* reset Audio Controller */
167 val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET);
168 val |= ACTL_RESET_BIT;
169 AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val);
170
171 val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET);
172 val &= (~ACTL_RESET_BIT);
173 AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val);
174
175 /* reset AC-link interface */
176
177 val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET);
178 val |= AC_RESET;
179 AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val);
180
181 val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET);
182 val &= ~AC_RESET;
183 AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val);
184
185 /* cold reset AC 97 */
186 val = AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON);
187 val |= AC_C_RES;
188 AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACCON, val);
189
190 val = AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON);
191 val &= (~AC_C_RES);
192 AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACCON, val);
193
194 udelay(100);
195
196 mutex_unlock(&ac97_mutex);
197
198}
199
200/* AC97 controller operations */
201struct snd_ac97_bus_ops soc_ac97_ops = {
202 .read = nuc900_ac97_read,
203 .write = nuc900_ac97_write,
204 .reset = nuc900_ac97_cold_reset,
205 .warm_reset = nuc900_ac97_warm_reset,
206}
207EXPORT_SYMBOL_GPL(soc_ac97_ops);
208
209static int nuc900_ac97_trigger(struct snd_pcm_substream *substream,
210 int cmd, struct snd_soc_dai *dai)
211{
212 struct nuc900_audio *nuc900_audio = nuc900_ac97_data;
213 int ret;
214 unsigned long val, tmp;
215
216 ret = 0;
217
218 switch (cmd) {
219 case SNDRV_PCM_TRIGGER_START:
220 case SNDRV_PCM_TRIGGER_RESUME:
221 val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET);
222 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
223 tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0);
224 tmp |= (SLOT3_VALID | SLOT4_VALID | VALID_FRAME);
225 AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, tmp);
226
227 tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_PSR);
228 tmp |= (P_DMA_END_IRQ | P_DMA_MIDDLE_IRQ);
229 AUDIO_WRITE(nuc900_audio->mmio + ACTL_PSR, tmp);
230 val |= AC_PLAY;
231 } else {
232 tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_RSR);
233 tmp |= (R_DMA_END_IRQ | R_DMA_MIDDLE_IRQ);
234
235 AUDIO_WRITE(nuc900_audio->mmio + ACTL_RSR, tmp);
236 val |= AC_RECORD;
237 }
238
239 AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val);
240
241 break;
242 case SNDRV_PCM_TRIGGER_STOP:
243 case SNDRV_PCM_TRIGGER_SUSPEND:
244 val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET);
245 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
246 tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0);
247 tmp &= ~(SLOT3_VALID | SLOT4_VALID);
248 AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, tmp);
249
250 AUDIO_WRITE(nuc900_audio->mmio + ACTL_PSR, RESET_PRSR);
251 val &= ~AC_PLAY;
252 } else {
253 AUDIO_WRITE(nuc900_audio->mmio + ACTL_RSR, RESET_PRSR);
254 val &= ~AC_RECORD;
255 }
256
257 AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val);
258
259 break;
260 default:
261 ret = -EINVAL;
262 }
263
264 return ret;
265}
266
267static int nuc900_ac97_probe(struct platform_device *pdev,
268 struct snd_soc_dai *dai)
269{
270 struct nuc900_audio *nuc900_audio = nuc900_ac97_data;
271 unsigned long val;
272
273 mutex_lock(&ac97_mutex);
274
275 /* enable unit clock */
276 clk_enable(nuc900_audio->clk);
277
278 /* enable audio controller and AC-link interface */
279 val = AUDIO_READ(nuc900_audio->mmio + ACTL_CON);
280 val |= (IIS_AC_PIN_SEL | ACLINK_EN);
281 AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val);
282
283 mutex_unlock(&ac97_mutex);
284
285 return 0;
286}
287
288static void nuc900_ac97_remove(struct platform_device *pdev,
289 struct snd_soc_dai *dai)
290{
291 struct nuc900_audio *nuc900_audio = nuc900_ac97_data;
292
293 clk_disable(nuc900_audio->clk);
294}
295
296static struct snd_soc_dai_ops nuc900_ac97_dai_ops = {
297 .trigger = nuc900_ac97_trigger,
298};
299
300struct snd_soc_dai nuc900_ac97_dai = {
301 .name = "nuc900-ac97",
302 .probe = nuc900_ac97_probe,
303 .remove = nuc900_ac97_remove,
304 .ac97_control = 1,
305 .playback = {
306 .rates = SNDRV_PCM_RATE_8000_48000,
307 .formats = SNDRV_PCM_FMTBIT_S16_LE,
308 .channels_min = 1,
309 .channels_max = 2,
310 },
311 .capture = {
312 .rates = SNDRV_PCM_RATE_8000_48000,
313 .formats = SNDRV_PCM_FMTBIT_S16_LE,
314 .channels_min = 1,
315 .channels_max = 2,
316 },
317 .ops = &nuc900_ac97_dai_ops,
318}
319EXPORT_SYMBOL_GPL(nuc900_ac97_dai);
320
321static int __devinit nuc900_ac97_drvprobe(struct platform_device *pdev)
322{
323 struct nuc900_audio *nuc900_audio;
324 int ret;
325
326 if (nuc900_ac97_data)
327 return -EBUSY;
328
329 nuc900_audio = kzalloc(sizeof(struct nuc900_audio), GFP_KERNEL);
330 if (!nuc900_audio)
331 return -ENOMEM;
332
333 spin_lock_init(&nuc900_audio->lock);
334
335 nuc900_audio->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
336 if (!nuc900_audio->res) {
337 ret = -ENODEV;
338 goto out0;
339 }
340
341 if (!request_mem_region(nuc900_audio->res->start,
342 resource_size(nuc900_audio->res), pdev->name)) {
343 ret = -EBUSY;
344 goto out0;
345 }
346
347 nuc900_audio->mmio = ioremap(nuc900_audio->res->start,
348 resource_size(nuc900_audio->res));
349 if (!nuc900_audio->mmio) {
350 ret = -ENOMEM;
351 goto out1;
352 }
353
354 nuc900_audio->clk = clk_get(&pdev->dev, NULL);
355 if (IS_ERR(nuc900_audio->clk)) {
356 ret = PTR_ERR(nuc900_audio->clk);
357 goto out2;
358 }
359
360 nuc900_audio->irq_num = platform_get_irq(pdev, 0);
361 if (!nuc900_audio->irq_num) {
362 ret = -EBUSY;
363 goto out2;
364 }
365
366 nuc900_ac97_data = nuc900_audio;
367
368 nuc900_audio->dev = nuc900_ac97_dai.dev = &pdev->dev;
369
370 ret = snd_soc_register_dai(&nuc900_ac97_dai);
371 if (ret)
372 goto out3;
373
374 mfp_set_groupg(nuc900_audio->dev); /* enbale ac97 multifunction pin*/
375
376 return 0;
377
378out3:
379 clk_put(nuc900_audio->clk);
380out2:
381 iounmap(nuc900_audio->mmio);
382out1:
383 release_mem_region(nuc900_audio->res->start,
384 resource_size(nuc900_audio->res));
385out0:
386 kfree(nuc900_audio);
387 return ret;
388}
389
390static int __devexit nuc900_ac97_drvremove(struct platform_device *pdev)
391{
392
393 snd_soc_unregister_dai(&nuc900_ac97_dai);
394
395 clk_put(nuc900_ac97_data->clk);
396 iounmap(nuc900_ac97_data->mmio);
397 release_mem_region(nuc900_ac97_data->res->start,
398 resource_size(nuc900_ac97_data->res));
399
400 nuc900_ac97_data = NULL;
401
402 return 0;
403}
404
405static struct platform_driver nuc900_ac97_driver = {
406 .driver = {
407 .name = "nuc900-audio",
408 .owner = THIS_MODULE,
409 },
410 .probe = nuc900_ac97_drvprobe,
411 .remove = __devexit_p(nuc900_ac97_drvremove),
412};
413
414static int __init nuc900_ac97_init(void)
415{
416 return platform_driver_register(&nuc900_ac97_driver);
417}
418
419static void __exit nuc900_ac97_exit(void)
420{
421 platform_driver_unregister(&nuc900_ac97_driver);
422}
423
424module_init(nuc900_ac97_init);
425module_exit(nuc900_ac97_exit);
426
427MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>");
428MODULE_DESCRIPTION("NUC900 AC97 SoC driver!");
429MODULE_LICENSE("GPL");
430MODULE_ALIAS("platform:nuc900-ac97");
diff --git a/sound/soc/nuc900/nuc900-audio.c b/sound/soc/nuc900/nuc900-audio.c
new file mode 100644
index 000000000000..72e6f518f7b2
--- /dev/null
+++ b/sound/soc/nuc900/nuc900-audio.c
@@ -0,0 +1,81 @@
1/*
2 * Copyright (c) 2010 Nuvoton technology corporation.
3 *
4 * Wan ZongShun <mcuos.com@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation;version 2 of the License.
9 *
10 */
11
12#include <linux/module.h>
13#include <linux/moduleparam.h>
14#include <linux/timer.h>
15#include <linux/interrupt.h>
16#include <linux/platform_device.h>
17
18#include <sound/core.h>
19#include <sound/pcm.h>
20#include <sound/soc.h>
21#include <sound/soc-dapm.h>
22
23#include "../codecs/ac97.h"
24#include "nuc900-audio.h"
25
26static struct snd_soc_dai_link nuc900evb_ac97_dai = {
27 .name = "AC97",
28 .stream_name = "AC97 HiFi",
29 .cpu_dai = &nuc900_ac97_dai,
30 .codec_dai = &ac97_dai,
31};
32
33static struct snd_soc_card nuc900evb_audio_machine = {
34 .name = "NUC900EVB_AC97",
35 .dai_link = &nuc900evb_ac97_dai,
36 .num_links = 1,
37 .platform = &nuc900_soc_platform,
38};
39
40static struct snd_soc_device nuc900evb_ac97_devdata = {
41 .card = &nuc900evb_audio_machine,
42 .codec_dev = &soc_codec_dev_ac97,
43};
44
45static struct platform_device *nuc900evb_asoc_dev;
46
47static int __init nuc900evb_audio_init(void)
48{
49 int ret;
50
51 ret = -ENOMEM;
52 nuc900evb_asoc_dev = platform_device_alloc("soc-audio", -1);
53 if (!nuc900evb_asoc_dev)
54 goto out;
55
56 /* nuc900 board audio device */
57 platform_set_drvdata(nuc900evb_asoc_dev, &nuc900evb_ac97_devdata);
58
59 nuc900evb_ac97_devdata.dev = &nuc900evb_asoc_dev->dev;
60 ret = platform_device_add(nuc900evb_asoc_dev);
61
62 if (ret) {
63 platform_device_put(nuc900evb_asoc_dev);
64 nuc900evb_asoc_dev = NULL;
65 }
66
67out:
68 return ret;
69}
70
71static void __exit nuc900evb_audio_exit(void)
72{
73 platform_device_unregister(nuc900evb_asoc_dev);
74}
75
76module_init(nuc900evb_audio_init);
77module_exit(nuc900evb_audio_exit);
78
79MODULE_LICENSE("GPL");
80MODULE_DESCRIPTION("NUC900 Series ASoC audio support");
81MODULE_AUTHOR("Wan ZongShun");
diff --git a/sound/soc/nuc900/nuc900-audio.h b/sound/soc/nuc900/nuc900-audio.h
new file mode 100644
index 000000000000..3038f519729f
--- /dev/null
+++ b/sound/soc/nuc900/nuc900-audio.h
@@ -0,0 +1,117 @@
1/*
2 * Copyright (c) 2010 Nuvoton technology corporation.
3 *
4 * Wan ZongShun <mcuos.com@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation;version 2 of the License.
9 *
10 */
11
12#ifndef _NUC900_AUDIO_H
13#define _NUC900_AUDIO_H
14
15#include <linux/io.h>
16
17/* Audio Control Registers */
18#define ACTL_CON 0x00
19#define ACTL_RESET 0x04
20#define ACTL_RDSTB 0x08
21#define ACTL_RDST_LENGTH 0x0C
22#define ACTL_RDSTC 0x10
23#define ACTL_RSR 0x14
24#define ACTL_PDSTB 0x18
25#define ACTL_PDST_LENGTH 0x1C
26#define ACTL_PDSTC 0x20
27#define ACTL_PSR 0x24
28#define ACTL_IISCON 0x28
29#define ACTL_ACCON 0x2C
30#define ACTL_ACOS0 0x30
31#define ACTL_ACOS1 0x34
32#define ACTL_ACOS2 0x38
33#define ACTL_ACIS0 0x3C
34#define ACTL_ACIS1 0x40
35#define ACTL_ACIS2 0x44
36#define ACTL_COUNTER 0x48
37
38/* bit definition of REG_ACTL_CON register */
39#define R_DMA_IRQ 0x1000
40#define T_DMA_IRQ 0x0800
41#define IIS_AC_PIN_SEL 0x0100
42#define FIFO_TH 0x0080
43#define ADC_EN 0x0010
44#define M80_EN 0x0008
45#define ACLINK_EN 0x0004
46#define IIS_EN 0x0002
47
48/* bit definition of REG_ACTL_RESET register */
49#define W5691_PLAY 0x20000
50#define ACTL_RESET_BIT 0x10000
51#define RECORD_RIGHT_CHNNEL 0x08000
52#define RECORD_LEFT_CHNNEL 0x04000
53#define PLAY_RIGHT_CHNNEL 0x02000
54#define PLAY_LEFT_CHNNEL 0x01000
55#define DAC_PLAY 0x00800
56#define ADC_RECORD 0x00400
57#define M80_PLAY 0x00200
58#define AC_RECORD 0x00100
59#define AC_PLAY 0x00080
60#define IIS_RECORD 0x00040
61#define IIS_PLAY 0x00020
62#define DAC_RESET 0x00010
63#define ADC_RESET 0x00008
64#define M80_RESET 0x00004
65#define AC_RESET 0x00002
66#define IIS_RESET 0x00001
67
68/* bit definition of REG_ACTL_ACCON register */
69#define AC_BCLK_PU_EN 0x20
70#define AC_R_FINISH 0x10
71#define AC_W_FINISH 0x08
72#define AC_W_RES 0x04
73#define AC_C_RES 0x02
74
75/* bit definition of ACTL_RSR register */
76#define R_FIFO_EMPTY 0x04
77#define R_DMA_END_IRQ 0x02
78#define R_DMA_MIDDLE_IRQ 0x01
79
80/* bit definition of ACTL_PSR register */
81#define P_FIFO_EMPTY 0x04
82#define P_DMA_END_IRQ 0x02
83#define P_DMA_MIDDLE_IRQ 0x01
84
85/* bit definition of ACTL_ACOS0 register */
86#define SLOT1_VALID 0x01
87#define SLOT2_VALID 0x02
88#define SLOT3_VALID 0x04
89#define SLOT4_VALID 0x08
90#define VALID_FRAME 0x10
91
92/* bit definition of ACTL_ACOS1 register */
93#define R_WB 0x80
94
95#define CODEC_READY 0x10
96#define RESET_PRSR 0x00
97#define AUDIO_WRITE(addr, val) __raw_writel(val, addr)
98#define AUDIO_READ(addr) __raw_readl(addr)
99
100struct nuc900_audio {
101 void __iomem *mmio;
102 spinlock_t lock;
103 dma_addr_t dma_addr[2];
104 unsigned long buffersize[2];
105 unsigned long irq_num;
106 struct snd_pcm_substream *substream;
107 struct resource *res;
108 struct clk *clk;
109 struct device *dev;
110
111};
112
113extern struct nuc900_audio *nuc900_ac97_data;
114extern struct snd_soc_dai nuc900_ac97_dai;
115extern struct snd_soc_platform nuc900_soc_platform;
116
117#endif /*end _NUC900_AUDIO_H */
diff --git a/sound/soc/nuc900/nuc900-pcm.c b/sound/soc/nuc900/nuc900-pcm.c
new file mode 100644
index 000000000000..e81e803b3a63
--- /dev/null
+++ b/sound/soc/nuc900/nuc900-pcm.c
@@ -0,0 +1,354 @@
1/*
2 * Copyright (c) 2010 Nuvoton technology corporation.
3 *
4 * Wan ZongShun <mcuos.com@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation;version 2 of the License.
9 *
10 */
11
12#include <linux/module.h>
13#include <linux/init.h>
14#include <linux/io.h>
15#include <linux/platform_device.h>
16#include <linux/slab.h>
17#include <linux/dma-mapping.h>
18
19#include <sound/core.h>
20#include <sound/pcm.h>
21#include <sound/pcm_params.h>
22#include <sound/soc.h>
23
24#include <mach/hardware.h>
25
26#include "nuc900-audio.h"
27
28static const struct snd_pcm_hardware nuc900_pcm_hardware = {
29 .info = SNDRV_PCM_INFO_INTERLEAVED |
30 SNDRV_PCM_INFO_BLOCK_TRANSFER |
31 SNDRV_PCM_INFO_MMAP |
32 SNDRV_PCM_INFO_MMAP_VALID |
33 SNDRV_PCM_INFO_PAUSE |
34 SNDRV_PCM_INFO_RESUME,
35 .formats = SNDRV_PCM_FMTBIT_S16_LE,
36 .channels_min = 1,
37 .channels_max = 2,
38 .buffer_bytes_max = 4*1024,
39 .period_bytes_min = 1*1024,
40 .period_bytes_max = 4*1024,
41 .periods_min = 1,
42 .periods_max = 1024,
43};
44
45static int nuc900_dma_hw_params(struct snd_pcm_substream *substream,
46 struct snd_pcm_hw_params *params)
47{
48 struct snd_pcm_runtime *runtime = substream->runtime;
49 struct nuc900_audio *nuc900_audio = runtime->private_data;
50 unsigned long flags;
51 int ret = 0;
52
53 spin_lock_irqsave(&nuc900_audio->lock, flags);
54
55 ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
56 if (ret < 0)
57 return ret;
58
59 nuc900_audio->substream = substream;
60 nuc900_audio->dma_addr[substream->stream] = runtime->dma_addr;
61 nuc900_audio->buffersize[substream->stream] =
62 params_buffer_bytes(params);
63
64 spin_unlock_irqrestore(&nuc900_audio->lock, flags);
65
66 return ret;
67}
68
69static void nuc900_update_dma_register(struct snd_pcm_substream *substream,
70 dma_addr_t dma_addr, size_t count)
71{
72 struct snd_pcm_runtime *runtime = substream->runtime;
73 struct nuc900_audio *nuc900_audio = runtime->private_data;
74 void __iomem *mmio_addr, *mmio_len;
75
76 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
77 mmio_addr = nuc900_audio->mmio + ACTL_PDSTB;
78 mmio_len = nuc900_audio->mmio + ACTL_PDST_LENGTH;
79 } else {
80 mmio_addr = nuc900_audio->mmio + ACTL_RDSTB;
81 mmio_len = nuc900_audio->mmio + ACTL_RDST_LENGTH;
82 }
83
84 AUDIO_WRITE(mmio_addr, dma_addr);
85 AUDIO_WRITE(mmio_len, count);
86}
87
88static void nuc900_dma_start(struct snd_pcm_substream *substream)
89{
90 struct snd_pcm_runtime *runtime = substream->runtime;
91 struct nuc900_audio *nuc900_audio = runtime->private_data;
92 unsigned long val;
93
94 val = AUDIO_READ(nuc900_audio->mmio + ACTL_CON);
95 val |= (T_DMA_IRQ | R_DMA_IRQ);
96 AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val);
97}
98
99static void nuc900_dma_stop(struct snd_pcm_substream *substream)
100{
101 struct snd_pcm_runtime *runtime = substream->runtime;
102 struct nuc900_audio *nuc900_audio = runtime->private_data;
103 unsigned long val;
104
105 val = AUDIO_READ(nuc900_audio->mmio + ACTL_CON);
106 val &= ~(T_DMA_IRQ | R_DMA_IRQ);
107 AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val);
108}
109
110static irqreturn_t nuc900_dma_interrupt(int irq, void *dev_id)
111{
112 struct snd_pcm_substream *substream = dev_id;
113 struct nuc900_audio *nuc900_audio = substream->runtime->private_data;
114 unsigned long val;
115
116 spin_lock(&nuc900_audio->lock);
117
118 val = AUDIO_READ(nuc900_audio->mmio + ACTL_CON);
119
120 if (val & R_DMA_IRQ) {
121 AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val | R_DMA_IRQ);
122
123 val = AUDIO_READ(nuc900_audio->mmio + ACTL_RSR);
124
125 if (val & R_DMA_MIDDLE_IRQ) {
126 val |= R_DMA_MIDDLE_IRQ;
127 AUDIO_WRITE(nuc900_audio->mmio + ACTL_RSR, val);
128 }
129
130 if (val & R_DMA_END_IRQ) {
131 val |= R_DMA_END_IRQ;
132 AUDIO_WRITE(nuc900_audio->mmio + ACTL_RSR, val);
133 }
134 } else if (val & T_DMA_IRQ) {
135 AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val | T_DMA_IRQ);
136
137 val = AUDIO_READ(nuc900_audio->mmio + ACTL_PSR);
138
139 if (val & P_DMA_MIDDLE_IRQ) {
140 val |= P_DMA_MIDDLE_IRQ;
141 AUDIO_WRITE(nuc900_audio->mmio + ACTL_PSR, val);
142 }
143
144 if (val & P_DMA_END_IRQ) {
145 val |= P_DMA_END_IRQ;
146 AUDIO_WRITE(nuc900_audio->mmio + ACTL_PSR, val);
147 }
148 } else {
149 dev_err(nuc900_audio->dev, "Wrong DMA interrupt status!\n");
150 spin_unlock(&nuc900_audio->lock);
151 return IRQ_HANDLED;
152 }
153
154 spin_unlock(&nuc900_audio->lock);
155
156 snd_pcm_period_elapsed(substream);
157
158 return IRQ_HANDLED;
159}
160
161static int nuc900_dma_hw_free(struct snd_pcm_substream *substream)
162{
163 snd_pcm_lib_free_pages(substream);
164 return 0;
165}
166
167static int nuc900_dma_prepare(struct snd_pcm_substream *substream)
168{
169 struct snd_pcm_runtime *runtime = substream->runtime;
170 struct nuc900_audio *nuc900_audio = runtime->private_data;
171 unsigned long flags, val;
172
173 spin_lock_irqsave(&nuc900_audio->lock, flags);
174
175 nuc900_update_dma_register(substream,
176 nuc900_audio->dma_addr[substream->stream],
177 nuc900_audio->buffersize[substream->stream]);
178
179 val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET);
180
181 switch (runtime->channels) {
182 case 1:
183 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
184 val &= ~(PLAY_LEFT_CHNNEL | PLAY_RIGHT_CHNNEL);
185 val |= PLAY_RIGHT_CHNNEL;
186 } else {
187 val &= ~(RECORD_LEFT_CHNNEL | RECORD_RIGHT_CHNNEL);
188 val |= RECORD_RIGHT_CHNNEL;
189 }
190 AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val);
191 break;
192 case 2:
193 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
194 val |= (PLAY_LEFT_CHNNEL | PLAY_RIGHT_CHNNEL);
195 else
196 val |= (RECORD_LEFT_CHNNEL | RECORD_RIGHT_CHNNEL);
197 AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val);
198 break;
199 default:
200 return -EINVAL;
201 }
202 spin_unlock_irqrestore(&nuc900_audio->lock, flags);
203 return 0;
204}
205
206static int nuc900_dma_trigger(struct snd_pcm_substream *substream, int cmd)
207{
208 int ret = 0;
209
210 switch (cmd) {
211 case SNDRV_PCM_TRIGGER_START:
212 case SNDRV_PCM_TRIGGER_RESUME:
213 nuc900_dma_start(substream);
214 break;
215
216 case SNDRV_PCM_TRIGGER_STOP:
217 case SNDRV_PCM_TRIGGER_SUSPEND:
218 nuc900_dma_stop(substream);
219 break;
220
221 default:
222 ret = -EINVAL;
223 break;
224 }
225
226 return ret;
227}
228
229int nuc900_dma_getposition(struct snd_pcm_substream *substream,
230 dma_addr_t *src, dma_addr_t *dst)
231{
232 struct snd_pcm_runtime *runtime = substream->runtime;
233 struct nuc900_audio *nuc900_audio = runtime->private_data;
234
235 if (src != NULL)
236 *src = AUDIO_READ(nuc900_audio->mmio + ACTL_PDSTC);
237
238 if (dst != NULL)
239 *dst = AUDIO_READ(nuc900_audio->mmio + ACTL_RDSTC);
240
241 return 0;
242}
243
244static snd_pcm_uframes_t nuc900_dma_pointer(struct snd_pcm_substream *substream)
245{
246 struct snd_pcm_runtime *runtime = substream->runtime;
247 dma_addr_t src, dst;
248 unsigned long res;
249
250 nuc900_dma_getposition(substream, &src, &dst);
251
252 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
253 res = dst - runtime->dma_addr;
254 else
255 res = src - runtime->dma_addr;
256
257 return bytes_to_frames(substream->runtime, res);
258}
259
260static int nuc900_dma_open(struct snd_pcm_substream *substream)
261{
262 struct snd_pcm_runtime *runtime = substream->runtime;
263 struct nuc900_audio *nuc900_audio;
264
265 snd_soc_set_runtime_hwparams(substream, &nuc900_pcm_hardware);
266
267 nuc900_audio = nuc900_ac97_data;
268
269 if (request_irq(nuc900_audio->irq_num, nuc900_dma_interrupt,
270 IRQF_DISABLED, "nuc900-dma", substream))
271 return -EBUSY;
272
273 runtime->private_data = nuc900_audio;
274
275 return 0;
276}
277
278static int nuc900_dma_close(struct snd_pcm_substream *substream)
279{
280 struct snd_pcm_runtime *runtime = substream->runtime;
281 struct nuc900_audio *nuc900_audio = runtime->private_data;
282
283 free_irq(nuc900_audio->irq_num, substream);
284
285 return 0;
286}
287
288static int nuc900_dma_mmap(struct snd_pcm_substream *substream,
289 struct vm_area_struct *vma)
290{
291 struct snd_pcm_runtime *runtime = substream->runtime;
292
293 return dma_mmap_writecombine(substream->pcm->card->dev, vma,
294 runtime->dma_area,
295 runtime->dma_addr,
296 runtime->dma_bytes);
297}
298
299static struct snd_pcm_ops nuc900_dma_ops = {
300 .open = nuc900_dma_open,
301 .close = nuc900_dma_close,
302 .ioctl = snd_pcm_lib_ioctl,
303 .hw_params = nuc900_dma_hw_params,
304 .hw_free = nuc900_dma_hw_free,
305 .prepare = nuc900_dma_prepare,
306 .trigger = nuc900_dma_trigger,
307 .pointer = nuc900_dma_pointer,
308 .mmap = nuc900_dma_mmap,
309};
310
311static void nuc900_dma_free_dma_buffers(struct snd_pcm *pcm)
312{
313 snd_pcm_lib_preallocate_free_for_all(pcm);
314}
315
316static u64 nuc900_pcm_dmamask = DMA_BIT_MASK(32);
317static int nuc900_dma_new(struct snd_card *card,
318 struct snd_soc_dai *dai, struct snd_pcm *pcm)
319{
320 if (!card->dev->dma_mask)
321 card->dev->dma_mask = &nuc900_pcm_dmamask;
322 if (!card->dev->coherent_dma_mask)
323 card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
324
325 snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
326 card->dev, 4 * 1024, (4 * 1024) - 1);
327
328 return 0;
329}
330
331struct snd_soc_platform nuc900_soc_platform = {
332 .name = "nuc900-dma",
333 .pcm_ops = &nuc900_dma_ops,
334 .pcm_new = nuc900_dma_new,
335 .pcm_free = nuc900_dma_free_dma_buffers,
336}
337EXPORT_SYMBOL_GPL(nuc900_soc_platform);
338
339static int __init nuc900_soc_platform_init(void)
340{
341 return snd_soc_register_platform(&nuc900_soc_platform);
342}
343
344static void __exit nuc900_soc_platform_exit(void)
345{
346 snd_soc_unregister_platform(&nuc900_soc_platform);
347}
348
349module_init(nuc900_soc_platform_init);
350module_exit(nuc900_soc_platform_exit);
351
352MODULE_AUTHOR("Wan ZongShun, <mcuos.com@gmail.com>");
353MODULE_DESCRIPTION("nuc900 Audio DMA module");
354MODULE_LICENSE("GPL");
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index 6f44cb4d30b8..86f213905e2c 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -59,6 +59,7 @@ struct omap_mcbsp_data {
59 int configured; 59 int configured;
60 unsigned int in_freq; 60 unsigned int in_freq;
61 int clk_div; 61 int clk_div;
62 int wlen;
62}; 63};
63 64
64#define to_mcbsp(priv) container_of((priv), struct omap_mcbsp_data, bus_id) 65#define to_mcbsp(priv) container_of((priv), struct omap_mcbsp_data, bus_id)
@@ -154,20 +155,51 @@ static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream)
154 struct snd_soc_pcm_runtime *rtd = substream->private_data; 155 struct snd_soc_pcm_runtime *rtd = substream->private_data;
155 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; 156 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
156 struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); 157 struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
158 struct omap_pcm_dma_data *dma_data;
157 int dma_op_mode = omap_mcbsp_get_dma_op_mode(mcbsp_data->bus_id); 159 int dma_op_mode = omap_mcbsp_get_dma_op_mode(mcbsp_data->bus_id);
158 int samples; 160 int words;
161
162 dma_data = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
159 163
160 /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */ 164 /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */
161 if (dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) 165 if (dma_op_mode == MCBSP_DMA_MODE_THRESHOLD)
162 samples = snd_pcm_lib_period_bytes(substream) >> 1; 166 /*
167 * Configure McBSP threshold based on either:
168 * packet_size, when the sDMA is in packet mode, or
169 * based on the period size.
170 */
171 if (dma_data->packet_size)
172 words = dma_data->packet_size;
173 else
174 words = snd_pcm_lib_period_bytes(substream) /
175 (mcbsp_data->wlen / 8);
163 else 176 else
164 samples = 1; 177 words = 1;
165 178
166 /* Configure McBSP internal buffer usage */ 179 /* Configure McBSP internal buffer usage */
167 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 180 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
168 omap_mcbsp_set_tx_threshold(mcbsp_data->bus_id, samples - 1); 181 omap_mcbsp_set_tx_threshold(mcbsp_data->bus_id, words);
169 else 182 else
170 omap_mcbsp_set_rx_threshold(mcbsp_data->bus_id, samples - 1); 183 omap_mcbsp_set_rx_threshold(mcbsp_data->bus_id, words);
184}
185
186static int omap_mcbsp_hwrule_min_buffersize(struct snd_pcm_hw_params *params,
187 struct snd_pcm_hw_rule *rule)
188{
189 struct snd_interval *buffer_size = hw_param_interval(params,
190 SNDRV_PCM_HW_PARAM_BUFFER_SIZE);
191 struct snd_interval *channels = hw_param_interval(params,
192 SNDRV_PCM_HW_PARAM_CHANNELS);
193 struct omap_mcbsp_data *mcbsp_data = rule->private;
194 struct snd_interval frames;
195 int size;
196
197 snd_interval_any(&frames);
198 size = omap_mcbsp_get_fifo_size(mcbsp_data->bus_id);
199
200 frames.min = size / channels->min;
201 frames.integer = 1;
202 return snd_interval_refine(buffer_size, &frames);
171} 203}
172 204
173static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream, 205static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
@@ -182,33 +214,35 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
182 if (!cpu_dai->active) 214 if (!cpu_dai->active)
183 err = omap_mcbsp_request(bus_id); 215 err = omap_mcbsp_request(bus_id);
184 216
217 /*
218 * OMAP3 McBSP FIFO is word structured.
219 * McBSP2 has 1024 + 256 = 1280 word long buffer,
220 * McBSP1,3,4,5 has 128 word long buffer
221 * This means that the size of the FIFO depends on the sample format.
222 * For example on McBSP3:
223 * 16bit samples: size is 128 * 2 = 256 bytes
224 * 32bit samples: size is 128 * 4 = 512 bytes
225 * It is simpler to place constraint for buffer and period based on
226 * channels.
227 * McBSP3 as example again (16 or 32 bit samples):
228 * 1 channel (mono): size is 128 frames (128 words)
229 * 2 channels (stereo): size is 128 / 2 = 64 frames (2 * 64 words)
230 * 4 channels: size is 128 / 4 = 32 frames (4 * 32 words)
231 */
185 if (cpu_is_omap343x()) { 232 if (cpu_is_omap343x()) {
186 int dma_op_mode = omap_mcbsp_get_dma_op_mode(bus_id);
187 int max_period;
188
189 /* 233 /*
190 * McBSP2 in OMAP3 has 1024 * 32-bit internal audio buffer. 234 * Rule for the buffer size. We should not allow
191 * Set constraint for minimum buffer size to the same than FIFO 235 * smaller buffer than the FIFO size to avoid underruns
192 * size in order to avoid underruns in playback startup because 236 */
193 * HW is keeping the DMA request active until FIFO is filled. 237 snd_pcm_hw_rule_add(substream->runtime, 0,
194 */ 238 SNDRV_PCM_HW_PARAM_CHANNELS,
195 if (bus_id == 1) 239 omap_mcbsp_hwrule_min_buffersize,
196 snd_pcm_hw_constraint_minmax(substream->runtime, 240 mcbsp_data,
197 SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 241 SNDRV_PCM_HW_PARAM_BUFFER_SIZE, -1);
198 4096, UINT_MAX); 242
199 243 /* Make sure, that the period size is always even */
200 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 244 snd_pcm_hw_constraint_step(substream->runtime, 0,
201 max_period = omap_mcbsp_get_max_tx_threshold(bus_id); 245 SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 2);
202 else
203 max_period = omap_mcbsp_get_max_rx_threshold(bus_id);
204
205 max_period++;
206 max_period <<= 1;
207
208 if (dma_op_mode == MCBSP_DMA_MODE_THRESHOLD)
209 snd_pcm_hw_constraint_minmax(substream->runtime,
210 SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
211 32, max_period);
212 } 246 }
213 247
214 return err; 248 return err;
@@ -289,11 +323,14 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
289 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; 323 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
290 struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); 324 struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
291 struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs; 325 struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
292 int dma, bus_id = mcbsp_data->bus_id, id = cpu_dai->id; 326 struct omap_pcm_dma_data *dma_data;
327 int dma, bus_id = mcbsp_data->bus_id;
293 int wlen, channels, wpf, sync_mode = OMAP_DMA_SYNC_ELEMENT; 328 int wlen, channels, wpf, sync_mode = OMAP_DMA_SYNC_ELEMENT;
329 int pkt_size = 0;
294 unsigned long port; 330 unsigned long port;
295 unsigned int format, div, framesize, master; 331 unsigned int format, div, framesize, master;
296 332
333 dma_data = &omap_mcbsp_dai_dma_params[cpu_dai->id][substream->stream];
297 if (cpu_class_is_omap1()) { 334 if (cpu_class_is_omap1()) {
298 dma = omap1_dma_reqs[bus_id][substream->stream]; 335 dma = omap1_dma_reqs[bus_id][substream->stream];
299 port = omap1_mcbsp_port[bus_id][substream->stream]; 336 port = omap1_mcbsp_port[bus_id][substream->stream];
@@ -306,35 +343,74 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
306 } else if (cpu_is_omap343x()) { 343 } else if (cpu_is_omap343x()) {
307 dma = omap24xx_dma_reqs[bus_id][substream->stream]; 344 dma = omap24xx_dma_reqs[bus_id][substream->stream];
308 port = omap34xx_mcbsp_port[bus_id][substream->stream]; 345 port = omap34xx_mcbsp_port[bus_id][substream->stream];
309 omap_mcbsp_dai_dma_params[id][substream->stream].set_threshold =
310 omap_mcbsp_set_threshold;
311 /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */
312 if (omap_mcbsp_get_dma_op_mode(bus_id) ==
313 MCBSP_DMA_MODE_THRESHOLD)
314 sync_mode = OMAP_DMA_SYNC_FRAME;
315 } else { 346 } else {
316 return -ENODEV; 347 return -ENODEV;
317 } 348 }
318 omap_mcbsp_dai_dma_params[id][substream->stream].name =
319 substream->stream ? "Audio Capture" : "Audio Playback";
320 omap_mcbsp_dai_dma_params[id][substream->stream].dma_req = dma;
321 omap_mcbsp_dai_dma_params[id][substream->stream].port_addr = port;
322 omap_mcbsp_dai_dma_params[id][substream->stream].sync_mode = sync_mode;
323 switch (params_format(params)) { 349 switch (params_format(params)) {
324 case SNDRV_PCM_FORMAT_S16_LE: 350 case SNDRV_PCM_FORMAT_S16_LE:
325 omap_mcbsp_dai_dma_params[id][substream->stream].data_type = 351 dma_data->data_type = OMAP_DMA_DATA_TYPE_S16;
326 OMAP_DMA_DATA_TYPE_S16; 352 wlen = 16;
327 break; 353 break;
328 case SNDRV_PCM_FORMAT_S32_LE: 354 case SNDRV_PCM_FORMAT_S32_LE:
329 omap_mcbsp_dai_dma_params[id][substream->stream].data_type = 355 dma_data->data_type = OMAP_DMA_DATA_TYPE_S32;
330 OMAP_DMA_DATA_TYPE_S32; 356 wlen = 32;
331 break; 357 break;
332 default: 358 default:
333 return -EINVAL; 359 return -EINVAL;
334 } 360 }
361 if (cpu_is_omap343x()) {
362 dma_data->set_threshold = omap_mcbsp_set_threshold;
363 /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */
364 if (omap_mcbsp_get_dma_op_mode(bus_id) ==
365 MCBSP_DMA_MODE_THRESHOLD) {
366 int period_words, max_thrsh;
367
368 period_words = params_period_bytes(params) / (wlen / 8);
369 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
370 max_thrsh = omap_mcbsp_get_max_tx_threshold(
371 mcbsp_data->bus_id);
372 else
373 max_thrsh = omap_mcbsp_get_max_rx_threshold(
374 mcbsp_data->bus_id);
375 /*
376 * If the period contains less or equal number of words,
377 * we are using the original threshold mode setup:
378 * McBSP threshold = sDMA frame size = period_size
379 * Otherwise we switch to sDMA packet mode:
380 * McBSP threshold = sDMA packet size
381 * sDMA frame size = period size
382 */
383 if (period_words > max_thrsh) {
384 int divider = 0;
385
386 /*
387 * Look for the biggest threshold value, which
388 * divides the period size evenly.
389 */
390 divider = period_words / max_thrsh;
391 if (period_words % max_thrsh)
392 divider++;
393 while (period_words % divider &&
394 divider < period_words)
395 divider++;
396 if (divider == period_words)
397 return -EINVAL;
398
399 pkt_size = period_words / divider;
400 sync_mode = OMAP_DMA_SYNC_PACKET;
401 } else {
402 sync_mode = OMAP_DMA_SYNC_FRAME;
403 }
404 }
405 }
335 406
336 snd_soc_dai_set_dma_data(cpu_dai, substream, 407 dma_data->name = substream->stream ? "Audio Capture" : "Audio Playback";
337 &omap_mcbsp_dai_dma_params[id][substream->stream]); 408 dma_data->dma_req = dma;
409 dma_data->port_addr = port;
410 dma_data->sync_mode = sync_mode;
411 dma_data->packet_size = pkt_size;
412
413 snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
338 414
339 if (mcbsp_data->configured) { 415 if (mcbsp_data->configured) {
340 /* McBSP already configured by another stream */ 416 /* McBSP already configured by another stream */
@@ -360,7 +436,6 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
360 switch (params_format(params)) { 436 switch (params_format(params)) {
361 case SNDRV_PCM_FORMAT_S16_LE: 437 case SNDRV_PCM_FORMAT_S16_LE:
362 /* Set word lengths */ 438 /* Set word lengths */
363 wlen = 16;
364 regs->rcr2 |= RWDLEN2(OMAP_MCBSP_WORD_16); 439 regs->rcr2 |= RWDLEN2(OMAP_MCBSP_WORD_16);
365 regs->rcr1 |= RWDLEN1(OMAP_MCBSP_WORD_16); 440 regs->rcr1 |= RWDLEN1(OMAP_MCBSP_WORD_16);
366 regs->xcr2 |= XWDLEN2(OMAP_MCBSP_WORD_16); 441 regs->xcr2 |= XWDLEN2(OMAP_MCBSP_WORD_16);
@@ -368,7 +443,6 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
368 break; 443 break;
369 case SNDRV_PCM_FORMAT_S32_LE: 444 case SNDRV_PCM_FORMAT_S32_LE:
370 /* Set word lengths */ 445 /* Set word lengths */
371 wlen = 32;
372 regs->rcr2 |= RWDLEN2(OMAP_MCBSP_WORD_32); 446 regs->rcr2 |= RWDLEN2(OMAP_MCBSP_WORD_32);
373 regs->rcr1 |= RWDLEN1(OMAP_MCBSP_WORD_32); 447 regs->rcr1 |= RWDLEN1(OMAP_MCBSP_WORD_32);
374 regs->xcr2 |= XWDLEN2(OMAP_MCBSP_WORD_32); 448 regs->xcr2 |= XWDLEN2(OMAP_MCBSP_WORD_32);
@@ -409,6 +483,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
409 } 483 }
410 484
411 omap_mcbsp_config(bus_id, &mcbsp_data->regs); 485 omap_mcbsp_config(bus_id, &mcbsp_data->regs);
486 mcbsp_data->wlen = wlen;
412 mcbsp_data->configured = 1; 487 mcbsp_data->configured = 1;
413 488
414 return 0; 489 return 0;
diff --git a/sound/soc/omap/omap3pandora.c b/sound/soc/omap/omap3pandora.c
index 87ce842fa2e8..9eecac135bbb 100644
--- a/sound/soc/omap/omap3pandora.c
+++ b/sound/soc/omap/omap3pandora.c
@@ -43,12 +43,14 @@
43 43
44static struct regulator *omap3pandora_dac_reg; 44static struct regulator *omap3pandora_dac_reg;
45 45
46static int omap3pandora_cmn_hw_params(struct snd_pcm_substream *substream, 46static int omap3pandora_hw_params(struct snd_pcm_substream *substream,
47 struct snd_pcm_hw_params *params, unsigned int fmt) 47 struct snd_pcm_hw_params *params)
48{ 48{
49 struct snd_soc_pcm_runtime *rtd = substream->private_data; 49 struct snd_soc_pcm_runtime *rtd = substream->private_data;
50 struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; 50 struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
51 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; 51 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
52 int fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
53 SND_SOC_DAIFMT_CBS_CFS;
52 int ret; 54 int ret;
53 55
54 /* Set codec DAI configuration */ 56 /* Set codec DAI configuration */
@@ -91,24 +93,6 @@ static int omap3pandora_cmn_hw_params(struct snd_pcm_substream *substream,
91 return 0; 93 return 0;
92} 94}
93 95
94static int omap3pandora_out_hw_params(struct snd_pcm_substream *substream,
95 struct snd_pcm_hw_params *params)
96{
97 return omap3pandora_cmn_hw_params(substream, params,
98 SND_SOC_DAIFMT_I2S |
99 SND_SOC_DAIFMT_IB_NF |
100 SND_SOC_DAIFMT_CBS_CFS);
101}
102
103static int omap3pandora_in_hw_params(struct snd_pcm_substream *substream,
104 struct snd_pcm_hw_params *params)
105{
106 return omap3pandora_cmn_hw_params(substream, params,
107 SND_SOC_DAIFMT_I2S |
108 SND_SOC_DAIFMT_NB_NF |
109 SND_SOC_DAIFMT_CBS_CFS);
110}
111
112static int omap3pandora_dac_event(struct snd_soc_dapm_widget *w, 96static int omap3pandora_dac_event(struct snd_soc_dapm_widget *w,
113 struct snd_kcontrol *k, int event) 97 struct snd_kcontrol *k, int event)
114{ 98{
@@ -231,12 +215,8 @@ static int omap3pandora_in_init(struct snd_soc_codec *codec)
231 return snd_soc_dapm_sync(codec); 215 return snd_soc_dapm_sync(codec);
232} 216}
233 217
234static struct snd_soc_ops omap3pandora_out_ops = { 218static struct snd_soc_ops omap3pandora_ops = {
235 .hw_params = omap3pandora_out_hw_params, 219 .hw_params = omap3pandora_hw_params,
236};
237
238static struct snd_soc_ops omap3pandora_in_ops = {
239 .hw_params = omap3pandora_in_hw_params,
240}; 220};
241 221
242/* Digital audio interface glue - connects codec <--> CPU */ 222/* Digital audio interface glue - connects codec <--> CPU */
@@ -246,14 +226,14 @@ static struct snd_soc_dai_link omap3pandora_dai[] = {
246 .stream_name = "HiFi Out", 226 .stream_name = "HiFi Out",
247 .cpu_dai = &omap_mcbsp_dai[0], 227 .cpu_dai = &omap_mcbsp_dai[0],
248 .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI], 228 .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
249 .ops = &omap3pandora_out_ops, 229 .ops = &omap3pandora_ops,
250 .init = omap3pandora_out_init, 230 .init = omap3pandora_out_init,
251 }, { 231 }, {
252 .name = "TWL4030", 232 .name = "TWL4030",
253 .stream_name = "Line/Mic In", 233 .stream_name = "Line/Mic In",
254 .cpu_dai = &omap_mcbsp_dai[1], 234 .cpu_dai = &omap_mcbsp_dai[1],
255 .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI], 235 .codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
256 .ops = &omap3pandora_in_ops, 236 .ops = &omap3pandora_ops,
257 .init = omap3pandora_in_init, 237 .init = omap3pandora_in_init,
258 } 238 }
259}; 239};
diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c
index 47d831ef2dbb..88052d29617f 100644
--- a/sound/soc/omap/rx51.c
+++ b/sound/soc/omap/rx51.c
@@ -27,6 +27,7 @@
27#include <linux/gpio.h> 27#include <linux/gpio.h>
28#include <linux/platform_device.h> 28#include <linux/platform_device.h>
29#include <sound/core.h> 29#include <sound/core.h>
30#include <sound/jack.h>
30#include <sound/pcm.h> 31#include <sound/pcm.h>
31#include <sound/soc.h> 32#include <sound/soc.h>
32#include <sound/soc-dapm.h> 33#include <sound/soc-dapm.h>
@@ -37,14 +38,22 @@
37#include "omap-pcm.h" 38#include "omap-pcm.h"
38#include "../codecs/tlv320aic3x.h" 39#include "../codecs/tlv320aic3x.h"
39 40
41#define RX51_TVOUT_SEL_GPIO 40
42#define RX51_JACK_DETECT_GPIO 177
40/* 43/*
41 * REVISIT: TWL4030 GPIO base in RX-51. Now statically defined to 192. This 44 * REVISIT: TWL4030 GPIO base in RX-51. Now statically defined to 192. This
42 * gpio is reserved in arch/arm/mach-omap2/board-rx51-peripherals.c 45 * gpio is reserved in arch/arm/mach-omap2/board-rx51-peripherals.c
43 */ 46 */
44#define RX51_SPEAKER_AMP_TWL_GPIO (192 + 7) 47#define RX51_SPEAKER_AMP_TWL_GPIO (192 + 7)
45 48
49enum {
50 RX51_JACK_DISABLED,
51 RX51_JACK_TVOUT, /* tv-out */
52};
53
46static int rx51_spk_func; 54static int rx51_spk_func;
47static int rx51_dmic_func; 55static int rx51_dmic_func;
56static int rx51_jack_func;
48 57
49static void rx51_ext_control(struct snd_soc_codec *codec) 58static void rx51_ext_control(struct snd_soc_codec *codec)
50{ 59{
@@ -57,6 +66,9 @@ static void rx51_ext_control(struct snd_soc_codec *codec)
57 else 66 else
58 snd_soc_dapm_disable_pin(codec, "DMic"); 67 snd_soc_dapm_disable_pin(codec, "DMic");
59 68
69 gpio_set_value(RX51_TVOUT_SEL_GPIO,
70 rx51_jack_func == RX51_JACK_TVOUT);
71
60 snd_soc_dapm_sync(codec); 72 snd_soc_dapm_sync(codec);
61} 73}
62 74
@@ -162,6 +174,40 @@ static int rx51_set_input(struct snd_kcontrol *kcontrol,
162 return 1; 174 return 1;
163} 175}
164 176
177static int rx51_get_jack(struct snd_kcontrol *kcontrol,
178 struct snd_ctl_elem_value *ucontrol)
179{
180 ucontrol->value.integer.value[0] = rx51_jack_func;
181
182 return 0;
183}
184
185static int rx51_set_jack(struct snd_kcontrol *kcontrol,
186 struct snd_ctl_elem_value *ucontrol)
187{
188 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
189
190 if (rx51_jack_func == ucontrol->value.integer.value[0])
191 return 0;
192
193 rx51_jack_func = ucontrol->value.integer.value[0];
194 rx51_ext_control(codec);
195
196 return 1;
197}
198
199static struct snd_soc_jack rx51_av_jack;
200
201static struct snd_soc_jack_gpio rx51_av_jack_gpios[] = {
202 {
203 .gpio = RX51_JACK_DETECT_GPIO,
204 .name = "avdet-gpio",
205 .report = SND_JACK_VIDEOOUT,
206 .invert = 1,
207 .debounce_time = 200,
208 },
209};
210
165static const struct snd_soc_dapm_widget aic34_dapm_widgets[] = { 211static const struct snd_soc_dapm_widget aic34_dapm_widgets[] = {
166 SND_SOC_DAPM_SPK("Ext Spk", rx51_spk_event), 212 SND_SOC_DAPM_SPK("Ext Spk", rx51_spk_event),
167 SND_SOC_DAPM_MIC("DMic", NULL), 213 SND_SOC_DAPM_MIC("DMic", NULL),
@@ -177,10 +223,12 @@ static const struct snd_soc_dapm_route audio_map[] = {
177 223
178static const char *spk_function[] = {"Off", "On"}; 224static const char *spk_function[] = {"Off", "On"};
179static const char *input_function[] = {"ADC", "Digital Mic"}; 225static const char *input_function[] = {"ADC", "Digital Mic"};
226static const char *jack_function[] = {"Off", "TV-OUT"};
180 227
181static const struct soc_enum rx51_enum[] = { 228static const struct soc_enum rx51_enum[] = {
182 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spk_function), spk_function), 229 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spk_function), spk_function),
183 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(input_function), input_function), 230 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(input_function), input_function),
231 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(jack_function), jack_function),
184}; 232};
185 233
186static const struct snd_kcontrol_new aic34_rx51_controls[] = { 234static const struct snd_kcontrol_new aic34_rx51_controls[] = {
@@ -188,10 +236,13 @@ static const struct snd_kcontrol_new aic34_rx51_controls[] = {
188 rx51_get_spk, rx51_set_spk), 236 rx51_get_spk, rx51_set_spk),
189 SOC_ENUM_EXT("Input Select", rx51_enum[1], 237 SOC_ENUM_EXT("Input Select", rx51_enum[1],
190 rx51_get_input, rx51_set_input), 238 rx51_get_input, rx51_set_input),
239 SOC_ENUM_EXT("Jack Function", rx51_enum[2],
240 rx51_get_jack, rx51_set_jack),
191}; 241};
192 242
193static int rx51_aic34_init(struct snd_soc_codec *codec) 243static int rx51_aic34_init(struct snd_soc_codec *codec)
194{ 244{
245 struct snd_soc_card *card = codec->socdev->card;
195 int err; 246 int err;
196 247
197 /* Set up NC codec pins */ 248 /* Set up NC codec pins */
@@ -214,7 +265,16 @@ static int rx51_aic34_init(struct snd_soc_codec *codec)
214 265
215 snd_soc_dapm_sync(codec); 266 snd_soc_dapm_sync(codec);
216 267
217 return 0; 268 /* AV jack detection */
269 err = snd_soc_jack_new(card, "AV Jack",
270 SND_JACK_VIDEOOUT, &rx51_av_jack);
271 if (err)
272 return err;
273 err = snd_soc_jack_add_gpios(&rx51_av_jack,
274 ARRAY_SIZE(rx51_av_jack_gpios),
275 rx51_av_jack_gpios);
276
277 return err;
218} 278}
219 279
220/* Digital audio interface glue - connects codec <--> CPU */ 280/* Digital audio interface glue - connects codec <--> CPU */
@@ -259,6 +319,11 @@ static int __init rx51_soc_init(void)
259 if (!machine_is_nokia_rx51()) 319 if (!machine_is_nokia_rx51())
260 return -ENODEV; 320 return -ENODEV;
261 321
322 err = gpio_request(RX51_TVOUT_SEL_GPIO, "tvout_sel");
323 if (err)
324 goto err_gpio_tvout_sel;
325 gpio_direction_output(RX51_TVOUT_SEL_GPIO, 0);
326
262 rx51_snd_device = platform_device_alloc("soc-audio", -1); 327 rx51_snd_device = platform_device_alloc("soc-audio", -1);
263 if (!rx51_snd_device) { 328 if (!rx51_snd_device) {
264 err = -ENOMEM; 329 err = -ENOMEM;
@@ -277,13 +342,19 @@ static int __init rx51_soc_init(void)
277err2: 342err2:
278 platform_device_put(rx51_snd_device); 343 platform_device_put(rx51_snd_device);
279err1: 344err1:
345 gpio_free(RX51_TVOUT_SEL_GPIO);
346err_gpio_tvout_sel:
280 347
281 return err; 348 return err;
282} 349}
283 350
284static void __exit rx51_soc_exit(void) 351static void __exit rx51_soc_exit(void)
285{ 352{
353 snd_soc_jack_free_gpios(&rx51_av_jack, ARRAY_SIZE(rx51_av_jack_gpios),
354 rx51_av_jack_gpios);
355
286 platform_device_unregister(rx51_snd_device); 356 platform_device_unregister(rx51_snd_device);
357 gpio_free(RX51_TVOUT_SEL_GPIO);
287} 358}
288 359
289module_init(rx51_soc_init); 360module_init(rx51_soc_init);
diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig
index 2a7cc222d098..213963ac3c28 100644
--- a/sound/soc/s3c24xx/Kconfig
+++ b/sound/soc/s3c24xx/Kconfig
@@ -1,6 +1,6 @@
1config SND_S3C24XX_SOC 1config SND_S3C24XX_SOC
2 tristate "SoC Audio for the Samsung S3CXXXX chips" 2 tristate "SoC Audio for the Samsung S3CXXXX chips"
3 depends on ARCH_S3C2410 || ARCH_S3C64XX 3 depends on ARCH_S3C2410 || ARCH_S3C64XX || ARCH_S5PC100 || ARCH_S5PV210
4 select S3C64XX_DMA if ARCH_S3C64XX 4 select S3C64XX_DMA if ARCH_S3C64XX
5 help 5 help
6 Say Y or M if you want to add support for codecs attached to 6 Say Y or M if you want to add support for codecs attached to
@@ -120,8 +120,14 @@ config SND_S3C24XX_SOC_SIMTEC_HERMES
120 120
121config SND_SOC_SMDK_WM9713 121config SND_SOC_SMDK_WM9713
122 tristate "SoC AC97 Audio support for SMDK with WM9713" 122 tristate "SoC AC97 Audio support for SMDK with WM9713"
123 depends on SND_S3C24XX_SOC && MACH_SMDK6410 123 depends on SND_S3C24XX_SOC && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110)
124 select SND_SOC_WM9713 124 select SND_SOC_WM9713
125 select SND_S3C_SOC_AC97 125 select SND_S3C_SOC_AC97
126 help 126 help
127 Sat Y if you want to add support for SoC audio on the SMDK. 127 Sat Y if you want to add support for SoC audio on the SMDK.
128
129config SND_S3C64XX_SOC_SMARTQ
130 tristate "SoC I2S Audio support for SmartQ board"
131 depends on SND_S3C24XX_SOC && MACH_SMARTQ
132 select SND_S3C64XX_SOC_I2S
133 select SND_SOC_WM8750
diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile
index 81d8dc503f87..50172c385d90 100644
--- a/sound/soc/s3c24xx/Makefile
+++ b/sound/soc/s3c24xx/Makefile
@@ -29,6 +29,7 @@ snd-soc-s3c24xx-simtec-hermes-objs := s3c24xx_simtec_hermes.o
29snd-soc-s3c24xx-simtec-tlv320aic23-objs := s3c24xx_simtec_tlv320aic23.o 29snd-soc-s3c24xx-simtec-tlv320aic23-objs := s3c24xx_simtec_tlv320aic23.o
30snd-soc-smdk64xx-wm8580-objs := smdk64xx_wm8580.o 30snd-soc-smdk64xx-wm8580-objs := smdk64xx_wm8580.o
31snd-soc-smdk-wm9713-objs := smdk_wm9713.o 31snd-soc-smdk-wm9713-objs := smdk_wm9713.o
32snd-soc-s3c64xx-smartq-wm8987-objs := smartq_wm8987.o
32 33
33obj-$(CONFIG_SND_S3C24XX_SOC_JIVE_WM8750) += snd-soc-jive-wm8750.o 34obj-$(CONFIG_SND_S3C24XX_SOC_JIVE_WM8750) += snd-soc-jive-wm8750.o
34obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o 35obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o
@@ -41,3 +42,4 @@ obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_HERMES) += snd-soc-s3c24xx-simtec-hermes.o
41obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_TLV320AIC23) += snd-soc-s3c24xx-simtec-tlv320aic23.o 42obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_TLV320AIC23) += snd-soc-s3c24xx-simtec-tlv320aic23.o
42obj-$(CONFIG_SND_S3C64XX_SOC_WM8580) += snd-soc-smdk64xx-wm8580.o 43obj-$(CONFIG_SND_S3C64XX_SOC_WM8580) += snd-soc-smdk64xx-wm8580.o
43obj-$(CONFIG_SND_SOC_SMDK_WM9713) += snd-soc-smdk-wm9713.o 44obj-$(CONFIG_SND_SOC_SMDK_WM9713) += snd-soc-smdk-wm9713.o
45obj-$(CONFIG_SND_S3C64XX_SOC_SMARTQ) += snd-soc-s3c64xx-smartq-wm8987.o
diff --git a/sound/soc/s3c24xx/s3c-ac97.c b/sound/soc/s3c24xx/s3c-ac97.c
index ecf4fd04ae96..31f6d45b6384 100644
--- a/sound/soc/s3c24xx/s3c-ac97.c
+++ b/sound/soc/s3c24xx/s3c-ac97.c
@@ -31,7 +31,6 @@
31#define AC_CMD_DATA(x) (x & 0xffff) 31#define AC_CMD_DATA(x) (x & 0xffff)
32 32
33struct s3c_ac97_info { 33struct s3c_ac97_info {
34 unsigned state;
35 struct clk *ac97_clk; 34 struct clk *ac97_clk;
36 void __iomem *regs; 35 void __iomem *regs;
37 struct mutex lock; 36 struct mutex lock;
diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.c b/sound/soc/s3c24xx/s3c-i2s-v2.c
index 13311c8cf965..64376b2aac73 100644
--- a/sound/soc/s3c24xx/s3c-i2s-v2.c
+++ b/sound/soc/s3c24xx/s3c-i2s-v2.c
@@ -32,7 +32,8 @@
32 32
33#undef S3C_IIS_V2_SUPPORTED 33#undef S3C_IIS_V2_SUPPORTED
34 34
35#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413) 35#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413) \
36 || defined(CONFIG_CPU_S5PV210)
36#define S3C_IIS_V2_SUPPORTED 37#define S3C_IIS_V2_SUPPORTED
37#endif 38#endif
38 39
diff --git a/sound/soc/s3c24xx/smartq_wm8987.c b/sound/soc/s3c24xx/smartq_wm8987.c
new file mode 100644
index 000000000000..b480348140b0
--- /dev/null
+++ b/sound/soc/s3c24xx/smartq_wm8987.c
@@ -0,0 +1,295 @@
1/* sound/soc/s3c24xx/smartq_wm8987.c
2 *
3 * Copyright 2010 Maurus Cuelenaere <mcuelenaere@gmail.com>
4 *
5 * Based on smdk6410_wm8987.c
6 * Copyright 2007 Wolfson Microelectronics PLC. - linux@wolfsonmicro.com
7 * Graeme Gregory - graeme.gregory@wolfsonmicro.com
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version.
13 *
14 */
15
16#include <linux/module.h>
17#include <linux/platform_device.h>
18#include <linux/gpio.h>
19
20#include <sound/pcm.h>
21#include <sound/pcm_params.h>
22#include <sound/soc-dapm.h>
23#include <sound/jack.h>
24
25#include <asm/mach-types.h>
26
27#include "s3c-dma.h"
28#include "s3c64xx-i2s.h"
29
30#include "../codecs/wm8750.h"
31
32/*
33 * WM8987 is register compatible with WM8750, so using that as base driver.
34 */
35
36static struct snd_soc_card snd_soc_smartq;
37
38static int smartq_hifi_hw_params(struct snd_pcm_substream *substream,
39 struct snd_pcm_hw_params *params)
40{
41 struct snd_soc_pcm_runtime *rtd = substream->private_data;
42 struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
43 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
44 struct s3c_i2sv2_rate_calc div;
45 unsigned int clk = 0;
46 int ret;
47
48 s3c_i2sv2_iis_calc_rate(&div, NULL, params_rate(params),
49 s3c_i2sv2_get_clock(cpu_dai));
50
51 switch (params_rate(params)) {
52 case 8000:
53 case 16000:
54 case 32000:
55 case 48000:
56 case 96000:
57 clk = 12288000;
58 break;
59 case 11025:
60 case 22050:
61 case 44100:
62 case 88200:
63 clk = 11289600;
64 break;
65 }
66
67 /* set codec DAI configuration */
68 ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
69 SND_SOC_DAIFMT_NB_NF |
70 SND_SOC_DAIFMT_CBS_CFS);
71 if (ret < 0)
72 return ret;
73
74 /* set cpu DAI configuration */
75 ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
76 SND_SOC_DAIFMT_NB_NF |
77 SND_SOC_DAIFMT_CBS_CFS);
78 if (ret < 0)
79 return ret;
80
81 /* set the codec system clock for DAC and ADC */
82 ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk,
83 SND_SOC_CLOCK_IN);
84 if (ret < 0)
85 return ret;
86
87 /* set MCLK division for sample rate */
88 ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C_I2SV2_DIV_RCLK, div.fs_div);
89 if (ret < 0)
90 return ret;
91
92 /* set prescaler division for sample rate */
93 ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C_I2SV2_DIV_PRESCALER,
94 div.clk_div - 1);
95 if (ret < 0)
96 return ret;
97
98 return 0;
99}
100
101/*
102 * SmartQ WM8987 HiFi DAI operations.
103 */
104static struct snd_soc_ops smartq_hifi_ops = {
105 .hw_params = smartq_hifi_hw_params,
106};
107
108static struct snd_soc_jack smartq_jack;
109
110static struct snd_soc_jack_pin smartq_jack_pins[] = {
111 /* Disable speaker when headphone is plugged in */
112 {
113 .pin = "Internal Speaker",
114 .mask = SND_JACK_HEADPHONE,
115 },
116};
117
118static struct snd_soc_jack_gpio smartq_jack_gpios[] = {
119 {
120 .gpio = S3C64XX_GPL(12),
121 .name = "headphone detect",
122 .report = SND_JACK_HEADPHONE,
123 .debounce_time = 200,
124 },
125};
126
127static const struct snd_kcontrol_new wm8987_smartq_controls[] = {
128 SOC_DAPM_PIN_SWITCH("Internal Speaker"),
129 SOC_DAPM_PIN_SWITCH("Headphone Jack"),
130 SOC_DAPM_PIN_SWITCH("Internal Mic"),
131};
132
133static int smartq_speaker_event(struct snd_soc_dapm_widget *w,
134 struct snd_kcontrol *k,
135 int event)
136{
137 gpio_set_value(S3C64XX_GPK(12), SND_SOC_DAPM_EVENT_OFF(event));
138
139 return 0;
140}
141
142static const struct snd_soc_dapm_widget wm8987_dapm_widgets[] = {
143 SND_SOC_DAPM_SPK("Internal Speaker", smartq_speaker_event),
144 SND_SOC_DAPM_HP("Headphone Jack", NULL),
145 SND_SOC_DAPM_MIC("Internal Mic", NULL),
146};
147
148static const struct snd_soc_dapm_route audio_map[] = {
149 {"Headphone Jack", NULL, "LOUT2"},
150 {"Headphone Jack", NULL, "ROUT2"},
151
152 {"Internal Speaker", NULL, "LOUT2"},
153 {"Internal Speaker", NULL, "ROUT2"},
154
155 {"Mic Bias", NULL, "Internal Mic"},
156 {"LINPUT2", NULL, "Mic Bias"},
157};
158
159static int smartq_wm8987_init(struct snd_soc_codec *codec)
160{
161 int err = 0;
162
163 /* Add SmartQ specific widgets */
164 snd_soc_dapm_new_controls(codec, wm8987_dapm_widgets,
165 ARRAY_SIZE(wm8987_dapm_widgets));
166
167 /* add SmartQ specific controls */
168 err = snd_soc_add_controls(codec, wm8987_smartq_controls,
169 ARRAY_SIZE(wm8987_smartq_controls));
170
171 if (err < 0)
172 return err;
173
174 /* setup SmartQ specific audio path */
175 snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
176
177 /* set endpoints to not connected */
178 snd_soc_dapm_nc_pin(codec, "LINPUT1");
179 snd_soc_dapm_nc_pin(codec, "RINPUT1");
180 snd_soc_dapm_nc_pin(codec, "OUT3");
181 snd_soc_dapm_nc_pin(codec, "ROUT1");
182
183 /* set endpoints to default off mode */
184 snd_soc_dapm_enable_pin(codec, "Internal Speaker");
185 snd_soc_dapm_enable_pin(codec, "Internal Mic");
186 snd_soc_dapm_disable_pin(codec, "Headphone Jack");
187
188 err = snd_soc_dapm_sync(codec);
189 if (err)
190 return err;
191
192 /* Headphone jack detection */
193 err = snd_soc_jack_new(&snd_soc_smartq, "Headphone Jack",
194 SND_JACK_HEADPHONE, &smartq_jack);
195 if (err)
196 return err;
197
198 err = snd_soc_jack_add_pins(&smartq_jack, ARRAY_SIZE(smartq_jack_pins),
199 smartq_jack_pins);
200 if (err)
201 return err;
202
203 err = snd_soc_jack_add_gpios(&smartq_jack,
204 ARRAY_SIZE(smartq_jack_gpios),
205 smartq_jack_gpios);
206
207 return err;
208}
209
210static struct snd_soc_dai_link smartq_dai[] = {
211 {
212 .name = "wm8987",
213 .stream_name = "SmartQ Hi-Fi",
214 .cpu_dai = &s3c64xx_i2s_dai[0],
215 .codec_dai = &wm8750_dai,
216 .init = smartq_wm8987_init,
217 .ops = &smartq_hifi_ops,
218 },
219};
220
221static struct snd_soc_card snd_soc_smartq = {
222 .name = "SmartQ",
223 .platform = &s3c24xx_soc_platform,
224 .dai_link = smartq_dai,
225 .num_links = ARRAY_SIZE(smartq_dai),
226};
227
228static struct snd_soc_device smartq_snd_devdata = {
229 .card = &snd_soc_smartq,
230 .codec_dev = &soc_codec_dev_wm8750,
231};
232
233static struct platform_device *smartq_snd_device;
234
235static int __init smartq_init(void)
236{
237 int ret;
238
239 if (!machine_is_smartq7() && !machine_is_smartq5()) {
240 pr_info("Only SmartQ is supported by this ASoC driver\n");
241 return -ENODEV;
242 }
243
244 smartq_snd_device = platform_device_alloc("soc-audio", -1);
245 if (!smartq_snd_device)
246 return -ENOMEM;
247
248 platform_set_drvdata(smartq_snd_device, &smartq_snd_devdata);
249 smartq_snd_devdata.dev = &smartq_snd_device->dev;
250
251 ret = platform_device_add(smartq_snd_device);
252 if (ret) {
253 platform_device_put(smartq_snd_device);
254 return ret;
255 }
256
257 /* Initialise GPIOs used by amplifiers */
258 ret = gpio_request(S3C64XX_GPK(12), "amplifiers shutdown");
259 if (ret) {
260 dev_err(&smartq_snd_device->dev, "Failed to register GPK12\n");
261 goto err_unregister_device;
262 }
263
264 /* Disable amplifiers */
265 ret = gpio_direction_output(S3C64XX_GPK(12), 1);
266 if (ret) {
267 dev_err(&smartq_snd_device->dev, "Failed to configure GPK12\n");
268 goto err_free_gpio_amp_shut;
269 }
270
271 return 0;
272
273err_free_gpio_amp_shut:
274 gpio_free(S3C64XX_GPK(12));
275err_unregister_device:
276 platform_device_unregister(smartq_snd_device);
277
278 return ret;
279}
280
281static void __exit smartq_exit(void)
282{
283 snd_soc_jack_free_gpios(&smartq_jack, ARRAY_SIZE(smartq_jack_gpios),
284 smartq_jack_gpios);
285
286 platform_device_unregister(smartq_snd_device);
287}
288
289module_init(smartq_init);
290module_exit(smartq_exit);
291
292/* Module information */
293MODULE_AUTHOR("Maurus Cuelenaere <mcuelenaere@gmail.com>");
294MODULE_DESCRIPTION("ALSA SoC SmartQ WM8987");
295MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/smdk_wm9713.c b/sound/soc/s3c24xx/smdk_wm9713.c
index 24fd39f38ccb..5527b9e88c98 100644
--- a/sound/soc/s3c24xx/smdk_wm9713.c
+++ b/sound/soc/s3c24xx/smdk_wm9713.c
@@ -25,6 +25,9 @@ static struct snd_soc_card smdk;
25 * Default CFG switch settings to use this driver: 25 * Default CFG switch settings to use this driver:
26 * 26 *
27 * SMDK6410: Set CFG1 1-3 On, CFG2 1-4 Off 27 * SMDK6410: Set CFG1 1-3 On, CFG2 1-4 Off
28 * SMDKC100: Set CFG6 1-3 On, CFG7 1 On
29 * SMDKC110: Set CFGB10 1-2 Off, CFGB12 1-3 On
30 * SMDKV210: Set CFGB10 1-2 Off, CFGB12 1-3 On
28 */ 31 */
29 32
30/* 33/*
diff --git a/sound/soc/s6000/s6000-i2s.c b/sound/soc/s6000/s6000-i2s.c
index 5b9ac1759bd2..59e3fa7bcb05 100644
--- a/sound/soc/s6000/s6000-i2s.c
+++ b/sound/soc/s6000/s6000-i2s.c
@@ -451,16 +451,15 @@ static int __devinit s6000_i2s_probe(struct platform_device *pdev)
451 goto err_release_none; 451 goto err_release_none;
452 } 452 }
453 453
454 region = request_mem_region(scbmem->start, 454 region = request_mem_region(scbmem->start, resource_size(scbmem),
455 scbmem->end - scbmem->start + 1, 455 pdev->name);
456 pdev->name);
457 if (!region) { 456 if (!region) {
458 dev_err(&pdev->dev, "I2S SCB region already claimed\n"); 457 dev_err(&pdev->dev, "I2S SCB region already claimed\n");
459 ret = -EBUSY; 458 ret = -EBUSY;
460 goto err_release_none; 459 goto err_release_none;
461 } 460 }
462 461
463 mmio = ioremap(scbmem->start, scbmem->end - scbmem->start + 1); 462 mmio = ioremap(scbmem->start, resource_size(scbmem));
464 if (!mmio) { 463 if (!mmio) {
465 dev_err(&pdev->dev, "can't ioremap SCB region\n"); 464 dev_err(&pdev->dev, "can't ioremap SCB region\n");
466 ret = -ENOMEM; 465 ret = -ENOMEM;
@@ -474,9 +473,8 @@ static int __devinit s6000_i2s_probe(struct platform_device *pdev)
474 goto err_release_map; 473 goto err_release_map;
475 } 474 }
476 475
477 region = request_mem_region(sifmem->start, 476 region = request_mem_region(sifmem->start, resource_size(sifmem),
478 sifmem->end - sifmem->start + 1, 477 pdev->name);
479 pdev->name);
480 if (!region) { 478 if (!region) {
481 dev_err(&pdev->dev, "I2S SIF region already claimed\n"); 479 dev_err(&pdev->dev, "I2S SIF region already claimed\n");
482 ret = -EBUSY; 480 ret = -EBUSY;
@@ -490,8 +488,8 @@ static int __devinit s6000_i2s_probe(struct platform_device *pdev)
490 goto err_release_sif; 488 goto err_release_sif;
491 } 489 }
492 490
493 region = request_mem_region(dma1->start, dma1->end - dma1->start + 1, 491 region = request_mem_region(dma1->start, resource_size(dma1),
494 pdev->name); 492 pdev->name);
495 if (!region) { 493 if (!region) {
496 dev_err(&pdev->dev, "I2S DMA region already claimed\n"); 494 dev_err(&pdev->dev, "I2S DMA region already claimed\n");
497 ret = -EBUSY; 495 ret = -EBUSY;
@@ -500,9 +498,8 @@ static int __devinit s6000_i2s_probe(struct platform_device *pdev)
500 498
501 dma2 = platform_get_resource(pdev, IORESOURCE_DMA, 1); 499 dma2 = platform_get_resource(pdev, IORESOURCE_DMA, 1);
502 if (dma2) { 500 if (dma2) {
503 region = request_mem_region(dma2->start, 501 region = request_mem_region(dma2->start, resource_size(dma2),
504 dma2->end - dma2->start + 1, 502 pdev->name);
505 pdev->name);
506 if (!region) { 503 if (!region) {
507 dev_err(&pdev->dev, 504 dev_err(&pdev->dev,
508 "I2S DMA region already claimed\n"); 505 "I2S DMA region already claimed\n");
@@ -561,15 +558,15 @@ err_release_dev:
561 kfree(dev); 558 kfree(dev);
562err_release_dma2: 559err_release_dma2:
563 if (dma2) 560 if (dma2)
564 release_mem_region(dma2->start, dma2->end - dma2->start + 1); 561 release_mem_region(dma2->start, resource_size(dma2));
565err_release_dma1: 562err_release_dma1:
566 release_mem_region(dma1->start, dma1->end - dma1->start + 1); 563 release_mem_region(dma1->start, resource_size(dma1));
567err_release_sif: 564err_release_sif:
568 release_mem_region(sifmem->start, (sifmem->end - sifmem->start) + 1); 565 release_mem_region(sifmem->start, resource_size(sifmem));
569err_release_map: 566err_release_map:
570 iounmap(mmio); 567 iounmap(mmio);
571err_release_scb: 568err_release_scb:
572 release_mem_region(scbmem->start, (scbmem->end - scbmem->start) + 1); 569 release_mem_region(scbmem->start, resource_size(scbmem));
573err_release_none: 570err_release_none:
574 return ret; 571 return ret;
575} 572}
@@ -590,19 +587,18 @@ static void __devexit s6000_i2s_remove(struct platform_device *pdev)
590 kfree(dev); 587 kfree(dev);
591 588
592 region = platform_get_resource(pdev, IORESOURCE_DMA, 0); 589 region = platform_get_resource(pdev, IORESOURCE_DMA, 0);
593 release_mem_region(region->start, region->end - region->start + 1); 590 release_mem_region(region->start, resource_size(region));
594 591
595 region = platform_get_resource(pdev, IORESOURCE_DMA, 1); 592 region = platform_get_resource(pdev, IORESOURCE_DMA, 1);
596 if (region) 593 if (region)
597 release_mem_region(region->start, 594 release_mem_region(region->start, resource_size(region));
598 region->end - region->start + 1);
599 595
600 region = platform_get_resource(pdev, IORESOURCE_MEM, 0); 596 region = platform_get_resource(pdev, IORESOURCE_MEM, 0);
601 release_mem_region(region->start, (region->end - region->start) + 1); 597 release_mem_region(region->start, resource_size(region));
602 598
603 iounmap(mmio); 599 iounmap(mmio);
604 region = platform_get_resource(pdev, IORESOURCE_IO, 0); 600 region = platform_get_resource(pdev, IORESOURCE_IO, 0);
605 release_mem_region(region->start, (region->end - region->start) + 1); 601 release_mem_region(region->start, resource_size(region));
606} 602}
607 603
608static struct platform_driver s6000_i2s_driver = { 604static struct platform_driver s6000_i2s_driver = {
diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig
index a1d14bc3c76f..52d7e8ed9c1f 100644
--- a/sound/soc/sh/Kconfig
+++ b/sound/soc/sh/Kconfig
@@ -48,7 +48,7 @@ config SND_SH7760_AC97
48 48
49config SND_FSI_AK4642 49config SND_FSI_AK4642
50 bool "FSI-AK4642 sound support" 50 bool "FSI-AK4642 sound support"
51 depends on SND_SOC_SH4_FSI 51 depends on SND_SOC_SH4_FSI && I2C_SH_MOBILE
52 select SND_SOC_AK4642 52 select SND_SOC_AK4642
53 help 53 help
54 This option enables generic sound support for the 54 This option enables generic sound support for the
@@ -56,7 +56,7 @@ config SND_FSI_AK4642
56 56
57config SND_FSI_DA7210 57config SND_FSI_DA7210
58 bool "FSI-DA7210 sound support" 58 bool "FSI-DA7210 sound support"
59 depends on SND_SOC_SH4_FSI 59 depends on SND_SOC_SH4_FSI && I2C_SH_MOBILE
60 select SND_SOC_DA7210 60 select SND_SOC_DA7210
61 help 61 help
62 This option enables generic sound support for the 62 This option enables generic sound support for the
diff --git a/sound/soc/sh/fsi-ak4642.c b/sound/soc/sh/fsi-ak4642.c
index be018542314e..dad575a22622 100644
--- a/sound/soc/sh/fsi-ak4642.c
+++ b/sound/soc/sh/fsi-ak4642.c
@@ -9,16 +9,7 @@
9 * for more details. 9 * for more details.
10 */ 10 */
11 11
12#include <linux/module.h>
13#include <linux/moduleparam.h>
14#include <linux/platform_device.h> 12#include <linux/platform_device.h>
15#include <linux/i2c.h>
16#include <linux/io.h>
17#include <sound/core.h>
18#include <sound/pcm.h>
19#include <sound/soc.h>
20#include <sound/soc-dapm.h>
21
22#include <sound/sh_fsi.h> 13#include <sound/sh_fsi.h>
23#include <../sound/soc/codecs/ak4642.h> 14#include <../sound/soc/codecs/ak4642.h>
24 15
@@ -38,7 +29,7 @@ static int fsi_ak4642_dai_init(struct snd_soc_codec *codec)
38static struct snd_soc_dai_link fsi_dai_link = { 29static struct snd_soc_dai_link fsi_dai_link = {
39 .name = "AK4642", 30 .name = "AK4642",
40 .stream_name = "AK4642", 31 .stream_name = "AK4642",
41 .cpu_dai = &fsi_soc_dai[0], /* fsi */ 32 .cpu_dai = &fsi_soc_dai[FSI_PORT_A],
42 .codec_dai = &ak4642_dai, 33 .codec_dai = &ak4642_dai,
43 .init = fsi_ak4642_dai_init, 34 .init = fsi_ak4642_dai_init,
44 .ops = NULL, 35 .ops = NULL,
@@ -62,7 +53,7 @@ static int __init fsi_ak4642_init(void)
62{ 53{
63 int ret = -ENOMEM; 54 int ret = -ENOMEM;
64 55
65 fsi_snd_device = platform_device_alloc("soc-audio", -1); 56 fsi_snd_device = platform_device_alloc("soc-audio", FSI_PORT_A);
66 if (!fsi_snd_device) 57 if (!fsi_snd_device)
67 goto out; 58 goto out;
68 59
diff --git a/sound/soc/sh/fsi-da7210.c b/sound/soc/sh/fsi-da7210.c
index 33b4d177f466..121bbb07bb03 100644
--- a/sound/soc/sh/fsi-da7210.c
+++ b/sound/soc/sh/fsi-da7210.c
@@ -10,16 +10,7 @@
10 * option) any later version. 10 * option) any later version.
11 */ 11 */
12 12
13#include <linux/interrupt.h>
14#include <linux/platform_device.h> 13#include <linux/platform_device.h>
15#include <linux/io.h>
16#include <linux/i2c.h>
17#include <sound/core.h>
18#include <sound/pcm.h>
19#include <sound/pcm_params.h>
20#include <sound/soc.h>
21#include <sound/soc-dapm.h>
22
23#include <sound/sh_fsi.h> 14#include <sound/sh_fsi.h>
24#include "../codecs/da7210.h" 15#include "../codecs/da7210.h"
25 16
@@ -33,7 +24,7 @@ static int fsi_da7210_init(struct snd_soc_codec *codec)
33static struct snd_soc_dai_link fsi_da7210_dai = { 24static struct snd_soc_dai_link fsi_da7210_dai = {
34 .name = "DA7210", 25 .name = "DA7210",
35 .stream_name = "DA7210", 26 .stream_name = "DA7210",
36 .cpu_dai = &fsi_soc_dai[1], /* FSI B */ 27 .cpu_dai = &fsi_soc_dai[FSI_PORT_B],
37 .codec_dai = &da7210_dai, 28 .codec_dai = &da7210_dai,
38 .init = fsi_da7210_init, 29 .init = fsi_da7210_init,
39}; 30};
@@ -56,7 +47,7 @@ static int __init fsi_da7210_sound_init(void)
56{ 47{
57 int ret; 48 int ret;
58 49
59 fsi_da7210_snd_device = platform_device_alloc("soc-audio", -1); 50 fsi_da7210_snd_device = platform_device_alloc("soc-audio", FSI_PORT_B);
60 if (!fsi_da7210_snd_device) 51 if (!fsi_da7210_snd_device)
61 return -ENOMEM; 52 return -ENOMEM;
62 53
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c
index ec4acac49ebd..58c6bec642de 100644
--- a/sound/soc/sh/fsi.c
+++ b/sound/soc/sh/fsi.c
@@ -12,21 +12,12 @@
12 * published by the Free Software Foundation. 12 * published by the Free Software Foundation.
13 */ 13 */
14 14
15#include <linux/init.h>
16#include <linux/module.h>
17#include <linux/platform_device.h>
18#include <linux/delay.h> 15#include <linux/delay.h>
19#include <linux/list.h>
20#include <linux/pm_runtime.h> 16#include <linux/pm_runtime.h>
21#include <linux/io.h> 17#include <linux/io.h>
22#include <linux/slab.h> 18#include <linux/slab.h>
23#include <sound/core.h>
24#include <sound/pcm.h>
25#include <sound/initval.h>
26#include <sound/soc.h> 19#include <sound/soc.h>
27#include <sound/pcm_params.h>
28#include <sound/sh_fsi.h> 20#include <sound/sh_fsi.h>
29#include <asm/atomic.h>
30 21
31#define DO_FMT 0x0000 22#define DO_FMT 0x0000
32#define DOFF_CTL 0x0004 23#define DOFF_CTL 0x0004
@@ -39,9 +30,11 @@
39#define DIDT 0x0020 30#define DIDT 0x0020
40#define DODT 0x0024 31#define DODT 0x0024
41#define MUTE_ST 0x0028 32#define MUTE_ST 0x0028
42#define REG_END MUTE_ST 33#define OUT_SEL 0x0030
43 34#define REG_END OUT_SEL
44 35
36#define A_MST_CTLR 0x0180
37#define B_MST_CTLR 0x01A0
45#define CPU_INT_ST 0x01F4 38#define CPU_INT_ST 0x01F4
46#define CPU_IEMSK 0x01F8 39#define CPU_IEMSK 0x01F8
47#define CPU_IMSK 0x01FC 40#define CPU_IMSK 0x01FC
@@ -52,18 +45,18 @@
52#define CLK_RST 0x0210 45#define CLK_RST 0x0210
53#define SOFT_RST 0x0214 46#define SOFT_RST 0x0214
54#define FIFO_SZ 0x0218 47#define FIFO_SZ 0x0218
55#define MREG_START CPU_INT_ST 48#define MREG_START A_MST_CTLR
56#define MREG_END FIFO_SZ 49#define MREG_END FIFO_SZ
57 50
58/* DO_FMT */ 51/* DO_FMT */
59/* DI_FMT */ 52/* DI_FMT */
60#define CR_FMT(param) ((param) << 4) 53#define CR_MONO (0x0 << 4)
61# define CR_MONO 0x0 54#define CR_MONO_D (0x1 << 4)
62# define CR_MONO_D 0x1 55#define CR_PCM (0x2 << 4)
63# define CR_PCM 0x2 56#define CR_I2S (0x3 << 4)
64# define CR_I2S 0x3 57#define CR_TDM (0x4 << 4)
65# define CR_TDM 0x4 58#define CR_TDM_D (0x5 << 4)
66# define CR_TDM_D 0x5 59#define CR_SPDIF 0x00100120
67 60
68/* DOFF_CTL */ 61/* DOFF_CTL */
69/* DIFF_CTL */ 62/* DIFF_CTL */
@@ -75,6 +68,14 @@
75#define ERR_UNDER 0x00000001 68#define ERR_UNDER 0x00000001
76#define ST_ERR (ERR_OVER | ERR_UNDER) 69#define ST_ERR (ERR_OVER | ERR_UNDER)
77 70
71/* CKG1 */
72#define ACKMD_MASK 0x00007000
73#define BPFMD_MASK 0x00000700
74
75/* A/B MST_CTLR */
76#define BP (1 << 4) /* Fix the signal of Biphase output */
77#define SE (1 << 0) /* Fix the master clock */
78
78/* CLK_RST */ 79/* CLK_RST */
79#define B_CLK 0x00000010 80#define B_CLK 0x00000010
80#define A_CLK 0x00000001 81#define A_CLK 0x00000001
@@ -119,9 +120,13 @@ struct fsi_priv {
119 int period_len; 120 int period_len;
120 int buffer_len; 121 int buffer_len;
121 int periods; 122 int periods;
123
124 u32 mst_ctrl;
122}; 125};
123 126
124struct fsi_regs { 127struct fsi_core {
128 int ver;
129
125 u32 int_st; 130 u32 int_st;
126 u32 iemsk; 131 u32 iemsk;
127 u32 imsk; 132 u32 imsk;
@@ -132,7 +137,7 @@ struct fsi_master {
132 int irq; 137 int irq;
133 struct fsi_priv fsia; 138 struct fsi_priv fsia;
134 struct fsi_priv fsib; 139 struct fsi_priv fsib;
135 struct fsi_regs *regs; 140 struct fsi_core *core;
136 struct sh_fsi_platform_info *info; 141 struct sh_fsi_platform_info *info;
137 spinlock_t lock; 142 spinlock_t lock;
138}; 143};
@@ -169,24 +174,30 @@ static void __fsi_reg_mask_set(u32 reg, u32 mask, u32 data)
169 174
170static void fsi_reg_write(struct fsi_priv *fsi, u32 reg, u32 data) 175static void fsi_reg_write(struct fsi_priv *fsi, u32 reg, u32 data)
171{ 176{
172 if (reg > REG_END) 177 if (reg > REG_END) {
178 pr_err("fsi: register access err (%s)\n", __func__);
173 return; 179 return;
180 }
174 181
175 __fsi_reg_write((u32)(fsi->base + reg), data); 182 __fsi_reg_write((u32)(fsi->base + reg), data);
176} 183}
177 184
178static u32 fsi_reg_read(struct fsi_priv *fsi, u32 reg) 185static u32 fsi_reg_read(struct fsi_priv *fsi, u32 reg)
179{ 186{
180 if (reg > REG_END) 187 if (reg > REG_END) {
188 pr_err("fsi: register access err (%s)\n", __func__);
181 return 0; 189 return 0;
190 }
182 191
183 return __fsi_reg_read((u32)(fsi->base + reg)); 192 return __fsi_reg_read((u32)(fsi->base + reg));
184} 193}
185 194
186static void fsi_reg_mask_set(struct fsi_priv *fsi, u32 reg, u32 mask, u32 data) 195static void fsi_reg_mask_set(struct fsi_priv *fsi, u32 reg, u32 mask, u32 data)
187{ 196{
188 if (reg > REG_END) 197 if (reg > REG_END) {
198 pr_err("fsi: register access err (%s)\n", __func__);
189 return; 199 return;
200 }
190 201
191 __fsi_reg_mask_set((u32)(fsi->base + reg), mask, data); 202 __fsi_reg_mask_set((u32)(fsi->base + reg), mask, data);
192} 203}
@@ -196,8 +207,10 @@ static void fsi_master_write(struct fsi_master *master, u32 reg, u32 data)
196 unsigned long flags; 207 unsigned long flags;
197 208
198 if ((reg < MREG_START) || 209 if ((reg < MREG_START) ||
199 (reg > MREG_END)) 210 (reg > MREG_END)) {
211 pr_err("fsi: register access err (%s)\n", __func__);
200 return; 212 return;
213 }
201 214
202 spin_lock_irqsave(&master->lock, flags); 215 spin_lock_irqsave(&master->lock, flags);
203 __fsi_reg_write((u32)(master->base + reg), data); 216 __fsi_reg_write((u32)(master->base + reg), data);
@@ -210,8 +223,10 @@ static u32 fsi_master_read(struct fsi_master *master, u32 reg)
210 unsigned long flags; 223 unsigned long flags;
211 224
212 if ((reg < MREG_START) || 225 if ((reg < MREG_START) ||
213 (reg > MREG_END)) 226 (reg > MREG_END)) {
227 pr_err("fsi: register access err (%s)\n", __func__);
214 return 0; 228 return 0;
229 }
215 230
216 spin_lock_irqsave(&master->lock, flags); 231 spin_lock_irqsave(&master->lock, flags);
217 ret = __fsi_reg_read((u32)(master->base + reg)); 232 ret = __fsi_reg_read((u32)(master->base + reg));
@@ -226,8 +241,10 @@ static void fsi_master_mask_set(struct fsi_master *master,
226 unsigned long flags; 241 unsigned long flags;
227 242
228 if ((reg < MREG_START) || 243 if ((reg < MREG_START) ||
229 (reg > MREG_END)) 244 (reg > MREG_END)) {
245 pr_err("fsi: register access err (%s)\n", __func__);
230 return; 246 return;
247 }
231 248
232 spin_lock_irqsave(&master->lock, flags); 249 spin_lock_irqsave(&master->lock, flags);
233 __fsi_reg_mask_set((u32)(master->base + reg), mask, data); 250 __fsi_reg_mask_set((u32)(master->base + reg), mask, data);
@@ -349,8 +366,8 @@ static void fsi_irq_enable(struct fsi_priv *fsi, int is_play)
349 u32 data = fsi_port_ab_io_bit(fsi, is_play); 366 u32 data = fsi_port_ab_io_bit(fsi, is_play);
350 struct fsi_master *master = fsi_get_master(fsi); 367 struct fsi_master *master = fsi_get_master(fsi);
351 368
352 fsi_master_mask_set(master, master->regs->imsk, data, data); 369 fsi_master_mask_set(master, master->core->imsk, data, data);
353 fsi_master_mask_set(master, master->regs->iemsk, data, data); 370 fsi_master_mask_set(master, master->core->iemsk, data, data);
354} 371}
355 372
356static void fsi_irq_disable(struct fsi_priv *fsi, int is_play) 373static void fsi_irq_disable(struct fsi_priv *fsi, int is_play)
@@ -358,18 +375,18 @@ static void fsi_irq_disable(struct fsi_priv *fsi, int is_play)
358 u32 data = fsi_port_ab_io_bit(fsi, is_play); 375 u32 data = fsi_port_ab_io_bit(fsi, is_play);
359 struct fsi_master *master = fsi_get_master(fsi); 376 struct fsi_master *master = fsi_get_master(fsi);
360 377
361 fsi_master_mask_set(master, master->regs->imsk, data, 0); 378 fsi_master_mask_set(master, master->core->imsk, data, 0);
362 fsi_master_mask_set(master, master->regs->iemsk, data, 0); 379 fsi_master_mask_set(master, master->core->iemsk, data, 0);
363} 380}
364 381
365static u32 fsi_irq_get_status(struct fsi_master *master) 382static u32 fsi_irq_get_status(struct fsi_master *master)
366{ 383{
367 return fsi_master_read(master, master->regs->int_st); 384 return fsi_master_read(master, master->core->int_st);
368} 385}
369 386
370static void fsi_irq_clear_all_status(struct fsi_master *master) 387static void fsi_irq_clear_all_status(struct fsi_master *master)
371{ 388{
372 fsi_master_write(master, master->regs->int_st, 0x0000000); 389 fsi_master_write(master, master->core->int_st, 0);
373} 390}
374 391
375static void fsi_irq_clear_status(struct fsi_priv *fsi) 392static void fsi_irq_clear_status(struct fsi_priv *fsi)
@@ -381,7 +398,30 @@ static void fsi_irq_clear_status(struct fsi_priv *fsi)
381 data |= fsi_port_ab_io_bit(fsi, 1); 398 data |= fsi_port_ab_io_bit(fsi, 1);
382 399
383 /* clear interrupt factor */ 400 /* clear interrupt factor */
384 fsi_master_mask_set(master, master->regs->int_st, data, 0); 401 fsi_master_mask_set(master, master->core->int_st, data, 0);
402}
403
404/************************************************************************
405
406
407 SPDIF master clock function
408
409These functions are used later FSI2
410************************************************************************/
411static void fsi_spdif_clk_ctrl(struct fsi_priv *fsi, int enable)
412{
413 struct fsi_master *master = fsi_get_master(fsi);
414 u32 val = BP | SE;
415
416 if (master->core->ver < 2) {
417 pr_err("fsi: register access err (%s)\n", __func__);
418 return;
419 }
420
421 if (enable)
422 fsi_master_mask_set(master, fsi->mst_ctrl, val, val);
423 else
424 fsi_master_mask_set(master, fsi->mst_ctrl, val, 0);
385} 425}
386 426
387/************************************************************************ 427/************************************************************************
@@ -662,8 +702,8 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream,
662 struct snd_soc_dai *dai) 702 struct snd_soc_dai *dai)
663{ 703{
664 struct fsi_priv *fsi = fsi_get_priv(substream); 704 struct fsi_priv *fsi = fsi_get_priv(substream);
665 const char *msg;
666 u32 flags = fsi_get_info_flags(fsi); 705 u32 flags = fsi_get_info_flags(fsi);
706 struct fsi_master *master = fsi_get_master(fsi);
667 u32 fmt; 707 u32 fmt;
668 u32 reg; 708 u32 reg;
669 u32 data; 709 u32 data;
@@ -700,36 +740,40 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream,
700 fmt = is_play ? SH_FSI_GET_OFMT(flags) : SH_FSI_GET_IFMT(flags); 740 fmt = is_play ? SH_FSI_GET_OFMT(flags) : SH_FSI_GET_IFMT(flags);
701 switch (fmt) { 741 switch (fmt) {
702 case SH_FSI_FMT_MONO: 742 case SH_FSI_FMT_MONO:
703 msg = "MONO"; 743 data = CR_MONO;
704 data = CR_FMT(CR_MONO);
705 fsi->chan = 1; 744 fsi->chan = 1;
706 break; 745 break;
707 case SH_FSI_FMT_MONO_DELAY: 746 case SH_FSI_FMT_MONO_DELAY:
708 msg = "MONO Delay"; 747 data = CR_MONO_D;
709 data = CR_FMT(CR_MONO_D);
710 fsi->chan = 1; 748 fsi->chan = 1;
711 break; 749 break;
712 case SH_FSI_FMT_PCM: 750 case SH_FSI_FMT_PCM:
713 msg = "PCM"; 751 data = CR_PCM;
714 data = CR_FMT(CR_PCM);
715 fsi->chan = 2; 752 fsi->chan = 2;
716 break; 753 break;
717 case SH_FSI_FMT_I2S: 754 case SH_FSI_FMT_I2S:
718 msg = "I2S"; 755 data = CR_I2S;
719 data = CR_FMT(CR_I2S);
720 fsi->chan = 2; 756 fsi->chan = 2;
721 break; 757 break;
722 case SH_FSI_FMT_TDM: 758 case SH_FSI_FMT_TDM:
723 msg = "TDM";
724 fsi->chan = is_play ? 759 fsi->chan = is_play ?
725 SH_FSI_GET_CH_O(flags) : SH_FSI_GET_CH_I(flags); 760 SH_FSI_GET_CH_O(flags) : SH_FSI_GET_CH_I(flags);
726 data = CR_FMT(CR_TDM) | (fsi->chan - 1); 761 data = CR_TDM | (fsi->chan - 1);
727 break; 762 break;
728 case SH_FSI_FMT_TDM_DELAY: 763 case SH_FSI_FMT_TDM_DELAY:
729 msg = "TDM Delay";
730 fsi->chan = is_play ? 764 fsi->chan = is_play ?
731 SH_FSI_GET_CH_O(flags) : SH_FSI_GET_CH_I(flags); 765 SH_FSI_GET_CH_O(flags) : SH_FSI_GET_CH_I(flags);
732 data = CR_FMT(CR_TDM_D) | (fsi->chan - 1); 766 data = CR_TDM_D | (fsi->chan - 1);
767 break;
768 case SH_FSI_FMT_SPDIF:
769 if (master->core->ver < 2) {
770 dev_err(dai->dev, "This FSI can not use SPDIF\n");
771 return -EINVAL;
772 }
773 data = CR_SPDIF;
774 fsi->chan = 2;
775 fsi_spdif_clk_ctrl(fsi, 1);
776 fsi_reg_mask_set(fsi, OUT_SEL, 0x0010, 0x0010);
733 break; 777 break;
734 default: 778 default:
735 dev_err(dai->dev, "unknown format.\n"); 779 dev_err(dai->dev, "unknown format.\n");
@@ -737,12 +781,6 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream,
737 } 781 }
738 fsi_reg_write(fsi, reg, data); 782 fsi_reg_write(fsi, reg, data);
739 783
740 /*
741 * clear clk reset if master mode
742 */
743 if (is_master)
744 fsi_clk_ctrl(fsi, 1);
745
746 /* irq clear */ 784 /* irq clear */
747 fsi_irq_disable(fsi, is_play); 785 fsi_irq_disable(fsi, is_play);
748 fsi_irq_clear_status(fsi); 786 fsi_irq_clear_status(fsi);
@@ -789,10 +827,93 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
789 return ret; 827 return ret;
790} 828}
791 829
830static int fsi_dai_hw_params(struct snd_pcm_substream *substream,
831 struct snd_pcm_hw_params *params,
832 struct snd_soc_dai *dai)
833{
834 struct fsi_priv *fsi = fsi_get_priv(substream);
835 struct fsi_master *master = fsi_get_master(fsi);
836 int (*set_rate)(int is_porta, int rate) = master->info->set_rate;
837 int fsi_ver = master->core->ver;
838 int is_play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
839 int ret;
840
841 /* if slave mode, set_rate is not needed */
842 if (!fsi_is_master_mode(fsi, is_play))
843 return 0;
844
845 /* it is error if no set_rate */
846 if (!set_rate)
847 return -EIO;
848
849 ret = set_rate(fsi_is_port_a(fsi), params_rate(params));
850 if (ret > 0) {
851 u32 data = 0;
852
853 switch (ret & SH_FSI_ACKMD_MASK) {
854 default:
855 /* FALL THROUGH */
856 case SH_FSI_ACKMD_512:
857 data |= (0x0 << 12);
858 break;
859 case SH_FSI_ACKMD_256:
860 data |= (0x1 << 12);
861 break;
862 case SH_FSI_ACKMD_128:
863 data |= (0x2 << 12);
864 break;
865 case SH_FSI_ACKMD_64:
866 data |= (0x3 << 12);
867 break;
868 case SH_FSI_ACKMD_32:
869 if (fsi_ver < 2)
870 dev_err(dai->dev, "unsupported ACKMD\n");
871 else
872 data |= (0x4 << 12);
873 break;
874 }
875
876 switch (ret & SH_FSI_BPFMD_MASK) {
877 default:
878 /* FALL THROUGH */
879 case SH_FSI_BPFMD_32:
880 data |= (0x0 << 8);
881 break;
882 case SH_FSI_BPFMD_64:
883 data |= (0x1 << 8);
884 break;
885 case SH_FSI_BPFMD_128:
886 data |= (0x2 << 8);
887 break;
888 case SH_FSI_BPFMD_256:
889 data |= (0x3 << 8);
890 break;
891 case SH_FSI_BPFMD_512:
892 data |= (0x4 << 8);
893 break;
894 case SH_FSI_BPFMD_16:
895 if (fsi_ver < 2)
896 dev_err(dai->dev, "unsupported ACKMD\n");
897 else
898 data |= (0x7 << 8);
899 break;
900 }
901
902 fsi_reg_mask_set(fsi, CKG1, (ACKMD_MASK | BPFMD_MASK) , data);
903 udelay(10);
904 fsi_clk_ctrl(fsi, 1);
905 ret = 0;
906 }
907
908 return ret;
909
910}
911
792static struct snd_soc_dai_ops fsi_dai_ops = { 912static struct snd_soc_dai_ops fsi_dai_ops = {
793 .startup = fsi_dai_startup, 913 .startup = fsi_dai_startup,
794 .shutdown = fsi_dai_shutdown, 914 .shutdown = fsi_dai_shutdown,
795 .trigger = fsi_dai_trigger, 915 .trigger = fsi_dai_trigger,
916 .hw_params = fsi_dai_hw_params,
796}; 917};
797 918
798/************************************************************************ 919/************************************************************************
@@ -965,11 +1086,6 @@ static int fsi_probe(struct platform_device *pdev)
965 unsigned int irq; 1086 unsigned int irq;
966 int ret; 1087 int ret;
967 1088
968 if (0 != pdev->id) {
969 dev_err(&pdev->dev, "current fsi support id 0 only now\n");
970 return -ENODEV;
971 }
972
973 id_entry = pdev->id_entry; 1089 id_entry = pdev->id_entry;
974 if (!id_entry) { 1090 if (!id_entry) {
975 dev_err(&pdev->dev, "unknown fsi device\n"); 1091 dev_err(&pdev->dev, "unknown fsi device\n");
@@ -998,14 +1114,21 @@ static int fsi_probe(struct platform_device *pdev)
998 goto exit_kfree; 1114 goto exit_kfree;
999 } 1115 }
1000 1116
1117 /* master setting */
1001 master->irq = irq; 1118 master->irq = irq;
1002 master->info = pdev->dev.platform_data; 1119 master->info = pdev->dev.platform_data;
1120 master->core = (struct fsi_core *)id_entry->driver_data;
1121 spin_lock_init(&master->lock);
1122
1123 /* FSI A setting */
1003 master->fsia.base = master->base; 1124 master->fsia.base = master->base;
1004 master->fsia.master = master; 1125 master->fsia.master = master;
1126 master->fsia.mst_ctrl = A_MST_CTLR;
1127
1128 /* FSI B setting */
1005 master->fsib.base = master->base + 0x40; 1129 master->fsib.base = master->base + 0x40;
1006 master->fsib.master = master; 1130 master->fsib.master = master;
1007 master->regs = (struct fsi_regs *)id_entry->driver_data; 1131 master->fsib.mst_ctrl = B_MST_CTLR;
1008 spin_lock_init(&master->lock);
1009 1132
1010 pm_runtime_enable(&pdev->dev); 1133 pm_runtime_enable(&pdev->dev);
1011 pm_runtime_resume(&pdev->dev); 1134 pm_runtime_resume(&pdev->dev);
@@ -1085,21 +1208,27 @@ static struct dev_pm_ops fsi_pm_ops = {
1085 .runtime_resume = fsi_runtime_nop, 1208 .runtime_resume = fsi_runtime_nop,
1086}; 1209};
1087 1210
1088static struct fsi_regs fsi_regs = { 1211static struct fsi_core fsi1_core = {
1212 .ver = 1,
1213
1214 /* Interrupt */
1089 .int_st = INT_ST, 1215 .int_st = INT_ST,
1090 .iemsk = IEMSK, 1216 .iemsk = IEMSK,
1091 .imsk = IMSK, 1217 .imsk = IMSK,
1092}; 1218};
1093 1219
1094static struct fsi_regs fsi2_regs = { 1220static struct fsi_core fsi2_core = {
1221 .ver = 2,
1222
1223 /* Interrupt */
1095 .int_st = CPU_INT_ST, 1224 .int_st = CPU_INT_ST,
1096 .iemsk = CPU_IEMSK, 1225 .iemsk = CPU_IEMSK,
1097 .imsk = CPU_IMSK, 1226 .imsk = CPU_IMSK,
1098}; 1227};
1099 1228
1100static struct platform_device_id fsi_id_table[] = { 1229static struct platform_device_id fsi_id_table[] = {
1101 { "sh_fsi", (kernel_ulong_t)&fsi_regs }, 1230 { "sh_fsi", (kernel_ulong_t)&fsi1_core },
1102 { "sh_fsi2", (kernel_ulong_t)&fsi2_regs }, 1231 { "sh_fsi2", (kernel_ulong_t)&fsi2_core },
1103}; 1232};
1104 1233
1105static struct platform_driver fsi_driver = { 1234static struct platform_driver fsi_driver = {
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 998569d60330..5299932db0b6 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -84,7 +84,7 @@ static int run_delayed_work(struct delayed_work *dwork)
84/* codec register dump */ 84/* codec register dump */
85static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf) 85static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf)
86{ 86{
87 int i, step = 1, count = 0; 87 int ret, i, step = 1, count = 0;
88 88
89 if (!codec->reg_cache_size) 89 if (!codec->reg_cache_size)
90 return 0; 90 return 0;
@@ -101,12 +101,24 @@ static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf)
101 if (count >= PAGE_SIZE - 1) 101 if (count >= PAGE_SIZE - 1)
102 break; 102 break;
103 103
104 if (codec->display_register) 104 if (codec->display_register) {
105 count += codec->display_register(codec, buf + count, 105 count += codec->display_register(codec, buf + count,
106 PAGE_SIZE - count, i); 106 PAGE_SIZE - count, i);
107 else 107 } else {
108 count += snprintf(buf + count, PAGE_SIZE - count, 108 /* If the read fails it's almost certainly due to
109 "%4x", codec->read(codec, i)); 109 * the register being volatile and the device being
110 * powered off.
111 */
112 ret = codec->read(codec, i);
113 if (ret >= 0)
114 count += snprintf(buf + count,
115 PAGE_SIZE - count,
116 "%4x", ret);
117 else
118 count += snprintf(buf + count,
119 PAGE_SIZE - count,
120 "<no data: %d>", ret);
121 }
110 122
111 if (count >= PAGE_SIZE - 1) 123 if (count >= PAGE_SIZE - 1)
112 break; 124 break;
@@ -2353,6 +2365,99 @@ int snd_soc_limit_volume(struct snd_soc_codec *codec,
2353EXPORT_SYMBOL_GPL(snd_soc_limit_volume); 2365EXPORT_SYMBOL_GPL(snd_soc_limit_volume);
2354 2366
2355/** 2367/**
2368 * snd_soc_info_volsw_2r_sx - double with tlv and variable data size
2369 * mixer info callback
2370 * @kcontrol: mixer control
2371 * @uinfo: control element information
2372 *
2373 * Returns 0 for success.
2374 */
2375int snd_soc_info_volsw_2r_sx(struct snd_kcontrol *kcontrol,
2376 struct snd_ctl_elem_info *uinfo)
2377{
2378 struct soc_mixer_control *mc =
2379 (struct soc_mixer_control *)kcontrol->private_value;
2380 int max = mc->max;
2381 int min = mc->min;
2382
2383 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
2384 uinfo->count = 2;
2385 uinfo->value.integer.min = 0;
2386 uinfo->value.integer.max = max-min;
2387
2388 return 0;
2389}
2390EXPORT_SYMBOL_GPL(snd_soc_info_volsw_2r_sx);
2391
2392/**
2393 * snd_soc_get_volsw_2r_sx - double with tlv and variable data size
2394 * mixer get callback
2395 * @kcontrol: mixer control
2396 * @uinfo: control element information
2397 *
2398 * Returns 0 for success.
2399 */
2400int snd_soc_get_volsw_2r_sx(struct snd_kcontrol *kcontrol,
2401 struct snd_ctl_elem_value *ucontrol)
2402{
2403 struct soc_mixer_control *mc =
2404 (struct soc_mixer_control *)kcontrol->private_value;
2405 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
2406 unsigned int mask = (1<<mc->shift)-1;
2407 int min = mc->min;
2408 int val = snd_soc_read(codec, mc->reg) & mask;
2409 int valr = snd_soc_read(codec, mc->rreg) & mask;
2410
2411 ucontrol->value.integer.value[0] = ((val & 0xff)-min) & mask;
2412 ucontrol->value.integer.value[1] = ((valr & 0xff)-min) & mask;
2413 return 0;
2414}
2415EXPORT_SYMBOL_GPL(snd_soc_get_volsw_2r_sx);
2416
2417/**
2418 * snd_soc_put_volsw_2r_sx - double with tlv and variable data size
2419 * mixer put callback
2420 * @kcontrol: mixer control
2421 * @uinfo: control element information
2422 *
2423 * Returns 0 for success.
2424 */
2425int snd_soc_put_volsw_2r_sx(struct snd_kcontrol *kcontrol,
2426 struct snd_ctl_elem_value *ucontrol)
2427{
2428 struct soc_mixer_control *mc =
2429 (struct soc_mixer_control *)kcontrol->private_value;
2430 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
2431 unsigned int mask = (1<<mc->shift)-1;
2432 int min = mc->min;
2433 int ret;
2434 unsigned int val, valr, oval, ovalr;
2435
2436 val = ((ucontrol->value.integer.value[0]+min) & 0xff);
2437 val &= mask;
2438 valr = ((ucontrol->value.integer.value[1]+min) & 0xff);
2439 valr &= mask;
2440
2441 oval = snd_soc_read(codec, mc->reg) & mask;
2442 ovalr = snd_soc_read(codec, mc->rreg) & mask;
2443
2444 ret = 0;
2445 if (oval != val) {
2446 ret = snd_soc_write(codec, mc->reg, val);
2447 if (ret < 0)
2448 return ret;
2449 }
2450 if (ovalr != valr) {
2451 ret = snd_soc_write(codec, mc->rreg, valr);
2452 if (ret < 0)
2453 return ret;
2454 }
2455
2456 return 0;
2457}
2458EXPORT_SYMBOL_GPL(snd_soc_put_volsw_2r_sx);
2459
2460/**
2356 * snd_soc_dai_set_sysclk - configure DAI system or master clock. 2461 * snd_soc_dai_set_sysclk - configure DAI system or master clock.
2357 * @dai: DAI 2462 * @dai: DAI
2358 * @clk_id: DAI specific clock ID 2463 * @clk_id: DAI specific clock ID