diff options
Diffstat (limited to 'sound/soc/s3c24xx')
-rw-r--r-- | sound/soc/s3c24xx/Kconfig | 35 | ||||
-rw-r--r-- | sound/soc/s3c24xx/Makefile | 9 | ||||
-rw-r--r-- | sound/soc/s3c24xx/neo1973_gta02_wm8753.c | 498 | ||||
-rw-r--r-- | sound/soc/s3c24xx/s3c-i2s-v2.c | 17 | ||||
-rw-r--r-- | sound/soc/s3c24xx/s3c2443-ac97.c | 20 | ||||
-rw-r--r-- | sound/soc/s3c24xx/s3c24xx-i2s.c | 5 | ||||
-rw-r--r-- | sound/soc/s3c24xx/s3c24xx-pcm.c | 2 | ||||
-rw-r--r-- | sound/soc/s3c24xx/s3c24xx_simtec.c | 394 | ||||
-rw-r--r-- | sound/soc/s3c24xx/s3c24xx_simtec.h | 22 | ||||
-rw-r--r-- | sound/soc/s3c24xx/s3c24xx_simtec_hermes.c | 153 | ||||
-rw-r--r-- | sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c | 137 |
11 files changed, 1280 insertions, 12 deletions
diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig index df494d1e346f..923428fc1adb 100644 --- a/sound/soc/s3c24xx/Kconfig +++ b/sound/soc/s3c24xx/Kconfig | |||
@@ -1,6 +1,7 @@ | |||
1 | config SND_S3C24XX_SOC | 1 | config SND_S3C24XX_SOC |
2 | tristate "SoC Audio for the Samsung S3CXXXX chips" | 2 | tristate "SoC Audio for the Samsung S3CXXXX chips" |
3 | depends on ARCH_S3C2410 | 3 | depends on ARCH_S3C2410 || ARCH_S3C64XX |
4 | select S3C64XX_DMA if ARCH_S3C64XX | ||
4 | help | 5 | help |
5 | Say Y or M if you want to add support for codecs attached to | 6 | Say Y or M if you want to add support for codecs attached to |
6 | the S3C24XX AC97 or I2S interfaces. You will also need to | 7 | the S3C24XX AC97 or I2S interfaces. You will also need to |
@@ -38,6 +39,15 @@ config SND_S3C24XX_SOC_NEO1973_WM8753 | |||
38 | Say Y if you want to add support for SoC audio on smdk2440 | 39 | Say Y if you want to add support for SoC audio on smdk2440 |
39 | with the WM8753. | 40 | with the WM8753. |
40 | 41 | ||
42 | config SND_S3C24XX_SOC_NEO1973_GTA02_WM8753 | ||
43 | tristate "Audio support for the Openmoko Neo FreeRunner (GTA02)" | ||
44 | depends on SND_S3C24XX_SOC && MACH_NEO1973_GTA02 | ||
45 | select SND_S3C24XX_SOC_I2S | ||
46 | select SND_SOC_WM8753 | ||
47 | help | ||
48 | This driver provides audio support for the Openmoko Neo FreeRunner | ||
49 | smartphone. | ||
50 | |||
41 | config SND_S3C24XX_SOC_JIVE_WM8750 | 51 | config SND_S3C24XX_SOC_JIVE_WM8750 |
42 | tristate "SoC I2S Audio support for Jive" | 52 | tristate "SoC I2S Audio support for Jive" |
43 | depends on SND_S3C24XX_SOC && MACH_JIVE | 53 | depends on SND_S3C24XX_SOC && MACH_JIVE |
@@ -57,7 +67,7 @@ config SND_S3C24XX_SOC_SMDK2443_WM9710 | |||
57 | 67 | ||
58 | config SND_S3C24XX_SOC_LN2440SBC_ALC650 | 68 | config SND_S3C24XX_SOC_LN2440SBC_ALC650 |
59 | tristate "SoC AC97 Audio support for LN2440SBC - ALC650" | 69 | tristate "SoC AC97 Audio support for LN2440SBC - ALC650" |
60 | depends on SND_S3C24XX_SOC | 70 | depends on SND_S3C24XX_SOC && ARCH_S3C2410 |
61 | select SND_S3C2443_SOC_AC97 | 71 | select SND_S3C2443_SOC_AC97 |
62 | select SND_SOC_AC97_CODEC | 72 | select SND_SOC_AC97_CODEC |
63 | help | 73 | help |
@@ -66,7 +76,26 @@ config SND_S3C24XX_SOC_LN2440SBC_ALC650 | |||
66 | 76 | ||
67 | config SND_S3C24XX_SOC_S3C24XX_UDA134X | 77 | config SND_S3C24XX_SOC_S3C24XX_UDA134X |
68 | tristate "SoC I2S Audio support UDA134X wired to a S3C24XX" | 78 | tristate "SoC I2S Audio support UDA134X wired to a S3C24XX" |
69 | depends on SND_S3C24XX_SOC | 79 | depends on SND_S3C24XX_SOC && ARCH_S3C2410 |
70 | select SND_S3C24XX_SOC_I2S | 80 | select SND_S3C24XX_SOC_I2S |
71 | select SND_SOC_L3 | 81 | select SND_SOC_L3 |
72 | select SND_SOC_UDA134X | 82 | select SND_SOC_UDA134X |
83 | |||
84 | config SND_S3C24XX_SOC_SIMTEC | ||
85 | tristate | ||
86 | help | ||
87 | Internal node for common S3C24XX/Simtec suppor | ||
88 | |||
89 | config SND_S3C24XX_SOC_SIMTEC_TLV320AIC23 | ||
90 | tristate "SoC I2S Audio support for TLV320AIC23 on Simtec boards" | ||
91 | depends on SND_S3C24XX_SOC && ARCH_S3C2410 | ||
92 | select SND_S3C24XX_SOC_I2S | ||
93 | select SND_SOC_TLV320AIC23 | ||
94 | select SND_S3C24XX_SOC_SIMTEC | ||
95 | |||
96 | config SND_S3C24XX_SOC_SIMTEC_HERMES | ||
97 | tristate "SoC I2S Audio support for Simtec Hermes board" | ||
98 | depends on SND_S3C24XX_SOC && ARCH_S3C2410 | ||
99 | select SND_S3C24XX_SOC_I2S | ||
100 | select SND_SOC_TLV320AIC3X | ||
101 | select SND_S3C24XX_SOC_SIMTEC | ||
diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile index 07a93a2ebe5f..99f5a7dd3fc6 100644 --- a/sound/soc/s3c24xx/Makefile +++ b/sound/soc/s3c24xx/Makefile | |||
@@ -16,12 +16,21 @@ obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o | |||
16 | # S3C24XX Machine Support | 16 | # S3C24XX Machine Support |
17 | snd-soc-jive-wm8750-objs := jive_wm8750.o | 17 | snd-soc-jive-wm8750-objs := jive_wm8750.o |
18 | snd-soc-neo1973-wm8753-objs := neo1973_wm8753.o | 18 | snd-soc-neo1973-wm8753-objs := neo1973_wm8753.o |
19 | snd-soc-neo1973-gta02-wm8753-objs := neo1973_gta02_wm8753.o | ||
19 | snd-soc-smdk2443-wm9710-objs := smdk2443_wm9710.o | 20 | snd-soc-smdk2443-wm9710-objs := smdk2443_wm9710.o |
20 | snd-soc-ln2440sbc-alc650-objs := ln2440sbc_alc650.o | 21 | snd-soc-ln2440sbc-alc650-objs := ln2440sbc_alc650.o |
21 | snd-soc-s3c24xx-uda134x-objs := s3c24xx_uda134x.o | 22 | snd-soc-s3c24xx-uda134x-objs := s3c24xx_uda134x.o |
23 | snd-soc-s3c24xx-simtec-objs := s3c24xx_simtec.o | ||
24 | snd-soc-s3c24xx-simtec-hermes-objs := s3c24xx_simtec_hermes.o | ||
25 | snd-soc-s3c24xx-simtec-tlv320aic23-objs := s3c24xx_simtec_tlv320aic23.o | ||
22 | 26 | ||
23 | obj-$(CONFIG_SND_S3C24XX_SOC_JIVE_WM8750) += snd-soc-jive-wm8750.o | 27 | obj-$(CONFIG_SND_S3C24XX_SOC_JIVE_WM8750) += snd-soc-jive-wm8750.o |
24 | obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o | 28 | obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o |
29 | obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_GTA02_WM8753) += snd-soc-neo1973-gta02-wm8753.o | ||
25 | obj-$(CONFIG_SND_S3C24XX_SOC_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o | 30 | obj-$(CONFIG_SND_S3C24XX_SOC_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o |
26 | obj-$(CONFIG_SND_S3C24XX_SOC_LN2440SBC_ALC650) += snd-soc-ln2440sbc-alc650.o | 31 | obj-$(CONFIG_SND_S3C24XX_SOC_LN2440SBC_ALC650) += snd-soc-ln2440sbc-alc650.o |
27 | obj-$(CONFIG_SND_S3C24XX_SOC_S3C24XX_UDA134X) += snd-soc-s3c24xx-uda134x.o | 32 | obj-$(CONFIG_SND_S3C24XX_SOC_S3C24XX_UDA134X) += snd-soc-s3c24xx-uda134x.o |
33 | obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC) += snd-soc-s3c24xx-simtec.o | ||
34 | obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_HERMES) += snd-soc-s3c24xx-simtec-hermes.o | ||
35 | obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_TLV320AIC23) += snd-soc-s3c24xx-simtec-tlv320aic23.o | ||
36 | |||
diff --git a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c new file mode 100644 index 000000000000..0c52e36ddd87 --- /dev/null +++ b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c | |||
@@ -0,0 +1,498 @@ | |||
1 | /* | ||
2 | * neo1973_gta02_wm8753.c -- SoC audio for Openmoko Freerunner(GTA02) | ||
3 | * | ||
4 | * Copyright 2007 Openmoko Inc | ||
5 | * Author: Graeme Gregory <graeme@openmoko.org> | ||
6 | * Copyright 2007 Wolfson Microelectronics PLC. | ||
7 | * Author: Graeme Gregory <linux@wolfsonmicro.com> | ||
8 | * Copyright 2009 Wolfson Microelectronics | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of the GNU General Public License as published by the | ||
12 | * Free Software Foundation; either version 2 of the License, or (at your | ||
13 | * option) any later version. | ||
14 | */ | ||
15 | |||
16 | #include <linux/module.h> | ||
17 | #include <linux/moduleparam.h> | ||
18 | #include <linux/timer.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/gpio.h> | ||
22 | #include <sound/core.h> | ||
23 | #include <sound/pcm.h> | ||
24 | #include <sound/soc.h> | ||
25 | #include <sound/soc-dapm.h> | ||
26 | |||
27 | #include <asm/mach-types.h> | ||
28 | |||
29 | #include <plat/regs-iis.h> | ||
30 | |||
31 | #include <mach/regs-clock.h> | ||
32 | #include <asm/io.h> | ||
33 | #include <mach/gta02.h> | ||
34 | #include "../codecs/wm8753.h" | ||
35 | #include "s3c24xx-pcm.h" | ||
36 | #include "s3c24xx-i2s.h" | ||
37 | |||
38 | static struct snd_soc_card neo1973_gta02; | ||
39 | |||
40 | static int neo1973_gta02_hifi_hw_params(struct snd_pcm_substream *substream, | ||
41 | struct snd_pcm_hw_params *params) | ||
42 | { | ||
43 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
44 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | ||
45 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
46 | unsigned int pll_out = 0, bclk = 0; | ||
47 | int ret = 0; | ||
48 | unsigned long iis_clkrate; | ||
49 | |||
50 | iis_clkrate = s3c24xx_i2s_get_clockrate(); | ||
51 | |||
52 | switch (params_rate(params)) { | ||
53 | case 8000: | ||
54 | case 16000: | ||
55 | pll_out = 12288000; | ||
56 | break; | ||
57 | case 48000: | ||
58 | bclk = WM8753_BCLK_DIV_4; | ||
59 | pll_out = 12288000; | ||
60 | break; | ||
61 | case 96000: | ||
62 | bclk = WM8753_BCLK_DIV_2; | ||
63 | pll_out = 12288000; | ||
64 | break; | ||
65 | case 11025: | ||
66 | bclk = WM8753_BCLK_DIV_16; | ||
67 | pll_out = 11289600; | ||
68 | break; | ||
69 | case 22050: | ||
70 | bclk = WM8753_BCLK_DIV_8; | ||
71 | pll_out = 11289600; | ||
72 | break; | ||
73 | case 44100: | ||
74 | bclk = WM8753_BCLK_DIV_4; | ||
75 | pll_out = 11289600; | ||
76 | break; | ||
77 | case 88200: | ||
78 | bclk = WM8753_BCLK_DIV_2; | ||
79 | pll_out = 11289600; | ||
80 | break; | ||
81 | } | ||
82 | |||
83 | /* set codec DAI configuration */ | ||
84 | ret = snd_soc_dai_set_fmt(codec_dai, | ||
85 | SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | | ||
86 | SND_SOC_DAIFMT_CBM_CFM); | ||
87 | if (ret < 0) | ||
88 | return ret; | ||
89 | |||
90 | /* set cpu DAI configuration */ | ||
91 | ret = snd_soc_dai_set_fmt(cpu_dai, | ||
92 | SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | | ||
93 | SND_SOC_DAIFMT_CBM_CFM); | ||
94 | if (ret < 0) | ||
95 | return ret; | ||
96 | |||
97 | /* set the codec system clock for DAC and ADC */ | ||
98 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, pll_out, | ||
99 | SND_SOC_CLOCK_IN); | ||
100 | if (ret < 0) | ||
101 | return ret; | ||
102 | |||
103 | /* set MCLK division for sample rate */ | ||
104 | ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK, | ||
105 | S3C2410_IISMOD_32FS); | ||
106 | if (ret < 0) | ||
107 | return ret; | ||
108 | |||
109 | /* set codec BCLK division for sample rate */ | ||
110 | ret = snd_soc_dai_set_clkdiv(codec_dai, | ||
111 | WM8753_BCLKDIV, bclk); | ||
112 | if (ret < 0) | ||
113 | return ret; | ||
114 | |||
115 | /* set prescaler division for sample rate */ | ||
116 | ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER, | ||
117 | S3C24XX_PRESCALE(4, 4)); | ||
118 | if (ret < 0) | ||
119 | return ret; | ||
120 | |||
121 | /* codec PLL input is PCLK/4 */ | ||
122 | ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, | ||
123 | iis_clkrate / 4, pll_out); | ||
124 | if (ret < 0) | ||
125 | return ret; | ||
126 | |||
127 | return 0; | ||
128 | } | ||
129 | |||
130 | static int neo1973_gta02_hifi_hw_free(struct snd_pcm_substream *substream) | ||
131 | { | ||
132 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
133 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | ||
134 | |||
135 | /* disable the PLL */ | ||
136 | return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0); | ||
137 | } | ||
138 | |||
139 | /* | ||
140 | * Neo1973 WM8753 HiFi DAI opserations. | ||
141 | */ | ||
142 | static struct snd_soc_ops neo1973_gta02_hifi_ops = { | ||
143 | .hw_params = neo1973_gta02_hifi_hw_params, | ||
144 | .hw_free = neo1973_gta02_hifi_hw_free, | ||
145 | }; | ||
146 | |||
147 | static int neo1973_gta02_voice_hw_params( | ||
148 | struct snd_pcm_substream *substream, | ||
149 | struct snd_pcm_hw_params *params) | ||
150 | { | ||
151 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
152 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | ||
153 | unsigned int pcmdiv = 0; | ||
154 | int ret = 0; | ||
155 | unsigned long iis_clkrate; | ||
156 | |||
157 | iis_clkrate = s3c24xx_i2s_get_clockrate(); | ||
158 | |||
159 | if (params_rate(params) != 8000) | ||
160 | return -EINVAL; | ||
161 | if (params_channels(params) != 1) | ||
162 | return -EINVAL; | ||
163 | |||
164 | pcmdiv = WM8753_PCM_DIV_6; /* 2.048 MHz */ | ||
165 | |||
166 | /* todo: gg check mode (DSP_B) against CSR datasheet */ | ||
167 | /* set codec DAI configuration */ | ||
168 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B | | ||
169 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); | ||
170 | if (ret < 0) | ||
171 | return ret; | ||
172 | |||
173 | /* set the codec system clock for DAC and ADC */ | ||
174 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_PCMCLK, | ||
175 | 12288000, SND_SOC_CLOCK_IN); | ||
176 | if (ret < 0) | ||
177 | return ret; | ||
178 | |||
179 | /* set codec PCM division for sample rate */ | ||
180 | ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_PCMDIV, | ||
181 | pcmdiv); | ||
182 | if (ret < 0) | ||
183 | return ret; | ||
184 | |||
185 | /* configue and enable PLL for 12.288MHz output */ | ||
186 | ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, | ||
187 | iis_clkrate / 4, 12288000); | ||
188 | if (ret < 0) | ||
189 | return ret; | ||
190 | |||
191 | return 0; | ||
192 | } | ||
193 | |||
194 | static int neo1973_gta02_voice_hw_free(struct snd_pcm_substream *substream) | ||
195 | { | ||
196 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
197 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | ||
198 | |||
199 | /* disable the PLL */ | ||
200 | return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0); | ||
201 | } | ||
202 | |||
203 | static struct snd_soc_ops neo1973_gta02_voice_ops = { | ||
204 | .hw_params = neo1973_gta02_voice_hw_params, | ||
205 | .hw_free = neo1973_gta02_voice_hw_free, | ||
206 | }; | ||
207 | |||
208 | #define LM4853_AMP 1 | ||
209 | #define LM4853_SPK 2 | ||
210 | |||
211 | static u8 lm4853_state; | ||
212 | |||
213 | /* This has no effect, it exists only to maintain compatibility with | ||
214 | * existing ALSA state files. | ||
215 | */ | ||
216 | static int lm4853_set_state(struct snd_kcontrol *kcontrol, | ||
217 | struct snd_ctl_elem_value *ucontrol) | ||
218 | { | ||
219 | int val = ucontrol->value.integer.value[0]; | ||
220 | |||
221 | if (val) | ||
222 | lm4853_state |= LM4853_AMP; | ||
223 | else | ||
224 | lm4853_state &= ~LM4853_AMP; | ||
225 | |||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | static int lm4853_get_state(struct snd_kcontrol *kcontrol, | ||
230 | struct snd_ctl_elem_value *ucontrol) | ||
231 | { | ||
232 | ucontrol->value.integer.value[0] = lm4853_state & LM4853_AMP; | ||
233 | |||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | static int lm4853_set_spk(struct snd_kcontrol *kcontrol, | ||
238 | struct snd_ctl_elem_value *ucontrol) | ||
239 | { | ||
240 | int val = ucontrol->value.integer.value[0]; | ||
241 | |||
242 | if (val) { | ||
243 | lm4853_state |= LM4853_SPK; | ||
244 | gpio_set_value(GTA02_GPIO_HP_IN, 0); | ||
245 | } else { | ||
246 | lm4853_state &= ~LM4853_SPK; | ||
247 | gpio_set_value(GTA02_GPIO_HP_IN, 1); | ||
248 | } | ||
249 | |||
250 | return 0; | ||
251 | } | ||
252 | |||
253 | static int lm4853_get_spk(struct snd_kcontrol *kcontrol, | ||
254 | struct snd_ctl_elem_value *ucontrol) | ||
255 | { | ||
256 | ucontrol->value.integer.value[0] = (lm4853_state & LM4853_SPK) >> 1; | ||
257 | |||
258 | return 0; | ||
259 | } | ||
260 | |||
261 | static int lm4853_event(struct snd_soc_dapm_widget *w, | ||
262 | struct snd_kcontrol *k, | ||
263 | int event) | ||
264 | { | ||
265 | gpio_set_value(GTA02_GPIO_AMP_SHUT, SND_SOC_DAPM_EVENT_OFF(value)); | ||
266 | |||
267 | return 0; | ||
268 | } | ||
269 | |||
270 | static const struct snd_soc_dapm_widget wm8753_dapm_widgets[] = { | ||
271 | SND_SOC_DAPM_SPK("Stereo Out", lm4853_event), | ||
272 | SND_SOC_DAPM_LINE("GSM Line Out", NULL), | ||
273 | SND_SOC_DAPM_LINE("GSM Line In", NULL), | ||
274 | SND_SOC_DAPM_MIC("Headset Mic", NULL), | ||
275 | SND_SOC_DAPM_MIC("Handset Mic", NULL), | ||
276 | SND_SOC_DAPM_SPK("Handset Spk", NULL), | ||
277 | }; | ||
278 | |||
279 | |||
280 | /* example machine audio_mapnections */ | ||
281 | static const struct snd_soc_dapm_route audio_map[] = { | ||
282 | |||
283 | /* Connections to the lm4853 amp */ | ||
284 | {"Stereo Out", NULL, "LOUT1"}, | ||
285 | {"Stereo Out", NULL, "ROUT1"}, | ||
286 | |||
287 | /* Connections to the GSM Module */ | ||
288 | {"GSM Line Out", NULL, "MONO1"}, | ||
289 | {"GSM Line Out", NULL, "MONO2"}, | ||
290 | {"RXP", NULL, "GSM Line In"}, | ||
291 | {"RXN", NULL, "GSM Line In"}, | ||
292 | |||
293 | /* Connections to Headset */ | ||
294 | {"MIC1", NULL, "Mic Bias"}, | ||
295 | {"Mic Bias", NULL, "Headset Mic"}, | ||
296 | |||
297 | /* Call Mic */ | ||
298 | {"MIC2", NULL, "Mic Bias"}, | ||
299 | {"MIC2N", NULL, "Mic Bias"}, | ||
300 | {"Mic Bias", NULL, "Handset Mic"}, | ||
301 | |||
302 | /* Call Speaker */ | ||
303 | {"Handset Spk", NULL, "LOUT2"}, | ||
304 | {"Handset Spk", NULL, "ROUT2"}, | ||
305 | |||
306 | /* Connect the ALC pins */ | ||
307 | {"ACIN", NULL, "ACOP"}, | ||
308 | }; | ||
309 | |||
310 | static const struct snd_kcontrol_new wm8753_neo1973_gta02_controls[] = { | ||
311 | SOC_DAPM_PIN_SWITCH("Stereo Out"), | ||
312 | SOC_DAPM_PIN_SWITCH("GSM Line Out"), | ||
313 | SOC_DAPM_PIN_SWITCH("GSM Line In"), | ||
314 | SOC_DAPM_PIN_SWITCH("Headset Mic"), | ||
315 | SOC_DAPM_PIN_SWITCH("Handset Mic"), | ||
316 | SOC_DAPM_PIN_SWITCH("Handset Spk"), | ||
317 | |||
318 | /* This has no effect, it exists only to maintain compatibility with | ||
319 | * existing ALSA state files. | ||
320 | */ | ||
321 | SOC_SINGLE_EXT("Amp State Switch", 6, 0, 1, 0, | ||
322 | lm4853_get_state, | ||
323 | lm4853_set_state), | ||
324 | SOC_SINGLE_EXT("Amp Spk Switch", 7, 0, 1, 0, | ||
325 | lm4853_get_spk, | ||
326 | lm4853_set_spk), | ||
327 | }; | ||
328 | |||
329 | /* | ||
330 | * This is an example machine initialisation for a wm8753 connected to a | ||
331 | * neo1973 GTA02. | ||
332 | */ | ||
333 | static int neo1973_gta02_wm8753_init(struct snd_soc_codec *codec) | ||
334 | { | ||
335 | int err; | ||
336 | |||
337 | /* set up NC codec pins */ | ||
338 | snd_soc_dapm_nc_pin(codec, "OUT3"); | ||
339 | snd_soc_dapm_nc_pin(codec, "OUT4"); | ||
340 | snd_soc_dapm_nc_pin(codec, "LINE1"); | ||
341 | snd_soc_dapm_nc_pin(codec, "LINE2"); | ||
342 | |||
343 | /* Add neo1973 gta02 specific widgets */ | ||
344 | snd_soc_dapm_new_controls(codec, wm8753_dapm_widgets, | ||
345 | ARRAY_SIZE(wm8753_dapm_widgets)); | ||
346 | |||
347 | /* add neo1973 gta02 specific controls */ | ||
348 | err = snd_soc_add_controls(codec, wm8753_neo1973_gta02_controls, | ||
349 | ARRAY_SIZE(wm8753_neo1973_gta02_controls)); | ||
350 | |||
351 | if (err < 0) | ||
352 | return err; | ||
353 | |||
354 | /* set up neo1973 gta02 specific audio path audio_map */ | ||
355 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | ||
356 | |||
357 | /* set endpoints to default off mode */ | ||
358 | snd_soc_dapm_disable_pin(codec, "Stereo Out"); | ||
359 | snd_soc_dapm_disable_pin(codec, "GSM Line Out"); | ||
360 | snd_soc_dapm_disable_pin(codec, "GSM Line In"); | ||
361 | snd_soc_dapm_disable_pin(codec, "Headset Mic"); | ||
362 | snd_soc_dapm_disable_pin(codec, "Handset Mic"); | ||
363 | snd_soc_dapm_disable_pin(codec, "Handset Spk"); | ||
364 | |||
365 | snd_soc_dapm_sync(codec); | ||
366 | |||
367 | return 0; | ||
368 | } | ||
369 | |||
370 | /* | ||
371 | * BT Codec DAI | ||
372 | */ | ||
373 | static struct snd_soc_dai bt_dai = { | ||
374 | .name = "Bluetooth", | ||
375 | .id = 0, | ||
376 | .playback = { | ||
377 | .channels_min = 1, | ||
378 | .channels_max = 1, | ||
379 | .rates = SNDRV_PCM_RATE_8000, | ||
380 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | ||
381 | .capture = { | ||
382 | .channels_min = 1, | ||
383 | .channels_max = 1, | ||
384 | .rates = SNDRV_PCM_RATE_8000, | ||
385 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | ||
386 | }; | ||
387 | |||
388 | static struct snd_soc_dai_link neo1973_gta02_dai[] = { | ||
389 | { /* Hifi Playback - for similatious use with voice below */ | ||
390 | .name = "WM8753", | ||
391 | .stream_name = "WM8753 HiFi", | ||
392 | .cpu_dai = &s3c24xx_i2s_dai, | ||
393 | .codec_dai = &wm8753_dai[WM8753_DAI_HIFI], | ||
394 | .init = neo1973_gta02_wm8753_init, | ||
395 | .ops = &neo1973_gta02_hifi_ops, | ||
396 | }, | ||
397 | { /* Voice via BT */ | ||
398 | .name = "Bluetooth", | ||
399 | .stream_name = "Voice", | ||
400 | .cpu_dai = &bt_dai, | ||
401 | .codec_dai = &wm8753_dai[WM8753_DAI_VOICE], | ||
402 | .ops = &neo1973_gta02_voice_ops, | ||
403 | }, | ||
404 | }; | ||
405 | |||
406 | static struct snd_soc_card neo1973_gta02 = { | ||
407 | .name = "neo1973-gta02", | ||
408 | .platform = &s3c24xx_soc_platform, | ||
409 | .dai_link = neo1973_gta02_dai, | ||
410 | .num_links = ARRAY_SIZE(neo1973_gta02_dai), | ||
411 | }; | ||
412 | |||
413 | static struct snd_soc_device neo1973_gta02_snd_devdata = { | ||
414 | .card = &neo1973_gta02, | ||
415 | .codec_dev = &soc_codec_dev_wm8753, | ||
416 | }; | ||
417 | |||
418 | static struct platform_device *neo1973_gta02_snd_device; | ||
419 | |||
420 | static int __init neo1973_gta02_init(void) | ||
421 | { | ||
422 | int ret; | ||
423 | |||
424 | if (!machine_is_neo1973_gta02()) { | ||
425 | printk(KERN_INFO | ||
426 | "Only GTA02 is supported by this ASoC driver\n"); | ||
427 | return -ENODEV; | ||
428 | } | ||
429 | |||
430 | /* register bluetooth DAI here */ | ||
431 | ret = snd_soc_register_dai(&bt_dai); | ||
432 | if (ret) | ||
433 | return ret; | ||
434 | |||
435 | neo1973_gta02_snd_device = platform_device_alloc("soc-audio", -1); | ||
436 | if (!neo1973_gta02_snd_device) | ||
437 | return -ENOMEM; | ||
438 | |||
439 | platform_set_drvdata(neo1973_gta02_snd_device, | ||
440 | &neo1973_gta02_snd_devdata); | ||
441 | neo1973_gta02_snd_devdata.dev = &neo1973_gta02_snd_device->dev; | ||
442 | ret = platform_device_add(neo1973_gta02_snd_device); | ||
443 | |||
444 | if (ret) { | ||
445 | platform_device_put(neo1973_gta02_snd_device); | ||
446 | return ret; | ||
447 | } | ||
448 | |||
449 | /* Initialise GPIOs used by amp */ | ||
450 | ret = gpio_request(GTA02_GPIO_HP_IN, "GTA02_HP_IN"); | ||
451 | if (ret) { | ||
452 | pr_err("gta02_wm8753: Failed to register GPIO %d\n", GTA02_GPIO_HP_IN); | ||
453 | goto err_unregister_device; | ||
454 | } | ||
455 | |||
456 | ret = gpio_direction_output(GTA02_GPIO_AMP_HP_IN, 1); | ||
457 | if (ret) { | ||
458 | pr_err("gta02_wm8753: Failed to configure GPIO %d\n", GTA02_GPIO_HP_IN); | ||
459 | goto err_free_gpio_hp_in; | ||
460 | } | ||
461 | |||
462 | ret = gpio_request(GTA02_GPIO_AMP_SHUT, "GTA02_AMP_SHUT"); | ||
463 | if (ret) { | ||
464 | pr_err("gta02_wm8753: Failed to register GPIO %d\n", GTA02_GPIO_AMP_SHUT); | ||
465 | goto err_free_gpio_hp_in; | ||
466 | } | ||
467 | |||
468 | ret = gpio_direction_output(GTA02_GPIO_AMP_SHUT, 1); | ||
469 | if (ret) { | ||
470 | pr_err("gta02_wm8753: Failed to configure GPIO %d\n", GTA02_GPIO_AMP_SHUT); | ||
471 | goto err_free_gpio_amp_shut; | ||
472 | } | ||
473 | |||
474 | return 0; | ||
475 | |||
476 | err_free_gpio_amp_shut: | ||
477 | gpio_free(GTA02_GPIO_AMP_SHUT); | ||
478 | err_free_gpio_hp_in: | ||
479 | gpio_free(GTA02_GPIO_HP_IN); | ||
480 | err_unregister_device: | ||
481 | platform_device_unregister(neo1973_gta02_snd_device); | ||
482 | return ret; | ||
483 | } | ||
484 | module_init(neo1973_gta02_init); | ||
485 | |||
486 | static void __exit neo1973_gta02_exit(void) | ||
487 | { | ||
488 | snd_soc_unregister_dai(&bt_dai); | ||
489 | platform_device_unregister(neo1973_gta02_snd_device); | ||
490 | gpio_free(GTA02_GPIO_HP_IN); | ||
491 | gpio_free(GTA02_GPIO_AMP_SHUT); | ||
492 | } | ||
493 | module_exit(neo1973_gta02_exit); | ||
494 | |||
495 | /* Module information */ | ||
496 | MODULE_AUTHOR("Graeme Gregory, graeme@openmoko.org"); | ||
497 | MODULE_DESCRIPTION("ALSA SoC WM8753 Neo1973 GTA02"); | ||
498 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.c b/sound/soc/s3c24xx/s3c-i2s-v2.c index 1a283170ca92..aa7af0b8d421 100644 --- a/sound/soc/s3c24xx/s3c-i2s-v2.c +++ b/sound/soc/s3c24xx/s3c-i2s-v2.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include <mach/dma.h> | 36 | #include <mach/dma.h> |
37 | 37 | ||
38 | #include "s3c-i2s-v2.h" | 38 | #include "s3c-i2s-v2.h" |
39 | #include "s3c24xx-pcm.h" | ||
39 | 40 | ||
40 | #undef S3C_IIS_V2_SUPPORTED | 41 | #undef S3C_IIS_V2_SUPPORTED |
41 | 42 | ||
@@ -357,19 +358,19 @@ static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream, | |||
357 | #endif | 358 | #endif |
358 | 359 | ||
359 | #ifdef CONFIG_PLAT_S3C64XX | 360 | #ifdef CONFIG_PLAT_S3C64XX |
360 | iismod &= ~0x606; | 361 | iismod &= ~(S3C64XX_IISMOD_BLC_MASK | S3C2412_IISMOD_BCLK_MASK); |
361 | /* Sample size */ | 362 | /* Sample size */ |
362 | switch (params_format(params)) { | 363 | switch (params_format(params)) { |
363 | case SNDRV_PCM_FORMAT_S8: | 364 | case SNDRV_PCM_FORMAT_S8: |
364 | /* 8 bit sample, 16fs BCLK */ | 365 | /* 8 bit sample, 16fs BCLK */ |
365 | iismod |= 0x2004; | 366 | iismod |= (S3C64XX_IISMOD_BLC_8BIT | S3C2412_IISMOD_BCLK_16FS); |
366 | break; | 367 | break; |
367 | case SNDRV_PCM_FORMAT_S16_LE: | 368 | case SNDRV_PCM_FORMAT_S16_LE: |
368 | /* 16 bit sample, 32fs BCLK */ | 369 | /* 16 bit sample, 32fs BCLK */ |
369 | break; | 370 | break; |
370 | case SNDRV_PCM_FORMAT_S24_LE: | 371 | case SNDRV_PCM_FORMAT_S24_LE: |
371 | /* 24 bit sample, 48fs BCLK */ | 372 | /* 24 bit sample, 48fs BCLK */ |
372 | iismod |= 0x4002; | 373 | iismod |= (S3C64XX_IISMOD_BLC_24BIT | S3C2412_IISMOD_BCLK_48FS); |
373 | break; | 374 | break; |
374 | } | 375 | } |
375 | #endif | 376 | #endif |
@@ -387,6 +388,8 @@ static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd, | |||
387 | int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); | 388 | int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); |
388 | unsigned long irqs; | 389 | unsigned long irqs; |
389 | int ret = 0; | 390 | int ret = 0; |
391 | int channel = ((struct s3c24xx_pcm_dma_params *) | ||
392 | rtd->dai->cpu_dai->dma_data)->channel; | ||
390 | 393 | ||
391 | pr_debug("Entered %s\n", __func__); | 394 | pr_debug("Entered %s\n", __func__); |
392 | 395 | ||
@@ -416,6 +419,14 @@ static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd, | |||
416 | s3c2412_snd_txctrl(i2s, 1); | 419 | s3c2412_snd_txctrl(i2s, 1); |
417 | 420 | ||
418 | local_irq_restore(irqs); | 421 | local_irq_restore(irqs); |
422 | |||
423 | /* | ||
424 | * Load the next buffer to DMA to meet the reqirement | ||
425 | * of the auto reload mechanism of S3C24XX. | ||
426 | * This call won't bother S3C64XX. | ||
427 | */ | ||
428 | s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STARTED); | ||
429 | |||
419 | break; | 430 | break; |
420 | 431 | ||
421 | case SNDRV_PCM_TRIGGER_STOP: | 432 | case SNDRV_PCM_TRIGGER_STOP: |
diff --git a/sound/soc/s3c24xx/s3c2443-ac97.c b/sound/soc/s3c24xx/s3c2443-ac97.c index 3f03d5ddfacd..fc1beb0930b9 100644 --- a/sound/soc/s3c24xx/s3c2443-ac97.c +++ b/sound/soc/s3c24xx/s3c2443-ac97.c | |||
@@ -47,7 +47,7 @@ static struct s3c24xx_ac97_info s3c24xx_ac97; | |||
47 | 47 | ||
48 | static DECLARE_COMPLETION(ac97_completion); | 48 | static DECLARE_COMPLETION(ac97_completion); |
49 | static u32 codec_ready; | 49 | static u32 codec_ready; |
50 | static DECLARE_MUTEX(ac97_mutex); | 50 | static DEFINE_MUTEX(ac97_mutex); |
51 | 51 | ||
52 | static unsigned short s3c2443_ac97_read(struct snd_ac97 *ac97, | 52 | static unsigned short s3c2443_ac97_read(struct snd_ac97 *ac97, |
53 | unsigned short reg) | 53 | unsigned short reg) |
@@ -56,7 +56,7 @@ static unsigned short s3c2443_ac97_read(struct snd_ac97 *ac97, | |||
56 | u32 ac_codec_cmd; | 56 | u32 ac_codec_cmd; |
57 | u32 stat, addr, data; | 57 | u32 stat, addr, data; |
58 | 58 | ||
59 | down(&ac97_mutex); | 59 | mutex_lock(&ac97_mutex); |
60 | 60 | ||
61 | codec_ready = S3C_AC97_GLBSTAT_CODECREADY; | 61 | codec_ready = S3C_AC97_GLBSTAT_CODECREADY; |
62 | ac_codec_cmd = readl(s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD); | 62 | ac_codec_cmd = readl(s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD); |
@@ -79,7 +79,7 @@ static unsigned short s3c2443_ac97_read(struct snd_ac97 *ac97, | |||
79 | printk(KERN_ERR "s3c24xx-ac97: req addr = %02x," | 79 | printk(KERN_ERR "s3c24xx-ac97: req addr = %02x," |
80 | " rep addr = %02x\n", reg, addr); | 80 | " rep addr = %02x\n", reg, addr); |
81 | 81 | ||
82 | up(&ac97_mutex); | 82 | mutex_unlock(&ac97_mutex); |
83 | 83 | ||
84 | return (unsigned short)data; | 84 | return (unsigned short)data; |
85 | } | 85 | } |
@@ -90,7 +90,7 @@ static void s3c2443_ac97_write(struct snd_ac97 *ac97, unsigned short reg, | |||
90 | u32 ac_glbctrl; | 90 | u32 ac_glbctrl; |
91 | u32 ac_codec_cmd; | 91 | u32 ac_codec_cmd; |
92 | 92 | ||
93 | down(&ac97_mutex); | 93 | mutex_lock(&ac97_mutex); |
94 | 94 | ||
95 | codec_ready = S3C_AC97_GLBSTAT_CODECREADY; | 95 | codec_ready = S3C_AC97_GLBSTAT_CODECREADY; |
96 | ac_codec_cmd = readl(s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD); | 96 | ac_codec_cmd = readl(s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD); |
@@ -109,7 +109,7 @@ static void s3c2443_ac97_write(struct snd_ac97 *ac97, unsigned short reg, | |||
109 | ac_codec_cmd |= S3C_AC97_CODEC_CMD_READ; | 109 | ac_codec_cmd |= S3C_AC97_CODEC_CMD_READ; |
110 | writel(ac_codec_cmd, s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD); | 110 | writel(ac_codec_cmd, s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD); |
111 | 111 | ||
112 | up(&ac97_mutex); | 112 | mutex_unlock(&ac97_mutex); |
113 | 113 | ||
114 | } | 114 | } |
115 | 115 | ||
@@ -290,6 +290,9 @@ static int s3c2443_ac97_trigger(struct snd_pcm_substream *substream, int cmd, | |||
290 | struct snd_soc_dai *dai) | 290 | struct snd_soc_dai *dai) |
291 | { | 291 | { |
292 | u32 ac_glbctrl; | 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; | ||
293 | 296 | ||
294 | ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); | 297 | ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); |
295 | switch (cmd) { | 298 | switch (cmd) { |
@@ -312,6 +315,8 @@ static int s3c2443_ac97_trigger(struct snd_pcm_substream *substream, int cmd, | |||
312 | } | 315 | } |
313 | writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); | 316 | writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); |
314 | 317 | ||
318 | s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STARTED); | ||
319 | |||
315 | return 0; | 320 | return 0; |
316 | } | 321 | } |
317 | 322 | ||
@@ -334,6 +339,9 @@ static int s3c2443_ac97_mic_trigger(struct snd_pcm_substream *substream, | |||
334 | int cmd, struct snd_soc_dai *dai) | 339 | int cmd, struct snd_soc_dai *dai) |
335 | { | 340 | { |
336 | u32 ac_glbctrl; | 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; | ||
337 | 345 | ||
338 | ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); | 346 | ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); |
339 | switch (cmd) { | 347 | switch (cmd) { |
@@ -349,6 +357,8 @@ static int s3c2443_ac97_mic_trigger(struct snd_pcm_substream *substream, | |||
349 | } | 357 | } |
350 | writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); | 358 | writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); |
351 | 359 | ||
360 | s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STARTED); | ||
361 | |||
352 | return 0; | 362 | return 0; |
353 | } | 363 | } |
354 | 364 | ||
diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c index 556e35f0ab73..40e2c4790f0d 100644 --- a/sound/soc/s3c24xx/s3c24xx-i2s.c +++ b/sound/soc/s3c24xx/s3c24xx-i2s.c | |||
@@ -279,6 +279,9 @@ static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd, | |||
279 | struct snd_soc_dai *dai) | 279 | struct snd_soc_dai *dai) |
280 | { | 280 | { |
281 | int ret = 0; | 281 | int ret = 0; |
282 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
283 | int channel = ((struct s3c24xx_pcm_dma_params *) | ||
284 | rtd->dai->cpu_dai->dma_data)->channel; | ||
282 | 285 | ||
283 | pr_debug("Entered %s\n", __func__); | 286 | pr_debug("Entered %s\n", __func__); |
284 | 287 | ||
@@ -296,6 +299,8 @@ static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd, | |||
296 | s3c24xx_snd_rxctrl(1); | 299 | s3c24xx_snd_rxctrl(1); |
297 | else | 300 | else |
298 | s3c24xx_snd_txctrl(1); | 301 | s3c24xx_snd_txctrl(1); |
302 | |||
303 | s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STARTED); | ||
299 | break; | 304 | break; |
300 | case SNDRV_PCM_TRIGGER_STOP: | 305 | case SNDRV_PCM_TRIGGER_STOP: |
301 | case SNDRV_PCM_TRIGGER_SUSPEND: | 306 | case SNDRV_PCM_TRIGGER_SUSPEND: |
diff --git a/sound/soc/s3c24xx/s3c24xx-pcm.c b/sound/soc/s3c24xx/s3c24xx-pcm.c index eecfa5eba06b..5cbbdc80fde3 100644 --- a/sound/soc/s3c24xx/s3c24xx-pcm.c +++ b/sound/soc/s3c24xx/s3c24xx-pcm.c | |||
@@ -255,7 +255,6 @@ static int s3c24xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | |||
255 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 255 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
256 | prtd->state |= ST_RUNNING; | 256 | prtd->state |= ST_RUNNING; |
257 | s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_START); | 257 | s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_START); |
258 | s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_STARTED); | ||
259 | break; | 258 | break; |
260 | 259 | ||
261 | case SNDRV_PCM_TRIGGER_STOP: | 260 | case SNDRV_PCM_TRIGGER_STOP: |
@@ -318,6 +317,7 @@ static int s3c24xx_pcm_open(struct snd_pcm_substream *substream) | |||
318 | 317 | ||
319 | pr_debug("Entered %s\n", __func__); | 318 | pr_debug("Entered %s\n", __func__); |
320 | 319 | ||
320 | snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); | ||
321 | snd_soc_set_runtime_hwparams(substream, &s3c24xx_pcm_hardware); | 321 | snd_soc_set_runtime_hwparams(substream, &s3c24xx_pcm_hardware); |
322 | 322 | ||
323 | prtd = kzalloc(sizeof(struct s3c24xx_runtime_data), GFP_KERNEL); | 323 | prtd = kzalloc(sizeof(struct s3c24xx_runtime_data), GFP_KERNEL); |
diff --git a/sound/soc/s3c24xx/s3c24xx_simtec.c b/sound/soc/s3c24xx/s3c24xx_simtec.c new file mode 100644 index 000000000000..1966e0d5652d --- /dev/null +++ b/sound/soc/s3c24xx/s3c24xx_simtec.c | |||
@@ -0,0 +1,394 @@ | |||
1 | /* sound/soc/s3c24xx/s3c24xx_simtec.c | ||
2 | * | ||
3 | * Copyright 2009 Simtec Electronics | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | #include <linux/module.h> | ||
11 | #include <linux/moduleparam.h> | ||
12 | #include <linux/platform_device.h> | ||
13 | #include <linux/gpio.h> | ||
14 | #include <linux/clk.h> | ||
15 | #include <linux/i2c.h> | ||
16 | |||
17 | #include <sound/core.h> | ||
18 | #include <sound/pcm.h> | ||
19 | #include <sound/soc.h> | ||
20 | #include <sound/soc-dapm.h> | ||
21 | |||
22 | #include <plat/audio-simtec.h> | ||
23 | |||
24 | #include "s3c24xx-pcm.h" | ||
25 | #include "s3c24xx-i2s.h" | ||
26 | #include "s3c24xx_simtec.h" | ||
27 | |||
28 | static struct s3c24xx_audio_simtec_pdata *pdata; | ||
29 | static struct clk *xtal_clk; | ||
30 | |||
31 | static int spk_gain; | ||
32 | static int spk_unmute; | ||
33 | |||
34 | /** | ||
35 | * speaker_gain_get - read the speaker gain setting. | ||
36 | * @kcontrol: The control for the speaker gain. | ||
37 | * @ucontrol: The value that needs to be updated. | ||
38 | * | ||
39 | * Read the value for the AMP gain control. | ||
40 | */ | ||
41 | static int speaker_gain_get(struct snd_kcontrol *kcontrol, | ||
42 | struct snd_ctl_elem_value *ucontrol) | ||
43 | { | ||
44 | ucontrol->value.integer.value[0] = spk_gain; | ||
45 | return 0; | ||
46 | } | ||
47 | |||
48 | /** | ||
49 | * speaker_gain_set - set the value of the speaker amp gain | ||
50 | * @value: The value to write. | ||
51 | */ | ||
52 | static void speaker_gain_set(int value) | ||
53 | { | ||
54 | gpio_set_value_cansleep(pdata->amp_gain[0], value & 1); | ||
55 | gpio_set_value_cansleep(pdata->amp_gain[1], value >> 1); | ||
56 | } | ||
57 | |||
58 | /** | ||
59 | * speaker_gain_put - set the speaker gain setting. | ||
60 | * @kcontrol: The control for the speaker gain. | ||
61 | * @ucontrol: The value that needs to be set. | ||
62 | * | ||
63 | * Set the value of the speaker gain from the specified | ||
64 | * @ucontrol setting. | ||
65 | * | ||
66 | * Note, if the speaker amp is muted, then we do not set a gain value | ||
67 | * as at-least one of the ICs that is fitted will try and power up even | ||
68 | * if the main control is set to off. | ||
69 | */ | ||
70 | static int speaker_gain_put(struct snd_kcontrol *kcontrol, | ||
71 | struct snd_ctl_elem_value *ucontrol) | ||
72 | { | ||
73 | int value = ucontrol->value.integer.value[0]; | ||
74 | |||
75 | spk_gain = value; | ||
76 | |||
77 | if (!spk_unmute) | ||
78 | speaker_gain_set(value); | ||
79 | |||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | static const struct snd_kcontrol_new amp_gain_controls[] = { | ||
84 | SOC_SINGLE_EXT("Speaker Gain", 0, 0, 3, 0, | ||
85 | speaker_gain_get, speaker_gain_put), | ||
86 | }; | ||
87 | |||
88 | /** | ||
89 | * spk_unmute_state - set the unmute state of the speaker | ||
90 | * @to: zero to unmute, non-zero to ununmute. | ||
91 | */ | ||
92 | static void spk_unmute_state(int to) | ||
93 | { | ||
94 | pr_debug("%s: to=%d\n", __func__, to); | ||
95 | |||
96 | spk_unmute = to; | ||
97 | gpio_set_value(pdata->amp_gpio, to); | ||
98 | |||
99 | /* if we're umuting, also re-set the gain */ | ||
100 | if (to && pdata->amp_gain[0] > 0) | ||
101 | speaker_gain_set(spk_gain); | ||
102 | } | ||
103 | |||
104 | /** | ||
105 | * speaker_unmute_get - read the speaker unmute setting. | ||
106 | * @kcontrol: The control for the speaker gain. | ||
107 | * @ucontrol: The value that needs to be updated. | ||
108 | * | ||
109 | * Read the value for the AMP gain control. | ||
110 | */ | ||
111 | static int speaker_unmute_get(struct snd_kcontrol *kcontrol, | ||
112 | struct snd_ctl_elem_value *ucontrol) | ||
113 | { | ||
114 | ucontrol->value.integer.value[0] = spk_unmute; | ||
115 | return 0; | ||
116 | } | ||
117 | |||
118 | /** | ||
119 | * speaker_unmute_put - set the speaker unmute setting. | ||
120 | * @kcontrol: The control for the speaker gain. | ||
121 | * @ucontrol: The value that needs to be set. | ||
122 | * | ||
123 | * Set the value of the speaker gain from the specified | ||
124 | * @ucontrol setting. | ||
125 | */ | ||
126 | static int speaker_unmute_put(struct snd_kcontrol *kcontrol, | ||
127 | struct snd_ctl_elem_value *ucontrol) | ||
128 | { | ||
129 | spk_unmute_state(ucontrol->value.integer.value[0]); | ||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | /* This is added as a manual control as the speaker amps create clicks | ||
134 | * when their power state is changed, which are far more noticeable than | ||
135 | * anything produced by the CODEC itself. | ||
136 | */ | ||
137 | static const struct snd_kcontrol_new amp_unmute_controls[] = { | ||
138 | SOC_SINGLE_EXT("Speaker Switch", 0, 0, 1, 0, | ||
139 | speaker_unmute_get, speaker_unmute_put), | ||
140 | }; | ||
141 | |||
142 | void simtec_audio_init(struct snd_soc_codec *codec) | ||
143 | { | ||
144 | if (pdata->amp_gpio > 0) { | ||
145 | pr_debug("%s: adding amp routes\n", __func__); | ||
146 | |||
147 | snd_soc_add_controls(codec, amp_unmute_controls, | ||
148 | ARRAY_SIZE(amp_unmute_controls)); | ||
149 | } | ||
150 | |||
151 | if (pdata->amp_gain[0] > 0) { | ||
152 | pr_debug("%s: adding amp controls\n", __func__); | ||
153 | snd_soc_add_controls(codec, amp_gain_controls, | ||
154 | ARRAY_SIZE(amp_gain_controls)); | ||
155 | } | ||
156 | } | ||
157 | EXPORT_SYMBOL_GPL(simtec_audio_init); | ||
158 | |||
159 | #define CODEC_CLOCK 12000000 | ||
160 | |||
161 | /** | ||
162 | * simtec_hw_params - update hardware parameters | ||
163 | * @substream: The audio substream instance. | ||
164 | * @params: The parameters requested. | ||
165 | * | ||
166 | * Update the codec data routing and configuration settings | ||
167 | * from the supplied data. | ||
168 | */ | ||
169 | static int simtec_hw_params(struct snd_pcm_substream *substream, | ||
170 | struct snd_pcm_hw_params *params) | ||
171 | { | ||
172 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
173 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | ||
174 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
175 | int ret; | ||
176 | |||
177 | /* Set the CODEC as the bus clock master, I2S */ | ||
178 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | | ||
179 | SND_SOC_DAIFMT_NB_NF | | ||
180 | SND_SOC_DAIFMT_CBM_CFM); | ||
181 | if (ret) { | ||
182 | pr_err("%s: failed set cpu dai format\n", __func__); | ||
183 | return ret; | ||
184 | } | ||
185 | |||
186 | /* Set the CODEC as the bus clock master */ | ||
187 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | | ||
188 | SND_SOC_DAIFMT_NB_NF | | ||
189 | SND_SOC_DAIFMT_CBM_CFM); | ||
190 | if (ret) { | ||
191 | pr_err("%s: failed set codec dai format\n", __func__); | ||
192 | return ret; | ||
193 | } | ||
194 | |||
195 | ret = snd_soc_dai_set_sysclk(codec_dai, 0, | ||
196 | CODEC_CLOCK, SND_SOC_CLOCK_IN); | ||
197 | if (ret) { | ||
198 | pr_err( "%s: failed setting codec sysclk\n", __func__); | ||
199 | return ret; | ||
200 | } | ||
201 | |||
202 | if (pdata->use_mpllin) { | ||
203 | ret = snd_soc_dai_set_sysclk(cpu_dai, S3C24XX_CLKSRC_MPLL, | ||
204 | 0, SND_SOC_CLOCK_OUT); | ||
205 | |||
206 | if (ret) { | ||
207 | pr_err("%s: failed to set MPLLin as clksrc\n", | ||
208 | __func__); | ||
209 | return ret; | ||
210 | } | ||
211 | } | ||
212 | |||
213 | if (pdata->output_cdclk) { | ||
214 | int cdclk_scale; | ||
215 | |||
216 | cdclk_scale = clk_get_rate(xtal_clk) / CODEC_CLOCK; | ||
217 | cdclk_scale--; | ||
218 | |||
219 | ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER, | ||
220 | cdclk_scale); | ||
221 | } | ||
222 | |||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | static int simtec_call_startup(struct s3c24xx_audio_simtec_pdata *pd) | ||
227 | { | ||
228 | /* call any board supplied startup code, this currently only | ||
229 | * covers the bast/vr1000 which have a CPLD in the way of the | ||
230 | * LRCLK */ | ||
231 | if (pd->startup) | ||
232 | pd->startup(); | ||
233 | |||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | static struct snd_soc_ops simtec_snd_ops = { | ||
238 | .hw_params = simtec_hw_params, | ||
239 | }; | ||
240 | |||
241 | /** | ||
242 | * attach_gpio_amp - get and configure the necessary gpios | ||
243 | * @dev: The device we're probing. | ||
244 | * @pd: The platform data supplied by the board. | ||
245 | * | ||
246 | * If there is a GPIO based amplifier attached to the board, claim | ||
247 | * the necessary GPIO lines for it, and set default values. | ||
248 | */ | ||
249 | static int attach_gpio_amp(struct device *dev, | ||
250 | struct s3c24xx_audio_simtec_pdata *pd) | ||
251 | { | ||
252 | int ret; | ||
253 | |||
254 | /* attach gpio amp gain (if any) */ | ||
255 | if (pdata->amp_gain[0] > 0) { | ||
256 | ret = gpio_request(pd->amp_gain[0], "gpio-amp-gain0"); | ||
257 | if (ret) { | ||
258 | dev_err(dev, "cannot get amp gpio gain0\n"); | ||
259 | return ret; | ||
260 | } | ||
261 | |||
262 | ret = gpio_request(pd->amp_gain[1], "gpio-amp-gain1"); | ||
263 | if (ret) { | ||
264 | dev_err(dev, "cannot get amp gpio gain1\n"); | ||
265 | gpio_free(pdata->amp_gain[0]); | ||
266 | return ret; | ||
267 | } | ||
268 | |||
269 | gpio_direction_output(pd->amp_gain[0], 0); | ||
270 | gpio_direction_output(pd->amp_gain[1], 0); | ||
271 | } | ||
272 | |||
273 | /* note, curently we assume GPA0 isn't valid amp */ | ||
274 | if (pdata->amp_gpio > 0) { | ||
275 | ret = gpio_request(pd->amp_gpio, "gpio-amp"); | ||
276 | if (ret) { | ||
277 | dev_err(dev, "cannot get amp gpio %d (%d)\n", | ||
278 | pd->amp_gpio, ret); | ||
279 | goto err_amp; | ||
280 | } | ||
281 | |||
282 | /* set the amp off at startup */ | ||
283 | spk_unmute_state(0); | ||
284 | } | ||
285 | |||
286 | return 0; | ||
287 | |||
288 | err_amp: | ||
289 | if (pd->amp_gain[0] > 0) { | ||
290 | gpio_free(pd->amp_gain[0]); | ||
291 | gpio_free(pd->amp_gain[1]); | ||
292 | } | ||
293 | |||
294 | return ret; | ||
295 | } | ||
296 | |||
297 | static void detach_gpio_amp(struct s3c24xx_audio_simtec_pdata *pd) | ||
298 | { | ||
299 | if (pd->amp_gain[0] > 0) { | ||
300 | gpio_free(pd->amp_gain[0]); | ||
301 | gpio_free(pd->amp_gain[1]); | ||
302 | } | ||
303 | |||
304 | if (pd->amp_gpio > 0) | ||
305 | gpio_free(pd->amp_gpio); | ||
306 | } | ||
307 | |||
308 | #ifdef CONFIG_PM | ||
309 | int simtec_audio_resume(struct device *dev) | ||
310 | { | ||
311 | simtec_call_startup(pdata); | ||
312 | return 0; | ||
313 | } | ||
314 | |||
315 | struct dev_pm_ops simtec_audio_pmops = { | ||
316 | .resume = simtec_audio_resume, | ||
317 | }; | ||
318 | EXPORT_SYMBOL_GPL(simtec_audio_pmops); | ||
319 | #endif | ||
320 | |||
321 | int __devinit simtec_audio_core_probe(struct platform_device *pdev, | ||
322 | struct snd_soc_device *socdev) | ||
323 | { | ||
324 | struct platform_device *snd_dev; | ||
325 | int ret; | ||
326 | |||
327 | socdev->card->dai_link->ops = &simtec_snd_ops; | ||
328 | |||
329 | pdata = pdev->dev.platform_data; | ||
330 | if (!pdata) { | ||
331 | dev_err(&pdev->dev, "no platform data supplied\n"); | ||
332 | return -EINVAL; | ||
333 | } | ||
334 | |||
335 | simtec_call_startup(pdata); | ||
336 | |||
337 | xtal_clk = clk_get(&pdev->dev, "xtal"); | ||
338 | if (IS_ERR(xtal_clk)) { | ||
339 | dev_err(&pdev->dev, "could not get clkout0\n"); | ||
340 | return -EINVAL; | ||
341 | } | ||
342 | |||
343 | dev_info(&pdev->dev, "xtal rate is %ld\n", clk_get_rate(xtal_clk)); | ||
344 | |||
345 | ret = attach_gpio_amp(&pdev->dev, pdata); | ||
346 | if (ret) | ||
347 | goto err_clk; | ||
348 | |||
349 | snd_dev = platform_device_alloc("soc-audio", -1); | ||
350 | if (!snd_dev) { | ||
351 | dev_err(&pdev->dev, "failed to alloc soc-audio devicec\n"); | ||
352 | ret = -ENOMEM; | ||
353 | goto err_gpio; | ||
354 | } | ||
355 | |||
356 | platform_set_drvdata(snd_dev, socdev); | ||
357 | socdev->dev = &snd_dev->dev; | ||
358 | |||
359 | ret = platform_device_add(snd_dev); | ||
360 | if (ret) { | ||
361 | dev_err(&pdev->dev, "failed to add soc-audio dev\n"); | ||
362 | goto err_pdev; | ||
363 | } | ||
364 | |||
365 | platform_set_drvdata(pdev, snd_dev); | ||
366 | return 0; | ||
367 | |||
368 | err_pdev: | ||
369 | platform_device_put(snd_dev); | ||
370 | |||
371 | err_gpio: | ||
372 | detach_gpio_amp(pdata); | ||
373 | |||
374 | err_clk: | ||
375 | clk_put(xtal_clk); | ||
376 | return ret; | ||
377 | } | ||
378 | EXPORT_SYMBOL_GPL(simtec_audio_core_probe); | ||
379 | |||
380 | int __devexit simtec_audio_remove(struct platform_device *pdev) | ||
381 | { | ||
382 | struct platform_device *snd_dev = platform_get_drvdata(pdev); | ||
383 | |||
384 | platform_device_unregister(snd_dev); | ||
385 | |||
386 | detach_gpio_amp(pdata); | ||
387 | clk_put(xtal_clk); | ||
388 | return 0; | ||
389 | } | ||
390 | EXPORT_SYMBOL_GPL(simtec_audio_remove); | ||
391 | |||
392 | MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); | ||
393 | MODULE_DESCRIPTION("ALSA SoC Simtec Audio common support"); | ||
394 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/s3c24xx/s3c24xx_simtec.h b/sound/soc/s3c24xx/s3c24xx_simtec.h new file mode 100644 index 000000000000..2714203af161 --- /dev/null +++ b/sound/soc/s3c24xx/s3c24xx_simtec.h | |||
@@ -0,0 +1,22 @@ | |||
1 | /* sound/soc/s3c24xx/s3c24xx_simtec.h | ||
2 | * | ||
3 | * Copyright 2009 Simtec Electronics | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | extern void simtec_audio_init(struct snd_soc_codec *codec); | ||
11 | |||
12 | extern int simtec_audio_core_probe(struct platform_device *pdev, | ||
13 | struct snd_soc_device *socdev); | ||
14 | |||
15 | extern int simtec_audio_remove(struct platform_device *pdev); | ||
16 | |||
17 | #ifdef CONFIG_PM | ||
18 | extern struct dev_pm_ops simtec_audio_pmops; | ||
19 | #define simtec_audio_pm &simtec_audio_pmops | ||
20 | #else | ||
21 | #define simtec_audio_pm NULL | ||
22 | #endif | ||
diff --git a/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c b/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c new file mode 100644 index 000000000000..8346bd96eaf5 --- /dev/null +++ b/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c | |||
@@ -0,0 +1,153 @@ | |||
1 | /* sound/soc/s3c24xx/s3c24xx_simtec_hermes.c | ||
2 | * | ||
3 | * Copyright 2009 Simtec Electronics | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | #include <linux/module.h> | ||
11 | #include <linux/clk.h> | ||
12 | #include <linux/platform_device.h> | ||
13 | |||
14 | #include <sound/core.h> | ||
15 | #include <sound/pcm.h> | ||
16 | #include <sound/soc.h> | ||
17 | #include <sound/soc-dapm.h> | ||
18 | |||
19 | #include <plat/audio-simtec.h> | ||
20 | |||
21 | #include "s3c24xx-pcm.h" | ||
22 | #include "s3c24xx-i2s.h" | ||
23 | #include "s3c24xx_simtec.h" | ||
24 | |||
25 | #include "../codecs/tlv320aic3x.h" | ||
26 | |||
27 | static const struct snd_soc_dapm_widget dapm_widgets[] = { | ||
28 | SND_SOC_DAPM_LINE("GSM Out", NULL), | ||
29 | SND_SOC_DAPM_LINE("GSM In", NULL), | ||
30 | SND_SOC_DAPM_LINE("Line In", NULL), | ||
31 | SND_SOC_DAPM_LINE("Line Out", NULL), | ||
32 | SND_SOC_DAPM_LINE("ZV", NULL), | ||
33 | SND_SOC_DAPM_MIC("Mic Jack", NULL), | ||
34 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | ||
35 | }; | ||
36 | |||
37 | static const struct snd_soc_dapm_route base_map[] = { | ||
38 | /* Headphone connected to HP{L,R}OUT and HP{L,R}COM */ | ||
39 | |||
40 | { "Headphone Jack", NULL, "HPLOUT" }, | ||
41 | { "Headphone Jack", NULL, "HPLCOM" }, | ||
42 | { "Headphone Jack", NULL, "HPROUT" }, | ||
43 | { "Headphone Jack", NULL, "HPRCOM" }, | ||
44 | |||
45 | /* ZV connected to Line1 */ | ||
46 | |||
47 | { "LINE1L", NULL, "ZV" }, | ||
48 | { "LINE1R", NULL, "ZV" }, | ||
49 | |||
50 | /* Line In connected to Line2 */ | ||
51 | |||
52 | { "LINE2L", NULL, "Line In" }, | ||
53 | { "LINE2R", NULL, "Line In" }, | ||
54 | |||
55 | /* Microphone connected to MIC3R and MIC_BIAS */ | ||
56 | |||
57 | { "MIC3L", NULL, "Mic Jack" }, | ||
58 | |||
59 | /* GSM connected to MONO_LOUT and MIC3L (in) */ | ||
60 | |||
61 | { "GSM Out", NULL, "MONO_LOUT" }, | ||
62 | { "MIC3L", NULL, "GSM In" }, | ||
63 | |||
64 | /* Speaker is connected to LINEOUT{LN,LP,RN,RP}, however we are | ||
65 | * not using the DAPM to power it up and down as there it makes | ||
66 | * a click when powering up. */ | ||
67 | }; | ||
68 | |||
69 | /** | ||
70 | * simtec_hermes_init - initialise and add controls | ||
71 | * @codec; The codec instance to attach to. | ||
72 | * | ||
73 | * Attach our controls and configure the necessary codec | ||
74 | * mappings for our sound card instance. | ||
75 | */ | ||
76 | static int simtec_hermes_init(struct snd_soc_codec *codec) | ||
77 | { | ||
78 | snd_soc_dapm_new_controls(codec, dapm_widgets, | ||
79 | ARRAY_SIZE(dapm_widgets)); | ||
80 | |||
81 | snd_soc_dapm_add_routes(codec, base_map, ARRAY_SIZE(base_map)); | ||
82 | |||
83 | snd_soc_dapm_enable_pin(codec, "Headphone Jack"); | ||
84 | snd_soc_dapm_enable_pin(codec, "Line In"); | ||
85 | snd_soc_dapm_enable_pin(codec, "Line Out"); | ||
86 | snd_soc_dapm_enable_pin(codec, "Mic Jack"); | ||
87 | |||
88 | simtec_audio_init(codec); | ||
89 | snd_soc_dapm_sync(codec); | ||
90 | |||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | static struct aic3x_setup_data codec_setup = { | ||
95 | }; | ||
96 | |||
97 | static struct snd_soc_dai_link simtec_dai_aic33 = { | ||
98 | .name = "tlv320aic33", | ||
99 | .stream_name = "TLV320AIC33", | ||
100 | .cpu_dai = &s3c24xx_i2s_dai, | ||
101 | .codec_dai = &aic3x_dai, | ||
102 | .init = simtec_hermes_init, | ||
103 | }; | ||
104 | |||
105 | /* simtec audio machine driver */ | ||
106 | static struct snd_soc_card snd_soc_machine_simtec_aic33 = { | ||
107 | .name = "Simtec-Hermes", | ||
108 | .platform = &s3c24xx_soc_platform, | ||
109 | .dai_link = &simtec_dai_aic33, | ||
110 | .num_links = 1, | ||
111 | }; | ||
112 | |||
113 | /* simtec audio subsystem */ | ||
114 | static struct snd_soc_device simtec_snd_devdata_aic33 = { | ||
115 | .card = &snd_soc_machine_simtec_aic33, | ||
116 | .codec_dev = &soc_codec_dev_aic3x, | ||
117 | .codec_data = &codec_setup, | ||
118 | }; | ||
119 | |||
120 | static int __devinit simtec_audio_hermes_probe(struct platform_device *pd) | ||
121 | { | ||
122 | dev_info(&pd->dev, "probing....\n"); | ||
123 | return simtec_audio_core_probe(pd, &simtec_snd_devdata_aic33); | ||
124 | } | ||
125 | |||
126 | static struct platform_driver simtec_audio_hermes_platdrv = { | ||
127 | .driver = { | ||
128 | .owner = THIS_MODULE, | ||
129 | .name = "s3c24xx-simtec-hermes-snd", | ||
130 | .pm = simtec_audio_pm, | ||
131 | }, | ||
132 | .probe = simtec_audio_hermes_probe, | ||
133 | .remove = __devexit_p(simtec_audio_remove), | ||
134 | }; | ||
135 | |||
136 | MODULE_ALIAS("platform:s3c24xx-simtec-hermes-snd"); | ||
137 | |||
138 | static int __init simtec_hermes_modinit(void) | ||
139 | { | ||
140 | return platform_driver_register(&simtec_audio_hermes_platdrv); | ||
141 | } | ||
142 | |||
143 | static void __exit simtec_hermes_modexit(void) | ||
144 | { | ||
145 | platform_driver_unregister(&simtec_audio_hermes_platdrv); | ||
146 | } | ||
147 | |||
148 | module_init(simtec_hermes_modinit); | ||
149 | module_exit(simtec_hermes_modexit); | ||
150 | |||
151 | MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); | ||
152 | MODULE_DESCRIPTION("ALSA SoC Simtec Audio support"); | ||
153 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c b/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c new file mode 100644 index 000000000000..25797e096175 --- /dev/null +++ b/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c | |||
@@ -0,0 +1,137 @@ | |||
1 | /* sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c | ||
2 | * | ||
3 | * Copyright 2009 Simtec Electronics | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | #include <linux/module.h> | ||
11 | #include <linux/clk.h> | ||
12 | #include <linux/platform_device.h> | ||
13 | |||
14 | #include <sound/core.h> | ||
15 | #include <sound/pcm.h> | ||
16 | #include <sound/soc.h> | ||
17 | #include <sound/soc-dapm.h> | ||
18 | |||
19 | #include <plat/audio-simtec.h> | ||
20 | |||
21 | #include "s3c24xx-pcm.h" | ||
22 | #include "s3c24xx-i2s.h" | ||
23 | #include "s3c24xx_simtec.h" | ||
24 | |||
25 | #include "../codecs/tlv320aic23.h" | ||
26 | |||
27 | /* supported machines: | ||
28 | * | ||
29 | * Machine Connections AMP | ||
30 | * ------- ----------- --- | ||
31 | * BAST MIC, HPOUT, LOUT, LIN TPA2001D1 (HPOUTL,R) (gain hardwired) | ||
32 | * VR1000 HPOUT, LIN None | ||
33 | * VR2000 LIN, LOUT, MIC, HP LM4871 (HPOUTL,R) | ||
34 | * DePicture LIN, LOUT, MIC, HP LM4871 (HPOUTL,R) | ||
35 | * Anubis LIN, LOUT, MIC, HP TPA2001D1 (HPOUTL,R) | ||
36 | */ | ||
37 | |||
38 | static const struct snd_soc_dapm_widget dapm_widgets[] = { | ||
39 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | ||
40 | SND_SOC_DAPM_LINE("Line In", NULL), | ||
41 | SND_SOC_DAPM_LINE("Line Out", NULL), | ||
42 | SND_SOC_DAPM_MIC("Mic Jack", NULL), | ||
43 | }; | ||
44 | |||
45 | static const struct snd_soc_dapm_route base_map[] = { | ||
46 | { "Headphone Jack", NULL, "LHPOUT"}, | ||
47 | { "Headphone Jack", NULL, "RHPOUT"}, | ||
48 | |||
49 | { "Line Out", NULL, "LOUT" }, | ||
50 | { "Line Out", NULL, "ROUT" }, | ||
51 | |||
52 | { "LLINEIN", NULL, "Line In"}, | ||
53 | { "RLINEIN", NULL, "Line In"}, | ||
54 | |||
55 | { "MICIN", NULL, "Mic Jack"}, | ||
56 | }; | ||
57 | |||
58 | /** | ||
59 | * simtec_tlv320aic23_init - initialise and add controls | ||
60 | * @codec; The codec instance to attach to. | ||
61 | * | ||
62 | * Attach our controls and configure the necessary codec | ||
63 | * mappings for our sound card instance. | ||
64 | */ | ||
65 | static int simtec_tlv320aic23_init(struct snd_soc_codec *codec) | ||
66 | { | ||
67 | snd_soc_dapm_new_controls(codec, dapm_widgets, | ||
68 | ARRAY_SIZE(dapm_widgets)); | ||
69 | |||
70 | snd_soc_dapm_add_routes(codec, base_map, ARRAY_SIZE(base_map)); | ||
71 | |||
72 | snd_soc_dapm_enable_pin(codec, "Headphone Jack"); | ||
73 | snd_soc_dapm_enable_pin(codec, "Line In"); | ||
74 | snd_soc_dapm_enable_pin(codec, "Line Out"); | ||
75 | snd_soc_dapm_enable_pin(codec, "Mic Jack"); | ||
76 | |||
77 | simtec_audio_init(codec); | ||
78 | snd_soc_dapm_sync(codec); | ||
79 | |||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | static struct snd_soc_dai_link simtec_dai_aic23 = { | ||
84 | .name = "tlv320aic23", | ||
85 | .stream_name = "TLV320AIC23", | ||
86 | .cpu_dai = &s3c24xx_i2s_dai, | ||
87 | .codec_dai = &tlv320aic23_dai, | ||
88 | .init = simtec_tlv320aic23_init, | ||
89 | }; | ||
90 | |||
91 | /* simtec audio machine driver */ | ||
92 | static struct snd_soc_card snd_soc_machine_simtec_aic23 = { | ||
93 | .name = "Simtec", | ||
94 | .platform = &s3c24xx_soc_platform, | ||
95 | .dai_link = &simtec_dai_aic23, | ||
96 | .num_links = 1, | ||
97 | }; | ||
98 | |||
99 | /* simtec audio subsystem */ | ||
100 | static struct snd_soc_device simtec_snd_devdata_aic23 = { | ||
101 | .card = &snd_soc_machine_simtec_aic23, | ||
102 | .codec_dev = &soc_codec_dev_tlv320aic23, | ||
103 | }; | ||
104 | |||
105 | static int __devinit simtec_audio_tlv320aic23_probe(struct platform_device *pd) | ||
106 | { | ||
107 | return simtec_audio_core_probe(pd, &simtec_snd_devdata_aic23); | ||
108 | } | ||
109 | |||
110 | static struct platform_driver simtec_audio_tlv320aic23_platdrv = { | ||
111 | .driver = { | ||
112 | .owner = THIS_MODULE, | ||
113 | .name = "s3c24xx-simtec-tlv320aic23", | ||
114 | .pm = simtec_audio_pm, | ||
115 | }, | ||
116 | .probe = simtec_audio_tlv320aic23_probe, | ||
117 | .remove = __devexit_p(simtec_audio_remove), | ||
118 | }; | ||
119 | |||
120 | MODULE_ALIAS("platform:s3c24xx-simtec-tlv320aic23"); | ||
121 | |||
122 | static int __init simtec_tlv320aic23_modinit(void) | ||
123 | { | ||
124 | return platform_driver_register(&simtec_audio_tlv320aic23_platdrv); | ||
125 | } | ||
126 | |||
127 | static void __exit simtec_tlv320aic23_modexit(void) | ||
128 | { | ||
129 | platform_driver_unregister(&simtec_audio_tlv320aic23_platdrv); | ||
130 | } | ||
131 | |||
132 | module_init(simtec_tlv320aic23_modinit); | ||
133 | module_exit(simtec_tlv320aic23_modexit); | ||
134 | |||
135 | MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); | ||
136 | MODULE_DESCRIPTION("ALSA SoC Simtec Audio support"); | ||
137 | MODULE_LICENSE("GPL"); | ||