aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/s3c24xx
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/s3c24xx')
-rw-r--r--sound/soc/s3c24xx/Kconfig34
-rw-r--r--sound/soc/s3c24xx/Makefile13
-rw-r--r--sound/soc/s3c24xx/jive_wm8750.c2
-rw-r--r--sound/soc/s3c24xx/ln2440sbc_alc650.c6
-rw-r--r--sound/soc/s3c24xx/neo1973_gta02_wm8753.c10
-rw-r--r--sound/soc/s3c24xx/neo1973_wm8753.c11
-rw-r--r--sound/soc/s3c24xx/s3c-ac97.c521
-rw-r--r--sound/soc/s3c24xx/s3c-ac97.h23
-rw-r--r--sound/soc/s3c24xx/s3c-dma.c (renamed from sound/soc/s3c24xx/s3c24xx-pcm.c)90
-rw-r--r--sound/soc/s3c24xx/s3c-dma.h (renamed from sound/soc/s3c24xx/s3c24xx-pcm.h)8
-rw-r--r--sound/soc/s3c24xx/s3c-i2s-v2.c46
-rw-r--r--sound/soc/s3c24xx/s3c-i2s-v2.h4
-rw-r--r--sound/soc/s3c24xx/s3c-pcm.c554
-rw-r--r--sound/soc/s3c24xx/s3c-pcm.h123
-rw-r--r--sound/soc/s3c24xx/s3c2412-i2s.c7
-rw-r--r--sound/soc/s3c24xx/s3c2443-ac97.c433
-rw-r--r--sound/soc/s3c24xx/s3c24xx-ac97.h25
-rw-r--r--sound/soc/s3c24xx/s3c24xx-i2s.c27
-rw-r--r--sound/soc/s3c24xx/s3c24xx_simtec.c6
-rw-r--r--sound/soc/s3c24xx/s3c24xx_simtec.h2
-rw-r--r--sound/soc/s3c24xx/s3c24xx_simtec_hermes.c2
-rw-r--r--sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c2
-rw-r--r--sound/soc/s3c24xx/s3c24xx_uda134x.c2
-rw-r--r--sound/soc/s3c24xx/s3c64xx-i2s.c146
-rw-r--r--sound/soc/s3c24xx/s3c64xx-i2s.h1
-rw-r--r--sound/soc/s3c24xx/smdk2443_wm9710.c6
-rw-r--r--sound/soc/s3c24xx/smdk64xx_wm8580.c268
-rw-r--r--sound/soc/s3c24xx/smdk_wm9713.c94
28 files changed, 1814 insertions, 652 deletions
diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig
index 923428fc1adb..15fe57e5a232 100644
--- a/sound/soc/s3c24xx/Kconfig
+++ b/sound/soc/s3c24xx/Kconfig
@@ -24,12 +24,13 @@ config SND_S3C64XX_SOC_I2S
24 select SND_S3C_I2SV2_SOC 24 select SND_S3C_I2SV2_SOC
25 select S3C64XX_DMA 25 select S3C64XX_DMA
26 26
27config SND_S3C2443_SOC_AC97 27config SND_S3C_SOC_PCM
28 tristate
29
30config SND_S3C_SOC_AC97
28 tristate 31 tristate
29 select S3C2410_DMA
30 select AC97_BUS
31 select SND_SOC_AC97_BUS 32 select SND_SOC_AC97_BUS
32 33
33config SND_S3C24XX_SOC_NEO1973_WM8753 34config SND_S3C24XX_SOC_NEO1973_WM8753
34 tristate "SoC I2S Audio support for NEO1973 - WM8753" 35 tristate "SoC I2S Audio support for NEO1973 - WM8753"
35 depends on SND_S3C24XX_SOC && MACH_NEO1973_GTA01 36 depends on SND_S3C24XX_SOC && MACH_NEO1973_GTA01
@@ -56,11 +57,22 @@ config SND_S3C24XX_SOC_JIVE_WM8750
56 help 57 help
57 Sat Y if you want to add support for SoC audio on the Jive. 58 Sat Y if you want to add support for SoC audio on the Jive.
58 59
60config SND_S3C64XX_SOC_WM8580
61 tristate "SoC I2S Audio support for WM8580 on SMDK64XX"
62 depends on SND_S3C24XX_SOC && (MACH_SMDK6400 || MACH_SMDK6410)
63 depends on BROKEN
64 select SND_SOC_WM8580
65 select SND_S3C64XX_SOC_I2S
66 help
67 Sat Y if you want to add support for SoC audio on the SMDK64XX.
68
59config SND_S3C24XX_SOC_SMDK2443_WM9710 69config SND_S3C24XX_SOC_SMDK2443_WM9710
60 tristate "SoC AC97 Audio support for SMDK2443 - WM9710" 70 tristate "SoC AC97 Audio support for SMDK2443 - WM9710"
61 depends on SND_S3C24XX_SOC && MACH_SMDK2443 71 depends on SND_S3C24XX_SOC && MACH_SMDK2443
62 select SND_S3C2443_SOC_AC97 72 select S3C2410_DMA
73 select AC97_BUS
63 select SND_SOC_AC97_CODEC 74 select SND_SOC_AC97_CODEC
75 select SND_S3C_SOC_AC97
64 help 76 help
65 Say Y if you want to add support for SoC audio on smdk2443 77 Say Y if you want to add support for SoC audio on smdk2443
66 with the WM9710. 78 with the WM9710.
@@ -68,8 +80,10 @@ config SND_S3C24XX_SOC_SMDK2443_WM9710
68config SND_S3C24XX_SOC_LN2440SBC_ALC650 80config SND_S3C24XX_SOC_LN2440SBC_ALC650
69 tristate "SoC AC97 Audio support for LN2440SBC - ALC650" 81 tristate "SoC AC97 Audio support for LN2440SBC - ALC650"
70 depends on SND_S3C24XX_SOC && ARCH_S3C2410 82 depends on SND_S3C24XX_SOC && ARCH_S3C2410
71 select SND_S3C2443_SOC_AC97 83 select S3C2410_DMA
84 select AC97_BUS
72 select SND_SOC_AC97_CODEC 85 select SND_SOC_AC97_CODEC
86 select SND_S3C_SOC_AC97
73 help 87 help
74 Say Y if you want to add support for SoC audio on ln2440sbc 88 Say Y if you want to add support for SoC audio on ln2440sbc
75 with the ALC650. 89 with the ALC650.
@@ -99,3 +113,11 @@ config SND_S3C24XX_SOC_SIMTEC_HERMES
99 select SND_S3C24XX_SOC_I2S 113 select SND_S3C24XX_SOC_I2S
100 select SND_SOC_TLV320AIC3X 114 select SND_SOC_TLV320AIC3X
101 select SND_S3C24XX_SOC_SIMTEC 115 select SND_S3C24XX_SOC_SIMTEC
116
117config SND_SOC_SMDK_WM9713
118 tristate "SoC AC97 Audio support for SMDK with WM9713"
119 depends on SND_S3C24XX_SOC && MACH_SMDK6410
120 select SND_SOC_WM9713
121 select SND_S3C_SOC_AC97
122 help
123 Sat Y if you want to add support for SoC audio on the SMDK.
diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile
index 99f5a7dd3fc6..df071a376fa2 100644
--- a/sound/soc/s3c24xx/Makefile
+++ b/sound/soc/s3c24xx/Makefile
@@ -1,17 +1,19 @@
1# S3c24XX Platform Support 1# S3c24XX Platform Support
2snd-soc-s3c24xx-objs := s3c24xx-pcm.o 2snd-soc-s3c24xx-objs := s3c-dma.o
3snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o 3snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o
4snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o 4snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o
5snd-soc-s3c64xx-i2s-objs := s3c64xx-i2s.o 5snd-soc-s3c64xx-i2s-objs := s3c64xx-i2s.o
6snd-soc-s3c2443-ac97-objs := s3c2443-ac97.o 6snd-soc-s3c-ac97-objs := s3c-ac97.o
7snd-soc-s3c-i2s-v2-objs := s3c-i2s-v2.o 7snd-soc-s3c-i2s-v2-objs := s3c-i2s-v2.o
8snd-soc-s3c-pcm-objs := s3c-pcm.o
8 9
9obj-$(CONFIG_SND_S3C24XX_SOC) += snd-soc-s3c24xx.o 10obj-$(CONFIG_SND_S3C24XX_SOC) += snd-soc-s3c24xx.o
10obj-$(CONFIG_SND_S3C24XX_SOC_I2S) += snd-soc-s3c24xx-i2s.o 11obj-$(CONFIG_SND_S3C24XX_SOC_I2S) += snd-soc-s3c24xx-i2s.o
11obj-$(CONFIG_SND_S3C2443_SOC_AC97) += snd-soc-s3c2443-ac97.o 12obj-$(CONFIG_SND_S3C_SOC_AC97) += snd-soc-s3c-ac97.o
12obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o 13obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o
13obj-$(CONFIG_SND_S3C64XX_SOC_I2S) += snd-soc-s3c64xx-i2s.o 14obj-$(CONFIG_SND_S3C64XX_SOC_I2S) += snd-soc-s3c64xx-i2s.o
14obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o 15obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o
16obj-$(CONFIG_SND_S3C_SOC_PCM) += snd-soc-s3c-pcm.o
15 17
16# S3C24XX Machine Support 18# S3C24XX Machine Support
17snd-soc-jive-wm8750-objs := jive_wm8750.o 19snd-soc-jive-wm8750-objs := jive_wm8750.o
@@ -23,6 +25,8 @@ snd-soc-s3c24xx-uda134x-objs := s3c24xx_uda134x.o
23snd-soc-s3c24xx-simtec-objs := s3c24xx_simtec.o 25snd-soc-s3c24xx-simtec-objs := s3c24xx_simtec.o
24snd-soc-s3c24xx-simtec-hermes-objs := s3c24xx_simtec_hermes.o 26snd-soc-s3c24xx-simtec-hermes-objs := s3c24xx_simtec_hermes.o
25snd-soc-s3c24xx-simtec-tlv320aic23-objs := s3c24xx_simtec_tlv320aic23.o 27snd-soc-s3c24xx-simtec-tlv320aic23-objs := s3c24xx_simtec_tlv320aic23.o
28snd-soc-smdk64xx-wm8580-objs := smdk64xx_wm8580.o
29snd-soc-smdk-wm9713-objs := smdk_wm9713.o
26 30
27obj-$(CONFIG_SND_S3C24XX_SOC_JIVE_WM8750) += snd-soc-jive-wm8750.o 31obj-$(CONFIG_SND_S3C24XX_SOC_JIVE_WM8750) += snd-soc-jive-wm8750.o
28obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o 32obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o
@@ -33,4 +37,5 @@ obj-$(CONFIG_SND_S3C24XX_SOC_S3C24XX_UDA134X) += snd-soc-s3c24xx-uda134x.o
33obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC) += snd-soc-s3c24xx-simtec.o 37obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC) += snd-soc-s3c24xx-simtec.o
34obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_HERMES) += snd-soc-s3c24xx-simtec-hermes.o 38obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_HERMES) += snd-soc-s3c24xx-simtec-hermes.o
35obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_TLV320AIC23) += snd-soc-s3c24xx-simtec-tlv320aic23.o 39obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_TLV320AIC23) += snd-soc-s3c24xx-simtec-tlv320aic23.o
36 40obj-$(CONFIG_SND_S3C64XX_SOC_WM8580) += snd-soc-smdk64xx-wm8580.o
41obj-$(CONFIG_SND_SOC_SMDK_WM9713) += snd-soc-smdk-wm9713.o
diff --git a/sound/soc/s3c24xx/jive_wm8750.c b/sound/soc/s3c24xx/jive_wm8750.c
index 93e6c87b7399..59dc2c6b56d9 100644
--- a/sound/soc/s3c24xx/jive_wm8750.c
+++ b/sound/soc/s3c24xx/jive_wm8750.c
@@ -25,7 +25,7 @@
25 25
26#include <asm/mach-types.h> 26#include <asm/mach-types.h>
27 27
28#include "s3c24xx-pcm.h" 28#include "s3c-dma.h"
29#include "s3c2412-i2s.h" 29#include "s3c2412-i2s.h"
30 30
31#include "../codecs/wm8750.h" 31#include "../codecs/wm8750.h"
diff --git a/sound/soc/s3c24xx/ln2440sbc_alc650.c b/sound/soc/s3c24xx/ln2440sbc_alc650.c
index 12c71482d258..ffa954fe6931 100644
--- a/sound/soc/s3c24xx/ln2440sbc_alc650.c
+++ b/sound/soc/s3c24xx/ln2440sbc_alc650.c
@@ -24,8 +24,8 @@
24#include <sound/soc-dapm.h> 24#include <sound/soc-dapm.h>
25 25
26#include "../codecs/ac97.h" 26#include "../codecs/ac97.h"
27#include "s3c24xx-pcm.h" 27#include "s3c-dma.h"
28#include "s3c24xx-ac97.h" 28#include "s3c-ac97.h"
29 29
30static struct snd_soc_card ln2440sbc; 30static struct snd_soc_card ln2440sbc;
31 31
@@ -33,7 +33,7 @@ static struct snd_soc_dai_link ln2440sbc_dai[] = {
33{ 33{
34 .name = "AC97", 34 .name = "AC97",
35 .stream_name = "AC97 HiFi", 35 .stream_name = "AC97 HiFi",
36 .cpu_dai = &s3c2443_ac97_dai[0], 36 .cpu_dai = &s3c_ac97_dai[S3C_AC97_DAI_PCM],
37 .codec_dai = &ac97_dai, 37 .codec_dai = &ac97_dai,
38}, 38},
39}; 39};
diff --git a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c
index 0c52e36ddd87..dea83d30a5c9 100644
--- a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c
+++ b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c
@@ -32,7 +32,7 @@
32#include <asm/io.h> 32#include <asm/io.h>
33#include <mach/gta02.h> 33#include <mach/gta02.h>
34#include "../codecs/wm8753.h" 34#include "../codecs/wm8753.h"
35#include "s3c24xx-pcm.h" 35#include "s3c-dma.h"
36#include "s3c24xx-i2s.h" 36#include "s3c24xx-i2s.h"
37 37
38static struct snd_soc_card neo1973_gta02; 38static struct snd_soc_card neo1973_gta02;
@@ -119,7 +119,7 @@ static int neo1973_gta02_hifi_hw_params(struct snd_pcm_substream *substream,
119 return ret; 119 return ret;
120 120
121 /* codec PLL input is PCLK/4 */ 121 /* codec PLL input is PCLK/4 */
122 ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 122 ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0,
123 iis_clkrate / 4, pll_out); 123 iis_clkrate / 4, pll_out);
124 if (ret < 0) 124 if (ret < 0)
125 return ret; 125 return ret;
@@ -133,7 +133,7 @@ static int neo1973_gta02_hifi_hw_free(struct snd_pcm_substream *substream)
133 struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; 133 struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
134 134
135 /* disable the PLL */ 135 /* disable the PLL */
136 return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0); 136 return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0, 0);
137} 137}
138 138
139/* 139/*
@@ -183,7 +183,7 @@ static int neo1973_gta02_voice_hw_params(
183 return ret; 183 return ret;
184 184
185 /* configue and enable PLL for 12.288MHz output */ 185 /* configue and enable PLL for 12.288MHz output */
186 ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 186 ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0,
187 iis_clkrate / 4, 12288000); 187 iis_clkrate / 4, 12288000);
188 if (ret < 0) 188 if (ret < 0)
189 return ret; 189 return ret;
@@ -197,7 +197,7 @@ static int neo1973_gta02_voice_hw_free(struct snd_pcm_substream *substream)
197 struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; 197 struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
198 198
199 /* disable the PLL */ 199 /* disable the PLL */
200 return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0); 200 return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0, 0);
201} 201}
202 202
203static struct snd_soc_ops neo1973_gta02_voice_ops = { 203static struct snd_soc_ops neo1973_gta02_voice_ops = {
diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c
index 906709e6dd5f..0cb4f86f6d1e 100644
--- a/sound/soc/s3c24xx/neo1973_wm8753.c
+++ b/sound/soc/s3c24xx/neo1973_wm8753.c
@@ -29,7 +29,6 @@
29#include <mach/regs-clock.h> 29#include <mach/regs-clock.h>
30#include <mach/regs-gpio.h> 30#include <mach/regs-gpio.h>
31#include <mach/hardware.h> 31#include <mach/hardware.h>
32#include <plat/audio.h>
33#include <linux/io.h> 32#include <linux/io.h>
34#include <mach/spi-gpio.h> 33#include <mach/spi-gpio.h>
35 34
@@ -37,7 +36,7 @@
37 36
38#include "../codecs/wm8753.h" 37#include "../codecs/wm8753.h"
39#include "lm4857.h" 38#include "lm4857.h"
40#include "s3c24xx-pcm.h" 39#include "s3c-dma.h"
41#include "s3c24xx-i2s.h" 40#include "s3c24xx-i2s.h"
42 41
43/* define the scenarios */ 42/* define the scenarios */
@@ -137,7 +136,7 @@ static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream,
137 return ret; 136 return ret;
138 137
139 /* codec PLL input is PCLK/4 */ 138 /* codec PLL input is PCLK/4 */
140 ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 139 ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0,
141 iis_clkrate / 4, pll_out); 140 iis_clkrate / 4, pll_out);
142 if (ret < 0) 141 if (ret < 0)
143 return ret; 142 return ret;
@@ -153,7 +152,7 @@ static int neo1973_hifi_hw_free(struct snd_pcm_substream *substream)
153 pr_debug("Entered %s\n", __func__); 152 pr_debug("Entered %s\n", __func__);
154 153
155 /* disable the PLL */ 154 /* disable the PLL */
156 return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0); 155 return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0, 0);
157} 156}
158 157
159/* 158/*
@@ -203,7 +202,7 @@ static int neo1973_voice_hw_params(struct snd_pcm_substream *substream,
203 return ret; 202 return ret;
204 203
205 /* configue and enable PLL for 12.288MHz output */ 204 /* configue and enable PLL for 12.288MHz output */
206 ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 205 ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0,
207 iis_clkrate / 4, 12288000); 206 iis_clkrate / 4, 12288000);
208 if (ret < 0) 207 if (ret < 0)
209 return ret; 208 return ret;
@@ -219,7 +218,7 @@ static int neo1973_voice_hw_free(struct snd_pcm_substream *substream)
219 pr_debug("Entered %s\n", __func__); 218 pr_debug("Entered %s\n", __func__);
220 219
221 /* disable the PLL */ 220 /* disable the PLL */
222 return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0); 221 return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0, 0);
223} 222}
224 223
225static struct snd_soc_ops neo1973_voice_ops = { 224static struct snd_soc_ops neo1973_voice_ops = {
diff --git a/sound/soc/s3c24xx/s3c-ac97.c b/sound/soc/s3c24xx/s3c-ac97.c
new file mode 100644
index 000000000000..ecf4fd04ae96
--- /dev/null
+++ b/sound/soc/s3c24xx/s3c-ac97.c
@@ -0,0 +1,521 @@
1/* sound/soc/s3c24xx/s3c-ac97.c
2 *
3 * ALSA SoC Audio Layer - S3C AC97 Controller driver
4 * Evolved from s3c2443-ac97.c
5 *
6 * Copyright (c) 2010 Samsung Electronics Co. Ltd
7 * Author: Jaswinder Singh <jassi.brar@samsung.com>
8 * Credits: Graeme Gregory, Sean Choi
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/init.h>
16#include <linux/module.h>
17#include <linux/io.h>
18#include <linux/delay.h>
19#include <linux/clk.h>
20
21#include <sound/soc.h>
22
23#include <plat/regs-ac97.h>
24#include <mach/dma.h>
25#include <plat/audio.h>
26
27#include "s3c-dma.h"
28#include "s3c-ac97.h"
29
30#define AC_CMD_ADDR(x) (x << 16)
31#define AC_CMD_DATA(x) (x & 0xffff)
32
33struct s3c_ac97_info {
34 unsigned state;
35 struct clk *ac97_clk;
36 void __iomem *regs;
37 struct mutex lock;
38 struct completion done;
39};
40static struct s3c_ac97_info s3c_ac97;
41
42static struct s3c2410_dma_client s3c_dma_client_out = {
43 .name = "AC97 PCMOut"
44};
45
46static struct s3c2410_dma_client s3c_dma_client_in = {
47 .name = "AC97 PCMIn"
48};
49
50static struct s3c2410_dma_client s3c_dma_client_micin = {
51 .name = "AC97 MicIn"
52};
53
54static struct s3c_dma_params s3c_ac97_pcm_out = {
55 .client = &s3c_dma_client_out,
56 .dma_size = 4,
57};
58
59static struct s3c_dma_params s3c_ac97_pcm_in = {
60 .client = &s3c_dma_client_in,
61 .dma_size = 4,
62};
63
64static struct s3c_dma_params s3c_ac97_mic_in = {
65 .client = &s3c_dma_client_micin,
66 .dma_size = 4,
67};
68
69static void s3c_ac97_activate(struct snd_ac97 *ac97)
70{
71 u32 ac_glbctrl, stat;
72
73 stat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT) & 0x7;
74 if (stat == S3C_AC97_GLBSTAT_MAINSTATE_ACTIVE)
75 return; /* Return if already active */
76
77 INIT_COMPLETION(s3c_ac97.done);
78
79 ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
80 ac_glbctrl = S3C_AC97_GLBCTRL_ACLINKON;
81 writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
82 msleep(1);
83
84 ac_glbctrl |= S3C_AC97_GLBCTRL_TRANSFERDATAENABLE;
85 writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
86 msleep(1);
87
88 ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
89 ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE;
90 writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
91
92 if (!wait_for_completion_timeout(&s3c_ac97.done, HZ))
93 printk(KERN_ERR "AC97: Unable to activate!");
94}
95
96static unsigned short s3c_ac97_read(struct snd_ac97 *ac97,
97 unsigned short reg)
98{
99 u32 ac_glbctrl, ac_codec_cmd;
100 u32 stat, addr, data;
101
102 mutex_lock(&s3c_ac97.lock);
103
104 s3c_ac97_activate(ac97);
105
106 INIT_COMPLETION(s3c_ac97.done);
107
108 ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD);
109 ac_codec_cmd = S3C_AC97_CODEC_CMD_READ | AC_CMD_ADDR(reg);
110 writel(ac_codec_cmd, s3c_ac97.regs + S3C_AC97_CODEC_CMD);
111
112 udelay(50);
113
114 ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
115 ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE;
116 writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
117
118 if (!wait_for_completion_timeout(&s3c_ac97.done, HZ))
119 printk(KERN_ERR "AC97: Unable to read!");
120
121 stat = readl(s3c_ac97.regs + S3C_AC97_STAT);
122 addr = (stat >> 16) & 0x7f;
123 data = (stat & 0xffff);
124
125 if (addr != reg)
126 printk(KERN_ERR "s3c-ac97: req addr = %02x, rep addr = %02x\n", reg, addr);
127
128 mutex_unlock(&s3c_ac97.lock);
129
130 return (unsigned short)data;
131}
132
133static void s3c_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
134 unsigned short val)
135{
136 u32 ac_glbctrl, ac_codec_cmd;
137
138 mutex_lock(&s3c_ac97.lock);
139
140 s3c_ac97_activate(ac97);
141
142 INIT_COMPLETION(s3c_ac97.done);
143
144 ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD);
145 ac_codec_cmd = AC_CMD_ADDR(reg) | AC_CMD_DATA(val);
146 writel(ac_codec_cmd, s3c_ac97.regs + S3C_AC97_CODEC_CMD);
147
148 udelay(50);
149
150 ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
151 ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE;
152 writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
153
154 if (!wait_for_completion_timeout(&s3c_ac97.done, HZ))
155 printk(KERN_ERR "AC97: Unable to write!");
156
157 ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD);
158 ac_codec_cmd |= S3C_AC97_CODEC_CMD_READ;
159 writel(ac_codec_cmd, s3c_ac97.regs + S3C_AC97_CODEC_CMD);
160
161 mutex_unlock(&s3c_ac97.lock);
162}
163
164static void s3c_ac97_cold_reset(struct snd_ac97 *ac97)
165{
166 writel(S3C_AC97_GLBCTRL_COLDRESET,
167 s3c_ac97.regs + S3C_AC97_GLBCTRL);
168 msleep(1);
169
170 writel(0, s3c_ac97.regs + S3C_AC97_GLBCTRL);
171 msleep(1);
172}
173
174static void s3c_ac97_warm_reset(struct snd_ac97 *ac97)
175{
176 u32 stat;
177
178 stat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT) & 0x7;
179 if (stat == S3C_AC97_GLBSTAT_MAINSTATE_ACTIVE)
180 return; /* Return if already active */
181
182 writel(S3C_AC97_GLBCTRL_WARMRESET, s3c_ac97.regs + S3C_AC97_GLBCTRL);
183 msleep(1);
184
185 writel(0, s3c_ac97.regs + S3C_AC97_GLBCTRL);
186 msleep(1);
187
188 s3c_ac97_activate(ac97);
189}
190
191static irqreturn_t s3c_ac97_irq(int irq, void *dev_id)
192{
193 u32 ac_glbctrl, ac_glbstat;
194
195 ac_glbstat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT);
196
197 if (ac_glbstat & S3C_AC97_GLBSTAT_CODECREADY) {
198
199 ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
200 ac_glbctrl &= ~S3C_AC97_GLBCTRL_CODECREADYIE;
201 writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
202
203 complete(&s3c_ac97.done);
204 }
205
206 ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
207 ac_glbctrl |= (1<<30); /* Clear interrupt */
208 writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
209
210 return IRQ_HANDLED;
211}
212
213struct snd_ac97_bus_ops soc_ac97_ops = {
214 .read = s3c_ac97_read,
215 .write = s3c_ac97_write,
216 .warm_reset = s3c_ac97_warm_reset,
217 .reset = s3c_ac97_cold_reset,
218};
219EXPORT_SYMBOL_GPL(soc_ac97_ops);
220
221static int s3c_ac97_hw_params(struct snd_pcm_substream *substream,
222 struct snd_pcm_hw_params *params,
223 struct snd_soc_dai *dai)
224{
225 struct snd_soc_pcm_runtime *rtd = substream->private_data;
226 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
227 struct s3c_dma_params *dma_data;
228
229 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
230 dma_data = &s3c_ac97_pcm_out;
231 else
232 dma_data = &s3c_ac97_pcm_in;
233
234 snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
235
236 return 0;
237}
238
239static int s3c_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
240 struct snd_soc_dai *dai)
241{
242 u32 ac_glbctrl;
243 struct snd_soc_pcm_runtime *rtd = substream->private_data;
244 struct s3c_dma_params *dma_data =
245 snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
246
247 ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
248 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
249 ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMINTM_MASK;
250 else
251 ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMOUTTM_MASK;
252
253 switch (cmd) {
254 case SNDRV_PCM_TRIGGER_START:
255 case SNDRV_PCM_TRIGGER_RESUME:
256 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
257 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
258 ac_glbctrl |= S3C_AC97_GLBCTRL_PCMINTM_DMA;
259 else
260 ac_glbctrl |= S3C_AC97_GLBCTRL_PCMOUTTM_DMA;
261 break;
262
263 case SNDRV_PCM_TRIGGER_STOP:
264 case SNDRV_PCM_TRIGGER_SUSPEND:
265 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
266 break;
267 }
268
269 writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
270
271 s3c2410_dma_ctrl(dma_data->channel, S3C2410_DMAOP_STARTED);
272
273 return 0;
274}
275
276static int s3c_ac97_hw_mic_params(struct snd_pcm_substream *substream,
277 struct snd_pcm_hw_params *params,
278 struct snd_soc_dai *dai)
279{
280 struct snd_soc_pcm_runtime *rtd = substream->private_data;
281 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
282
283 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
284 return -ENODEV;
285 else
286 snd_soc_dai_set_dma_data(cpu_dai, substream, &s3c_ac97_mic_in);
287
288 return 0;
289}
290
291static int s3c_ac97_mic_trigger(struct snd_pcm_substream *substream,
292 int cmd, struct snd_soc_dai *dai)
293{
294 u32 ac_glbctrl;
295 struct snd_soc_pcm_runtime *rtd = substream->private_data;
296 struct s3c_dma_params *dma_data =
297 snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
298
299 ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
300 ac_glbctrl &= ~S3C_AC97_GLBCTRL_MICINTM_MASK;
301
302 switch (cmd) {
303 case SNDRV_PCM_TRIGGER_START:
304 case SNDRV_PCM_TRIGGER_RESUME:
305 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
306 ac_glbctrl |= S3C_AC97_GLBCTRL_MICINTM_DMA;
307 break;
308
309 case SNDRV_PCM_TRIGGER_STOP:
310 case SNDRV_PCM_TRIGGER_SUSPEND:
311 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
312 break;
313 }
314
315 writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
316
317 s3c2410_dma_ctrl(dma_data->channel, S3C2410_DMAOP_STARTED);
318
319 return 0;
320}
321
322static struct snd_soc_dai_ops s3c_ac97_dai_ops = {
323 .hw_params = s3c_ac97_hw_params,
324 .trigger = s3c_ac97_trigger,
325};
326
327static struct snd_soc_dai_ops s3c_ac97_mic_dai_ops = {
328 .hw_params = s3c_ac97_hw_mic_params,
329 .trigger = s3c_ac97_mic_trigger,
330};
331
332struct snd_soc_dai s3c_ac97_dai[] = {
333 [S3C_AC97_DAI_PCM] = {
334 .name = "s3c-ac97",
335 .id = S3C_AC97_DAI_PCM,
336 .ac97_control = 1,
337 .playback = {
338 .stream_name = "AC97 Playback",
339 .channels_min = 2,
340 .channels_max = 2,
341 .rates = SNDRV_PCM_RATE_8000_48000,
342 .formats = SNDRV_PCM_FMTBIT_S16_LE,},
343 .capture = {
344 .stream_name = "AC97 Capture",
345 .channels_min = 2,
346 .channels_max = 2,
347 .rates = SNDRV_PCM_RATE_8000_48000,
348 .formats = SNDRV_PCM_FMTBIT_S16_LE,},
349 .ops = &s3c_ac97_dai_ops,
350 },
351 [S3C_AC97_DAI_MIC] = {
352 .name = "s3c-ac97-mic",
353 .id = S3C_AC97_DAI_MIC,
354 .ac97_control = 1,
355 .capture = {
356 .stream_name = "AC97 Mic Capture",
357 .channels_min = 1,
358 .channels_max = 1,
359 .rates = SNDRV_PCM_RATE_8000_48000,
360 .formats = SNDRV_PCM_FMTBIT_S16_LE,},
361 .ops = &s3c_ac97_mic_dai_ops,
362 },
363};
364EXPORT_SYMBOL_GPL(s3c_ac97_dai);
365
366static __devinit int s3c_ac97_probe(struct platform_device *pdev)
367{
368 struct resource *mem_res, *dmatx_res, *dmarx_res, *dmamic_res, *irq_res;
369 struct s3c_audio_pdata *ac97_pdata;
370 int ret;
371
372 ac97_pdata = pdev->dev.platform_data;
373 if (!ac97_pdata || !ac97_pdata->cfg_gpio) {
374 dev_err(&pdev->dev, "cfg_gpio callback not provided!\n");
375 return -EINVAL;
376 }
377
378 /* Check for availability of necessary resource */
379 dmatx_res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
380 if (!dmatx_res) {
381 dev_err(&pdev->dev, "Unable to get AC97-TX dma resource\n");
382 return -ENXIO;
383 }
384
385 dmarx_res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
386 if (!dmarx_res) {
387 dev_err(&pdev->dev, "Unable to get AC97-RX dma resource\n");
388 return -ENXIO;
389 }
390
391 dmamic_res = platform_get_resource(pdev, IORESOURCE_DMA, 2);
392 if (!dmamic_res) {
393 dev_err(&pdev->dev, "Unable to get AC97-MIC dma resource\n");
394 return -ENXIO;
395 }
396
397 mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
398 if (!mem_res) {
399 dev_err(&pdev->dev, "Unable to get register resource\n");
400 return -ENXIO;
401 }
402
403 irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
404 if (!irq_res) {
405 dev_err(&pdev->dev, "AC97 IRQ not provided!\n");
406 return -ENXIO;
407 }
408
409 if (!request_mem_region(mem_res->start,
410 resource_size(mem_res), "s3c-ac97")) {
411 dev_err(&pdev->dev, "Unable to request register region\n");
412 return -EBUSY;
413 }
414
415 s3c_ac97_pcm_out.channel = dmatx_res->start;
416 s3c_ac97_pcm_out.dma_addr = mem_res->start + S3C_AC97_PCM_DATA;
417 s3c_ac97_pcm_in.channel = dmarx_res->start;
418 s3c_ac97_pcm_in.dma_addr = mem_res->start + S3C_AC97_PCM_DATA;
419 s3c_ac97_mic_in.channel = dmamic_res->start;
420 s3c_ac97_mic_in.dma_addr = mem_res->start + S3C_AC97_MIC_DATA;
421
422 init_completion(&s3c_ac97.done);
423 mutex_init(&s3c_ac97.lock);
424
425 s3c_ac97.regs = ioremap(mem_res->start, resource_size(mem_res));
426 if (s3c_ac97.regs == NULL) {
427 dev_err(&pdev->dev, "Unable to ioremap register region\n");
428 ret = -ENXIO;
429 goto err1;
430 }
431
432 s3c_ac97.ac97_clk = clk_get(&pdev->dev, "ac97");
433 if (IS_ERR(s3c_ac97.ac97_clk)) {
434 dev_err(&pdev->dev, "s3c-ac97 failed to get ac97_clock\n");
435 ret = -ENODEV;
436 goto err2;
437 }
438 clk_enable(s3c_ac97.ac97_clk);
439
440 if (ac97_pdata->cfg_gpio(pdev)) {
441 dev_err(&pdev->dev, "Unable to configure gpio\n");
442 ret = -EINVAL;
443 goto err3;
444 }
445
446 ret = request_irq(irq_res->start, s3c_ac97_irq,
447 IRQF_DISABLED, "AC97", NULL);
448 if (ret < 0) {
449 printk(KERN_ERR "s3c-ac97: interrupt request failed.\n");
450 goto err4;
451 }
452
453 s3c_ac97_dai[S3C_AC97_DAI_PCM].dev = &pdev->dev;
454 s3c_ac97_dai[S3C_AC97_DAI_MIC].dev = &pdev->dev;
455
456 ret = snd_soc_register_dais(s3c_ac97_dai, ARRAY_SIZE(s3c_ac97_dai));
457 if (ret)
458 goto err5;
459
460 return 0;
461
462err5:
463 free_irq(irq_res->start, NULL);
464err4:
465err3:
466 clk_disable(s3c_ac97.ac97_clk);
467 clk_put(s3c_ac97.ac97_clk);
468err2:
469 iounmap(s3c_ac97.regs);
470err1:
471 release_mem_region(mem_res->start, resource_size(mem_res));
472
473 return ret;
474}
475
476static __devexit int s3c_ac97_remove(struct platform_device *pdev)
477{
478 struct resource *mem_res, *irq_res;
479
480 snd_soc_unregister_dais(s3c_ac97_dai, ARRAY_SIZE(s3c_ac97_dai));
481
482 irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
483 if (irq_res)
484 free_irq(irq_res->start, NULL);
485
486 clk_disable(s3c_ac97.ac97_clk);
487 clk_put(s3c_ac97.ac97_clk);
488
489 iounmap(s3c_ac97.regs);
490
491 mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
492 if (mem_res)
493 release_mem_region(mem_res->start, resource_size(mem_res));
494
495 return 0;
496}
497
498static struct platform_driver s3c_ac97_driver = {
499 .probe = s3c_ac97_probe,
500 .remove = s3c_ac97_remove,
501 .driver = {
502 .name = "s3c-ac97",
503 .owner = THIS_MODULE,
504 },
505};
506
507static int __init s3c_ac97_init(void)
508{
509 return platform_driver_register(&s3c_ac97_driver);
510}
511module_init(s3c_ac97_init);
512
513static void __exit s3c_ac97_exit(void)
514{
515 platform_driver_unregister(&s3c_ac97_driver);
516}
517module_exit(s3c_ac97_exit);
518
519MODULE_AUTHOR("Jaswinder Singh, <jassi.brar@samsung.com>");
520MODULE_DESCRIPTION("AC97 driver for the Samsung SoC");
521MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/s3c-ac97.h b/sound/soc/s3c24xx/s3c-ac97.h
new file mode 100644
index 000000000000..278198379def
--- /dev/null
+++ b/sound/soc/s3c24xx/s3c-ac97.h
@@ -0,0 +1,23 @@
1/* sound/soc/s3c24xx/s3c-ac97.h
2 *
3 * ALSA SoC Audio Layer - S3C AC97 Controller driver
4 * Evolved from s3c2443-ac97.h
5 *
6 * Copyright (c) 2010 Samsung Electronics Co. Ltd
7 * Author: Jaswinder Singh <jassi.brar@samsung.com>
8 * Credits: Graeme Gregory, Sean Choi
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 */
14
15#ifndef __S3C_AC97_H_
16#define __S3C_AC97_H_
17
18#define S3C_AC97_DAI_PCM 0
19#define S3C_AC97_DAI_MIC 1
20
21extern struct snd_soc_dai s3c_ac97_dai[];
22
23#endif /* __S3C_AC97_H_ */
diff --git a/sound/soc/s3c24xx/s3c24xx-pcm.c b/sound/soc/s3c24xx/s3c-dma.c
index 1f35c6fcf5fd..1b61c23ff300 100644
--- a/sound/soc/s3c24xx/s3c24xx-pcm.c
+++ b/sound/soc/s3c24xx/s3c-dma.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * s3c24xx-pcm.c -- ALSA Soc Audio Layer 2 * s3c-dma.c -- ALSA Soc Audio Layer
3 * 3 *
4 * (c) 2006 Wolfson Microelectronics PLC. 4 * (c) 2006 Wolfson Microelectronics PLC.
5 * Graeme Gregory graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com 5 * Graeme Gregory graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
@@ -29,11 +29,10 @@
29#include <asm/dma.h> 29#include <asm/dma.h>
30#include <mach/hardware.h> 30#include <mach/hardware.h>
31#include <mach/dma.h> 31#include <mach/dma.h>
32#include <plat/audio.h>
33 32
34#include "s3c24xx-pcm.h" 33#include "s3c-dma.h"
35 34
36static const struct snd_pcm_hardware s3c24xx_pcm_hardware = { 35static const struct snd_pcm_hardware s3c_dma_hardware = {
37 .info = SNDRV_PCM_INFO_INTERLEAVED | 36 .info = SNDRV_PCM_INFO_INTERLEAVED |
38 SNDRV_PCM_INFO_BLOCK_TRANSFER | 37 SNDRV_PCM_INFO_BLOCK_TRANSFER |
39 SNDRV_PCM_INFO_MMAP | 38 SNDRV_PCM_INFO_MMAP |
@@ -63,15 +62,15 @@ struct s3c24xx_runtime_data {
63 dma_addr_t dma_start; 62 dma_addr_t dma_start;
64 dma_addr_t dma_pos; 63 dma_addr_t dma_pos;
65 dma_addr_t dma_end; 64 dma_addr_t dma_end;
66 struct s3c24xx_pcm_dma_params *params; 65 struct s3c_dma_params *params;
67}; 66};
68 67
69/* s3c24xx_pcm_enqueue 68/* s3c_dma_enqueue
70 * 69 *
71 * place a dma buffer onto the queue for the dma system 70 * place a dma buffer onto the queue for the dma system
72 * to handle. 71 * to handle.
73*/ 72*/
74static void s3c24xx_pcm_enqueue(struct snd_pcm_substream *substream) 73static void s3c_dma_enqueue(struct snd_pcm_substream *substream)
75{ 74{
76 struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; 75 struct s3c24xx_runtime_data *prtd = substream->runtime->private_data;
77 dma_addr_t pos = prtd->dma_pos; 76 dma_addr_t pos = prtd->dma_pos;
@@ -80,12 +79,13 @@ static void s3c24xx_pcm_enqueue(struct snd_pcm_substream *substream)
80 79
81 pr_debug("Entered %s\n", __func__); 80 pr_debug("Entered %s\n", __func__);
82 81
83 if (s3c_dma_has_circular()) { 82 if (s3c_dma_has_circular())
84 limit = (prtd->dma_end - prtd->dma_start) / prtd->dma_period; 83 limit = (prtd->dma_end - prtd->dma_start) / prtd->dma_period;
85 } else 84 else
86 limit = prtd->dma_limit; 85 limit = prtd->dma_limit;
87 86
88 pr_debug("%s: loaded %d, limit %d\n", __func__, prtd->dma_loaded, limit); 87 pr_debug("%s: loaded %d, limit %d\n",
88 __func__, prtd->dma_loaded, limit);
89 89
90 while (prtd->dma_loaded < limit) { 90 while (prtd->dma_loaded < limit) {
91 unsigned long len = prtd->dma_period; 91 unsigned long len = prtd->dma_period;
@@ -133,22 +133,24 @@ static void s3c24xx_audio_buffdone(struct s3c2410_dma_chan *channel,
133 spin_lock(&prtd->lock); 133 spin_lock(&prtd->lock);
134 if (prtd->state & ST_RUNNING && !s3c_dma_has_circular()) { 134 if (prtd->state & ST_RUNNING && !s3c_dma_has_circular()) {
135 prtd->dma_loaded--; 135 prtd->dma_loaded--;
136 s3c24xx_pcm_enqueue(substream); 136 s3c_dma_enqueue(substream);
137 } 137 }
138 138
139 spin_unlock(&prtd->lock); 139 spin_unlock(&prtd->lock);
140} 140}
141 141
142static int s3c24xx_pcm_hw_params(struct snd_pcm_substream *substream, 142static int s3c_dma_hw_params(struct snd_pcm_substream *substream,
143 struct snd_pcm_hw_params *params) 143 struct snd_pcm_hw_params *params)
144{ 144{
145 struct snd_pcm_runtime *runtime = substream->runtime; 145 struct snd_pcm_runtime *runtime = substream->runtime;
146 struct s3c24xx_runtime_data *prtd = runtime->private_data; 146 struct s3c24xx_runtime_data *prtd = runtime->private_data;
147 struct snd_soc_pcm_runtime *rtd = substream->private_data; 147 struct snd_soc_pcm_runtime *rtd = substream->private_data;
148 struct s3c24xx_pcm_dma_params *dma = rtd->dai->cpu_dai->dma_data;
149 unsigned long totbytes = params_buffer_bytes(params); 148 unsigned long totbytes = params_buffer_bytes(params);
149 struct s3c_dma_params *dma =
150 snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
150 int ret = 0; 151 int ret = 0;
151 152
153
152 pr_debug("Entered %s\n", __func__); 154 pr_debug("Entered %s\n", __func__);
153 155
154 /* return if this is a bufferless transfer e.g. 156 /* return if this is a bufferless transfer e.g.
@@ -198,7 +200,7 @@ static int s3c24xx_pcm_hw_params(struct snd_pcm_substream *substream,
198 return 0; 200 return 0;
199} 201}
200 202
201static int s3c24xx_pcm_hw_free(struct snd_pcm_substream *substream) 203static int s3c_dma_hw_free(struct snd_pcm_substream *substream)
202{ 204{
203 struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; 205 struct s3c24xx_runtime_data *prtd = substream->runtime->private_data;
204 206
@@ -215,7 +217,7 @@ static int s3c24xx_pcm_hw_free(struct snd_pcm_substream *substream)
215 return 0; 217 return 0;
216} 218}
217 219
218static int s3c24xx_pcm_prepare(struct snd_pcm_substream *substream) 220static int s3c_dma_prepare(struct snd_pcm_substream *substream)
219{ 221{
220 struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; 222 struct s3c24xx_runtime_data *prtd = substream->runtime->private_data;
221 int ret = 0; 223 int ret = 0;
@@ -248,12 +250,12 @@ static int s3c24xx_pcm_prepare(struct snd_pcm_substream *substream)
248 prtd->dma_pos = prtd->dma_start; 250 prtd->dma_pos = prtd->dma_start;
249 251
250 /* enqueue dma buffers */ 252 /* enqueue dma buffers */
251 s3c24xx_pcm_enqueue(substream); 253 s3c_dma_enqueue(substream);
252 254
253 return ret; 255 return ret;
254} 256}
255 257
256static int s3c24xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) 258static int s3c_dma_trigger(struct snd_pcm_substream *substream, int cmd)
257{ 259{
258 struct s3c24xx_runtime_data *prtd = substream->runtime->private_data; 260 struct s3c24xx_runtime_data *prtd = substream->runtime->private_data;
259 int ret = 0; 261 int ret = 0;
@@ -288,7 +290,7 @@ static int s3c24xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
288} 290}
289 291
290static snd_pcm_uframes_t 292static snd_pcm_uframes_t
291s3c24xx_pcm_pointer(struct snd_pcm_substream *substream) 293s3c_dma_pointer(struct snd_pcm_substream *substream)
292{ 294{
293 struct snd_pcm_runtime *runtime = substream->runtime; 295 struct snd_pcm_runtime *runtime = substream->runtime;
294 struct s3c24xx_runtime_data *prtd = runtime->private_data; 296 struct s3c24xx_runtime_data *prtd = runtime->private_data;
@@ -323,7 +325,7 @@ s3c24xx_pcm_pointer(struct snd_pcm_substream *substream)
323 return bytes_to_frames(substream->runtime, res); 325 return bytes_to_frames(substream->runtime, res);
324} 326}
325 327
326static int s3c24xx_pcm_open(struct snd_pcm_substream *substream) 328static int s3c_dma_open(struct snd_pcm_substream *substream)
327{ 329{
328 struct snd_pcm_runtime *runtime = substream->runtime; 330 struct snd_pcm_runtime *runtime = substream->runtime;
329 struct s3c24xx_runtime_data *prtd; 331 struct s3c24xx_runtime_data *prtd;
@@ -331,7 +333,7 @@ static int s3c24xx_pcm_open(struct snd_pcm_substream *substream)
331 pr_debug("Entered %s\n", __func__); 333 pr_debug("Entered %s\n", __func__);
332 334
333 snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); 335 snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
334 snd_soc_set_runtime_hwparams(substream, &s3c24xx_pcm_hardware); 336 snd_soc_set_runtime_hwparams(substream, &s3c_dma_hardware);
335 337
336 prtd = kzalloc(sizeof(struct s3c24xx_runtime_data), GFP_KERNEL); 338 prtd = kzalloc(sizeof(struct s3c24xx_runtime_data), GFP_KERNEL);
337 if (prtd == NULL) 339 if (prtd == NULL)
@@ -343,7 +345,7 @@ static int s3c24xx_pcm_open(struct snd_pcm_substream *substream)
343 return 0; 345 return 0;
344} 346}
345 347
346static int s3c24xx_pcm_close(struct snd_pcm_substream *substream) 348static int s3c_dma_close(struct snd_pcm_substream *substream)
347{ 349{
348 struct snd_pcm_runtime *runtime = substream->runtime; 350 struct snd_pcm_runtime *runtime = substream->runtime;
349 struct s3c24xx_runtime_data *prtd = runtime->private_data; 351 struct s3c24xx_runtime_data *prtd = runtime->private_data;
@@ -351,14 +353,14 @@ static int s3c24xx_pcm_close(struct snd_pcm_substream *substream)
351 pr_debug("Entered %s\n", __func__); 353 pr_debug("Entered %s\n", __func__);
352 354
353 if (!prtd) 355 if (!prtd)
354 pr_debug("s3c24xx_pcm_close called with prtd == NULL\n"); 356 pr_debug("s3c_dma_close called with prtd == NULL\n");
355 357
356 kfree(prtd); 358 kfree(prtd);
357 359
358 return 0; 360 return 0;
359} 361}
360 362
361static int s3c24xx_pcm_mmap(struct snd_pcm_substream *substream, 363static int s3c_dma_mmap(struct snd_pcm_substream *substream,
362 struct vm_area_struct *vma) 364 struct vm_area_struct *vma)
363{ 365{
364 struct snd_pcm_runtime *runtime = substream->runtime; 366 struct snd_pcm_runtime *runtime = substream->runtime;
@@ -371,23 +373,23 @@ static int s3c24xx_pcm_mmap(struct snd_pcm_substream *substream,
371 runtime->dma_bytes); 373 runtime->dma_bytes);
372} 374}
373 375
374static struct snd_pcm_ops s3c24xx_pcm_ops = { 376static struct snd_pcm_ops s3c_dma_ops = {
375 .open = s3c24xx_pcm_open, 377 .open = s3c_dma_open,
376 .close = s3c24xx_pcm_close, 378 .close = s3c_dma_close,
377 .ioctl = snd_pcm_lib_ioctl, 379 .ioctl = snd_pcm_lib_ioctl,
378 .hw_params = s3c24xx_pcm_hw_params, 380 .hw_params = s3c_dma_hw_params,
379 .hw_free = s3c24xx_pcm_hw_free, 381 .hw_free = s3c_dma_hw_free,
380 .prepare = s3c24xx_pcm_prepare, 382 .prepare = s3c_dma_prepare,
381 .trigger = s3c24xx_pcm_trigger, 383 .trigger = s3c_dma_trigger,
382 .pointer = s3c24xx_pcm_pointer, 384 .pointer = s3c_dma_pointer,
383 .mmap = s3c24xx_pcm_mmap, 385 .mmap = s3c_dma_mmap,
384}; 386};
385 387
386static int s3c24xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) 388static int s3c_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
387{ 389{
388 struct snd_pcm_substream *substream = pcm->streams[stream].substream; 390 struct snd_pcm_substream *substream = pcm->streams[stream].substream;
389 struct snd_dma_buffer *buf = &substream->dma_buffer; 391 struct snd_dma_buffer *buf = &substream->dma_buffer;
390 size_t size = s3c24xx_pcm_hardware.buffer_bytes_max; 392 size_t size = s3c_dma_hardware.buffer_bytes_max;
391 393
392 pr_debug("Entered %s\n", __func__); 394 pr_debug("Entered %s\n", __func__);
393 395
@@ -402,7 +404,7 @@ static int s3c24xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
402 return 0; 404 return 0;
403} 405}
404 406
405static void s3c24xx_pcm_free_dma_buffers(struct snd_pcm *pcm) 407static void s3c_dma_free_dma_buffers(struct snd_pcm *pcm)
406{ 408{
407 struct snd_pcm_substream *substream; 409 struct snd_pcm_substream *substream;
408 struct snd_dma_buffer *buf; 410 struct snd_dma_buffer *buf;
@@ -425,9 +427,9 @@ static void s3c24xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
425 } 427 }
426} 428}
427 429
428static u64 s3c24xx_pcm_dmamask = DMA_BIT_MASK(32); 430static u64 s3c_dma_mask = DMA_BIT_MASK(32);
429 431
430static int s3c24xx_pcm_new(struct snd_card *card, 432static int s3c_dma_new(struct snd_card *card,
431 struct snd_soc_dai *dai, struct snd_pcm *pcm) 433 struct snd_soc_dai *dai, struct snd_pcm *pcm)
432{ 434{
433 int ret = 0; 435 int ret = 0;
@@ -435,19 +437,19 @@ static int s3c24xx_pcm_new(struct snd_card *card,
435 pr_debug("Entered %s\n", __func__); 437 pr_debug("Entered %s\n", __func__);
436 438
437 if (!card->dev->dma_mask) 439 if (!card->dev->dma_mask)
438 card->dev->dma_mask = &s3c24xx_pcm_dmamask; 440 card->dev->dma_mask = &s3c_dma_mask;
439 if (!card->dev->coherent_dma_mask) 441 if (!card->dev->coherent_dma_mask)
440 card->dev->coherent_dma_mask = 0xffffffff; 442 card->dev->coherent_dma_mask = 0xffffffff;
441 443
442 if (dai->playback.channels_min) { 444 if (dai->playback.channels_min) {
443 ret = s3c24xx_pcm_preallocate_dma_buffer(pcm, 445 ret = s3c_preallocate_dma_buffer(pcm,
444 SNDRV_PCM_STREAM_PLAYBACK); 446 SNDRV_PCM_STREAM_PLAYBACK);
445 if (ret) 447 if (ret)
446 goto out; 448 goto out;
447 } 449 }
448 450
449 if (dai->capture.channels_min) { 451 if (dai->capture.channels_min) {
450 ret = s3c24xx_pcm_preallocate_dma_buffer(pcm, 452 ret = s3c_preallocate_dma_buffer(pcm,
451 SNDRV_PCM_STREAM_CAPTURE); 453 SNDRV_PCM_STREAM_CAPTURE);
452 if (ret) 454 if (ret)
453 goto out; 455 goto out;
@@ -458,9 +460,9 @@ static int s3c24xx_pcm_new(struct snd_card *card,
458 460
459struct snd_soc_platform s3c24xx_soc_platform = { 461struct snd_soc_platform s3c24xx_soc_platform = {
460 .name = "s3c24xx-audio", 462 .name = "s3c24xx-audio",
461 .pcm_ops = &s3c24xx_pcm_ops, 463 .pcm_ops = &s3c_dma_ops,
462 .pcm_new = s3c24xx_pcm_new, 464 .pcm_new = s3c_dma_new,
463 .pcm_free = s3c24xx_pcm_free_dma_buffers, 465 .pcm_free = s3c_dma_free_dma_buffers,
464}; 466};
465EXPORT_SYMBOL_GPL(s3c24xx_soc_platform); 467EXPORT_SYMBOL_GPL(s3c24xx_soc_platform);
466 468
@@ -477,5 +479,5 @@ static void __exit s3c24xx_soc_platform_exit(void)
477module_exit(s3c24xx_soc_platform_exit); 479module_exit(s3c24xx_soc_platform_exit);
478 480
479MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>"); 481MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
480MODULE_DESCRIPTION("Samsung S3C24XX PCM DMA module"); 482MODULE_DESCRIPTION("Samsung S3C Audio DMA module");
481MODULE_LICENSE("GPL"); 483MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/s3c24xx-pcm.h b/sound/soc/s3c24xx/s3c-dma.h
index 0088c79822ea..69bb6bf6fc1c 100644
--- a/sound/soc/s3c24xx/s3c24xx-pcm.h
+++ b/sound/soc/s3c24xx/s3c-dma.h
@@ -1,5 +1,5 @@
1/* 1/*
2 * s3c24xx-pcm.h -- 2 * s3c-dma.h --
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify it 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 5 * under the terms of the GNU General Public License as published by the
@@ -9,13 +9,13 @@
9 * ALSA PCM interface for the Samsung S3C24xx CPU 9 * ALSA PCM interface for the Samsung S3C24xx CPU
10 */ 10 */
11 11
12#ifndef _S3C24XX_PCM_H 12#ifndef _S3C_AUDIO_H
13#define _S3C24XX_PCM_H 13#define _S3C_AUDIO_H
14 14
15#define ST_RUNNING (1<<0) 15#define ST_RUNNING (1<<0)
16#define ST_OPENED (1<<1) 16#define ST_OPENED (1<<1)
17 17
18struct s3c24xx_pcm_dma_params { 18struct s3c_dma_params {
19 struct s3c2410_dma_client *client; /* stream identifier */ 19 struct s3c2410_dma_client *client; /* stream identifier */
20 int channel; /* Channel ID */ 20 int channel; /* Channel ID */
21 dma_addr_t dma_addr; 21 dma_addr_t dma_addr;
diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.c b/sound/soc/s3c24xx/s3c-i2s-v2.c
index 9bc4aa35caab..88515946b6c0 100644
--- a/sound/soc/s3c24xx/s3c-i2s-v2.c
+++ b/sound/soc/s3c24xx/s3c-i2s-v2.c
@@ -32,11 +32,10 @@
32 32
33#include <plat/regs-s3c2412-iis.h> 33#include <plat/regs-s3c2412-iis.h>
34 34
35#include <plat/audio.h>
36#include <mach/dma.h> 35#include <mach/dma.h>
37 36
38#include "s3c-i2s-v2.h" 37#include "s3c-i2s-v2.h"
39#include "s3c24xx-pcm.h" 38#include "s3c-dma.h"
40 39
41#undef S3C_IIS_V2_SUPPORTED 40#undef S3C_IIS_V2_SUPPORTED
42 41
@@ -312,12 +311,15 @@ static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
312 311
313 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 312 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
314 case SND_SOC_DAIFMT_RIGHT_J: 313 case SND_SOC_DAIFMT_RIGHT_J:
314 iismod |= S3C2412_IISMOD_LR_RLOW;
315 iismod |= S3C2412_IISMOD_SDF_MSB; 315 iismod |= S3C2412_IISMOD_SDF_MSB;
316 break; 316 break;
317 case SND_SOC_DAIFMT_LEFT_J: 317 case SND_SOC_DAIFMT_LEFT_J:
318 iismod |= S3C2412_IISMOD_LR_RLOW;
318 iismod |= S3C2412_IISMOD_SDF_LSB; 319 iismod |= S3C2412_IISMOD_SDF_LSB;
319 break; 320 break;
320 case SND_SOC_DAIFMT_I2S: 321 case SND_SOC_DAIFMT_I2S:
322 iismod &= ~S3C2412_IISMOD_LR_RLOW;
321 iismod |= S3C2412_IISMOD_SDF_IIS; 323 iismod |= S3C2412_IISMOD_SDF_IIS;
322 break; 324 break;
323 default: 325 default:
@@ -337,14 +339,17 @@ static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream,
337 struct snd_soc_pcm_runtime *rtd = substream->private_data; 339 struct snd_soc_pcm_runtime *rtd = substream->private_data;
338 struct snd_soc_dai_link *dai = rtd->dai; 340 struct snd_soc_dai_link *dai = rtd->dai;
339 struct s3c_i2sv2_info *i2s = to_info(dai->cpu_dai); 341 struct s3c_i2sv2_info *i2s = to_info(dai->cpu_dai);
342 struct s3c_dma_params *dma_data;
340 u32 iismod; 343 u32 iismod;
341 344
342 pr_debug("Entered %s\n", __func__); 345 pr_debug("Entered %s\n", __func__);
343 346
344 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 347 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
345 dai->cpu_dai->dma_data = i2s->dma_playback; 348 dma_data = i2s->dma_playback;
346 else 349 else
347 dai->cpu_dai->dma_data = i2s->dma_capture; 350 dma_data = i2s->dma_capture;
351
352 snd_soc_dai_set_dma_data(dai->cpu_dai, substream, dma_data);
348 353
349 /* Working copies of register */ 354 /* Working copies of register */
350 iismod = readl(i2s->regs + S3C2412_IISMOD); 355 iismod = readl(i2s->regs + S3C2412_IISMOD);
@@ -392,8 +397,8 @@ static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
392 int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); 397 int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
393 unsigned long irqs; 398 unsigned long irqs;
394 int ret = 0; 399 int ret = 0;
395 int channel = ((struct s3c24xx_pcm_dma_params *) 400 struct s3c_dma_params *dma_data =
396 rtd->dai->cpu_dai->dma_data)->channel; 401 snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
397 402
398 pr_debug("Entered %s\n", __func__); 403 pr_debug("Entered %s\n", __func__);
399 404
@@ -429,7 +434,7 @@ static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
429 * of the auto reload mechanism of S3C24XX. 434 * of the auto reload mechanism of S3C24XX.
430 * This call won't bother S3C64XX. 435 * This call won't bother S3C64XX.
431 */ 436 */
432 s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STARTED); 437 s3c2410_dma_ctrl(dma_data->channel, S3C2410_DMAOP_STARTED);
433 438
434 break; 439 break;
435 440
@@ -467,6 +472,31 @@ static int s3c2412_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,
467 472
468 switch (div_id) { 473 switch (div_id) {
469 case S3C_I2SV2_DIV_BCLK: 474 case S3C_I2SV2_DIV_BCLK:
475 if (div > 3) {
476 /* convert value to bit field */
477
478 switch (div) {
479 case 16:
480 div = S3C2412_IISMOD_BCLK_16FS;
481 break;
482
483 case 32:
484 div = S3C2412_IISMOD_BCLK_32FS;
485 break;
486
487 case 24:
488 div = S3C2412_IISMOD_BCLK_24FS;
489 break;
490
491 case 48:
492 div = S3C2412_IISMOD_BCLK_48FS;
493 break;
494
495 default:
496 return -EINVAL;
497 }
498 }
499
470 reg = readl(i2s->regs + S3C2412_IISMOD); 500 reg = readl(i2s->regs + S3C2412_IISMOD);
471 reg &= ~S3C2412_IISMOD_BCLK_MASK; 501 reg &= ~S3C2412_IISMOD_BCLK_MASK;
472 writel(reg | div, i2s->regs + S3C2412_IISMOD); 502 writel(reg | div, i2s->regs + S3C2412_IISMOD);
@@ -626,7 +656,7 @@ int s3c_i2sv2_probe(struct platform_device *pdev,
626 } 656 }
627 657
628 i2s->iis_pclk = clk_get(dev, "iis"); 658 i2s->iis_pclk = clk_get(dev, "iis");
629 if (i2s->iis_pclk == NULL) { 659 if (IS_ERR(i2s->iis_pclk)) {
630 dev_err(dev, "failed to get iis_clock\n"); 660 dev_err(dev, "failed to get iis_clock\n");
631 iounmap(i2s->regs); 661 iounmap(i2s->regs);
632 return -ENOENT; 662 return -ENOENT;
diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.h b/sound/soc/s3c24xx/s3c-i2s-v2.h
index f66854a77fb2..ecf8eaaed1db 100644
--- a/sound/soc/s3c24xx/s3c-i2s-v2.h
+++ b/sound/soc/s3c24xx/s3c-i2s-v2.h
@@ -49,8 +49,8 @@ struct s3c_i2sv2_info {
49 49
50 unsigned char master; 50 unsigned char master;
51 51
52 struct s3c24xx_pcm_dma_params *dma_playback; 52 struct s3c_dma_params *dma_playback;
53 struct s3c24xx_pcm_dma_params *dma_capture; 53 struct s3c_dma_params *dma_capture;
54 54
55 u32 suspend_iismod; 55 u32 suspend_iismod;
56 u32 suspend_iiscon; 56 u32 suspend_iiscon;
diff --git a/sound/soc/s3c24xx/s3c-pcm.c b/sound/soc/s3c24xx/s3c-pcm.c
new file mode 100644
index 000000000000..326f0a9e7e30
--- /dev/null
+++ b/sound/soc/s3c24xx/s3c-pcm.c
@@ -0,0 +1,554 @@
1/* sound/soc/s3c24xx/s3c-pcm.c
2 *
3 * ALSA SoC Audio Layer - S3C PCM-Controller driver
4 *
5 * Copyright (c) 2009 Samsung Electronics Co. Ltd
6 * Author: Jaswinder Singh <jassi.brar@samsung.com>
7 * based upon I2S drivers by Ben Dooks.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#include <linux/init.h>
15#include <linux/module.h>
16#include <linux/device.h>
17#include <linux/delay.h>
18#include <linux/clk.h>
19#include <linux/kernel.h>
20#include <linux/gpio.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 <plat/audio.h>
30#include <plat/dma.h>
31
32#include "s3c-dma.h"
33#include "s3c-pcm.h"
34
35static struct s3c2410_dma_client s3c_pcm_dma_client_out = {
36 .name = "PCM Stereo out"
37};
38
39static struct s3c2410_dma_client s3c_pcm_dma_client_in = {
40 .name = "PCM Stereo in"
41};
42
43static struct s3c_dma_params s3c_pcm_stereo_out[] = {
44 [0] = {
45 .client = &s3c_pcm_dma_client_out,
46 .dma_size = 4,
47 },
48 [1] = {
49 .client = &s3c_pcm_dma_client_out,
50 .dma_size = 4,
51 },
52};
53
54static struct s3c_dma_params s3c_pcm_stereo_in[] = {
55 [0] = {
56 .client = &s3c_pcm_dma_client_in,
57 .dma_size = 4,
58 },
59 [1] = {
60 .client = &s3c_pcm_dma_client_in,
61 .dma_size = 4,
62 },
63};
64
65static struct s3c_pcm_info s3c_pcm[2];
66
67static inline struct s3c_pcm_info *to_info(struct snd_soc_dai *cpu_dai)
68{
69 return cpu_dai->private_data;
70}
71
72static void s3c_pcm_snd_txctrl(struct s3c_pcm_info *pcm, int on)
73{
74 void __iomem *regs = pcm->regs;
75 u32 ctl, clkctl;
76
77 clkctl = readl(regs + S3C_PCM_CLKCTL);
78 ctl = readl(regs + S3C_PCM_CTL);
79 ctl &= ~(S3C_PCM_CTL_TXDIPSTICK_MASK
80 << S3C_PCM_CTL_TXDIPSTICK_SHIFT);
81
82 if (on) {
83 ctl |= S3C_PCM_CTL_TXDMA_EN;
84 ctl |= S3C_PCM_CTL_TXFIFO_EN;
85 ctl |= S3C_PCM_CTL_ENABLE;
86 ctl |= (0x20<<S3C_PCM_CTL_TXDIPSTICK_SHIFT);
87 clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
88 } else {
89 ctl &= ~S3C_PCM_CTL_TXDMA_EN;
90 ctl &= ~S3C_PCM_CTL_TXFIFO_EN;
91
92 if (!(ctl & S3C_PCM_CTL_RXFIFO_EN)) {
93 ctl &= ~S3C_PCM_CTL_ENABLE;
94 if (!pcm->idleclk)
95 clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
96 }
97 }
98
99 writel(clkctl, regs + S3C_PCM_CLKCTL);
100 writel(ctl, regs + S3C_PCM_CTL);
101}
102
103static void s3c_pcm_snd_rxctrl(struct s3c_pcm_info *pcm, int on)
104{
105 void __iomem *regs = pcm->regs;
106 u32 ctl, clkctl;
107
108 ctl = readl(regs + S3C_PCM_CTL);
109 clkctl = readl(regs + S3C_PCM_CLKCTL);
110
111 if (on) {
112 ctl |= S3C_PCM_CTL_RXDMA_EN;
113 ctl |= S3C_PCM_CTL_RXFIFO_EN;
114 ctl |= S3C_PCM_CTL_ENABLE;
115 clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
116 } else {
117 ctl &= ~S3C_PCM_CTL_RXDMA_EN;
118 ctl &= ~S3C_PCM_CTL_RXFIFO_EN;
119
120 if (!(ctl & S3C_PCM_CTL_TXFIFO_EN)) {
121 ctl &= ~S3C_PCM_CTL_ENABLE;
122 if (!pcm->idleclk)
123 clkctl |= S3C_PCM_CLKCTL_SERCLK_EN;
124 }
125 }
126
127 writel(clkctl, regs + S3C_PCM_CLKCTL);
128 writel(ctl, regs + S3C_PCM_CTL);
129}
130
131static int s3c_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
132 struct snd_soc_dai *dai)
133{
134 struct snd_soc_pcm_runtime *rtd = substream->private_data;
135 struct s3c_pcm_info *pcm = to_info(rtd->dai->cpu_dai);
136 unsigned long flags;
137
138 dev_dbg(pcm->dev, "Entered %s\n", __func__);
139
140 switch (cmd) {
141 case SNDRV_PCM_TRIGGER_START:
142 case SNDRV_PCM_TRIGGER_RESUME:
143 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
144 spin_lock_irqsave(&pcm->lock, flags);
145
146 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
147 s3c_pcm_snd_rxctrl(pcm, 1);
148 else
149 s3c_pcm_snd_txctrl(pcm, 1);
150
151 spin_unlock_irqrestore(&pcm->lock, flags);
152 break;
153
154 case SNDRV_PCM_TRIGGER_STOP:
155 case SNDRV_PCM_TRIGGER_SUSPEND:
156 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
157 spin_lock_irqsave(&pcm->lock, flags);
158
159 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
160 s3c_pcm_snd_rxctrl(pcm, 0);
161 else
162 s3c_pcm_snd_txctrl(pcm, 0);
163
164 spin_unlock_irqrestore(&pcm->lock, flags);
165 break;
166
167 default:
168 return -EINVAL;
169 }
170
171 return 0;
172}
173
174static int s3c_pcm_hw_params(struct snd_pcm_substream *substream,
175 struct snd_pcm_hw_params *params,
176 struct snd_soc_dai *socdai)
177{
178 struct snd_soc_pcm_runtime *rtd = substream->private_data;
179 struct snd_soc_dai_link *dai = rtd->dai;
180 struct s3c_pcm_info *pcm = to_info(dai->cpu_dai);
181 struct s3c_dma_params *dma_data;
182 void __iomem *regs = pcm->regs;
183 struct clk *clk;
184 int sclk_div, sync_div;
185 unsigned long flags;
186 u32 clkctl;
187
188 dev_dbg(pcm->dev, "Entered %s\n", __func__);
189
190 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
191 dma_data = pcm->dma_playback;
192 else
193 dma_data = pcm->dma_capture;
194
195 snd_soc_dai_set_dma_data(dai->cpu_dai, substream, dma_data);
196
197 /* Strictly check for sample size */
198 switch (params_format(params)) {
199 case SNDRV_PCM_FORMAT_S16_LE:
200 break;
201 default:
202 return -EINVAL;
203 }
204
205 spin_lock_irqsave(&pcm->lock, flags);
206
207 /* Get hold of the PCMSOURCE_CLK */
208 clkctl = readl(regs + S3C_PCM_CLKCTL);
209 if (clkctl & S3C_PCM_CLKCTL_SERCLKSEL_PCLK)
210 clk = pcm->pclk;
211 else
212 clk = pcm->cclk;
213
214 /* Set the SCLK divider */
215 sclk_div = clk_get_rate(clk) / pcm->sclk_per_fs /
216 params_rate(params) / 2 - 1;
217
218 clkctl &= ~(S3C_PCM_CLKCTL_SCLKDIV_MASK
219 << S3C_PCM_CLKCTL_SCLKDIV_SHIFT);
220 clkctl |= ((sclk_div & S3C_PCM_CLKCTL_SCLKDIV_MASK)
221 << S3C_PCM_CLKCTL_SCLKDIV_SHIFT);
222
223 /* Set the SYNC divider */
224 sync_div = pcm->sclk_per_fs - 1;
225
226 clkctl &= ~(S3C_PCM_CLKCTL_SYNCDIV_MASK
227 << S3C_PCM_CLKCTL_SYNCDIV_SHIFT);
228 clkctl |= ((sync_div & S3C_PCM_CLKCTL_SYNCDIV_MASK)
229 << S3C_PCM_CLKCTL_SYNCDIV_SHIFT);
230
231 writel(clkctl, regs + S3C_PCM_CLKCTL);
232
233 spin_unlock_irqrestore(&pcm->lock, flags);
234
235 dev_dbg(pcm->dev, "PCMSOURCE_CLK-%lu SCLK=%ufs SCLK_DIV=%d SYNC_DIV=%d\n",
236 clk_get_rate(clk), pcm->sclk_per_fs,
237 sclk_div, sync_div);
238
239 return 0;
240}
241
242static int s3c_pcm_set_fmt(struct snd_soc_dai *cpu_dai,
243 unsigned int fmt)
244{
245 struct s3c_pcm_info *pcm = to_info(cpu_dai);
246 void __iomem *regs = pcm->regs;
247 unsigned long flags;
248 int ret = 0;
249 u32 ctl;
250
251 dev_dbg(pcm->dev, "Entered %s\n", __func__);
252
253 spin_lock_irqsave(&pcm->lock, flags);
254
255 ctl = readl(regs + S3C_PCM_CTL);
256
257 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
258 case SND_SOC_DAIFMT_NB_NF:
259 /* Nothing to do, NB_NF by default */
260 break;
261 default:
262 dev_err(pcm->dev, "Unsupported clock inversion!\n");
263 ret = -EINVAL;
264 goto exit;
265 }
266
267 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
268 case SND_SOC_DAIFMT_CBS_CFS:
269 /* Nothing to do, Master by default */
270 break;
271 default:
272 dev_err(pcm->dev, "Unsupported master/slave format!\n");
273 ret = -EINVAL;
274 goto exit;
275 }
276
277 switch (fmt & SND_SOC_DAIFMT_CLOCK_MASK) {
278 case SND_SOC_DAIFMT_CONT:
279 pcm->idleclk = 1;
280 break;
281 case SND_SOC_DAIFMT_GATED:
282 pcm->idleclk = 0;
283 break;
284 default:
285 dev_err(pcm->dev, "Invalid Clock gating request!\n");
286 ret = -EINVAL;
287 goto exit;
288 }
289
290 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
291 case SND_SOC_DAIFMT_DSP_A:
292 ctl |= S3C_PCM_CTL_TXMSB_AFTER_FSYNC;
293 ctl |= S3C_PCM_CTL_RXMSB_AFTER_FSYNC;
294 break;
295 case SND_SOC_DAIFMT_DSP_B:
296 ctl &= ~S3C_PCM_CTL_TXMSB_AFTER_FSYNC;
297 ctl &= ~S3C_PCM_CTL_RXMSB_AFTER_FSYNC;
298 break;
299 default:
300 dev_err(pcm->dev, "Unsupported data format!\n");
301 ret = -EINVAL;
302 goto exit;
303 }
304
305 writel(ctl, regs + S3C_PCM_CTL);
306
307exit:
308 spin_unlock_irqrestore(&pcm->lock, flags);
309
310 return ret;
311}
312
313static int s3c_pcm_set_clkdiv(struct snd_soc_dai *cpu_dai,
314 int div_id, int div)
315{
316 struct s3c_pcm_info *pcm = to_info(cpu_dai);
317
318 switch (div_id) {
319 case S3C_PCM_SCLK_PER_FS:
320 pcm->sclk_per_fs = div;
321 break;
322
323 default:
324 return -EINVAL;
325 }
326
327 return 0;
328}
329
330static int s3c_pcm_set_sysclk(struct snd_soc_dai *cpu_dai,
331 int clk_id, unsigned int freq, int dir)
332{
333 struct s3c_pcm_info *pcm = to_info(cpu_dai);
334 void __iomem *regs = pcm->regs;
335 u32 clkctl = readl(regs + S3C_PCM_CLKCTL);
336
337 switch (clk_id) {
338 case S3C_PCM_CLKSRC_PCLK:
339 clkctl |= S3C_PCM_CLKCTL_SERCLKSEL_PCLK;
340 break;
341
342 case S3C_PCM_CLKSRC_MUX:
343 clkctl &= ~S3C_PCM_CLKCTL_SERCLKSEL_PCLK;
344
345 if (clk_get_rate(pcm->cclk) != freq)
346 clk_set_rate(pcm->cclk, freq);
347
348 break;
349
350 default:
351 return -EINVAL;
352 }
353
354 writel(clkctl, regs + S3C_PCM_CLKCTL);
355
356 return 0;
357}
358
359static struct snd_soc_dai_ops s3c_pcm_dai_ops = {
360 .set_sysclk = s3c_pcm_set_sysclk,
361 .set_clkdiv = s3c_pcm_set_clkdiv,
362 .trigger = s3c_pcm_trigger,
363 .hw_params = s3c_pcm_hw_params,
364 .set_fmt = s3c_pcm_set_fmt,
365};
366
367#define S3C_PCM_RATES SNDRV_PCM_RATE_8000_96000
368
369#define S3C_PCM_DECLARE(n) \
370{ \
371 .name = "samsung-pcm", \
372 .id = (n), \
373 .symmetric_rates = 1, \
374 .ops = &s3c_pcm_dai_ops, \
375 .playback = { \
376 .channels_min = 2, \
377 .channels_max = 2, \
378 .rates = S3C_PCM_RATES, \
379 .formats = SNDRV_PCM_FMTBIT_S16_LE, \
380 }, \
381 .capture = { \
382 .channels_min = 2, \
383 .channels_max = 2, \
384 .rates = S3C_PCM_RATES, \
385 .formats = SNDRV_PCM_FMTBIT_S16_LE, \
386 }, \
387}
388
389struct snd_soc_dai s3c_pcm_dai[] = {
390 S3C_PCM_DECLARE(0),
391 S3C_PCM_DECLARE(1),
392};
393EXPORT_SYMBOL_GPL(s3c_pcm_dai);
394
395static __devinit int s3c_pcm_dev_probe(struct platform_device *pdev)
396{
397 struct s3c_pcm_info *pcm;
398 struct snd_soc_dai *dai;
399 struct resource *mem_res, *dmatx_res, *dmarx_res;
400 struct s3c_audio_pdata *pcm_pdata;
401 int ret;
402
403 /* Check for valid device index */
404 if ((pdev->id < 0) || pdev->id >= ARRAY_SIZE(s3c_pcm)) {
405 dev_err(&pdev->dev, "id %d out of range\n", pdev->id);
406 return -EINVAL;
407 }
408
409 pcm_pdata = pdev->dev.platform_data;
410
411 /* Check for availability of necessary resource */
412 dmatx_res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
413 if (!dmatx_res) {
414 dev_err(&pdev->dev, "Unable to get PCM-TX dma resource\n");
415 return -ENXIO;
416 }
417
418 dmarx_res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
419 if (!dmarx_res) {
420 dev_err(&pdev->dev, "Unable to get PCM-RX dma resource\n");
421 return -ENXIO;
422 }
423
424 mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
425 if (!mem_res) {
426 dev_err(&pdev->dev, "Unable to get register resource\n");
427 return -ENXIO;
428 }
429
430 if (pcm_pdata && pcm_pdata->cfg_gpio && pcm_pdata->cfg_gpio(pdev)) {
431 dev_err(&pdev->dev, "Unable to configure gpio\n");
432 return -EINVAL;
433 }
434
435 pcm = &s3c_pcm[pdev->id];
436 pcm->dev = &pdev->dev;
437
438 spin_lock_init(&pcm->lock);
439
440 dai = &s3c_pcm_dai[pdev->id];
441 dai->dev = &pdev->dev;
442
443 /* Default is 128fs */
444 pcm->sclk_per_fs = 128;
445
446 pcm->cclk = clk_get(&pdev->dev, "audio-bus");
447 if (IS_ERR(pcm->cclk)) {
448 dev_err(&pdev->dev, "failed to get audio-bus\n");
449 ret = PTR_ERR(pcm->cclk);
450 goto err1;
451 }
452 clk_enable(pcm->cclk);
453
454 /* record our pcm structure for later use in the callbacks */
455 dai->private_data = pcm;
456
457 if (!request_mem_region(mem_res->start,
458 resource_size(mem_res), "samsung-pcm")) {
459 dev_err(&pdev->dev, "Unable to request register region\n");
460 ret = -EBUSY;
461 goto err2;
462 }
463
464 pcm->regs = ioremap(mem_res->start, 0x100);
465 if (pcm->regs == NULL) {
466 dev_err(&pdev->dev, "cannot ioremap registers\n");
467 ret = -ENXIO;
468 goto err3;
469 }
470
471 pcm->pclk = clk_get(&pdev->dev, "pcm");
472 if (IS_ERR(pcm->pclk)) {
473 dev_err(&pdev->dev, "failed to get pcm_clock\n");
474 ret = -ENOENT;
475 goto err4;
476 }
477 clk_enable(pcm->pclk);
478
479 ret = snd_soc_register_dai(dai);
480 if (ret != 0) {
481 dev_err(&pdev->dev, "failed to get pcm_clock\n");
482 goto err5;
483 }
484
485 s3c_pcm_stereo_in[pdev->id].dma_addr = mem_res->start
486 + S3C_PCM_RXFIFO;
487 s3c_pcm_stereo_out[pdev->id].dma_addr = mem_res->start
488 + S3C_PCM_TXFIFO;
489
490 s3c_pcm_stereo_in[pdev->id].channel = dmarx_res->start;
491 s3c_pcm_stereo_out[pdev->id].channel = dmatx_res->start;
492
493 pcm->dma_capture = &s3c_pcm_stereo_in[pdev->id];
494 pcm->dma_playback = &s3c_pcm_stereo_out[pdev->id];
495
496 return 0;
497
498err5:
499 clk_disable(pcm->pclk);
500 clk_put(pcm->pclk);
501err4:
502 iounmap(pcm->regs);
503err3:
504 release_mem_region(mem_res->start, resource_size(mem_res));
505err2:
506 clk_disable(pcm->cclk);
507 clk_put(pcm->cclk);
508err1:
509 return ret;
510}
511
512static __devexit int s3c_pcm_dev_remove(struct platform_device *pdev)
513{
514 struct s3c_pcm_info *pcm = &s3c_pcm[pdev->id];
515 struct resource *mem_res;
516
517 iounmap(pcm->regs);
518
519 mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
520 release_mem_region(mem_res->start, resource_size(mem_res));
521
522 clk_disable(pcm->cclk);
523 clk_disable(pcm->pclk);
524 clk_put(pcm->pclk);
525 clk_put(pcm->cclk);
526
527 return 0;
528}
529
530static struct platform_driver s3c_pcm_driver = {
531 .probe = s3c_pcm_dev_probe,
532 .remove = s3c_pcm_dev_remove,
533 .driver = {
534 .name = "samsung-pcm",
535 .owner = THIS_MODULE,
536 },
537};
538
539static int __init s3c_pcm_init(void)
540{
541 return platform_driver_register(&s3c_pcm_driver);
542}
543module_init(s3c_pcm_init);
544
545static void __exit s3c_pcm_exit(void)
546{
547 platform_driver_unregister(&s3c_pcm_driver);
548}
549module_exit(s3c_pcm_exit);
550
551/* Module information */
552MODULE_AUTHOR("Jaswinder Singh, <jassi.brar@samsung.com>");
553MODULE_DESCRIPTION("S3C PCM Controller Driver");
554MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/s3c-pcm.h b/sound/soc/s3c24xx/s3c-pcm.h
new file mode 100644
index 000000000000..69ff9971692f
--- /dev/null
+++ b/sound/soc/s3c24xx/s3c-pcm.h
@@ -0,0 +1,123 @@
1/* sound/soc/s3c24xx/s3c-pcm.h
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
9#ifndef __S3C_PCM_H
10#define __S3C_PCM_H __FILE__
11
12/*Register Offsets */
13#define S3C_PCM_CTL (0x00)
14#define S3C_PCM_CLKCTL (0x04)
15#define S3C_PCM_TXFIFO (0x08)
16#define S3C_PCM_RXFIFO (0x0C)
17#define S3C_PCM_IRQCTL (0x10)
18#define S3C_PCM_IRQSTAT (0x14)
19#define S3C_PCM_FIFOSTAT (0x18)
20#define S3C_PCM_CLRINT (0x20)
21
22/* PCM_CTL Bit-Fields */
23#define S3C_PCM_CTL_TXDIPSTICK_MASK (0x3f)
24#define S3C_PCM_CTL_TXDIPSTICK_SHIFT (13)
25#define S3C_PCM_CTL_RXDIPSTICK_MSK (0x3f<<7)
26#define S3C_PCM_CTL_TXDMA_EN (0x1<<6)
27#define S3C_PCM_CTL_RXDMA_EN (0x1<<5)
28#define S3C_PCM_CTL_TXMSB_AFTER_FSYNC (0x1<<4)
29#define S3C_PCM_CTL_RXMSB_AFTER_FSYNC (0x1<<3)
30#define S3C_PCM_CTL_TXFIFO_EN (0x1<<2)
31#define S3C_PCM_CTL_RXFIFO_EN (0x1<<1)
32#define S3C_PCM_CTL_ENABLE (0x1<<0)
33
34/* PCM_CLKCTL Bit-Fields */
35#define S3C_PCM_CLKCTL_SERCLK_EN (0x1<<19)
36#define S3C_PCM_CLKCTL_SERCLKSEL_PCLK (0x1<<18)
37#define S3C_PCM_CLKCTL_SCLKDIV_MASK (0x1ff)
38#define S3C_PCM_CLKCTL_SYNCDIV_MASK (0x1ff)
39#define S3C_PCM_CLKCTL_SCLKDIV_SHIFT (9)
40#define S3C_PCM_CLKCTL_SYNCDIV_SHIFT (0)
41
42/* PCM_TXFIFO Bit-Fields */
43#define S3C_PCM_TXFIFO_DVALID (0x1<<16)
44#define S3C_PCM_TXFIFO_DATA_MSK (0xffff<<0)
45
46/* PCM_RXFIFO Bit-Fields */
47#define S3C_PCM_RXFIFO_DVALID (0x1<<16)
48#define S3C_PCM_RXFIFO_DATA_MSK (0xffff<<0)
49
50/* PCM_IRQCTL Bit-Fields */
51#define S3C_PCM_IRQCTL_IRQEN (0x1<<14)
52#define S3C_PCM_IRQCTL_WRDEN (0x1<<12)
53#define S3C_PCM_IRQCTL_TXEMPTYEN (0x1<<11)
54#define S3C_PCM_IRQCTL_TXALMSTEMPTYEN (0x1<<10)
55#define S3C_PCM_IRQCTL_TXFULLEN (0x1<<9)
56#define S3C_PCM_IRQCTL_TXALMSTFULLEN (0x1<<8)
57#define S3C_PCM_IRQCTL_TXSTARVEN (0x1<<7)
58#define S3C_PCM_IRQCTL_TXERROVRFLEN (0x1<<6)
59#define S3C_PCM_IRQCTL_RXEMPTEN (0x1<<5)
60#define S3C_PCM_IRQCTL_RXALMSTEMPTEN (0x1<<4)
61#define S3C_PCM_IRQCTL_RXFULLEN (0x1<<3)
62#define S3C_PCM_IRQCTL_RXALMSTFULLEN (0x1<<2)
63#define S3C_PCM_IRQCTL_RXSTARVEN (0x1<<1)
64#define S3C_PCM_IRQCTL_RXERROVRFLEN (0x1<<0)
65
66/* PCM_IRQSTAT Bit-Fields */
67#define S3C_PCM_IRQSTAT_IRQPND (0x1<<13)
68#define S3C_PCM_IRQSTAT_WRD_XFER (0x1<<12)
69#define S3C_PCM_IRQSTAT_TXEMPTY (0x1<<11)
70#define S3C_PCM_IRQSTAT_TXALMSTEMPTY (0x1<<10)
71#define S3C_PCM_IRQSTAT_TXFULL (0x1<<9)
72#define S3C_PCM_IRQSTAT_TXALMSTFULL (0x1<<8)
73#define S3C_PCM_IRQSTAT_TXSTARV (0x1<<7)
74#define S3C_PCM_IRQSTAT_TXERROVRFL (0x1<<6)
75#define S3C_PCM_IRQSTAT_RXEMPT (0x1<<5)
76#define S3C_PCM_IRQSTAT_RXALMSTEMPT (0x1<<4)
77#define S3C_PCM_IRQSTAT_RXFULL (0x1<<3)
78#define S3C_PCM_IRQSTAT_RXALMSTFULL (0x1<<2)
79#define S3C_PCM_IRQSTAT_RXSTARV (0x1<<1)
80#define S3C_PCM_IRQSTAT_RXERROVRFL (0x1<<0)
81
82/* PCM_FIFOSTAT Bit-Fields */
83#define S3C_PCM_FIFOSTAT_TXCNT_MSK (0x3f<<14)
84#define S3C_PCM_FIFOSTAT_TXFIFOEMPTY (0x1<<13)
85#define S3C_PCM_FIFOSTAT_TXFIFOALMSTEMPTY (0x1<<12)
86#define S3C_PCM_FIFOSTAT_TXFIFOFULL (0x1<<11)
87#define S3C_PCM_FIFOSTAT_TXFIFOALMSTFULL (0x1<<10)
88#define S3C_PCM_FIFOSTAT_RXCNT_MSK (0x3f<<4)
89#define S3C_PCM_FIFOSTAT_RXFIFOEMPTY (0x1<<3)
90#define S3C_PCM_FIFOSTAT_RXFIFOALMSTEMPTY (0x1<<2)
91#define S3C_PCM_FIFOSTAT_RXFIFOFULL (0x1<<1)
92#define S3C_PCM_FIFOSTAT_RXFIFOALMSTFULL (0x1<<0)
93
94#define S3C_PCM_CLKSRC_PCLK 0
95#define S3C_PCM_CLKSRC_MUX 1
96
97#define S3C_PCM_SCLK_PER_FS 0
98
99/**
100 * struct s3c_pcm_info - S3C PCM Controller information
101 * @dev: The parent device passed to use from the probe.
102 * @regs: The pointer to the device register block.
103 * @dma_playback: DMA information for playback channel.
104 * @dma_capture: DMA information for capture channel.
105 */
106struct s3c_pcm_info {
107 spinlock_t lock;
108 struct device *dev;
109 void __iomem *regs;
110
111 unsigned int sclk_per_fs;
112
113 /* Whether to keep PCMSCLK enabled even when idle(no active xfer) */
114 unsigned int idleclk;
115
116 struct clk *pclk;
117 struct clk *cclk;
118
119 struct s3c_dma_params *dma_playback;
120 struct s3c_dma_params *dma_capture;
121};
122
123#endif /* __S3C_PCM_H */
diff --git a/sound/soc/s3c24xx/s3c2412-i2s.c b/sound/soc/s3c24xx/s3c2412-i2s.c
index a587ec40b449..359e59346ba2 100644
--- a/sound/soc/s3c24xx/s3c2412-i2s.c
+++ b/sound/soc/s3c24xx/s3c2412-i2s.c
@@ -34,11 +34,10 @@
34 34
35#include <plat/regs-s3c2412-iis.h> 35#include <plat/regs-s3c2412-iis.h>
36 36
37#include <plat/audio.h>
38#include <mach/regs-gpio.h> 37#include <mach/regs-gpio.h>
39#include <mach/dma.h> 38#include <mach/dma.h>
40 39
41#include "s3c24xx-pcm.h" 40#include "s3c-dma.h"
42#include "s3c2412-i2s.h" 41#include "s3c2412-i2s.h"
43 42
44#define S3C2412_I2S_DEBUG 0 43#define S3C2412_I2S_DEBUG 0
@@ -51,14 +50,14 @@ static struct s3c2410_dma_client s3c2412_dma_client_in = {
51 .name = "I2S PCM Stereo in" 50 .name = "I2S PCM Stereo in"
52}; 51};
53 52
54static struct s3c24xx_pcm_dma_params s3c2412_i2s_pcm_stereo_out = { 53static struct s3c_dma_params s3c2412_i2s_pcm_stereo_out = {
55 .client = &s3c2412_dma_client_out, 54 .client = &s3c2412_dma_client_out,
56 .channel = DMACH_I2S_OUT, 55 .channel = DMACH_I2S_OUT,
57 .dma_addr = S3C2410_PA_IIS + S3C2412_IISTXD, 56 .dma_addr = S3C2410_PA_IIS + S3C2412_IISTXD,
58 .dma_size = 4, 57 .dma_size = 4,
59}; 58};
60 59
61static struct s3c24xx_pcm_dma_params s3c2412_i2s_pcm_stereo_in = { 60static struct s3c_dma_params s3c2412_i2s_pcm_stereo_in = {
62 .client = &s3c2412_dma_client_in, 61 .client = &s3c2412_dma_client_in,
63 .channel = DMACH_I2S_IN, 62 .channel = DMACH_I2S_IN,
64 .dma_addr = S3C2410_PA_IIS + S3C2412_IISRXD, 63 .dma_addr = S3C2410_PA_IIS + S3C2412_IISRXD,
diff --git a/sound/soc/s3c24xx/s3c2443-ac97.c b/sound/soc/s3c24xx/s3c2443-ac97.c
deleted file mode 100644
index fc1beb0930b9..000000000000
--- a/sound/soc/s3c24xx/s3c2443-ac97.c
+++ /dev/null
@@ -1,433 +0,0 @@
1/*
2 * s3c2443-ac97.c -- ALSA Soc Audio Layer
3 *
4 * (c) 2007 Wolfson Microelectronics PLC.
5 * Graeme Gregory graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
6 *
7 * Copyright (C) 2005, Sean Choi <sh428.choi@samsung.com>
8 * All rights reserved.
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/init.h>
16#include <linux/module.h>
17#include <linux/platform_device.h>
18#include <linux/interrupt.h>
19#include <linux/io.h>
20#include <linux/wait.h>
21#include <linux/delay.h>
22#include <linux/gpio.h>
23#include <linux/clk.h>
24
25#include <sound/core.h>
26#include <sound/pcm.h>
27#include <sound/ac97_codec.h>
28#include <sound/initval.h>
29#include <sound/soc.h>
30
31#include <mach/hardware.h>
32#include <plat/regs-ac97.h>
33#include <mach/regs-gpio.h>
34#include <mach/regs-clock.h>
35#include <plat/audio.h>
36#include <asm/dma.h>
37#include <mach/dma.h>
38
39#include "s3c24xx-pcm.h"
40#include "s3c24xx-ac97.h"
41
42struct s3c24xx_ac97_info {
43 void __iomem *regs;
44 struct clk *ac97_clk;
45};
46static struct s3c24xx_ac97_info s3c24xx_ac97;
47
48static DECLARE_COMPLETION(ac97_completion);
49static u32 codec_ready;
50static DEFINE_MUTEX(ac97_mutex);
51
52static unsigned short s3c2443_ac97_read(struct snd_ac97 *ac97,
53 unsigned short reg)
54{
55 u32 ac_glbctrl;
56 u32 ac_codec_cmd;
57 u32 stat, addr, data;
58
59 mutex_lock(&ac97_mutex);
60
61 codec_ready = S3C_AC97_GLBSTAT_CODECREADY;
62 ac_codec_cmd = readl(s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD);
63 ac_codec_cmd = S3C_AC97_CODEC_CMD_READ | AC_CMD_ADDR(reg);
64 writel(ac_codec_cmd, s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD);
65
66 udelay(50);
67
68 ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
69 ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE;
70 writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
71
72 wait_for_completion(&ac97_completion);
73
74 stat = readl(s3c24xx_ac97.regs + S3C_AC97_STAT);
75 addr = (stat >> 16) & 0x7f;
76 data = (stat & 0xffff);
77
78 if (addr != reg)
79 printk(KERN_ERR "s3c24xx-ac97: req addr = %02x,"
80 " rep addr = %02x\n", reg, addr);
81
82 mutex_unlock(&ac97_mutex);
83
84 return (unsigned short)data;
85}
86
87static void s3c2443_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
88 unsigned short val)
89{
90 u32 ac_glbctrl;
91 u32 ac_codec_cmd;
92
93 mutex_lock(&ac97_mutex);
94
95 codec_ready = S3C_AC97_GLBSTAT_CODECREADY;
96 ac_codec_cmd = readl(s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD);
97 ac_codec_cmd = AC_CMD_ADDR(reg) | AC_CMD_DATA(val);
98 writel(ac_codec_cmd, s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD);
99
100 udelay(50);
101
102 ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
103 ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE;
104 writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
105
106 wait_for_completion(&ac97_completion);
107
108 ac_codec_cmd = readl(s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD);
109 ac_codec_cmd |= S3C_AC97_CODEC_CMD_READ;
110 writel(ac_codec_cmd, s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD);
111
112 mutex_unlock(&ac97_mutex);
113
114}
115
116static void s3c2443_ac97_warm_reset(struct snd_ac97 *ac97)
117{
118 u32 ac_glbctrl;
119
120 ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
121 ac_glbctrl = S3C_AC97_GLBCTRL_WARMRESET;
122 writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
123 msleep(1);
124
125 ac_glbctrl = 0;
126 writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
127 msleep(1);
128}
129
130static void s3c2443_ac97_cold_reset(struct snd_ac97 *ac97)
131{
132 u32 ac_glbctrl;
133
134 ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
135 ac_glbctrl = S3C_AC97_GLBCTRL_COLDRESET;
136 writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
137 msleep(1);
138
139 ac_glbctrl = 0;
140 writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
141 msleep(1);
142
143 ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
144 ac_glbctrl = S3C_AC97_GLBCTRL_ACLINKON;
145 writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
146 msleep(1);
147
148 ac_glbctrl |= S3C_AC97_GLBCTRL_TRANSFERDATAENABLE;
149 writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
150 msleep(1);
151
152 ac_glbctrl |= S3C_AC97_GLBCTRL_PCMOUTTM_DMA |
153 S3C_AC97_GLBCTRL_PCMINTM_DMA | S3C_AC97_GLBCTRL_MICINTM_DMA;
154 writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
155}
156
157static irqreturn_t s3c2443_ac97_irq(int irq, void *dev_id)
158{
159 int status;
160 u32 ac_glbctrl;
161
162 status = readl(s3c24xx_ac97.regs + S3C_AC97_GLBSTAT) & codec_ready;
163
164 if (status) {
165 ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
166 ac_glbctrl &= ~S3C_AC97_GLBCTRL_CODECREADYIE;
167 writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
168 complete(&ac97_completion);
169 }
170 return IRQ_HANDLED;
171}
172
173struct snd_ac97_bus_ops soc_ac97_ops = {
174 .read = s3c2443_ac97_read,
175 .write = s3c2443_ac97_write,
176 .warm_reset = s3c2443_ac97_warm_reset,
177 .reset = s3c2443_ac97_cold_reset,
178};
179
180static struct s3c2410_dma_client s3c2443_dma_client_out = {
181 .name = "AC97 PCM Stereo out"
182};
183
184static struct s3c2410_dma_client s3c2443_dma_client_in = {
185 .name = "AC97 PCM Stereo in"
186};
187
188static struct s3c2410_dma_client s3c2443_dma_client_micin = {
189 .name = "AC97 Mic Mono in"
190};
191
192static struct s3c24xx_pcm_dma_params s3c2443_ac97_pcm_stereo_out = {
193 .client = &s3c2443_dma_client_out,
194 .channel = DMACH_PCM_OUT,
195 .dma_addr = S3C2440_PA_AC97 + S3C_AC97_PCM_DATA,
196 .dma_size = 4,
197};
198
199static struct s3c24xx_pcm_dma_params s3c2443_ac97_pcm_stereo_in = {
200 .client = &s3c2443_dma_client_in,
201 .channel = DMACH_PCM_IN,
202 .dma_addr = S3C2440_PA_AC97 + S3C_AC97_PCM_DATA,
203 .dma_size = 4,
204};
205
206static struct s3c24xx_pcm_dma_params s3c2443_ac97_mic_mono_in = {
207 .client = &s3c2443_dma_client_micin,
208 .channel = DMACH_MIC_IN,
209 .dma_addr = S3C2440_PA_AC97 + S3C_AC97_MIC_DATA,
210 .dma_size = 4,
211};
212
213static int s3c2443_ac97_probe(struct platform_device *pdev,
214 struct snd_soc_dai *dai)
215{
216 int ret;
217 u32 ac_glbctrl;
218
219 s3c24xx_ac97.regs = ioremap(S3C2440_PA_AC97, 0x100);
220 if (s3c24xx_ac97.regs == NULL)
221 return -ENXIO;
222
223 s3c24xx_ac97.ac97_clk = clk_get(&pdev->dev, "ac97");
224 if (s3c24xx_ac97.ac97_clk == NULL) {
225 printk(KERN_ERR "s3c2443-ac97 failed to get ac97_clock\n");
226 iounmap(s3c24xx_ac97.regs);
227 return -ENODEV;
228 }
229 clk_enable(s3c24xx_ac97.ac97_clk);
230
231 s3c2410_gpio_cfgpin(S3C2410_GPE0, S3C2443_GPE0_AC_nRESET);
232 s3c2410_gpio_cfgpin(S3C2410_GPE1, S3C2443_GPE1_AC_SYNC);
233 s3c2410_gpio_cfgpin(S3C2410_GPE2, S3C2443_GPE2_AC_BITCLK);
234 s3c2410_gpio_cfgpin(S3C2410_GPE3, S3C2443_GPE3_AC_SDI);
235 s3c2410_gpio_cfgpin(S3C2410_GPE4, S3C2443_GPE4_AC_SDO);
236
237 ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
238 ac_glbctrl = S3C_AC97_GLBCTRL_COLDRESET;
239 writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
240 msleep(1);
241
242 ac_glbctrl = 0;
243 writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
244 msleep(1);
245
246 ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
247 ac_glbctrl = S3C_AC97_GLBCTRL_ACLINKON;
248 writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
249 msleep(1);
250
251 ac_glbctrl |= S3C_AC97_GLBCTRL_TRANSFERDATAENABLE;
252 writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
253
254 ret = request_irq(IRQ_S3C244x_AC97, s3c2443_ac97_irq,
255 IRQF_DISABLED, "AC97", NULL);
256 if (ret < 0) {
257 printk(KERN_ERR "s3c24xx-ac97: interrupt request failed.\n");
258 clk_disable(s3c24xx_ac97.ac97_clk);
259 clk_put(s3c24xx_ac97.ac97_clk);
260 iounmap(s3c24xx_ac97.regs);
261 }
262 return ret;
263}
264
265static void s3c2443_ac97_remove(struct platform_device *pdev,
266 struct snd_soc_dai *dai)
267{
268 free_irq(IRQ_S3C244x_AC97, NULL);
269 clk_disable(s3c24xx_ac97.ac97_clk);
270 clk_put(s3c24xx_ac97.ac97_clk);
271 iounmap(s3c24xx_ac97.regs);
272}
273
274static int s3c2443_ac97_hw_params(struct snd_pcm_substream *substream,
275 struct snd_pcm_hw_params *params,
276 struct snd_soc_dai *dai)
277{
278 struct snd_soc_pcm_runtime *rtd = substream->private_data;
279 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
280
281 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
282 cpu_dai->dma_data = &s3c2443_ac97_pcm_stereo_out;
283 else
284 cpu_dai->dma_data = &s3c2443_ac97_pcm_stereo_in;
285
286 return 0;
287}
288
289static int s3c2443_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
290 struct snd_soc_dai *dai)
291{
292 u32 ac_glbctrl;
293 struct snd_soc_pcm_runtime *rtd = substream->private_data;
294 int channel = ((struct s3c24xx_pcm_dma_params *)
295 rtd->dai->cpu_dai->dma_data)->channel;
296
297 ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
298 switch (cmd) {
299 case SNDRV_PCM_TRIGGER_START:
300 case SNDRV_PCM_TRIGGER_RESUME:
301 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
302 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
303 ac_glbctrl |= S3C_AC97_GLBCTRL_PCMINTM_DMA;
304 else
305 ac_glbctrl |= S3C_AC97_GLBCTRL_PCMOUTTM_DMA;
306 break;
307 case SNDRV_PCM_TRIGGER_STOP:
308 case SNDRV_PCM_TRIGGER_SUSPEND:
309 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
310 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
311 ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMINTM_MASK;
312 else
313 ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMOUTTM_MASK;
314 break;
315 }
316 writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
317
318 s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STARTED);
319
320 return 0;
321}
322
323static int s3c2443_ac97_hw_mic_params(struct snd_pcm_substream *substream,
324 struct snd_pcm_hw_params *params,
325 struct snd_soc_dai *dai)
326{
327 struct snd_soc_pcm_runtime *rtd = substream->private_data;
328 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
329
330 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
331 return -ENODEV;
332 else
333 cpu_dai->dma_data = &s3c2443_ac97_mic_mono_in;
334
335 return 0;
336}
337
338static int s3c2443_ac97_mic_trigger(struct snd_pcm_substream *substream,
339 int cmd, struct snd_soc_dai *dai)
340{
341 u32 ac_glbctrl;
342 struct snd_soc_pcm_runtime *rtd = substream->private_data;
343 int channel = ((struct s3c24xx_pcm_dma_params *)
344 rtd->dai->cpu_dai->dma_data)->channel;
345
346 ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
347 switch (cmd) {
348 case SNDRV_PCM_TRIGGER_START:
349 case SNDRV_PCM_TRIGGER_RESUME:
350 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
351 ac_glbctrl |= S3C_AC97_GLBCTRL_PCMINTM_DMA;
352 break;
353 case SNDRV_PCM_TRIGGER_STOP:
354 case SNDRV_PCM_TRIGGER_SUSPEND:
355 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
356 ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMINTM_MASK;
357 }
358 writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
359
360 s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STARTED);
361
362 return 0;
363}
364
365#define s3c2443_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
366 SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \
367 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
368
369static struct snd_soc_dai_ops s3c2443_ac97_dai_ops = {
370 .hw_params = s3c2443_ac97_hw_params,
371 .trigger = s3c2443_ac97_trigger,
372};
373
374static struct snd_soc_dai_ops s3c2443_ac97_mic_dai_ops = {
375 .hw_params = s3c2443_ac97_hw_mic_params,
376 .trigger = s3c2443_ac97_mic_trigger,
377};
378
379struct snd_soc_dai s3c2443_ac97_dai[] = {
380{
381 .name = "s3c2443-ac97",
382 .id = 0,
383 .ac97_control = 1,
384 .probe = s3c2443_ac97_probe,
385 .remove = s3c2443_ac97_remove,
386 .playback = {
387 .stream_name = "AC97 Playback",
388 .channels_min = 2,
389 .channels_max = 2,
390 .rates = s3c2443_AC97_RATES,
391 .formats = SNDRV_PCM_FMTBIT_S16_LE,},
392 .capture = {
393 .stream_name = "AC97 Capture",
394 .channels_min = 2,
395 .channels_max = 2,
396 .rates = s3c2443_AC97_RATES,
397 .formats = SNDRV_PCM_FMTBIT_S16_LE,},
398 .ops = &s3c2443_ac97_dai_ops,
399},
400{
401 .name = "pxa2xx-ac97-mic",
402 .id = 1,
403 .ac97_control = 1,
404 .capture = {
405 .stream_name = "AC97 Mic Capture",
406 .channels_min = 1,
407 .channels_max = 1,
408 .rates = s3c2443_AC97_RATES,
409 .formats = SNDRV_PCM_FMTBIT_S16_LE,},
410 .ops = &s3c2443_ac97_mic_dai_ops,
411},
412};
413EXPORT_SYMBOL_GPL(s3c2443_ac97_dai);
414EXPORT_SYMBOL_GPL(soc_ac97_ops);
415
416static int __init s3c2443_ac97_init(void)
417{
418 return snd_soc_register_dais(s3c2443_ac97_dai,
419 ARRAY_SIZE(s3c2443_ac97_dai));
420}
421module_init(s3c2443_ac97_init);
422
423static void __exit s3c2443_ac97_exit(void)
424{
425 snd_soc_unregister_dais(s3c2443_ac97_dai,
426 ARRAY_SIZE(s3c2443_ac97_dai));
427}
428module_exit(s3c2443_ac97_exit);
429
430
431MODULE_AUTHOR("Graeme Gregory");
432MODULE_DESCRIPTION("AC97 driver for the Samsung s3c2443 chip");
433MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/s3c24xx-ac97.h b/sound/soc/s3c24xx/s3c24xx-ac97.h
deleted file mode 100644
index e96f941a810b..000000000000
--- a/sound/soc/s3c24xx/s3c24xx-ac97.h
+++ /dev/null
@@ -1,25 +0,0 @@
1/*
2 * s3c24xx-ac97.c -- ALSA Soc Audio Layer
3 *
4 * (c) 2007 Wolfson Microelectronics PLC.
5 * Author: Graeme Gregory
6 * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 *
13 * Revision history
14 * 10th Nov 2006 Initial version.
15 */
16
17#ifndef S3C24XXAC97_H_
18#define S3C24XXAC97_H_
19
20#define AC_CMD_ADDR(x) (x << 16)
21#define AC_CMD_DATA(x) (x & 0xffff)
22
23extern struct snd_soc_dai s3c2443_ac97_dai[];
24
25#endif /*S3C24XXAC97_H_*/
diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c
index 40e2c4790f0d..c3ac890a3986 100644
--- a/sound/soc/s3c24xx/s3c24xx-i2s.c
+++ b/sound/soc/s3c24xx/s3c24xx-i2s.c
@@ -32,13 +32,13 @@
32#include <mach/hardware.h> 32#include <mach/hardware.h>
33#include <mach/regs-gpio.h> 33#include <mach/regs-gpio.h>
34#include <mach/regs-clock.h> 34#include <mach/regs-clock.h>
35#include <plat/audio.h> 35
36#include <asm/dma.h> 36#include <asm/dma.h>
37#include <mach/dma.h> 37#include <mach/dma.h>
38 38
39#include <plat/regs-iis.h> 39#include <plat/regs-iis.h>
40 40
41#include "s3c24xx-pcm.h" 41#include "s3c-dma.h"
42#include "s3c24xx-i2s.h" 42#include "s3c24xx-i2s.h"
43 43
44static struct s3c2410_dma_client s3c24xx_dma_client_out = { 44static struct s3c2410_dma_client s3c24xx_dma_client_out = {
@@ -49,14 +49,14 @@ static struct s3c2410_dma_client s3c24xx_dma_client_in = {
49 .name = "I2S PCM Stereo in" 49 .name = "I2S PCM Stereo in"
50}; 50};
51 51
52static struct s3c24xx_pcm_dma_params s3c24xx_i2s_pcm_stereo_out = { 52static struct s3c_dma_params s3c24xx_i2s_pcm_stereo_out = {
53 .client = &s3c24xx_dma_client_out, 53 .client = &s3c24xx_dma_client_out,
54 .channel = DMACH_I2S_OUT, 54 .channel = DMACH_I2S_OUT,
55 .dma_addr = S3C2410_PA_IIS + S3C2410_IISFIFO, 55 .dma_addr = S3C2410_PA_IIS + S3C2410_IISFIFO,
56 .dma_size = 2, 56 .dma_size = 2,
57}; 57};
58 58
59static struct s3c24xx_pcm_dma_params s3c24xx_i2s_pcm_stereo_in = { 59static struct s3c_dma_params s3c24xx_i2s_pcm_stereo_in = {
60 .client = &s3c24xx_dma_client_in, 60 .client = &s3c24xx_dma_client_in,
61 .channel = DMACH_I2S_IN, 61 .channel = DMACH_I2S_IN,
62 .dma_addr = S3C2410_PA_IIS + S3C2410_IISFIFO, 62 .dma_addr = S3C2410_PA_IIS + S3C2410_IISFIFO,
@@ -242,14 +242,17 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream,
242 struct snd_soc_dai *dai) 242 struct snd_soc_dai *dai)
243{ 243{
244 struct snd_soc_pcm_runtime *rtd = substream->private_data; 244 struct snd_soc_pcm_runtime *rtd = substream->private_data;
245 struct s3c_dma_params *dma_data;
245 u32 iismod; 246 u32 iismod;
246 247
247 pr_debug("Entered %s\n", __func__); 248 pr_debug("Entered %s\n", __func__);
248 249
249 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 250 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
250 rtd->dai->cpu_dai->dma_data = &s3c24xx_i2s_pcm_stereo_out; 251 dma_data = &s3c24xx_i2s_pcm_stereo_out;
251 else 252 else
252 rtd->dai->cpu_dai->dma_data = &s3c24xx_i2s_pcm_stereo_in; 253 dma_data = &s3c24xx_i2s_pcm_stereo_in;
254
255 snd_soc_dai_set_dma_data(rtd->dai->cpu_dai, substream, dma_data);
253 256
254 /* Working copies of register */ 257 /* Working copies of register */
255 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); 258 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
@@ -258,13 +261,11 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream,
258 switch (params_format(params)) { 261 switch (params_format(params)) {
259 case SNDRV_PCM_FORMAT_S8: 262 case SNDRV_PCM_FORMAT_S8:
260 iismod &= ~S3C2410_IISMOD_16BIT; 263 iismod &= ~S3C2410_IISMOD_16BIT;
261 ((struct s3c24xx_pcm_dma_params *) 264 dma_data->dma_size = 1;
262 rtd->dai->cpu_dai->dma_data)->dma_size = 1;
263 break; 265 break;
264 case SNDRV_PCM_FORMAT_S16_LE: 266 case SNDRV_PCM_FORMAT_S16_LE:
265 iismod |= S3C2410_IISMOD_16BIT; 267 iismod |= S3C2410_IISMOD_16BIT;
266 ((struct s3c24xx_pcm_dma_params *) 268 dma_data->dma_size = 2;
267 rtd->dai->cpu_dai->dma_data)->dma_size = 2;
268 break; 269 break;
269 default: 270 default:
270 return -EINVAL; 271 return -EINVAL;
@@ -280,8 +281,8 @@ static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
280{ 281{
281 int ret = 0; 282 int ret = 0;
282 struct snd_soc_pcm_runtime *rtd = substream->private_data; 283 struct snd_soc_pcm_runtime *rtd = substream->private_data;
283 int channel = ((struct s3c24xx_pcm_dma_params *) 284 struct s3c_dma_params *dma_data =
284 rtd->dai->cpu_dai->dma_data)->channel; 285 snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
285 286
286 pr_debug("Entered %s\n", __func__); 287 pr_debug("Entered %s\n", __func__);
287 288
@@ -300,7 +301,7 @@ static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
300 else 301 else
301 s3c24xx_snd_txctrl(1); 302 s3c24xx_snd_txctrl(1);
302 303
303 s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STARTED); 304 s3c2410_dma_ctrl(dma_data->channel, S3C2410_DMAOP_STARTED);
304 break; 305 break;
305 case SNDRV_PCM_TRIGGER_STOP: 306 case SNDRV_PCM_TRIGGER_STOP:
306 case SNDRV_PCM_TRIGGER_SUSPEND: 307 case SNDRV_PCM_TRIGGER_SUSPEND:
diff --git a/sound/soc/s3c24xx/s3c24xx_simtec.c b/sound/soc/s3c24xx/s3c24xx_simtec.c
index 1966e0d5652d..4984754f3298 100644
--- a/sound/soc/s3c24xx/s3c24xx_simtec.c
+++ b/sound/soc/s3c24xx/s3c24xx_simtec.c
@@ -21,7 +21,7 @@
21 21
22#include <plat/audio-simtec.h> 22#include <plat/audio-simtec.h>
23 23
24#include "s3c24xx-pcm.h" 24#include "s3c-dma.h"
25#include "s3c24xx-i2s.h" 25#include "s3c24xx-i2s.h"
26#include "s3c24xx_simtec.h" 26#include "s3c24xx_simtec.h"
27 27
@@ -270,7 +270,7 @@ static int attach_gpio_amp(struct device *dev,
270 gpio_direction_output(pd->amp_gain[1], 0); 270 gpio_direction_output(pd->amp_gain[1], 0);
271 } 271 }
272 272
273 /* note, curently we assume GPA0 isn't valid amp */ 273 /* note, currently we assume GPA0 isn't valid amp */
274 if (pdata->amp_gpio > 0) { 274 if (pdata->amp_gpio > 0) {
275 ret = gpio_request(pd->amp_gpio, "gpio-amp"); 275 ret = gpio_request(pd->amp_gpio, "gpio-amp");
276 if (ret) { 276 if (ret) {
@@ -312,7 +312,7 @@ int simtec_audio_resume(struct device *dev)
312 return 0; 312 return 0;
313} 313}
314 314
315struct dev_pm_ops simtec_audio_pmops = { 315const struct dev_pm_ops simtec_audio_pmops = {
316 .resume = simtec_audio_resume, 316 .resume = simtec_audio_resume,
317}; 317};
318EXPORT_SYMBOL_GPL(simtec_audio_pmops); 318EXPORT_SYMBOL_GPL(simtec_audio_pmops);
diff --git a/sound/soc/s3c24xx/s3c24xx_simtec.h b/sound/soc/s3c24xx/s3c24xx_simtec.h
index 2714203af161..e18faee30cce 100644
--- a/sound/soc/s3c24xx/s3c24xx_simtec.h
+++ b/sound/soc/s3c24xx/s3c24xx_simtec.h
@@ -15,7 +15,7 @@ extern int simtec_audio_core_probe(struct platform_device *pdev,
15extern int simtec_audio_remove(struct platform_device *pdev); 15extern int simtec_audio_remove(struct platform_device *pdev);
16 16
17#ifdef CONFIG_PM 17#ifdef CONFIG_PM
18extern struct dev_pm_ops simtec_audio_pmops; 18extern const struct dev_pm_ops simtec_audio_pmops;
19#define simtec_audio_pm &simtec_audio_pmops 19#define simtec_audio_pm &simtec_audio_pmops
20#else 20#else
21#define simtec_audio_pm NULL 21#define simtec_audio_pm NULL
diff --git a/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c b/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c
index 8346bd96eaf5..bdf8951af8e3 100644
--- a/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c
+++ b/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c
@@ -18,7 +18,7 @@
18 18
19#include <plat/audio-simtec.h> 19#include <plat/audio-simtec.h>
20 20
21#include "s3c24xx-pcm.h" 21#include "s3c-dma.h"
22#include "s3c24xx-i2s.h" 22#include "s3c24xx-i2s.h"
23#include "s3c24xx_simtec.h" 23#include "s3c24xx_simtec.h"
24 24
diff --git a/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c b/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c
index 25797e096175..185c0acb5ce6 100644
--- a/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c
+++ b/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c
@@ -18,7 +18,7 @@
18 18
19#include <plat/audio-simtec.h> 19#include <plat/audio-simtec.h>
20 20
21#include "s3c24xx-pcm.h" 21#include "s3c-dma.h"
22#include "s3c24xx-i2s.h" 22#include "s3c24xx-i2s.h"
23#include "s3c24xx_simtec.h" 23#include "s3c24xx_simtec.h"
24 24
diff --git a/sound/soc/s3c24xx/s3c24xx_uda134x.c b/sound/soc/s3c24xx/s3c24xx_uda134x.c
index c215d32d6322..052d59659c29 100644
--- a/sound/soc/s3c24xx/s3c24xx_uda134x.c
+++ b/sound/soc/s3c24xx/s3c24xx_uda134x.c
@@ -24,7 +24,7 @@
24 24
25#include <plat/regs-iis.h> 25#include <plat/regs-iis.h>
26 26
27#include "s3c24xx-pcm.h" 27#include "s3c-dma.h"
28#include "s3c24xx-i2s.h" 28#include "s3c24xx-i2s.h"
29#include "../codecs/uda134x.h" 29#include "../codecs/uda134x.h"
30 30
diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.c b/sound/soc/s3c24xx/s3c64xx-i2s.c
index 105a77eeded0..a72c251401ac 100644
--- a/sound/soc/s3c24xx/s3c64xx-i2s.c
+++ b/sound/soc/s3c24xx/s3c64xx-i2s.c
@@ -15,30 +15,28 @@
15#include <linux/init.h> 15#include <linux/init.h>
16#include <linux/module.h> 16#include <linux/module.h>
17#include <linux/device.h> 17#include <linux/device.h>
18#include <linux/delay.h>
19#include <linux/clk.h> 18#include <linux/clk.h>
20#include <linux/kernel.h>
21#include <linux/gpio.h> 19#include <linux/gpio.h>
22#include <linux/io.h> 20#include <linux/io.h>
23 21
24#include <sound/core.h>
25#include <sound/pcm.h>
26#include <sound/pcm_params.h>
27#include <sound/initval.h>
28#include <sound/soc.h> 22#include <sound/soc.h>
29 23
30#include <plat/regs-s3c2412-iis.h> 24#include <plat/regs-s3c2412-iis.h>
31#include <plat/gpio-bank-d.h> 25#include <mach/gpio-bank-d.h>
32#include <plat/gpio-bank-e.h> 26#include <mach/gpio-bank-e.h>
33#include <plat/gpio-cfg.h> 27#include <plat/gpio-cfg.h>
34#include <plat/audio.h>
35 28
36#include <mach/map.h> 29#include <mach/map.h>
37#include <mach/dma.h> 30#include <mach/dma.h>
38 31
39#include "s3c24xx-pcm.h" 32#include "s3c-dma.h"
40#include "s3c64xx-i2s.h" 33#include "s3c64xx-i2s.h"
41 34
35/* The value should be set to maximum of the total number
36 * of I2Sv3 controllers that any supported SoC has.
37 */
38#define MAX_I2SV3 2
39
42static struct s3c2410_dma_client s3c64xx_dma_client_out = { 40static struct s3c2410_dma_client s3c64xx_dma_client_out = {
43 .name = "I2S PCM Stereo out" 41 .name = "I2S PCM Stereo out"
44}; 42};
@@ -47,37 +45,12 @@ static struct s3c2410_dma_client s3c64xx_dma_client_in = {
47 .name = "I2S PCM Stereo in" 45 .name = "I2S PCM Stereo in"
48}; 46};
49 47
50static struct s3c24xx_pcm_dma_params s3c64xx_i2s_pcm_stereo_out[2] = { 48static struct s3c_dma_params s3c64xx_i2s_pcm_stereo_out[MAX_I2SV3];
51 [0] = { 49static struct s3c_dma_params s3c64xx_i2s_pcm_stereo_in[MAX_I2SV3];
52 .channel = DMACH_I2S0_OUT, 50static struct s3c_i2sv2_info s3c64xx_i2s[MAX_I2SV3];
53 .client = &s3c64xx_dma_client_out,
54 .dma_addr = S3C64XX_PA_IIS0 + S3C2412_IISTXD,
55 .dma_size = 4,
56 },
57 [1] = {
58 .channel = DMACH_I2S1_OUT,
59 .client = &s3c64xx_dma_client_out,
60 .dma_addr = S3C64XX_PA_IIS1 + S3C2412_IISTXD,
61 .dma_size = 4,
62 },
63};
64 51
65static struct s3c24xx_pcm_dma_params s3c64xx_i2s_pcm_stereo_in[2] = { 52struct snd_soc_dai s3c64xx_i2s_dai[MAX_I2SV3];
66 [0] = { 53EXPORT_SYMBOL_GPL(s3c64xx_i2s_dai);
67 .channel = DMACH_I2S0_IN,
68 .client = &s3c64xx_dma_client_in,
69 .dma_addr = S3C64XX_PA_IIS0 + S3C2412_IISRXD,
70 .dma_size = 4,
71 },
72 [1] = {
73 .channel = DMACH_I2S1_IN,
74 .client = &s3c64xx_dma_client_in,
75 .dma_addr = S3C64XX_PA_IIS1 + S3C2412_IISRXD,
76 .dma_size = 4,
77 },
78};
79
80static struct s3c_i2sv2_info s3c64xx_i2s[2];
81 54
82static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai) 55static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai)
83{ 56{
@@ -99,6 +72,19 @@ static int s3c64xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
99 iismod |= S3C64XX_IISMOD_IMS_SYSMUX; 72 iismod |= S3C64XX_IISMOD_IMS_SYSMUX;
100 break; 73 break;
101 74
75 case S3C64XX_CLKSRC_CDCLK:
76 switch (dir) {
77 case SND_SOC_CLOCK_IN:
78 iismod |= S3C64XX_IISMOD_CDCLKCON;
79 break;
80 case SND_SOC_CLOCK_OUT:
81 iismod &= ~S3C64XX_IISMOD_CDCLKCON;
82 break;
83 default:
84 return -EINVAL;
85 }
86 break;
87
102 default: 88 default:
103 return -EINVAL; 89 return -EINVAL;
104 } 90 }
@@ -111,8 +97,12 @@ static int s3c64xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
111struct clk *s3c64xx_i2s_get_clock(struct snd_soc_dai *dai) 97struct clk *s3c64xx_i2s_get_clock(struct snd_soc_dai *dai)
112{ 98{
113 struct s3c_i2sv2_info *i2s = to_info(dai); 99 struct s3c_i2sv2_info *i2s = to_info(dai);
100 u32 iismod = readl(i2s->regs + S3C2412_IISMOD);
114 101
115 return i2s->iis_cclk; 102 if (iismod & S3C64XX_IISMOD_IMS_SYSMUX)
103 return i2s->iis_cclk;
104 else
105 return i2s->iis_pclk;
116} 106}
117EXPORT_SYMBOL_GPL(s3c64xx_i2s_get_clock); 107EXPORT_SYMBOL_GPL(s3c64xx_i2s_get_clock);
118 108
@@ -153,55 +143,13 @@ static struct snd_soc_dai_ops s3c64xx_i2s_dai_ops = {
153 .set_sysclk = s3c64xx_i2s_set_sysclk, 143 .set_sysclk = s3c64xx_i2s_set_sysclk,
154}; 144};
155 145
156struct snd_soc_dai s3c64xx_i2s_dai[] = {
157 {
158 .name = "s3c64xx-i2s",
159 .id = 0,
160 .probe = s3c64xx_i2s_probe,
161 .playback = {
162 .channels_min = 2,
163 .channels_max = 2,
164 .rates = S3C64XX_I2S_RATES,
165 .formats = S3C64XX_I2S_FMTS,
166 },
167 .capture = {
168 .channels_min = 2,
169 .channels_max = 2,
170 .rates = S3C64XX_I2S_RATES,
171 .formats = S3C64XX_I2S_FMTS,
172 },
173 .ops = &s3c64xx_i2s_dai_ops,
174 .symmetric_rates = 1,
175 },
176 {
177 .name = "s3c64xx-i2s",
178 .id = 1,
179 .probe = s3c64xx_i2s_probe,
180 .playback = {
181 .channels_min = 2,
182 .channels_max = 2,
183 .rates = S3C64XX_I2S_RATES,
184 .formats = S3C64XX_I2S_FMTS,
185 },
186 .capture = {
187 .channels_min = 2,
188 .channels_max = 2,
189 .rates = S3C64XX_I2S_RATES,
190 .formats = S3C64XX_I2S_FMTS,
191 },
192 .ops = &s3c64xx_i2s_dai_ops,
193 .symmetric_rates = 1,
194 },
195};
196EXPORT_SYMBOL_GPL(s3c64xx_i2s_dai);
197
198static __devinit int s3c64xx_iis_dev_probe(struct platform_device *pdev) 146static __devinit int s3c64xx_iis_dev_probe(struct platform_device *pdev)
199{ 147{
200 struct s3c_i2sv2_info *i2s; 148 struct s3c_i2sv2_info *i2s;
201 struct snd_soc_dai *dai; 149 struct snd_soc_dai *dai;
202 int ret; 150 int ret;
203 151
204 if (pdev->id >= ARRAY_SIZE(s3c64xx_i2s)) { 152 if (pdev->id >= MAX_I2SV3) {
205 dev_err(&pdev->dev, "id %d out of range\n", pdev->id); 153 dev_err(&pdev->dev, "id %d out of range\n", pdev->id);
206 return -EINVAL; 154 return -EINVAL;
207 } 155 }
@@ -209,10 +157,40 @@ static __devinit int s3c64xx_iis_dev_probe(struct platform_device *pdev)
209 i2s = &s3c64xx_i2s[pdev->id]; 157 i2s = &s3c64xx_i2s[pdev->id];
210 dai = &s3c64xx_i2s_dai[pdev->id]; 158 dai = &s3c64xx_i2s_dai[pdev->id];
211 dai->dev = &pdev->dev; 159 dai->dev = &pdev->dev;
160 dai->name = "s3c64xx-i2s";
161 dai->id = pdev->id;
162 dai->symmetric_rates = 1;
163 dai->playback.channels_min = 2;
164 dai->playback.channels_max = 2;
165 dai->playback.rates = S3C64XX_I2S_RATES;
166 dai->playback.formats = S3C64XX_I2S_FMTS;
167 dai->capture.channels_min = 2;
168 dai->capture.channels_max = 2;
169 dai->capture.rates = S3C64XX_I2S_RATES;
170 dai->capture.formats = S3C64XX_I2S_FMTS;
171 dai->probe = s3c64xx_i2s_probe;
172 dai->ops = &s3c64xx_i2s_dai_ops;
212 173
213 i2s->dma_capture = &s3c64xx_i2s_pcm_stereo_in[pdev->id]; 174 i2s->dma_capture = &s3c64xx_i2s_pcm_stereo_in[pdev->id];
214 i2s->dma_playback = &s3c64xx_i2s_pcm_stereo_out[pdev->id]; 175 i2s->dma_playback = &s3c64xx_i2s_pcm_stereo_out[pdev->id];
215 176
177 if (pdev->id == 0) {
178 i2s->dma_capture->channel = DMACH_I2S0_IN;
179 i2s->dma_capture->dma_addr = S3C64XX_PA_IIS0 + S3C2412_IISRXD;
180 i2s->dma_playback->channel = DMACH_I2S0_OUT;
181 i2s->dma_playback->dma_addr = S3C64XX_PA_IIS0 + S3C2412_IISTXD;
182 } else {
183 i2s->dma_capture->channel = DMACH_I2S1_IN;
184 i2s->dma_capture->dma_addr = S3C64XX_PA_IIS1 + S3C2412_IISRXD;
185 i2s->dma_playback->channel = DMACH_I2S1_OUT;
186 i2s->dma_playback->dma_addr = S3C64XX_PA_IIS1 + S3C2412_IISTXD;
187 }
188
189 i2s->dma_capture->client = &s3c64xx_dma_client_in;
190 i2s->dma_capture->dma_size = 4;
191 i2s->dma_playback->client = &s3c64xx_dma_client_out;
192 i2s->dma_playback->dma_size = 4;
193
216 i2s->iis_cclk = clk_get(&pdev->dev, "audio-bus"); 194 i2s->iis_cclk = clk_get(&pdev->dev, "audio-bus");
217 if (IS_ERR(i2s->iis_cclk)) { 195 if (IS_ERR(i2s->iis_cclk)) {
218 dev_err(&pdev->dev, "failed to get audio-bus\n"); 196 dev_err(&pdev->dev, "failed to get audio-bus\n");
diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.h b/sound/soc/s3c24xx/s3c64xx-i2s.h
index 02148cee2613..abe7253b55fc 100644
--- a/sound/soc/s3c24xx/s3c64xx-i2s.h
+++ b/sound/soc/s3c24xx/s3c64xx-i2s.h
@@ -25,6 +25,7 @@ struct clk;
25 25
26#define S3C64XX_CLKSRC_PCLK (0) 26#define S3C64XX_CLKSRC_PCLK (0)
27#define S3C64XX_CLKSRC_MUX (1) 27#define S3C64XX_CLKSRC_MUX (1)
28#define S3C64XX_CLKSRC_CDCLK (2)
28 29
29extern struct snd_soc_dai s3c64xx_i2s_dai[]; 30extern struct snd_soc_dai s3c64xx_i2s_dai[];
30 31
diff --git a/sound/soc/s3c24xx/smdk2443_wm9710.c b/sound/soc/s3c24xx/smdk2443_wm9710.c
index a2a4f5323c17..362258835e8d 100644
--- a/sound/soc/s3c24xx/smdk2443_wm9710.c
+++ b/sound/soc/s3c24xx/smdk2443_wm9710.c
@@ -20,8 +20,8 @@
20#include <sound/soc-dapm.h> 20#include <sound/soc-dapm.h>
21 21
22#include "../codecs/ac97.h" 22#include "../codecs/ac97.h"
23#include "s3c24xx-pcm.h" 23#include "s3c-dma.h"
24#include "s3c24xx-ac97.h" 24#include "s3c-ac97.h"
25 25
26static struct snd_soc_card smdk2443; 26static struct snd_soc_card smdk2443;
27 27
@@ -29,7 +29,7 @@ static struct snd_soc_dai_link smdk2443_dai[] = {
29{ 29{
30 .name = "AC97", 30 .name = "AC97",
31 .stream_name = "AC97 HiFi", 31 .stream_name = "AC97 HiFi",
32 .cpu_dai = &s3c2443_ac97_dai[0], 32 .cpu_dai = &s3c_ac97_dai[S3C_AC97_DAI_PCM],
33 .codec_dai = &ac97_dai, 33 .codec_dai = &ac97_dai,
34}, 34},
35}; 35};
diff --git a/sound/soc/s3c24xx/smdk64xx_wm8580.c b/sound/soc/s3c24xx/smdk64xx_wm8580.c
new file mode 100644
index 000000000000..efe4901213a3
--- /dev/null
+++ b/sound/soc/s3c24xx/smdk64xx_wm8580.c
@@ -0,0 +1,268 @@
1/*
2 * smdk64xx_wm8580.c
3 *
4 * Copyright (c) 2009 Samsung Electronics Co. Ltd
5 * Author: Jaswinder Singh <jassi.brar@samsung.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#include <linux/platform_device.h>
14#include <linux/clk.h>
15#include <sound/core.h>
16#include <sound/pcm.h>
17#include <sound/pcm_params.h>
18#include <sound/soc.h>
19#include <sound/soc-dapm.h>
20
21#include "../codecs/wm8580.h"
22#include "s3c-dma.h"
23#include "s3c64xx-i2s.h"
24
25#define S3C64XX_I2S_V4 2
26
27/* SMDK64XX has a 12MHZ crystal attached to WM8580 */
28#define SMDK64XX_WM8580_FREQ 12000000
29
30static int smdk64xx_hw_params(struct snd_pcm_substream *substream,
31 struct snd_pcm_hw_params *params)
32{
33 struct snd_soc_pcm_runtime *rtd = substream->private_data;
34 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
35 struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
36 unsigned int pll_out;
37 int bfs, rfs, ret;
38
39 switch (params_format(params)) {
40 case SNDRV_PCM_FORMAT_U8:
41 case SNDRV_PCM_FORMAT_S8:
42 bfs = 16;
43 break;
44 case SNDRV_PCM_FORMAT_U16_LE:
45 case SNDRV_PCM_FORMAT_S16_LE:
46 bfs = 32;
47 break;
48 default:
49 return -EINVAL;
50 }
51
52 /* The Fvco for WM8580 PLLs must fall within [90,100]MHz.
53 * This criterion can't be met if we request PLL output
54 * as {8000x256, 64000x256, 11025x256}Hz.
55 * As a wayout, we rather change rfs to a minimum value that
56 * results in (params_rate(params) * rfs), and itself, acceptable
57 * to both - the CODEC and the CPU.
58 */
59 switch (params_rate(params)) {
60 case 16000:
61 case 22050:
62 case 32000:
63 case 44100:
64 case 48000:
65 case 88200:
66 case 96000:
67 rfs = 256;
68 break;
69 case 64000:
70 rfs = 384;
71 break;
72 case 8000:
73 case 11025:
74 rfs = 512;
75 break;
76 default:
77 return -EINVAL;
78 }
79 pll_out = params_rate(params) * rfs;
80
81 /* Set the Codec DAI configuration */
82 ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S
83 | SND_SOC_DAIFMT_NB_NF
84 | SND_SOC_DAIFMT_CBM_CFM);
85 if (ret < 0)
86 return ret;
87
88 /* Set the AP DAI configuration */
89 ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S
90 | SND_SOC_DAIFMT_NB_NF
91 | SND_SOC_DAIFMT_CBM_CFM);
92 if (ret < 0)
93 return ret;
94
95 ret = snd_soc_dai_set_sysclk(cpu_dai, S3C64XX_CLKSRC_CDCLK,
96 0, SND_SOC_CLOCK_IN);
97 if (ret < 0)
98 return ret;
99
100 /* We use PCLK for basic ops in SoC-Slave mode */
101 ret = snd_soc_dai_set_sysclk(cpu_dai, S3C64XX_CLKSRC_PCLK,
102 0, SND_SOC_CLOCK_IN);
103 if (ret < 0)
104 return ret;
105
106 /* Set WM8580 to drive MCLK from its PLLA */
107 ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK,
108 WM8580_CLKSRC_PLLA);
109 if (ret < 0)
110 return ret;
111
112 /* Explicitly set WM8580-DAC to source from MCLK */
113 ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_DAC_CLKSEL,
114 WM8580_CLKSRC_MCLK);
115 if (ret < 0)
116 return ret;
117
118 ret = snd_soc_dai_set_pll(codec_dai, WM8580_PLLA, 0,
119 SMDK64XX_WM8580_FREQ, pll_out);
120 if (ret < 0)
121 return ret;
122
123 ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C_I2SV2_DIV_BCLK, bfs);
124 if (ret < 0)
125 return ret;
126
127 ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C_I2SV2_DIV_RCLK, rfs);
128 if (ret < 0)
129 return ret;
130
131 return 0;
132}
133
134/*
135 * SMDK64XX WM8580 DAI operations.
136 */
137static struct snd_soc_ops smdk64xx_ops = {
138 .hw_params = smdk64xx_hw_params,
139};
140
141/* SMDK64xx Playback widgets */
142static const struct snd_soc_dapm_widget wm8580_dapm_widgets_pbk[] = {
143 SND_SOC_DAPM_HP("Front-L/R", NULL),
144 SND_SOC_DAPM_HP("Center/Sub", NULL),
145 SND_SOC_DAPM_HP("Rear-L/R", NULL),
146};
147
148/* SMDK64xx Capture widgets */
149static const struct snd_soc_dapm_widget wm8580_dapm_widgets_cpt[] = {
150 SND_SOC_DAPM_MIC("MicIn", NULL),
151 SND_SOC_DAPM_LINE("LineIn", NULL),
152};
153
154/* SMDK-PAIFTX connections */
155static const struct snd_soc_dapm_route audio_map_tx[] = {
156 /* MicIn feeds AINL */
157 {"AINL", NULL, "MicIn"},
158
159 /* LineIn feeds AINL/R */
160 {"AINL", NULL, "LineIn"},
161 {"AINR", NULL, "LineIn"},
162};
163
164/* SMDK-PAIFRX connections */
165static const struct snd_soc_dapm_route audio_map_rx[] = {
166 /* Front Left/Right are fed VOUT1L/R */
167 {"Front-L/R", NULL, "VOUT1L"},
168 {"Front-L/R", NULL, "VOUT1R"},
169
170 /* Center/Sub are fed VOUT2L/R */
171 {"Center/Sub", NULL, "VOUT2L"},
172 {"Center/Sub", NULL, "VOUT2R"},
173
174 /* Rear Left/Right are fed VOUT3L/R */
175 {"Rear-L/R", NULL, "VOUT3L"},
176 {"Rear-L/R", NULL, "VOUT3R"},
177};
178
179static int smdk64xx_wm8580_init_paiftx(struct snd_soc_codec *codec)
180{
181 /* Add smdk64xx specific Capture widgets */
182 snd_soc_dapm_new_controls(codec, wm8580_dapm_widgets_cpt,
183 ARRAY_SIZE(wm8580_dapm_widgets_cpt));
184
185 /* Set up PAIFTX audio path */
186 snd_soc_dapm_add_routes(codec, audio_map_tx, ARRAY_SIZE(audio_map_tx));
187
188 /* Enabling the microphone requires the fitting of a 0R
189 * resistor to connect the line from the microphone jack.
190 */
191 snd_soc_dapm_disable_pin(codec, "MicIn");
192
193 /* signal a DAPM event */
194 snd_soc_dapm_sync(codec);
195
196 return 0;
197}
198
199static int smdk64xx_wm8580_init_paifrx(struct snd_soc_codec *codec)
200{
201 /* Add smdk64xx specific Playback widgets */
202 snd_soc_dapm_new_controls(codec, wm8580_dapm_widgets_pbk,
203 ARRAY_SIZE(wm8580_dapm_widgets_pbk));
204
205 /* Set up PAIFRX audio path */
206 snd_soc_dapm_add_routes(codec, audio_map_rx, ARRAY_SIZE(audio_map_rx));
207
208 /* signal a DAPM event */
209 snd_soc_dapm_sync(codec);
210
211 return 0;
212}
213
214static struct snd_soc_dai_link smdk64xx_dai[] = {
215{ /* Primary Playback i/f */
216 .name = "WM8580 PAIF RX",
217 .stream_name = "Playback",
218 .cpu_dai = &s3c64xx_i2s_dai[S3C64XX_I2S_V4],
219 .codec_dai = &wm8580_dai[WM8580_DAI_PAIFRX],
220 .init = smdk64xx_wm8580_init_paifrx,
221 .ops = &smdk64xx_ops,
222},
223{ /* Primary Capture i/f */
224 .name = "WM8580 PAIF TX",
225 .stream_name = "Capture",
226 .cpu_dai = &s3c64xx_i2s_dai[S3C64XX_I2S_V4],
227 .codec_dai = &wm8580_dai[WM8580_DAI_PAIFTX],
228 .init = smdk64xx_wm8580_init_paiftx,
229 .ops = &smdk64xx_ops,
230},
231};
232
233static struct snd_soc_card smdk64xx = {
234 .name = "smdk64xx",
235 .platform = &s3c24xx_soc_platform,
236 .dai_link = smdk64xx_dai,
237 .num_links = ARRAY_SIZE(smdk64xx_dai),
238};
239
240static struct snd_soc_device smdk64xx_snd_devdata = {
241 .card = &smdk64xx,
242 .codec_dev = &soc_codec_dev_wm8580,
243};
244
245static struct platform_device *smdk64xx_snd_device;
246
247static int __init smdk64xx_audio_init(void)
248{
249 int ret;
250
251 smdk64xx_snd_device = platform_device_alloc("soc-audio", -1);
252 if (!smdk64xx_snd_device)
253 return -ENOMEM;
254
255 platform_set_drvdata(smdk64xx_snd_device, &smdk64xx_snd_devdata);
256 smdk64xx_snd_devdata.dev = &smdk64xx_snd_device->dev;
257 ret = platform_device_add(smdk64xx_snd_device);
258
259 if (ret)
260 platform_device_put(smdk64xx_snd_device);
261
262 return ret;
263}
264module_init(smdk64xx_audio_init);
265
266MODULE_AUTHOR("Jaswinder Singh, jassi.brar@samsung.com");
267MODULE_DESCRIPTION("ALSA SoC SMDK64XX WM8580");
268MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/smdk_wm9713.c b/sound/soc/s3c24xx/smdk_wm9713.c
new file mode 100644
index 000000000000..24fd39f38ccb
--- /dev/null
+++ b/sound/soc/s3c24xx/smdk_wm9713.c
@@ -0,0 +1,94 @@
1/*
2 * smdk_wm9713.c -- SoC audio for SMDK
3 *
4 * Copyright 2010 Samsung Electronics Co. Ltd.
5 * Author: Jaswinder Singh Brar <jassi.brar@samsung.com>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) any later version.
11 *
12 */
13
14#include <linux/module.h>
15#include <linux/device.h>
16#include <sound/soc.h>
17
18#include "../codecs/wm9713.h"
19#include "s3c-dma.h"
20#include "s3c-ac97.h"
21
22static struct snd_soc_card smdk;
23
24/*
25 * Default CFG switch settings to use this driver:
26 *
27 * SMDK6410: Set CFG1 1-3 On, CFG2 1-4 Off
28 */
29
30/*
31 Playback (HeadPhone):-
32 $ amixer sset 'Headphone' unmute
33 $ amixer sset 'Right Headphone Out Mux' 'Headphone'
34 $ amixer sset 'Left Headphone Out Mux' 'Headphone'
35 $ amixer sset 'Right HP Mixer PCM' unmute
36 $ amixer sset 'Left HP Mixer PCM' unmute
37
38 Capture (LineIn):-
39 $ amixer sset 'Right Capture Source' 'Line'
40 $ amixer sset 'Left Capture Source' 'Line'
41*/
42
43static struct snd_soc_dai_link smdk_dai = {
44 .name = "AC97",
45 .stream_name = "AC97 PCM",
46 .cpu_dai = &s3c_ac97_dai[S3C_AC97_DAI_PCM],
47 .codec_dai = &wm9713_dai[WM9713_DAI_AC97_HIFI],
48};
49
50static struct snd_soc_card smdk = {
51 .name = "SMDK",
52 .platform = &s3c24xx_soc_platform,
53 .dai_link = &smdk_dai,
54 .num_links = 1,
55};
56
57static struct snd_soc_device smdk_snd_ac97_devdata = {
58 .card = &smdk,
59 .codec_dev = &soc_codec_dev_wm9713,
60};
61
62static struct platform_device *smdk_snd_ac97_device;
63
64static int __init smdk_init(void)
65{
66 int ret;
67
68 smdk_snd_ac97_device = platform_device_alloc("soc-audio", -1);
69 if (!smdk_snd_ac97_device)
70 return -ENOMEM;
71
72 platform_set_drvdata(smdk_snd_ac97_device,
73 &smdk_snd_ac97_devdata);
74 smdk_snd_ac97_devdata.dev = &smdk_snd_ac97_device->dev;
75
76 ret = platform_device_add(smdk_snd_ac97_device);
77 if (ret)
78 platform_device_put(smdk_snd_ac97_device);
79
80 return ret;
81}
82
83static void __exit smdk_exit(void)
84{
85 platform_device_unregister(smdk_snd_ac97_device);
86}
87
88module_init(smdk_init);
89module_exit(smdk_exit);
90
91/* Module information */
92MODULE_AUTHOR("Jaswinder Singh Brar, jassi.brar@samsung.com");
93MODULE_DESCRIPTION("ALSA SoC SMDK+WM9713");
94MODULE_LICENSE("GPL");