aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
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.c15
-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/Kconfig16
-rw-r--r--sound/soc/codecs/Makefile4
-rw-r--r--sound/soc/codecs/ad193x.c41
-rw-r--r--sound/soc/codecs/ad193x.h5
-rw-r--r--sound/soc/codecs/ak4642.c32
-rw-r--r--sound/soc/codecs/cs42l51.c763
-rw-r--r--sound/soc/codecs/cs42l51.h163
-rw-r--r--sound/soc/codecs/da7210.c9
-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.c57
-rw-r--r--sound/soc/codecs/twl4030.c291
-rw-r--r--sound/soc/codecs/twl4030.h3
-rw-r--r--sound/soc/codecs/twl6040.c2
-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/wm8750.c11
-rw-r--r--sound/soc/codecs/wm8960.c99
-rw-r--r--sound/soc/codecs/wm8990.c4
-rw-r--r--sound/soc/codecs/wm8994.c43
-rw-r--r--sound/soc/codecs/wm8994.h3
-rw-r--r--sound/soc/davinci/davinci-i2s.c153
-rw-r--r--sound/soc/davinci/davinci-i2s.h5
-rw-r--r--sound/soc/davinci/davinci-pcm.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.c136
-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.c112
-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/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.c9
-rw-r--r--sound/soc/sh/fsi-da7210.c9
-rw-r--r--sound/soc/sh/fsi.c199
-rw-r--r--sound/soc/soc-core.c93
85 files changed, 7504 insertions, 418 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 495be6e71931..6083fe7799fa 100644
--- a/sound/soc/au1x/psc-i2s.c
+++ b/sound/soc/au1x/psc-i2s.c
@@ -300,7 +300,7 @@ struct snd_soc_dai au1xpsc_i2s_dai = {
300}; 300};
301EXPORT_SYMBOL(au1xpsc_i2s_dai); 301EXPORT_SYMBOL(au1xpsc_i2s_dai);
302 302
303static int __init au1xpsc_i2s_drvprobe(struct platform_device *pdev) 303static int __devinit au1xpsc_i2s_drvprobe(struct platform_device *pdev)
304{ 304{
305 struct resource *r; 305 struct resource *r;
306 unsigned long sel; 306 unsigned long sel;
@@ -321,12 +321,10 @@ static int __init 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 __init 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 31ac5538fe7e..ea1f5edde3d6 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
@@ -120,13 +122,13 @@ config SND_SOC_AK4671
120config SND_SOC_CQ0093VC 122config SND_SOC_CQ0093VC
121 tristate 123 tristate
122 124
125config SND_SOC_CS42L51
126 tristate
127
123# Cirrus Logic CS4270 Codec 128# Cirrus Logic CS4270 Codec
124config SND_SOC_CS4270 129config SND_SOC_CS4270
125 tristate 130 tristate
126 131
127config SND_SOC_DA7210
128 tristate
129
130# Cirrus Logic CS4270 Codec VD = 3.3V Errata 132# Cirrus Logic CS4270 Codec VD = 3.3V Errata
131# Select if you are affected by the errata where the part will not function 133# 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 134# if MCLK divide-by-1.5 is selected and VD is set to 3.3V. The driver will
@@ -138,9 +140,15 @@ config SND_SOC_CS4270_VD33_ERRATA
138config SND_SOC_CX20442 140config SND_SOC_CX20442
139 tristate 141 tristate
140 142
143config SND_SOC_JZ4740_CODEC
144 tristate
145
141config SND_SOC_L3 146config SND_SOC_L3
142 tristate 147 tristate
143 148
149config SND_SOC_DA7210
150 tristate
151
144config SND_SOC_PCM3008 152config SND_SOC_PCM3008
145 tristate 153 tristate
146 154
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 91429eab0707..d8d9eebf78b5 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
@@ -56,6 +57,7 @@ snd-soc-wm9705-objs := wm9705.o
56snd-soc-wm9712-objs := wm9712.o 57snd-soc-wm9712-objs := wm9712.o
57snd-soc-wm9713-objs := wm9713.o 58snd-soc-wm9713-objs := wm9713.o
58snd-soc-wm-hubs-objs := wm_hubs.o 59snd-soc-wm-hubs-objs := wm_hubs.o
60snd-soc-jz4740-codec-objs := jz4740.o
59 61
60# Amp 62# Amp
61snd-soc-max9877-objs := max9877.o 63snd-soc-max9877-objs := max9877.o
@@ -74,10 +76,12 @@ obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o
74obj-$(CONFIG_SND_SOC_AK4642) += snd-soc-ak4642.o 76obj-$(CONFIG_SND_SOC_AK4642) += snd-soc-ak4642.o
75obj-$(CONFIG_SND_SOC_AK4671) += snd-soc-ak4671.o 77obj-$(CONFIG_SND_SOC_AK4671) += snd-soc-ak4671.o
76obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o 78obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o
79obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o
77obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o 80obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o
78obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o 81obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o
79obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o 82obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o
80obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o 83obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o
84obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o
81obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o 85obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o
82obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o 86obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o
83obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o 87obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o
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..60b83b482467 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);
@@ -548,6 +555,9 @@ static int ak4642_probe(struct platform_device *pdev)
548 goto pcm_err; 555 goto pcm_err;
549 } 556 }
550 557
558 snd_soc_add_controls(ak4642_codec, ak4642_snd_controls,
559 ARRAY_SIZE(ak4642_snd_controls));
560
551 dev_info(&pdev->dev, "AK4642 Audio Codec %s", AK4642_VERSION); 561 dev_info(&pdev->dev, "AK4642 Audio Codec %s", AK4642_VERSION);
552 return ret; 562 return ret;
553 563
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..a83aa187a7f2 100644
--- a/sound/soc/codecs/da7210.c
+++ b/sound/soc/codecs/da7210.c
@@ -15,23 +15,14 @@
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>
35 26
36#include "da7210.h" 27#include "da7210.h"
37 28
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..2fa946ce23a2 100644
--- a/sound/soc/codecs/tlv320dac33.c
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -120,6 +120,8 @@ struct tlv320dac33_priv {
120 * samples */ 120 * samples */
121 unsigned int mode7_us_to_lthr; /* Time to reach lthr from uthr */ 121 unsigned int mode7_us_to_lthr; /* Time to reach lthr from uthr */
122 122
123 unsigned int uthr;
124
123 enum dac33_state state; 125 enum dac33_state state;
124}; 126};
125 127
@@ -442,6 +444,39 @@ static int dac33_set_nsample(struct snd_kcontrol *kcontrol,
442 return ret; 444 return ret;
443} 445}
444 446
447static int dac33_get_uthr(struct snd_kcontrol *kcontrol,
448 struct snd_ctl_elem_value *ucontrol)
449{
450 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
451 struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
452
453 ucontrol->value.integer.value[0] = dac33->uthr;
454
455 return 0;
456}
457
458static int dac33_set_uthr(struct snd_kcontrol *kcontrol,
459 struct snd_ctl_elem_value *ucontrol)
460{
461 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
462 struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
463 int ret = 0;
464
465 if (dac33->substream)
466 return -EBUSY;
467
468 if (dac33->uthr == ucontrol->value.integer.value[0])
469 return 0;
470
471 if (ucontrol->value.integer.value[0] < (MODE7_LTHR + 10) ||
472 ucontrol->value.integer.value[0] > MODE7_UTHR)
473 ret = -EINVAL;
474 else
475 dac33->uthr = ucontrol->value.integer.value[0];
476
477 return ret;
478}
479
445static int dac33_get_fifo_mode(struct snd_kcontrol *kcontrol, 480static int dac33_get_fifo_mode(struct snd_kcontrol *kcontrol,
446 struct snd_ctl_elem_value *ucontrol) 481 struct snd_ctl_elem_value *ucontrol)
447{ 482{
@@ -506,6 +541,8 @@ static const struct snd_kcontrol_new dac33_snd_controls[] = {
506static const struct snd_kcontrol_new dac33_nsample_snd_controls[] = { 541static const struct snd_kcontrol_new dac33_nsample_snd_controls[] = {
507 SOC_SINGLE_EXT("nSample", 0, 0, 5900, 0, 542 SOC_SINGLE_EXT("nSample", 0, 0, 5900, 0,
508 dac33_get_nsample, dac33_set_nsample), 543 dac33_get_nsample, dac33_set_nsample),
544 SOC_SINGLE_EXT("UTHR", 0, 0, MODE7_UTHR, 0,
545 dac33_get_uthr, dac33_set_uthr),
509 SOC_ENUM_EXT("FIFO Mode", dac33_fifo_mode_enum, 546 SOC_ENUM_EXT("FIFO Mode", dac33_fifo_mode_enum,
510 dac33_get_fifo_mode, dac33_set_fifo_mode), 547 dac33_get_fifo_mode, dac33_set_fifo_mode),
511}; 548};
@@ -985,7 +1022,7 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream)
985 * Configure the threshold levels, and leave 10 sample space 1022 * Configure the threshold levels, and leave 10 sample space
986 * at the bottom, and also at the top of the FIFO 1023 * at the bottom, and also at the top of the FIFO
987 */ 1024 */
988 dac33_write16(codec, DAC33_UTHR_MSB, DAC33_THRREG(MODE7_UTHR)); 1025 dac33_write16(codec, DAC33_UTHR_MSB, DAC33_THRREG(dac33->uthr));
989 dac33_write16(codec, DAC33_LTHR_MSB, DAC33_THRREG(MODE7_LTHR)); 1026 dac33_write16(codec, DAC33_LTHR_MSB, DAC33_THRREG(MODE7_LTHR));
990 break; 1027 break;
991 default: 1028 default:
@@ -1052,8 +1089,8 @@ static void dac33_calculate_times(struct snd_pcm_substream *substream)
1052 break; 1089 break;
1053 case DAC33_FIFO_MODE7: 1090 case DAC33_FIFO_MODE7:
1054 dac33->mode7_us_to_lthr = 1091 dac33->mode7_us_to_lthr =
1055 SAMPLES_TO_US(substream->runtime->rate, 1092 SAMPLES_TO_US(substream->runtime->rate,
1056 MODE7_UTHR - MODE7_LTHR + 1); 1093 dac33->uthr - MODE7_LTHR + 1);
1057 dac33->t_stamp1 = 0; 1094 dac33->t_stamp1 = 0;
1058 break; 1095 break;
1059 default: 1096 default:
@@ -1104,7 +1141,7 @@ static snd_pcm_sframes_t dac33_dai_delay(
1104 struct snd_soc_codec *codec = socdev->card->codec; 1141 struct snd_soc_codec *codec = socdev->card->codec;
1105 struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); 1142 struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
1106 unsigned long long t0, t1, t_now; 1143 unsigned long long t0, t1, t_now;
1107 unsigned int time_delta; 1144 unsigned int time_delta, uthr;
1108 int samples_out, samples_in, samples; 1145 int samples_out, samples_in, samples;
1109 snd_pcm_sframes_t delay = 0; 1146 snd_pcm_sframes_t delay = 0;
1110 1147
@@ -1182,6 +1219,7 @@ static snd_pcm_sframes_t dac33_dai_delay(
1182 case DAC33_FIFO_MODE7: 1219 case DAC33_FIFO_MODE7:
1183 spin_lock(&dac33->lock); 1220 spin_lock(&dac33->lock);
1184 t0 = dac33->t_stamp1; 1221 t0 = dac33->t_stamp1;
1222 uthr = dac33->uthr;
1185 spin_unlock(&dac33->lock); 1223 spin_unlock(&dac33->lock);
1186 t_now = ktime_to_us(ktime_get()); 1224 t_now = ktime_to_us(ktime_get());
1187 1225
@@ -1194,7 +1232,7 @@ static snd_pcm_sframes_t dac33_dai_delay(
1194 * Either the timestamps are messed or equal. Report 1232 * Either the timestamps are messed or equal. Report
1195 * maximum delay 1233 * maximum delay
1196 */ 1234 */
1197 delay = MODE7_UTHR; 1235 delay = uthr;
1198 goto out; 1236 goto out;
1199 } 1237 }
1200 1238
@@ -1208,8 +1246,8 @@ static snd_pcm_sframes_t dac33_dai_delay(
1208 substream->runtime->rate, 1246 substream->runtime->rate,
1209 time_delta); 1247 time_delta);
1210 1248
1211 if (likely(MODE7_UTHR > samples_out)) 1249 if (likely(uthr > samples_out))
1212 delay = MODE7_UTHR - samples_out; 1250 delay = uthr - samples_out;
1213 else 1251 else
1214 delay = 0; 1252 delay = 0;
1215 } else { 1253 } else {
@@ -1227,8 +1265,8 @@ static snd_pcm_sframes_t dac33_dai_delay(
1227 time_delta); 1265 time_delta);
1228 delay = MODE7_LTHR + samples_in - samples_out; 1266 delay = MODE7_LTHR + samples_in - samples_out;
1229 1267
1230 if (unlikely(delay > MODE7_UTHR)) 1268 if (unlikely(delay > uthr))
1231 delay = MODE7_UTHR; 1269 delay = uthr;
1232 } 1270 }
1233 break; 1271 break;
1234 default: 1272 default:
@@ -1484,6 +1522,7 @@ static int __devinit dac33_i2c_probe(struct i2c_client *client,
1484 dac33->irq = client->irq; 1522 dac33->irq = client->irq;
1485 dac33->nsample = NSAMPLE_MAX; 1523 dac33->nsample = NSAMPLE_MAX;
1486 dac33->nsample_max = NSAMPLE_MAX; 1524 dac33->nsample_max = NSAMPLE_MAX;
1525 dac33->uthr = MODE7_UTHR;
1487 /* Disable FIFO use by default */ 1526 /* Disable FIFO use by default */
1488 dac33->fifo_mode = DAC33_FIFO_BYPASS; 1527 dac33->fifo_mode = DAC33_FIFO_BYPASS;
1489 1528
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index b4fcdb01fc49..8d36bfa20552 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) */
@@ -244,58 +244,93 @@ static void twl4030_codec_enable(struct snd_soc_codec *codec, int enable)
244 udelay(10); 244 udelay(10);
245} 245}
246 246
247static void twl4030_init_chip(struct snd_soc_codec *codec) 247static inline void twl4030_check_defaults(struct snd_soc_codec *codec)
248{ 248{
249 u8 *cache = codec->reg_cache; 249 int i, difference = 0;
250 int i; 250 u8 val;
251
252 dev_dbg(codec->dev, "Checking TWL audio default configuration\n");
253 for (i = 1; i <= TWL4030_REG_MISC_SET_2; i++) {
254 twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &val, i);
255 if (val != twl4030_reg[i]) {
256 difference++;
257 dev_dbg(codec->dev,
258 "Reg 0x%02x: chip: 0x%02x driver: 0x%02x\n",
259 i, val, twl4030_reg[i]);
260 }
261 }
262 dev_dbg(codec->dev, "Found %d non maching registers. %s\n",
263 difference, difference ? "Not OK" : "OK");
264}
251 265
252 /* clear CODECPDZ prior to setting register defaults */ 266static inline void twl4030_reset_registers(struct snd_soc_codec *codec)
253 twl4030_codec_enable(codec, 0); 267{
268 int i;
254 269
255 /* set all audio section registers to reasonable defaults */ 270 /* set all audio section registers to reasonable defaults */
256 for (i = TWL4030_REG_OPTION; i <= TWL4030_REG_MISC_SET_2; i++) 271 for (i = TWL4030_REG_OPTION; i <= TWL4030_REG_MISC_SET_2; i++)
257 if (i != TWL4030_REG_APLL_CTL) 272 if (i != TWL4030_REG_APLL_CTL)
258 twl4030_write(codec, i, cache[i]); 273 twl4030_write(codec, i, twl4030_reg[i]);
259 274
260} 275}
261 276
262static void twl4030_apll_enable(struct snd_soc_codec *codec, int enable) 277static void twl4030_init_chip(struct platform_device *pdev)
263{ 278{
279 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
280 struct twl4030_setup_data *setup = socdev->codec_data;
281 struct snd_soc_codec *codec = socdev->card->codec;
264 struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); 282 struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
265 int status = -1; 283 u8 reg, byte;
284 int i = 0;
266 285
267 if (enable) { 286 /* Check defaults, if instructed before anything else */
268 twl4030->apll_enabled++; 287 if (setup && setup->check_defaults)
269 if (twl4030->apll_enabled == 1) 288 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 289
279 if (status >= 0) 290 /* Reset registers, if no setup data or if instructed to do so */
280 twl4030_write_reg_cache(codec, TWL4030_REG_APLL_CTL, status); 291 if (!setup || (setup && setup->reset_registers))
281} 292 twl4030_reset_registers(codec);
282 293
283static void twl4030_power_up(struct snd_soc_codec *codec) 294 /* Refresh APLL_CTL register from HW */
284{ 295 twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &byte,
285 struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); 296 TWL4030_REG_APLL_CTL);
286 u8 anamicl, regmisc1, byte; 297 twl4030_write_reg_cache(codec, TWL4030_REG_APLL_CTL, byte);
287 int i = 0;
288 298
289 if (twl4030->codec_powered) 299 /* anti-pop when changing analog gain */
300 reg = twl4030_read_reg_cache(codec, TWL4030_REG_MISC_SET_1);
301 twl4030_write(codec, TWL4030_REG_MISC_SET_1,
302 reg | TWL4030_SMOOTH_ANAVOL_EN);
303
304 twl4030_write(codec, TWL4030_REG_OPTION,
305 TWL4030_ATXL1_EN | TWL4030_ATXR1_EN |
306 TWL4030_ARXL2_EN | TWL4030_ARXR2_EN);
307
308 /* REG_ARXR2_APGA_CTL reset according to the TRM: 0dB, DA_EN */
309 twl4030_write(codec, TWL4030_REG_ARXR2_APGA_CTL, 0x32);
310
311 /* Machine dependent setup */
312 if (!setup)
290 return; 313 return;
291 314
292 /* set CODECPDZ to turn on codec */ 315 /* Configuration for headset ramp delay from setup data */
293 twl4030_codec_enable(codec, 1); 316 if (setup->sysclk != twl4030->sysclk)
317 dev_warn(codec->dev,
318 "Mismatch in APLL mclk: %u (configured: %u)\n",
319 setup->sysclk, twl4030->sysclk);
320
321 reg = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET);
322 reg &= ~TWL4030_RAMP_DELAY;
323 reg |= (setup->ramp_delay_value << 2);
324 twl4030_write_reg_cache(codec, TWL4030_REG_HS_POPN_SET, reg);
294 325
295 /* initiate offset cancellation */ 326 /* initiate offset cancellation */
296 anamicl = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL); 327 twl4030_codec_enable(codec, 1);
328
329 reg = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL);
330 reg &= ~TWL4030_OFFSET_CNCL_SEL;
331 reg |= setup->offset_cncl_path;
297 twl4030_write(codec, TWL4030_REG_ANAMICL, 332 twl4030_write(codec, TWL4030_REG_ANAMICL,
298 anamicl | TWL4030_CNCL_OFFSET_START); 333 reg | TWL4030_CNCL_OFFSET_START);
299 334
300 /* wait for offset cancellation to complete */ 335 /* wait for offset cancellation to complete */
301 do { 336 do {
@@ -310,23 +345,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 */ 345 /* Make sure that the reg_cache has the same value as the HW */
311 twl4030_write_reg_cache(codec, TWL4030_REG_ANAMICL, byte); 346 twl4030_write_reg_cache(codec, TWL4030_REG_ANAMICL, byte);
312 347
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); 348 twl4030_codec_enable(codec, 0);
320 twl4030_codec_enable(codec, 1);
321} 349}
322 350
323/* 351static 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{ 352{
328 /* power down */ 353 struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
329 twl4030_codec_enable(codec, 0); 354 int status = -1;
355
356 if (enable) {
357 twl4030->apll_enabled++;
358 if (twl4030->apll_enabled == 1)
359 status = twl4030_codec_enable_resource(
360 TWL4030_CODEC_RES_APLL);
361 } else {
362 twl4030->apll_enabled--;
363 if (!twl4030->apll_enabled)
364 status = twl4030_codec_disable_resource(
365 TWL4030_CODEC_RES_APLL);
366 }
367
368 if (status >= 0)
369 twl4030_write_reg_cache(codec, TWL4030_REG_APLL_CTL, status);
330} 370}
331 371
332/* Earpiece */ 372/* Earpiece */
@@ -1605,10 +1645,10 @@ static int twl4030_set_bias_level(struct snd_soc_codec *codec,
1605 break; 1645 break;
1606 case SND_SOC_BIAS_STANDBY: 1646 case SND_SOC_BIAS_STANDBY:
1607 if (codec->bias_level == SND_SOC_BIAS_OFF) 1647 if (codec->bias_level == SND_SOC_BIAS_OFF)
1608 twl4030_power_up(codec); 1648 twl4030_codec_enable(codec, 1);
1609 break; 1649 break;
1610 case SND_SOC_BIAS_OFF: 1650 case SND_SOC_BIAS_OFF:
1611 twl4030_power_down(codec); 1651 twl4030_codec_enable(codec, 0);
1612 break; 1652 break;
1613 } 1653 }
1614 codec->bias_level = level; 1654 codec->bias_level = level;
@@ -1794,13 +1834,6 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
1794 return -EINVAL; 1834 return -EINVAL;
1795 } 1835 }
1796 1836
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 */ 1837 /* sample size */
1805 old_format = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF); 1838 old_format = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF);
1806 format = old_format; 1839 format = old_format;
@@ -1818,16 +1851,20 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
1818 return -EINVAL; 1851 return -EINVAL;
1819 } 1852 }
1820 1853
1821 if (format != old_format) { 1854 if (format != old_format || mode != old_mode) {
1822 1855 if (twl4030->codec_powered) {
1823 /* clear CODECPDZ before changing format (codec requirement) */ 1856 /*
1824 twl4030_codec_enable(codec, 0); 1857 * If the codec is powered, than we need to toggle the
1825 1858 * codec power.
1826 /* change format */ 1859 */
1827 twl4030_write(codec, TWL4030_REG_AUDIO_IF, format); 1860 twl4030_codec_enable(codec, 0);
1828 1861 twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode);
1829 /* set CODECPDZ afterwards */ 1862 twl4030_write(codec, TWL4030_REG_AUDIO_IF, format);
1830 twl4030_codec_enable(codec, 1); 1863 twl4030_codec_enable(codec, 1);
1864 } else {
1865 twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode);
1866 twl4030_write(codec, TWL4030_REG_AUDIO_IF, format);
1867 }
1831 } 1868 }
1832 1869
1833 /* Store the important parameters for the DAI configuration and set 1870 /* Store the important parameters for the DAI configuration and set
@@ -1877,6 +1914,7 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai,
1877 unsigned int fmt) 1914 unsigned int fmt)
1878{ 1915{
1879 struct snd_soc_codec *codec = codec_dai->codec; 1916 struct snd_soc_codec *codec = codec_dai->codec;
1917 struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
1880 u8 old_format, format; 1918 u8 old_format, format;
1881 1919
1882 /* get format */ 1920 /* get format */
@@ -1911,15 +1949,17 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai,
1911 } 1949 }
1912 1950
1913 if (format != old_format) { 1951 if (format != old_format) {
1914 1952 if (twl4030->codec_powered) {
1915 /* clear CODECPDZ before changing format (codec requirement) */ 1953 /*
1916 twl4030_codec_enable(codec, 0); 1954 * If the codec is powered, than we need to toggle the
1917 1955 * codec power.
1918 /* change format */ 1956 */
1919 twl4030_write(codec, TWL4030_REG_AUDIO_IF, format); 1957 twl4030_codec_enable(codec, 0);
1920 1958 twl4030_write(codec, TWL4030_REG_AUDIO_IF, format);
1921 /* set CODECPDZ afterwards */ 1959 twl4030_codec_enable(codec, 1);
1922 twl4030_codec_enable(codec, 1); 1960 } else {
1961 twl4030_write(codec, TWL4030_REG_AUDIO_IF, format);
1962 }
1923 } 1963 }
1924 1964
1925 return 0; 1965 return 0;
@@ -2011,6 +2051,7 @@ static int twl4030_voice_hw_params(struct snd_pcm_substream *substream,
2011 struct snd_soc_pcm_runtime *rtd = substream->private_data; 2051 struct snd_soc_pcm_runtime *rtd = substream->private_data;
2012 struct snd_soc_device *socdev = rtd->socdev; 2052 struct snd_soc_device *socdev = rtd->socdev;
2013 struct snd_soc_codec *codec = socdev->card->codec; 2053 struct snd_soc_codec *codec = socdev->card->codec;
2054 struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
2014 u8 old_mode, mode; 2055 u8 old_mode, mode;
2015 2056
2016 /* Enable voice digital filters */ 2057 /* Enable voice digital filters */
@@ -2035,10 +2076,17 @@ static int twl4030_voice_hw_params(struct snd_pcm_substream *substream,
2035 } 2076 }
2036 2077
2037 if (mode != old_mode) { 2078 if (mode != old_mode) {
2038 /* change rate and set CODECPDZ */ 2079 if (twl4030->codec_powered) {
2039 twl4030_codec_enable(codec, 0); 2080 /*
2040 twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode); 2081 * If the codec is powered, than we need to toggle the
2041 twl4030_codec_enable(codec, 1); 2082 * codec power.
2083 */
2084 twl4030_codec_enable(codec, 0);
2085 twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode);
2086 twl4030_codec_enable(codec, 1);
2087 } else {
2088 twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode);
2089 }
2042 } 2090 }
2043 2091
2044 return 0; 2092 return 0;
@@ -2068,6 +2116,7 @@ static int twl4030_voice_set_dai_fmt(struct snd_soc_dai *codec_dai,
2068 unsigned int fmt) 2116 unsigned int fmt)
2069{ 2117{
2070 struct snd_soc_codec *codec = codec_dai->codec; 2118 struct snd_soc_codec *codec = codec_dai->codec;
2119 struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
2071 u8 old_format, format; 2120 u8 old_format, format;
2072 2121
2073 /* get format */ 2122 /* get format */
@@ -2099,10 +2148,17 @@ static int twl4030_voice_set_dai_fmt(struct snd_soc_dai *codec_dai,
2099 } 2148 }
2100 2149
2101 if (format != old_format) { 2150 if (format != old_format) {
2102 /* change format and set CODECPDZ */ 2151 if (twl4030->codec_powered) {
2103 twl4030_codec_enable(codec, 0); 2152 /*
2104 twl4030_write(codec, TWL4030_REG_VOICE_IF, format); 2153 * If the codec is powered, than we need to toggle the
2105 twl4030_codec_enable(codec, 1); 2154 * codec power.
2155 */
2156 twl4030_codec_enable(codec, 0);
2157 twl4030_write(codec, TWL4030_REG_VOICE_IF, format);
2158 twl4030_codec_enable(codec, 1);
2159 } else {
2160 twl4030_write(codec, TWL4030_REG_VOICE_IF, format);
2161 }
2106 } 2162 }
2107 2163
2108 return 0; 2164 return 0;
@@ -2202,31 +2258,15 @@ static struct snd_soc_codec *twl4030_codec;
2202static int twl4030_soc_probe(struct platform_device *pdev) 2258static int twl4030_soc_probe(struct platform_device *pdev)
2203{ 2259{
2204 struct snd_soc_device *socdev = platform_get_drvdata(pdev); 2260 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
2205 struct twl4030_setup_data *setup = socdev->codec_data;
2206 struct snd_soc_codec *codec; 2261 struct snd_soc_codec *codec;
2207 struct twl4030_priv *twl4030;
2208 int ret; 2262 int ret;
2209 2263
2210 BUG_ON(!twl4030_codec); 2264 BUG_ON(!twl4030_codec);
2211 2265
2212 codec = twl4030_codec; 2266 codec = twl4030_codec;
2213 twl4030 = snd_soc_codec_get_drvdata(codec);
2214 socdev->card->codec = codec; 2267 socdev->card->codec = codec;
2215 2268
2216 /* Configuration for headset ramp delay from setup data */ 2269 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 2270
2231 /* register pcms */ 2271 /* register pcms */
2232 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); 2272 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
@@ -2247,6 +2287,8 @@ static int twl4030_soc_remove(struct platform_device *pdev)
2247 struct snd_soc_device *socdev = platform_get_drvdata(pdev); 2287 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
2248 struct snd_soc_codec *codec = socdev->card->codec; 2288 struct snd_soc_codec *codec = socdev->card->codec;
2249 2289
2290 /* Reset registers to their chip default before leaving */
2291 twl4030_reset_registers(codec);
2250 twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF); 2292 twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF);
2251 snd_soc_free_pcms(socdev); 2293 snd_soc_free_pcms(socdev);
2252 snd_soc_dapm_free(socdev); 2294 snd_soc_dapm_free(socdev);
@@ -2287,6 +2329,7 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev)
2287 codec->read = twl4030_read_reg_cache; 2329 codec->read = twl4030_read_reg_cache;
2288 codec->write = twl4030_write; 2330 codec->write = twl4030_write;
2289 codec->set_bias_level = twl4030_set_bias_level; 2331 codec->set_bias_level = twl4030_set_bias_level;
2332 codec->idle_bias_off = 1;
2290 codec->dai = twl4030_dai; 2333 codec->dai = twl4030_dai;
2291 codec->num_dai = ARRAY_SIZE(twl4030_dai); 2334 codec->num_dai = ARRAY_SIZE(twl4030_dai);
2292 codec->reg_cache_size = sizeof(twl4030_reg); 2335 codec->reg_cache_size = sizeof(twl4030_reg);
@@ -2302,9 +2345,7 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev)
2302 2345
2303 /* Set the defaults, and power up the codec */ 2346 /* Set the defaults, and power up the codec */
2304 twl4030->sysclk = twl4030_codec_get_mclk() / 1000; 2347 twl4030->sysclk = twl4030_codec_get_mclk() / 1000;
2305 twl4030_init_chip(codec);
2306 codec->bias_level = SND_SOC_BIAS_OFF; 2348 codec->bias_level = SND_SOC_BIAS_OFF;
2307 twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
2308 2349
2309 ret = snd_soc_register_codec(codec); 2350 ret = snd_soc_register_codec(codec);
2310 if (ret != 0) { 2351 if (ret != 0) {
@@ -2322,7 +2363,7 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev)
2322 return 0; 2363 return 0;
2323 2364
2324error_codec: 2365error_codec:
2325 twl4030_power_down(codec); 2366 twl4030_codec_enable(codec, 0);
2326 kfree(codec->reg_cache); 2367 kfree(codec->reg_cache);
2327error_cache: 2368error_cache:
2328 kfree(twl4030); 2369 kfree(twl4030);
diff --git a/sound/soc/codecs/twl4030.h b/sound/soc/codecs/twl4030.h
index f206d242ca31..788e3d125099 100644
--- a/sound/soc/codecs/twl4030.h
+++ b/sound/soc/codecs/twl4030.h
@@ -42,6 +42,9 @@ extern struct snd_soc_codec_device soc_codec_dev_twl4030;
42struct twl4030_setup_data { 42struct twl4030_setup_data {
43 unsigned int ramp_delay_value; 43 unsigned int ramp_delay_value;
44 unsigned int sysclk; 44 unsigned int sysclk;
45 unsigned int offset_cncl_path;
46 unsigned int check_defaults:1;
47 unsigned int reset_registers:1;
45 unsigned int hs_extmute:1; 48 unsigned int hs_extmute:1;
46 void (*set_hs_extmute)(int mute); 49 void (*set_hs_extmute)(int mute);
47}; 50};
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c
index af36346ff336..85dd4fb4c681 100644
--- a/sound/soc/codecs/twl6040.c
+++ b/sound/soc/codecs/twl6040.c
@@ -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/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/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/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..c41cf47f4009 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;
@@ -2472,6 +2492,7 @@ static const struct snd_kcontrol_new aif3adc_mux =
2472static const struct snd_soc_dapm_widget wm8994_dapm_widgets[] = { 2492static const struct snd_soc_dapm_widget wm8994_dapm_widgets[] = {
2473SND_SOC_DAPM_INPUT("DMIC1DAT"), 2493SND_SOC_DAPM_INPUT("DMIC1DAT"),
2474SND_SOC_DAPM_INPUT("DMIC2DAT"), 2494SND_SOC_DAPM_INPUT("DMIC2DAT"),
2495SND_SOC_DAPM_INPUT("Clock"),
2475 2496
2476SND_SOC_DAPM_SUPPLY("CLK_SYS", SND_SOC_NOPM, 0, 0, clk_sys_event, 2497SND_SOC_DAPM_SUPPLY("CLK_SYS", SND_SOC_NOPM, 0, 0, clk_sys_event,
2477 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), 2498 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
@@ -2946,11 +2967,14 @@ static int wm8994_set_fll(struct snd_soc_dai *dai, int id, int src,
2946 return 0; 2967 return 0;
2947} 2968}
2948 2969
2970static int opclk_divs[] = { 10, 20, 30, 40, 55, 60, 80, 120, 160 };
2971
2949static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai, 2972static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai,
2950 int clk_id, unsigned int freq, int dir) 2973 int clk_id, unsigned int freq, int dir)
2951{ 2974{
2952 struct snd_soc_codec *codec = dai->codec; 2975 struct snd_soc_codec *codec = dai->codec;
2953 struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); 2976 struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
2977 int i;
2954 2978
2955 switch (dai->id) { 2979 switch (dai->id) {
2956 case 1: 2980 case 1:
@@ -2988,6 +3012,25 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai,
2988 dev_dbg(dai->dev, "AIF%d using FLL2\n", dai->id); 3012 dev_dbg(dai->dev, "AIF%d using FLL2\n", dai->id);
2989 break; 3013 break;
2990 3014
3015 case WM8994_SYSCLK_OPCLK:
3016 /* Special case - a division (times 10) is given and
3017 * no effect on main clocking.
3018 */
3019 if (freq) {
3020 for (i = 0; i < ARRAY_SIZE(opclk_divs); i++)
3021 if (opclk_divs[i] == freq)
3022 break;
3023 if (i == ARRAY_SIZE(opclk_divs))
3024 return -EINVAL;
3025 snd_soc_update_bits(codec, WM8994_CLOCKING_2,
3026 WM8994_OPCLK_DIV_MASK, i);
3027 snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_2,
3028 WM8994_OPCLK_ENA, WM8994_OPCLK_ENA);
3029 } else {
3030 snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_2,
3031 WM8994_OPCLK_ENA, 0);
3032 }
3033
2991 default: 3034 default:
2992 return -EINVAL; 3035 return -EINVAL;
2993 } 3036 }
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/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c
index adadcd3aa1b1..b251bc9a9812 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
@@ -552,6 +674,8 @@ static int davinci_i2s_probe(struct platform_device *pdev)
552 pdata->sram_size_playback; 674 pdata->sram_size_playback;
553 dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].sram_size = 675 dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].sram_size =
554 pdata->sram_size_capture; 676 pdata->sram_size_capture;
677 dev->clk_input_pin = pdata->clk_input_pin;
678 dev->i2s_accurate_sck = pdata->i2s_accurate_sck;
555 } 679 }
556 dev->clk = clk_get(&pdev->dev, NULL); 680 dev->clk = clk_get(&pdev->dev, NULL);
557 if (IS_ERR(dev->clk)) { 681 if (IS_ERR(dev->clk)) {
@@ -584,6 +708,7 @@ static int davinci_i2s_probe(struct platform_device *pdev)
584 goto err_free_mem; 708 goto err_free_mem;
585 } 709 }
586 dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].channel = res->start; 710 dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].channel = res->start;
711 dev->dev = &pdev->dev;
587 712
588 davinci_i2s_dai.private_data = dev; 713 davinci_i2s_dai.private_data = dev;
589 davinci_i2s_dai.capture.dma_data = dev->dma_params; 714 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-pcm.c b/sound/soc/davinci/davinci-pcm.c
index 2dc406f42fe7..def454e42fcb 100644
--- a/sound/soc/davinci/davinci-pcm.c
+++ b/sound/soc/davinci/davinci-pcm.c
@@ -800,7 +800,7 @@ static void davinci_pcm_free(struct snd_pcm *pcm)
800 dma_free_writecombine(pcm->card->dev, buf->bytes, 800 dma_free_writecombine(pcm->card->dev, buf->bytes,
801 buf->area, buf->addr); 801 buf->area, buf->addr);
802 buf->area = NULL; 802 buf->area = NULL;
803 iram_dma = (struct snd_dma_buffer *)buf->private_data; 803 iram_dma = buf->private_data;
804 if (iram_dma) { 804 if (iram_dma) {
805 sram_free(iram_dma->area, iram_dma->bytes); 805 sram_free(iram_dma->area, iram_dma->bytes);
806 kfree(iram_dma); 806 kfree(iram_dma);
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..2f0d6d3e75dc 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 SSI4 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..45f5e4b32cb5
--- /dev/null
+++ b/sound/soc/imx/eukrea-tlv320.c
@@ -0,0 +1,136 @@
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 /* return happy. We might run on a totally different machine */
106 return 0;
107
108 eukrea_tlv320_snd_device = platform_device_alloc("soc-audio", -1);
109 if (!eukrea_tlv320_snd_device)
110 return -ENOMEM;
111
112 eukrea_tlv320_dai.cpu_dai = &imx_ssi_pcm_dai[0];
113
114 platform_set_drvdata(eukrea_tlv320_snd_device, &eukrea_tlv320_snd_devdata);
115 eukrea_tlv320_snd_devdata.dev = &eukrea_tlv320_snd_device->dev;
116 ret = platform_device_add(eukrea_tlv320_snd_device);
117
118 if (ret) {
119 printk(KERN_ERR "ASoC: Platform device allocation failed\n");
120 platform_device_put(eukrea_tlv320_snd_device);
121 }
122
123 return ret;
124}
125
126static void __exit eukrea_tlv320_exit(void)
127{
128 platform_device_unregister(eukrea_tlv320_snd_device);
129}
130
131module_init(eukrea_tlv320_init);
132module_exit(eukrea_tlv320_exit);
133
134MODULE_AUTHOR("Eric Bénard <eric@eukrea.com>");
135MODULE_DESCRIPTION("CPUIMX ALSA SoC driver");
136MODULE_LICENSE("GPL");
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..aebd3af2ab79 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)
@@ -155,19 +156,65 @@ static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream)
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);
157 int dma_op_mode = omap_mcbsp_get_dma_op_mode(mcbsp_data->bus_id); 158 int dma_op_mode = omap_mcbsp_get_dma_op_mode(mcbsp_data->bus_id);
158 int samples; 159 int words;
159 160
160 /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */ 161 /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */
161 if (dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) 162 if (dma_op_mode == MCBSP_DMA_MODE_THRESHOLD)
162 samples = snd_pcm_lib_period_bytes(substream) >> 1; 163 /* The FIFO size depends on the McBSP word configuration */
164 words = snd_pcm_lib_period_bytes(substream) /
165 (mcbsp_data->wlen / 8);
163 else 166 else
164 samples = 1; 167 words = 1;
165 168
166 /* Configure McBSP internal buffer usage */ 169 /* Configure McBSP internal buffer usage */
167 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 170 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
168 omap_mcbsp_set_tx_threshold(mcbsp_data->bus_id, samples - 1); 171 omap_mcbsp_set_tx_threshold(mcbsp_data->bus_id, words);
169 else 172 else
170 omap_mcbsp_set_rx_threshold(mcbsp_data->bus_id, samples - 1); 173 omap_mcbsp_set_rx_threshold(mcbsp_data->bus_id, words);
174}
175
176static int omap_mcbsp_hwrule_min_buffersize(struct snd_pcm_hw_params *params,
177 struct snd_pcm_hw_rule *rule)
178{
179 struct snd_interval *buffer_size = hw_param_interval(params,
180 SNDRV_PCM_HW_PARAM_BUFFER_SIZE);
181 struct snd_interval *channels = hw_param_interval(params,
182 SNDRV_PCM_HW_PARAM_CHANNELS);
183 struct omap_mcbsp_data *mcbsp_data = rule->private;
184 struct snd_interval frames;
185 int size;
186
187 snd_interval_any(&frames);
188 size = omap_mcbsp_get_fifo_size(mcbsp_data->bus_id);
189
190 frames.min = size / channels->min;
191 frames.integer = 1;
192 return snd_interval_refine(buffer_size, &frames);
193}
194
195static int omap_mcbsp_hwrule_max_periodsize(struct snd_pcm_hw_params *params,
196 struct snd_pcm_hw_rule *rule)
197{
198 struct snd_interval *period_size = hw_param_interval(params,
199 SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
200 struct snd_interval *channels = hw_param_interval(params,
201 SNDRV_PCM_HW_PARAM_CHANNELS);
202 struct snd_pcm_substream *substream = rule->private;
203 struct snd_soc_pcm_runtime *rtd = substream->private_data;
204 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
205 struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
206 struct snd_interval frames;
207 int size;
208
209 snd_interval_any(&frames);
210 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
211 size = omap_mcbsp_get_max_tx_threshold(mcbsp_data->bus_id);
212 else
213 size = omap_mcbsp_get_max_rx_threshold(mcbsp_data->bus_id);
214
215 frames.max = size / channels->min;
216 frames.integer = 1;
217 return snd_interval_refine(period_size, &frames);
171} 218}
172 219
173static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream, 220static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
@@ -182,33 +229,45 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
182 if (!cpu_dai->active) 229 if (!cpu_dai->active)
183 err = omap_mcbsp_request(bus_id); 230 err = omap_mcbsp_request(bus_id);
184 231
232 /*
233 * OMAP3 McBSP FIFO is word structured.
234 * McBSP2 has 1024 + 256 = 1280 word long buffer,
235 * McBSP1,3,4,5 has 128 word long buffer
236 * This means that the size of the FIFO depends on the sample format.
237 * For example on McBSP3:
238 * 16bit samples: size is 128 * 2 = 256 bytes
239 * 32bit samples: size is 128 * 4 = 512 bytes
240 * It is simpler to place constraint for buffer and period based on
241 * channels.
242 * McBSP3 as example again (16 or 32 bit samples):
243 * 1 channel (mono): size is 128 frames (128 words)
244 * 2 channels (stereo): size is 128 / 2 = 64 frames (2 * 64 words)
245 * 4 channels: size is 128 / 4 = 32 frames (4 * 32 words)
246 */
185 if (cpu_is_omap343x()) { 247 if (cpu_is_omap343x()) {
186 int dma_op_mode = omap_mcbsp_get_dma_op_mode(bus_id); 248 int dma_op_mode = omap_mcbsp_get_dma_op_mode(bus_id);
187 int max_period;
188 249
189 /* 250 /*
190 * McBSP2 in OMAP3 has 1024 * 32-bit internal audio buffer. 251 * The first rule is for the buffer size, we should not allow
191 * Set constraint for minimum buffer size to the same than FIFO 252 * smaller buffer than the FIFO size to avoid underruns
192 * size in order to avoid underruns in playback startup because 253 */
193 * HW is keeping the DMA request active until FIFO is filled. 254 snd_pcm_hw_rule_add(substream->runtime, 0,
194 */ 255 SNDRV_PCM_HW_PARAM_CHANNELS,
195 if (bus_id == 1) 256 omap_mcbsp_hwrule_min_buffersize,
196 snd_pcm_hw_constraint_minmax(substream->runtime, 257 mcbsp_data,
197 SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 258 SNDRV_PCM_HW_PARAM_BUFFER_SIZE, -1);
198 4096, UINT_MAX);
199
200 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
201 max_period = omap_mcbsp_get_max_tx_threshold(bus_id);
202 else
203 max_period = omap_mcbsp_get_max_rx_threshold(bus_id);
204
205 max_period++;
206 max_period <<= 1;
207 259
260 /*
261 * In case of threshold mode, the rule will ensure, that the
262 * period size is not bigger than the maximum allowed threshold
263 * value.
264 */
208 if (dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) 265 if (dma_op_mode == MCBSP_DMA_MODE_THRESHOLD)
209 snd_pcm_hw_constraint_minmax(substream->runtime, 266 snd_pcm_hw_rule_add(substream->runtime, 0,
210 SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 267 SNDRV_PCM_HW_PARAM_CHANNELS,
211 32, max_period); 268 omap_mcbsp_hwrule_max_periodsize,
269 substream,
270 SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1);
212 } 271 }
213 272
214 return err; 273 return err;
@@ -409,6 +468,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
409 } 468 }
410 469
411 omap_mcbsp_config(bus_id, &mcbsp_data->regs); 470 omap_mcbsp_config(bus_id, &mcbsp_data->regs);
471 mcbsp_data->wlen = wlen;
412 mcbsp_data->configured = 1; 472 mcbsp_data->configured = 1;
413 473
414 return 0; 474 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/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..2871a200160c 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
diff --git a/sound/soc/sh/fsi-da7210.c b/sound/soc/sh/fsi-da7210.c
index 33b4d177f466..4d4fd777b45a 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
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c
index ec4acac49ebd..a1ce6089177c 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
@@ -57,13 +48,12 @@
57 48
58/* DO_FMT */ 49/* DO_FMT */
59/* DI_FMT */ 50/* DI_FMT */
60#define CR_FMT(param) ((param) << 4) 51#define CR_MONO (0x0 << 4)
61# define CR_MONO 0x0 52#define CR_MONO_D (0x1 << 4)
62# define CR_MONO_D 0x1 53#define CR_PCM (0x2 << 4)
63# define CR_PCM 0x2 54#define CR_I2S (0x3 << 4)
64# define CR_I2S 0x3 55#define CR_TDM (0x4 << 4)
65# define CR_TDM 0x4 56#define CR_TDM_D (0x5 << 4)
66# define CR_TDM_D 0x5
67 57
68/* DOFF_CTL */ 58/* DOFF_CTL */
69/* DIFF_CTL */ 59/* DIFF_CTL */
@@ -75,6 +65,10 @@
75#define ERR_UNDER 0x00000001 65#define ERR_UNDER 0x00000001
76#define ST_ERR (ERR_OVER | ERR_UNDER) 66#define ST_ERR (ERR_OVER | ERR_UNDER)
77 67
68/* CKG1 */
69#define ACKMD_MASK 0x00007000
70#define BPFMD_MASK 0x00000700
71
78/* CLK_RST */ 72/* CLK_RST */
79#define B_CLK 0x00000010 73#define B_CLK 0x00000010
80#define A_CLK 0x00000001 74#define A_CLK 0x00000001
@@ -121,7 +115,9 @@ struct fsi_priv {
121 int periods; 115 int periods;
122}; 116};
123 117
124struct fsi_regs { 118struct fsi_core {
119 int ver;
120
125 u32 int_st; 121 u32 int_st;
126 u32 iemsk; 122 u32 iemsk;
127 u32 imsk; 123 u32 imsk;
@@ -132,7 +128,7 @@ struct fsi_master {
132 int irq; 128 int irq;
133 struct fsi_priv fsia; 129 struct fsi_priv fsia;
134 struct fsi_priv fsib; 130 struct fsi_priv fsib;
135 struct fsi_regs *regs; 131 struct fsi_core *core;
136 struct sh_fsi_platform_info *info; 132 struct sh_fsi_platform_info *info;
137 spinlock_t lock; 133 spinlock_t lock;
138}; 134};
@@ -169,24 +165,30 @@ static void __fsi_reg_mask_set(u32 reg, u32 mask, u32 data)
169 165
170static void fsi_reg_write(struct fsi_priv *fsi, u32 reg, u32 data) 166static void fsi_reg_write(struct fsi_priv *fsi, u32 reg, u32 data)
171{ 167{
172 if (reg > REG_END) 168 if (reg > REG_END) {
169 pr_err("fsi: register access err (%s)\n", __func__);
173 return; 170 return;
171 }
174 172
175 __fsi_reg_write((u32)(fsi->base + reg), data); 173 __fsi_reg_write((u32)(fsi->base + reg), data);
176} 174}
177 175
178static u32 fsi_reg_read(struct fsi_priv *fsi, u32 reg) 176static u32 fsi_reg_read(struct fsi_priv *fsi, u32 reg)
179{ 177{
180 if (reg > REG_END) 178 if (reg > REG_END) {
179 pr_err("fsi: register access err (%s)\n", __func__);
181 return 0; 180 return 0;
181 }
182 182
183 return __fsi_reg_read((u32)(fsi->base + reg)); 183 return __fsi_reg_read((u32)(fsi->base + reg));
184} 184}
185 185
186static void fsi_reg_mask_set(struct fsi_priv *fsi, u32 reg, u32 mask, u32 data) 186static void fsi_reg_mask_set(struct fsi_priv *fsi, u32 reg, u32 mask, u32 data)
187{ 187{
188 if (reg > REG_END) 188 if (reg > REG_END) {
189 pr_err("fsi: register access err (%s)\n", __func__);
189 return; 190 return;
191 }
190 192
191 __fsi_reg_mask_set((u32)(fsi->base + reg), mask, data); 193 __fsi_reg_mask_set((u32)(fsi->base + reg), mask, data);
192} 194}
@@ -196,8 +198,10 @@ static void fsi_master_write(struct fsi_master *master, u32 reg, u32 data)
196 unsigned long flags; 198 unsigned long flags;
197 199
198 if ((reg < MREG_START) || 200 if ((reg < MREG_START) ||
199 (reg > MREG_END)) 201 (reg > MREG_END)) {
202 pr_err("fsi: register access err (%s)\n", __func__);
200 return; 203 return;
204 }
201 205
202 spin_lock_irqsave(&master->lock, flags); 206 spin_lock_irqsave(&master->lock, flags);
203 __fsi_reg_write((u32)(master->base + reg), data); 207 __fsi_reg_write((u32)(master->base + reg), data);
@@ -210,8 +214,10 @@ static u32 fsi_master_read(struct fsi_master *master, u32 reg)
210 unsigned long flags; 214 unsigned long flags;
211 215
212 if ((reg < MREG_START) || 216 if ((reg < MREG_START) ||
213 (reg > MREG_END)) 217 (reg > MREG_END)) {
218 pr_err("fsi: register access err (%s)\n", __func__);
214 return 0; 219 return 0;
220 }
215 221
216 spin_lock_irqsave(&master->lock, flags); 222 spin_lock_irqsave(&master->lock, flags);
217 ret = __fsi_reg_read((u32)(master->base + reg)); 223 ret = __fsi_reg_read((u32)(master->base + reg));
@@ -226,8 +232,10 @@ static void fsi_master_mask_set(struct fsi_master *master,
226 unsigned long flags; 232 unsigned long flags;
227 233
228 if ((reg < MREG_START) || 234 if ((reg < MREG_START) ||
229 (reg > MREG_END)) 235 (reg > MREG_END)) {
236 pr_err("fsi: register access err (%s)\n", __func__);
230 return; 237 return;
238 }
231 239
232 spin_lock_irqsave(&master->lock, flags); 240 spin_lock_irqsave(&master->lock, flags);
233 __fsi_reg_mask_set((u32)(master->base + reg), mask, data); 241 __fsi_reg_mask_set((u32)(master->base + reg), mask, data);
@@ -349,8 +357,8 @@ static void fsi_irq_enable(struct fsi_priv *fsi, int is_play)
349 u32 data = fsi_port_ab_io_bit(fsi, is_play); 357 u32 data = fsi_port_ab_io_bit(fsi, is_play);
350 struct fsi_master *master = fsi_get_master(fsi); 358 struct fsi_master *master = fsi_get_master(fsi);
351 359
352 fsi_master_mask_set(master, master->regs->imsk, data, data); 360 fsi_master_mask_set(master, master->core->imsk, data, data);
353 fsi_master_mask_set(master, master->regs->iemsk, data, data); 361 fsi_master_mask_set(master, master->core->iemsk, data, data);
354} 362}
355 363
356static void fsi_irq_disable(struct fsi_priv *fsi, int is_play) 364static void fsi_irq_disable(struct fsi_priv *fsi, int is_play)
@@ -358,18 +366,18 @@ static void fsi_irq_disable(struct fsi_priv *fsi, int is_play)
358 u32 data = fsi_port_ab_io_bit(fsi, is_play); 366 u32 data = fsi_port_ab_io_bit(fsi, is_play);
359 struct fsi_master *master = fsi_get_master(fsi); 367 struct fsi_master *master = fsi_get_master(fsi);
360 368
361 fsi_master_mask_set(master, master->regs->imsk, data, 0); 369 fsi_master_mask_set(master, master->core->imsk, data, 0);
362 fsi_master_mask_set(master, master->regs->iemsk, data, 0); 370 fsi_master_mask_set(master, master->core->iemsk, data, 0);
363} 371}
364 372
365static u32 fsi_irq_get_status(struct fsi_master *master) 373static u32 fsi_irq_get_status(struct fsi_master *master)
366{ 374{
367 return fsi_master_read(master, master->regs->int_st); 375 return fsi_master_read(master, master->core->int_st);
368} 376}
369 377
370static void fsi_irq_clear_all_status(struct fsi_master *master) 378static void fsi_irq_clear_all_status(struct fsi_master *master)
371{ 379{
372 fsi_master_write(master, master->regs->int_st, 0x0000000); 380 fsi_master_write(master, master->core->int_st, 0);
373} 381}
374 382
375static void fsi_irq_clear_status(struct fsi_priv *fsi) 383static void fsi_irq_clear_status(struct fsi_priv *fsi)
@@ -381,7 +389,7 @@ static void fsi_irq_clear_status(struct fsi_priv *fsi)
381 data |= fsi_port_ab_io_bit(fsi, 1); 389 data |= fsi_port_ab_io_bit(fsi, 1);
382 390
383 /* clear interrupt factor */ 391 /* clear interrupt factor */
384 fsi_master_mask_set(master, master->regs->int_st, data, 0); 392 fsi_master_mask_set(master, master->core->int_st, data, 0);
385} 393}
386 394
387/************************************************************************ 395/************************************************************************
@@ -662,7 +670,6 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream,
662 struct snd_soc_dai *dai) 670 struct snd_soc_dai *dai)
663{ 671{
664 struct fsi_priv *fsi = fsi_get_priv(substream); 672 struct fsi_priv *fsi = fsi_get_priv(substream);
665 const char *msg;
666 u32 flags = fsi_get_info_flags(fsi); 673 u32 flags = fsi_get_info_flags(fsi);
667 u32 fmt; 674 u32 fmt;
668 u32 reg; 675 u32 reg;
@@ -700,36 +707,30 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream,
700 fmt = is_play ? SH_FSI_GET_OFMT(flags) : SH_FSI_GET_IFMT(flags); 707 fmt = is_play ? SH_FSI_GET_OFMT(flags) : SH_FSI_GET_IFMT(flags);
701 switch (fmt) { 708 switch (fmt) {
702 case SH_FSI_FMT_MONO: 709 case SH_FSI_FMT_MONO:
703 msg = "MONO"; 710 data = CR_MONO;
704 data = CR_FMT(CR_MONO);
705 fsi->chan = 1; 711 fsi->chan = 1;
706 break; 712 break;
707 case SH_FSI_FMT_MONO_DELAY: 713 case SH_FSI_FMT_MONO_DELAY:
708 msg = "MONO Delay"; 714 data = CR_MONO_D;
709 data = CR_FMT(CR_MONO_D);
710 fsi->chan = 1; 715 fsi->chan = 1;
711 break; 716 break;
712 case SH_FSI_FMT_PCM: 717 case SH_FSI_FMT_PCM:
713 msg = "PCM"; 718 data = CR_PCM;
714 data = CR_FMT(CR_PCM);
715 fsi->chan = 2; 719 fsi->chan = 2;
716 break; 720 break;
717 case SH_FSI_FMT_I2S: 721 case SH_FSI_FMT_I2S:
718 msg = "I2S"; 722 data = CR_I2S;
719 data = CR_FMT(CR_I2S);
720 fsi->chan = 2; 723 fsi->chan = 2;
721 break; 724 break;
722 case SH_FSI_FMT_TDM: 725 case SH_FSI_FMT_TDM:
723 msg = "TDM";
724 fsi->chan = is_play ? 726 fsi->chan = is_play ?
725 SH_FSI_GET_CH_O(flags) : SH_FSI_GET_CH_I(flags); 727 SH_FSI_GET_CH_O(flags) : SH_FSI_GET_CH_I(flags);
726 data = CR_FMT(CR_TDM) | (fsi->chan - 1); 728 data = CR_TDM | (fsi->chan - 1);
727 break; 729 break;
728 case SH_FSI_FMT_TDM_DELAY: 730 case SH_FSI_FMT_TDM_DELAY:
729 msg = "TDM Delay";
730 fsi->chan = is_play ? 731 fsi->chan = is_play ?
731 SH_FSI_GET_CH_O(flags) : SH_FSI_GET_CH_I(flags); 732 SH_FSI_GET_CH_O(flags) : SH_FSI_GET_CH_I(flags);
732 data = CR_FMT(CR_TDM_D) | (fsi->chan - 1); 733 data = CR_TDM_D | (fsi->chan - 1);
733 break; 734 break;
734 default: 735 default:
735 dev_err(dai->dev, "unknown format.\n"); 736 dev_err(dai->dev, "unknown format.\n");
@@ -737,12 +738,6 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream,
737 } 738 }
738 fsi_reg_write(fsi, reg, data); 739 fsi_reg_write(fsi, reg, data);
739 740
740 /*
741 * clear clk reset if master mode
742 */
743 if (is_master)
744 fsi_clk_ctrl(fsi, 1);
745
746 /* irq clear */ 741 /* irq clear */
747 fsi_irq_disable(fsi, is_play); 742 fsi_irq_disable(fsi, is_play);
748 fsi_irq_clear_status(fsi); 743 fsi_irq_clear_status(fsi);
@@ -789,10 +784,98 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
789 return ret; 784 return ret;
790} 785}
791 786
787static int fsi_dai_hw_params(struct snd_pcm_substream *substream,
788 struct snd_pcm_hw_params *params,
789 struct snd_soc_dai *dai)
790{
791 struct fsi_priv *fsi = fsi_get_priv(substream);
792 struct fsi_master *master = fsi_get_master(fsi);
793 int (*set_rate)(int is_porta, int rate) = master->info->set_rate;
794 int fsi_ver = master->core->ver;
795 int is_play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
796 int ret;
797
798 /* if slave mode, set_rate is not needed */
799 if (!fsi_is_master_mode(fsi, is_play))
800 return 0;
801
802 /* it is error if no set_rate */
803 if (!set_rate)
804 return -EIO;
805
806 /* clock stop */
807 pm_runtime_put_sync(dai->dev);
808 fsi_clk_ctrl(fsi, 0);
809
810 ret = set_rate(fsi_is_port_a(fsi), params_rate(params));
811 if (ret > 0) {
812 u32 data = 0;
813
814 switch (ret & SH_FSI_ACKMD_MASK) {
815 default:
816 /* FALL THROUGH */
817 case SH_FSI_ACKMD_512:
818 data |= (0x0 << 12);
819 break;
820 case SH_FSI_ACKMD_256:
821 data |= (0x1 << 12);
822 break;
823 case SH_FSI_ACKMD_128:
824 data |= (0x2 << 12);
825 break;
826 case SH_FSI_ACKMD_64:
827 data |= (0x3 << 12);
828 break;
829 case SH_FSI_ACKMD_32:
830 if (fsi_ver < 2)
831 dev_err(dai->dev, "unsupported ACKMD\n");
832 else
833 data |= (0x4 << 12);
834 break;
835 }
836
837 switch (ret & SH_FSI_BPFMD_MASK) {
838 default:
839 /* FALL THROUGH */
840 case SH_FSI_BPFMD_32:
841 data |= (0x0 << 8);
842 break;
843 case SH_FSI_BPFMD_64:
844 data |= (0x1 << 8);
845 break;
846 case SH_FSI_BPFMD_128:
847 data |= (0x2 << 8);
848 break;
849 case SH_FSI_BPFMD_256:
850 data |= (0x3 << 8);
851 break;
852 case SH_FSI_BPFMD_512:
853 data |= (0x4 << 8);
854 break;
855 case SH_FSI_BPFMD_16:
856 if (fsi_ver < 2)
857 dev_err(dai->dev, "unsupported ACKMD\n");
858 else
859 data |= (0x7 << 8);
860 break;
861 }
862
863 fsi_reg_mask_set(fsi, CKG1, (ACKMD_MASK | BPFMD_MASK) , data);
864 udelay(10);
865 fsi_clk_ctrl(fsi, 1);
866 ret = 0;
867 }
868 pm_runtime_get_sync(dai->dev);
869
870 return ret;
871
872}
873
792static struct snd_soc_dai_ops fsi_dai_ops = { 874static struct snd_soc_dai_ops fsi_dai_ops = {
793 .startup = fsi_dai_startup, 875 .startup = fsi_dai_startup,
794 .shutdown = fsi_dai_shutdown, 876 .shutdown = fsi_dai_shutdown,
795 .trigger = fsi_dai_trigger, 877 .trigger = fsi_dai_trigger,
878 .hw_params = fsi_dai_hw_params,
796}; 879};
797 880
798/************************************************************************ 881/************************************************************************
@@ -1004,7 +1087,7 @@ static int fsi_probe(struct platform_device *pdev)
1004 master->fsia.master = master; 1087 master->fsia.master = master;
1005 master->fsib.base = master->base + 0x40; 1088 master->fsib.base = master->base + 0x40;
1006 master->fsib.master = master; 1089 master->fsib.master = master;
1007 master->regs = (struct fsi_regs *)id_entry->driver_data; 1090 master->core = (struct fsi_core *)id_entry->driver_data;
1008 spin_lock_init(&master->lock); 1091 spin_lock_init(&master->lock);
1009 1092
1010 pm_runtime_enable(&pdev->dev); 1093 pm_runtime_enable(&pdev->dev);
@@ -1085,21 +1168,27 @@ static struct dev_pm_ops fsi_pm_ops = {
1085 .runtime_resume = fsi_runtime_nop, 1168 .runtime_resume = fsi_runtime_nop,
1086}; 1169};
1087 1170
1088static struct fsi_regs fsi_regs = { 1171static struct fsi_core fsi1_core = {
1172 .ver = 1,
1173
1174 /* Interrupt */
1089 .int_st = INT_ST, 1175 .int_st = INT_ST,
1090 .iemsk = IEMSK, 1176 .iemsk = IEMSK,
1091 .imsk = IMSK, 1177 .imsk = IMSK,
1092}; 1178};
1093 1179
1094static struct fsi_regs fsi2_regs = { 1180static struct fsi_core fsi2_core = {
1181 .ver = 2,
1182
1183 /* Interrupt */
1095 .int_st = CPU_INT_ST, 1184 .int_st = CPU_INT_ST,
1096 .iemsk = CPU_IEMSK, 1185 .iemsk = CPU_IEMSK,
1097 .imsk = CPU_IMSK, 1186 .imsk = CPU_IMSK,
1098}; 1187};
1099 1188
1100static struct platform_device_id fsi_id_table[] = { 1189static struct platform_device_id fsi_id_table[] = {
1101 { "sh_fsi", (kernel_ulong_t)&fsi_regs }, 1190 { "sh_fsi", (kernel_ulong_t)&fsi1_core },
1102 { "sh_fsi2", (kernel_ulong_t)&fsi2_regs }, 1191 { "sh_fsi2", (kernel_ulong_t)&fsi2_core },
1103}; 1192};
1104 1193
1105static struct platform_driver fsi_driver = { 1194static struct platform_driver fsi_driver = {
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 998569d60330..8b79d90efdc1 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -2353,6 +2353,99 @@ int snd_soc_limit_volume(struct snd_soc_codec *codec,
2353EXPORT_SYMBOL_GPL(snd_soc_limit_volume); 2353EXPORT_SYMBOL_GPL(snd_soc_limit_volume);
2354 2354
2355/** 2355/**
2356 * snd_soc_info_volsw_2r_sx - double with tlv and variable data size
2357 * mixer info callback
2358 * @kcontrol: mixer control
2359 * @uinfo: control element information
2360 *
2361 * Returns 0 for success.
2362 */
2363int snd_soc_info_volsw_2r_sx(struct snd_kcontrol *kcontrol,
2364 struct snd_ctl_elem_info *uinfo)
2365{
2366 struct soc_mixer_control *mc =
2367 (struct soc_mixer_control *)kcontrol->private_value;
2368 int max = mc->max;
2369 int min = mc->min;
2370
2371 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
2372 uinfo->count = 2;
2373 uinfo->value.integer.min = 0;
2374 uinfo->value.integer.max = max-min;
2375
2376 return 0;
2377}
2378EXPORT_SYMBOL_GPL(snd_soc_info_volsw_2r_sx);
2379
2380/**
2381 * snd_soc_get_volsw_2r_sx - double with tlv and variable data size
2382 * mixer get callback
2383 * @kcontrol: mixer control
2384 * @uinfo: control element information
2385 *
2386 * Returns 0 for success.
2387 */
2388int snd_soc_get_volsw_2r_sx(struct snd_kcontrol *kcontrol,
2389 struct snd_ctl_elem_value *ucontrol)
2390{
2391 struct soc_mixer_control *mc =
2392 (struct soc_mixer_control *)kcontrol->private_value;
2393 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
2394 unsigned int mask = (1<<mc->shift)-1;
2395 int min = mc->min;
2396 int val = snd_soc_read(codec, mc->reg) & mask;
2397 int valr = snd_soc_read(codec, mc->rreg) & mask;
2398
2399 ucontrol->value.integer.value[0] = ((val & 0xff)-min) & mask;
2400 ucontrol->value.integer.value[1] = ((valr & 0xff)-min) & mask;
2401 return 0;
2402}
2403EXPORT_SYMBOL_GPL(snd_soc_get_volsw_2r_sx);
2404
2405/**
2406 * snd_soc_put_volsw_2r_sx - double with tlv and variable data size
2407 * mixer put callback
2408 * @kcontrol: mixer control
2409 * @uinfo: control element information
2410 *
2411 * Returns 0 for success.
2412 */
2413int snd_soc_put_volsw_2r_sx(struct snd_kcontrol *kcontrol,
2414 struct snd_ctl_elem_value *ucontrol)
2415{
2416 struct soc_mixer_control *mc =
2417 (struct soc_mixer_control *)kcontrol->private_value;
2418 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
2419 unsigned int mask = (1<<mc->shift)-1;
2420 int min = mc->min;
2421 int ret;
2422 unsigned int val, valr, oval, ovalr;
2423
2424 val = ((ucontrol->value.integer.value[0]+min) & 0xff);
2425 val &= mask;
2426 valr = ((ucontrol->value.integer.value[1]+min) & 0xff);
2427 valr &= mask;
2428
2429 oval = snd_soc_read(codec, mc->reg) & mask;
2430 ovalr = snd_soc_read(codec, mc->rreg) & mask;
2431
2432 ret = 0;
2433 if (oval != val) {
2434 ret = snd_soc_write(codec, mc->reg, val);
2435 if (ret < 0)
2436 return ret;
2437 }
2438 if (ovalr != valr) {
2439 ret = snd_soc_write(codec, mc->rreg, valr);
2440 if (ret < 0)
2441 return ret;
2442 }
2443
2444 return 0;
2445}
2446EXPORT_SYMBOL_GPL(snd_soc_put_volsw_2r_sx);
2447
2448/**
2356 * snd_soc_dai_set_sysclk - configure DAI system or master clock. 2449 * snd_soc_dai_set_sysclk - configure DAI system or master clock.
2357 * @dai: DAI 2450 * @dai: DAI
2358 * @clk_id: DAI specific clock ID 2451 * @clk_id: DAI specific clock ID