Commit 87bea31c7b59a07fe5a1c827eb01db3b7c3ae672
1 parent
4f4c007222
Exists in
master
and in
6 other branches
ASoC: Remove redundant snd_soc_dapm_sync() calls from machine drivers
The core will sync DAPM as part of the card initialization, there is no need for machine drivers to do so during their setup. OMAP drivers are omitted as I know Peter already has patches for them. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Showing 31 changed files with 0 additions and 73 deletions Inline Diff
- sound/soc/atmel/playpaq_wm8510.c
- sound/soc/atmel/sam9g20_wm8731.c
- sound/soc/atmel/snd-soc-afeb9260.c
- sound/soc/davinci/davinci-evm.c
- sound/soc/kirkwood/kirkwood-t5325.c
- sound/soc/mid-x86/mfld_machine.c
- sound/soc/pxa/corgi.c
- sound/soc/pxa/e740_wm9705.c
- sound/soc/pxa/e750_wm9705.c
- sound/soc/pxa/e800_wm9712.c
- sound/soc/pxa/magician.c
- sound/soc/pxa/mioa701_wm9713.c
- sound/soc/pxa/palm27x.c
- sound/soc/pxa/saarb.c
- sound/soc/pxa/tavorevb3.c
- sound/soc/pxa/tosa.c
- sound/soc/pxa/z2.c
- sound/soc/pxa/zylonite.c
- sound/soc/samsung/goni_wm8994.c
- sound/soc/samsung/h1940_uda1380.c
- sound/soc/samsung/jive_wm8750.c
- sound/soc/samsung/neo1973_wm8753.c
- sound/soc/samsung/rx1950_uda1380.c
- sound/soc/samsung/s3c24xx_simtec_hermes.c
- sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c
- sound/soc/samsung/smartq_wm8987.c
- sound/soc/samsung/smdk_wm8580.c
- sound/soc/samsung/smdk_wm8994.c
- sound/soc/sh/sh7760-ac97.c
- sound/soc/tegra/tegra_wm8903.c
- sound/soc/tegra/trimslice.c
sound/soc/atmel/playpaq_wm8510.c
1 | /* sound/soc/at32/playpaq_wm8510.c | 1 | /* sound/soc/at32/playpaq_wm8510.c |
2 | * ASoC machine driver for PlayPaq using WM8510 codec | 2 | * ASoC machine driver for PlayPaq using WM8510 codec |
3 | * | 3 | * |
4 | * Copyright (C) 2008 Long Range Systems | 4 | * Copyright (C) 2008 Long Range Systems |
5 | * Geoffrey Wossum <gwossum@acm.org> | 5 | * Geoffrey Wossum <gwossum@acm.org> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License version 2 as | 8 | * it under the terms of the GNU General Public License version 2 as |
9 | * published by the Free Software Foundation. | 9 | * published by the Free Software Foundation. |
10 | * | 10 | * |
11 | * This code is largely inspired by sound/soc/at91/eti_b1_wm8731.c | 11 | * This code is largely inspired by sound/soc/at91/eti_b1_wm8731.c |
12 | * | 12 | * |
13 | * NOTE: If you don't have the AT32 enhanced portmux configured (which | 13 | * NOTE: If you don't have the AT32 enhanced portmux configured (which |
14 | * isn't currently in the mainline or Atmel patched kernel), you will | 14 | * isn't currently in the mainline or Atmel patched kernel), you will |
15 | * need to set the MCLK pin (PA30) to peripheral A in your board initialization | 15 | * need to set the MCLK pin (PA30) to peripheral A in your board initialization |
16 | * code. Something like: | 16 | * code. Something like: |
17 | * at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0); | 17 | * at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0); |
18 | * | 18 | * |
19 | */ | 19 | */ |
20 | 20 | ||
21 | /* #define DEBUG */ | 21 | /* #define DEBUG */ |
22 | 22 | ||
23 | #include <linux/module.h> | 23 | #include <linux/module.h> |
24 | #include <linux/moduleparam.h> | 24 | #include <linux/moduleparam.h> |
25 | #include <linux/kernel.h> | 25 | #include <linux/kernel.h> |
26 | #include <linux/errno.h> | 26 | #include <linux/errno.h> |
27 | #include <linux/clk.h> | 27 | #include <linux/clk.h> |
28 | #include <linux/timer.h> | 28 | #include <linux/timer.h> |
29 | #include <linux/interrupt.h> | 29 | #include <linux/interrupt.h> |
30 | #include <linux/platform_device.h> | 30 | #include <linux/platform_device.h> |
31 | 31 | ||
32 | #include <sound/core.h> | 32 | #include <sound/core.h> |
33 | #include <sound/pcm.h> | 33 | #include <sound/pcm.h> |
34 | #include <sound/pcm_params.h> | 34 | #include <sound/pcm_params.h> |
35 | #include <sound/soc.h> | 35 | #include <sound/soc.h> |
36 | 36 | ||
37 | #include <mach/at32ap700x.h> | 37 | #include <mach/at32ap700x.h> |
38 | #include <mach/portmux.h> | 38 | #include <mach/portmux.h> |
39 | 39 | ||
40 | #include "../codecs/wm8510.h" | 40 | #include "../codecs/wm8510.h" |
41 | #include "atmel-pcm.h" | 41 | #include "atmel-pcm.h" |
42 | #include "atmel_ssc_dai.h" | 42 | #include "atmel_ssc_dai.h" |
43 | 43 | ||
44 | 44 | ||
45 | /*-------------------------------------------------------------------------*\ | 45 | /*-------------------------------------------------------------------------*\ |
46 | * constants | 46 | * constants |
47 | \*-------------------------------------------------------------------------*/ | 47 | \*-------------------------------------------------------------------------*/ |
48 | #define MCLK_PIN GPIO_PIN_PA(30) | 48 | #define MCLK_PIN GPIO_PIN_PA(30) |
49 | #define MCLK_PERIPH GPIO_PERIPH_A | 49 | #define MCLK_PERIPH GPIO_PERIPH_A |
50 | 50 | ||
51 | 51 | ||
52 | /*-------------------------------------------------------------------------*\ | 52 | /*-------------------------------------------------------------------------*\ |
53 | * data types | 53 | * data types |
54 | \*-------------------------------------------------------------------------*/ | 54 | \*-------------------------------------------------------------------------*/ |
55 | /* SSC clocking data */ | 55 | /* SSC clocking data */ |
56 | struct ssc_clock_data { | 56 | struct ssc_clock_data { |
57 | /* CMR div */ | 57 | /* CMR div */ |
58 | unsigned int cmr_div; | 58 | unsigned int cmr_div; |
59 | 59 | ||
60 | /* Frame period (as needed by xCMR.PERIOD) */ | 60 | /* Frame period (as needed by xCMR.PERIOD) */ |
61 | unsigned int period; | 61 | unsigned int period; |
62 | 62 | ||
63 | /* The SSC clock rate these settings where calculated for */ | 63 | /* The SSC clock rate these settings where calculated for */ |
64 | unsigned long ssc_rate; | 64 | unsigned long ssc_rate; |
65 | }; | 65 | }; |
66 | 66 | ||
67 | 67 | ||
68 | /*-------------------------------------------------------------------------*\ | 68 | /*-------------------------------------------------------------------------*\ |
69 | * module data | 69 | * module data |
70 | \*-------------------------------------------------------------------------*/ | 70 | \*-------------------------------------------------------------------------*/ |
71 | static struct clk *_gclk0; | 71 | static struct clk *_gclk0; |
72 | static struct clk *_pll0; | 72 | static struct clk *_pll0; |
73 | 73 | ||
74 | #define CODEC_CLK (_gclk0) | 74 | #define CODEC_CLK (_gclk0) |
75 | 75 | ||
76 | 76 | ||
77 | /*-------------------------------------------------------------------------*\ | 77 | /*-------------------------------------------------------------------------*\ |
78 | * Sound SOC operations | 78 | * Sound SOC operations |
79 | \*-------------------------------------------------------------------------*/ | 79 | \*-------------------------------------------------------------------------*/ |
80 | #if defined CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE | 80 | #if defined CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE |
81 | static struct ssc_clock_data playpaq_wm8510_calc_ssc_clock( | 81 | static struct ssc_clock_data playpaq_wm8510_calc_ssc_clock( |
82 | struct snd_pcm_hw_params *params, | 82 | struct snd_pcm_hw_params *params, |
83 | struct snd_soc_dai *cpu_dai) | 83 | struct snd_soc_dai *cpu_dai) |
84 | { | 84 | { |
85 | struct at32_ssc_info *ssc_p = snd_soc_dai_get_drvdata(cpu_dai); | 85 | struct at32_ssc_info *ssc_p = snd_soc_dai_get_drvdata(cpu_dai); |
86 | struct ssc_device *ssc = ssc_p->ssc; | 86 | struct ssc_device *ssc = ssc_p->ssc; |
87 | struct ssc_clock_data cd; | 87 | struct ssc_clock_data cd; |
88 | unsigned int rate, width_bits, channels; | 88 | unsigned int rate, width_bits, channels; |
89 | unsigned int bitrate, ssc_div; | 89 | unsigned int bitrate, ssc_div; |
90 | unsigned actual_rate; | 90 | unsigned actual_rate; |
91 | 91 | ||
92 | 92 | ||
93 | /* | 93 | /* |
94 | * Figure out required bitrate | 94 | * Figure out required bitrate |
95 | */ | 95 | */ |
96 | rate = params_rate(params); | 96 | rate = params_rate(params); |
97 | channels = params_channels(params); | 97 | channels = params_channels(params); |
98 | width_bits = snd_pcm_format_physical_width(params_format(params)); | 98 | width_bits = snd_pcm_format_physical_width(params_format(params)); |
99 | bitrate = rate * width_bits * channels; | 99 | bitrate = rate * width_bits * channels; |
100 | 100 | ||
101 | 101 | ||
102 | /* | 102 | /* |
103 | * Figure out required SSC divider and period for required bitrate | 103 | * Figure out required SSC divider and period for required bitrate |
104 | */ | 104 | */ |
105 | cd.ssc_rate = clk_get_rate(ssc->clk); | 105 | cd.ssc_rate = clk_get_rate(ssc->clk); |
106 | ssc_div = cd.ssc_rate / bitrate; | 106 | ssc_div = cd.ssc_rate / bitrate; |
107 | cd.cmr_div = ssc_div / 2; | 107 | cd.cmr_div = ssc_div / 2; |
108 | if (ssc_div & 1) { | 108 | if (ssc_div & 1) { |
109 | /* round cmr_div up */ | 109 | /* round cmr_div up */ |
110 | cd.cmr_div++; | 110 | cd.cmr_div++; |
111 | } | 111 | } |
112 | cd.period = width_bits - 1; | 112 | cd.period = width_bits - 1; |
113 | 113 | ||
114 | 114 | ||
115 | /* | 115 | /* |
116 | * Find actual rate, compare to requested rate | 116 | * Find actual rate, compare to requested rate |
117 | */ | 117 | */ |
118 | actual_rate = (cd.ssc_rate / (cd.cmr_div * 2)) / (2 * (cd.period + 1)); | 118 | actual_rate = (cd.ssc_rate / (cd.cmr_div * 2)) / (2 * (cd.period + 1)); |
119 | pr_debug("playpaq_wm8510: Request rate = %u, actual rate = %u\n", | 119 | pr_debug("playpaq_wm8510: Request rate = %u, actual rate = %u\n", |
120 | rate, actual_rate); | 120 | rate, actual_rate); |
121 | 121 | ||
122 | 122 | ||
123 | return cd; | 123 | return cd; |
124 | } | 124 | } |
125 | #endif /* CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE */ | 125 | #endif /* CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE */ |
126 | 126 | ||
127 | 127 | ||
128 | 128 | ||
129 | static int playpaq_wm8510_hw_params(struct snd_pcm_substream *substream, | 129 | static int playpaq_wm8510_hw_params(struct snd_pcm_substream *substream, |
130 | struct snd_pcm_hw_params *params) | 130 | struct snd_pcm_hw_params *params) |
131 | { | 131 | { |
132 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 132 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
133 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 133 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
134 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 134 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
135 | struct at32_ssc_info *ssc_p = snd_soc_dai_get_drvdata(cpu_dai); | 135 | struct at32_ssc_info *ssc_p = snd_soc_dai_get_drvdata(cpu_dai); |
136 | struct ssc_device *ssc = ssc_p->ssc; | 136 | struct ssc_device *ssc = ssc_p->ssc; |
137 | unsigned int pll_out = 0, bclk = 0, mclk_div = 0; | 137 | unsigned int pll_out = 0, bclk = 0, mclk_div = 0; |
138 | int ret; | 138 | int ret; |
139 | 139 | ||
140 | 140 | ||
141 | /* Due to difficulties with getting the correct clocks from the AT32's | 141 | /* Due to difficulties with getting the correct clocks from the AT32's |
142 | * PLL0, we're going to let the CODEC be in charge of all the clocks | 142 | * PLL0, we're going to let the CODEC be in charge of all the clocks |
143 | */ | 143 | */ |
144 | #if !defined CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE | 144 | #if !defined CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE |
145 | const unsigned int fmt = (SND_SOC_DAIFMT_I2S | | 145 | const unsigned int fmt = (SND_SOC_DAIFMT_I2S | |
146 | SND_SOC_DAIFMT_NB_NF | | 146 | SND_SOC_DAIFMT_NB_NF | |
147 | SND_SOC_DAIFMT_CBM_CFM); | 147 | SND_SOC_DAIFMT_CBM_CFM); |
148 | #else | 148 | #else |
149 | struct ssc_clock_data cd; | 149 | struct ssc_clock_data cd; |
150 | const unsigned int fmt = (SND_SOC_DAIFMT_I2S | | 150 | const unsigned int fmt = (SND_SOC_DAIFMT_I2S | |
151 | SND_SOC_DAIFMT_NB_NF | | 151 | SND_SOC_DAIFMT_NB_NF | |
152 | SND_SOC_DAIFMT_CBS_CFS); | 152 | SND_SOC_DAIFMT_CBS_CFS); |
153 | #endif | 153 | #endif |
154 | 154 | ||
155 | if (ssc == NULL) { | 155 | if (ssc == NULL) { |
156 | pr_warning("playpaq_wm8510_hw_params: ssc is NULL!\n"); | 156 | pr_warning("playpaq_wm8510_hw_params: ssc is NULL!\n"); |
157 | return -EINVAL; | 157 | return -EINVAL; |
158 | } | 158 | } |
159 | 159 | ||
160 | 160 | ||
161 | /* | 161 | /* |
162 | * Figure out PLL and BCLK dividers for WM8510 | 162 | * Figure out PLL and BCLK dividers for WM8510 |
163 | */ | 163 | */ |
164 | switch (params_rate(params)) { | 164 | switch (params_rate(params)) { |
165 | case 48000: | 165 | case 48000: |
166 | pll_out = 24576000; | 166 | pll_out = 24576000; |
167 | mclk_div = WM8510_MCLKDIV_2; | 167 | mclk_div = WM8510_MCLKDIV_2; |
168 | bclk = WM8510_BCLKDIV_8; | 168 | bclk = WM8510_BCLKDIV_8; |
169 | break; | 169 | break; |
170 | 170 | ||
171 | case 44100: | 171 | case 44100: |
172 | pll_out = 22579200; | 172 | pll_out = 22579200; |
173 | mclk_div = WM8510_MCLKDIV_2; | 173 | mclk_div = WM8510_MCLKDIV_2; |
174 | bclk = WM8510_BCLKDIV_8; | 174 | bclk = WM8510_BCLKDIV_8; |
175 | break; | 175 | break; |
176 | 176 | ||
177 | case 22050: | 177 | case 22050: |
178 | pll_out = 22579200; | 178 | pll_out = 22579200; |
179 | mclk_div = WM8510_MCLKDIV_4; | 179 | mclk_div = WM8510_MCLKDIV_4; |
180 | bclk = WM8510_BCLKDIV_8; | 180 | bclk = WM8510_BCLKDIV_8; |
181 | break; | 181 | break; |
182 | 182 | ||
183 | case 16000: | 183 | case 16000: |
184 | pll_out = 24576000; | 184 | pll_out = 24576000; |
185 | mclk_div = WM8510_MCLKDIV_6; | 185 | mclk_div = WM8510_MCLKDIV_6; |
186 | bclk = WM8510_BCLKDIV_8; | 186 | bclk = WM8510_BCLKDIV_8; |
187 | break; | 187 | break; |
188 | 188 | ||
189 | case 11025: | 189 | case 11025: |
190 | pll_out = 22579200; | 190 | pll_out = 22579200; |
191 | mclk_div = WM8510_MCLKDIV_8; | 191 | mclk_div = WM8510_MCLKDIV_8; |
192 | bclk = WM8510_BCLKDIV_8; | 192 | bclk = WM8510_BCLKDIV_8; |
193 | break; | 193 | break; |
194 | 194 | ||
195 | case 8000: | 195 | case 8000: |
196 | pll_out = 24576000; | 196 | pll_out = 24576000; |
197 | mclk_div = WM8510_MCLKDIV_12; | 197 | mclk_div = WM8510_MCLKDIV_12; |
198 | bclk = WM8510_BCLKDIV_8; | 198 | bclk = WM8510_BCLKDIV_8; |
199 | break; | 199 | break; |
200 | 200 | ||
201 | default: | 201 | default: |
202 | pr_warning("playpaq_wm8510: Unsupported sample rate %d\n", | 202 | pr_warning("playpaq_wm8510: Unsupported sample rate %d\n", |
203 | params_rate(params)); | 203 | params_rate(params)); |
204 | return -EINVAL; | 204 | return -EINVAL; |
205 | } | 205 | } |
206 | 206 | ||
207 | 207 | ||
208 | /* | 208 | /* |
209 | * set CPU and CODEC DAI configuration | 209 | * set CPU and CODEC DAI configuration |
210 | */ | 210 | */ |
211 | ret = snd_soc_dai_set_fmt(codec_dai, fmt); | 211 | ret = snd_soc_dai_set_fmt(codec_dai, fmt); |
212 | if (ret < 0) { | 212 | if (ret < 0) { |
213 | pr_warning("playpaq_wm8510: " | 213 | pr_warning("playpaq_wm8510: " |
214 | "Failed to set CODEC DAI format (%d)\n", | 214 | "Failed to set CODEC DAI format (%d)\n", |
215 | ret); | 215 | ret); |
216 | return ret; | 216 | return ret; |
217 | } | 217 | } |
218 | ret = snd_soc_dai_set_fmt(cpu_dai, fmt); | 218 | ret = snd_soc_dai_set_fmt(cpu_dai, fmt); |
219 | if (ret < 0) { | 219 | if (ret < 0) { |
220 | pr_warning("playpaq_wm8510: " | 220 | pr_warning("playpaq_wm8510: " |
221 | "Failed to set CPU DAI format (%d)\n", | 221 | "Failed to set CPU DAI format (%d)\n", |
222 | ret); | 222 | ret); |
223 | return ret; | 223 | return ret; |
224 | } | 224 | } |
225 | 225 | ||
226 | 226 | ||
227 | /* | 227 | /* |
228 | * Set CPU clock configuration | 228 | * Set CPU clock configuration |
229 | */ | 229 | */ |
230 | #if defined CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE | 230 | #if defined CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE |
231 | cd = playpaq_wm8510_calc_ssc_clock(params, cpu_dai); | 231 | cd = playpaq_wm8510_calc_ssc_clock(params, cpu_dai); |
232 | pr_debug("playpaq_wm8510: cmr_div = %d, period = %d\n", | 232 | pr_debug("playpaq_wm8510: cmr_div = %d, period = %d\n", |
233 | cd.cmr_div, cd.period); | 233 | cd.cmr_div, cd.period); |
234 | ret = snd_soc_dai_set_clkdiv(cpu_dai, AT32_SSC_CMR_DIV, cd.cmr_div); | 234 | ret = snd_soc_dai_set_clkdiv(cpu_dai, AT32_SSC_CMR_DIV, cd.cmr_div); |
235 | if (ret < 0) { | 235 | if (ret < 0) { |
236 | pr_warning("playpaq_wm8510: Failed to set CPU CMR_DIV (%d)\n", | 236 | pr_warning("playpaq_wm8510: Failed to set CPU CMR_DIV (%d)\n", |
237 | ret); | 237 | ret); |
238 | return ret; | 238 | return ret; |
239 | } | 239 | } |
240 | ret = snd_soc_dai_set_clkdiv(cpu_dai, AT32_SSC_TCMR_PERIOD, | 240 | ret = snd_soc_dai_set_clkdiv(cpu_dai, AT32_SSC_TCMR_PERIOD, |
241 | cd.period); | 241 | cd.period); |
242 | if (ret < 0) { | 242 | if (ret < 0) { |
243 | pr_warning("playpaq_wm8510: " | 243 | pr_warning("playpaq_wm8510: " |
244 | "Failed to set CPU transmit period (%d)\n", | 244 | "Failed to set CPU transmit period (%d)\n", |
245 | ret); | 245 | ret); |
246 | return ret; | 246 | return ret; |
247 | } | 247 | } |
248 | #endif /* CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE */ | 248 | #endif /* CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE */ |
249 | 249 | ||
250 | 250 | ||
251 | /* | 251 | /* |
252 | * Set CODEC clock configuration | 252 | * Set CODEC clock configuration |
253 | */ | 253 | */ |
254 | pr_debug("playpaq_wm8510: " | 254 | pr_debug("playpaq_wm8510: " |
255 | "pll_in = %ld, pll_out = %u, bclk = %x, mclk = %x\n", | 255 | "pll_in = %ld, pll_out = %u, bclk = %x, mclk = %x\n", |
256 | clk_get_rate(CODEC_CLK), pll_out, bclk, mclk_div); | 256 | clk_get_rate(CODEC_CLK), pll_out, bclk, mclk_div); |
257 | 257 | ||
258 | 258 | ||
259 | #if !defined CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE | 259 | #if !defined CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE |
260 | ret = snd_soc_dai_set_clkdiv(codec_dai, WM8510_BCLKDIV, bclk); | 260 | ret = snd_soc_dai_set_clkdiv(codec_dai, WM8510_BCLKDIV, bclk); |
261 | if (ret < 0) { | 261 | if (ret < 0) { |
262 | pr_warning | 262 | pr_warning |
263 | ("playpaq_wm8510: Failed to set CODEC DAI BCLKDIV (%d)\n", | 263 | ("playpaq_wm8510: Failed to set CODEC DAI BCLKDIV (%d)\n", |
264 | ret); | 264 | ret); |
265 | return ret; | 265 | return ret; |
266 | } | 266 | } |
267 | #endif /* CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE */ | 267 | #endif /* CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE */ |
268 | 268 | ||
269 | 269 | ||
270 | ret = snd_soc_dai_set_pll(codec_dai, 0, 0, | 270 | ret = snd_soc_dai_set_pll(codec_dai, 0, 0, |
271 | clk_get_rate(CODEC_CLK), pll_out); | 271 | clk_get_rate(CODEC_CLK), pll_out); |
272 | if (ret < 0) { | 272 | if (ret < 0) { |
273 | pr_warning("playpaq_wm8510: Failed to set CODEC DAI PLL (%d)\n", | 273 | pr_warning("playpaq_wm8510: Failed to set CODEC DAI PLL (%d)\n", |
274 | ret); | 274 | ret); |
275 | return ret; | 275 | return ret; |
276 | } | 276 | } |
277 | 277 | ||
278 | 278 | ||
279 | ret = snd_soc_dai_set_clkdiv(codec_dai, WM8510_MCLKDIV, mclk_div); | 279 | ret = snd_soc_dai_set_clkdiv(codec_dai, WM8510_MCLKDIV, mclk_div); |
280 | if (ret < 0) { | 280 | if (ret < 0) { |
281 | pr_warning("playpaq_wm8510: Failed to set CODEC MCLKDIV (%d)\n", | 281 | pr_warning("playpaq_wm8510: Failed to set CODEC MCLKDIV (%d)\n", |
282 | ret); | 282 | ret); |
283 | return ret; | 283 | return ret; |
284 | } | 284 | } |
285 | 285 | ||
286 | 286 | ||
287 | return 0; | 287 | return 0; |
288 | } | 288 | } |
289 | 289 | ||
290 | 290 | ||
291 | 291 | ||
292 | static struct snd_soc_ops playpaq_wm8510_ops = { | 292 | static struct snd_soc_ops playpaq_wm8510_ops = { |
293 | .hw_params = playpaq_wm8510_hw_params, | 293 | .hw_params = playpaq_wm8510_hw_params, |
294 | }; | 294 | }; |
295 | 295 | ||
296 | 296 | ||
297 | 297 | ||
298 | static const struct snd_soc_dapm_widget playpaq_dapm_widgets[] = { | 298 | static const struct snd_soc_dapm_widget playpaq_dapm_widgets[] = { |
299 | SND_SOC_DAPM_MIC("Int Mic", NULL), | 299 | SND_SOC_DAPM_MIC("Int Mic", NULL), |
300 | SND_SOC_DAPM_SPK("Ext Spk", NULL), | 300 | SND_SOC_DAPM_SPK("Ext Spk", NULL), |
301 | }; | 301 | }; |
302 | 302 | ||
303 | 303 | ||
304 | 304 | ||
305 | static const struct snd_soc_dapm_route intercon[] = { | 305 | static const struct snd_soc_dapm_route intercon[] = { |
306 | /* speaker connected to SPKOUT */ | 306 | /* speaker connected to SPKOUT */ |
307 | {"Ext Spk", NULL, "SPKOUTP"}, | 307 | {"Ext Spk", NULL, "SPKOUTP"}, |
308 | {"Ext Spk", NULL, "SPKOUTN"}, | 308 | {"Ext Spk", NULL, "SPKOUTN"}, |
309 | 309 | ||
310 | {"Mic Bias", NULL, "Int Mic"}, | 310 | {"Mic Bias", NULL, "Int Mic"}, |
311 | {"MICN", NULL, "Mic Bias"}, | 311 | {"MICN", NULL, "Mic Bias"}, |
312 | {"MICP", NULL, "Mic Bias"}, | 312 | {"MICP", NULL, "Mic Bias"}, |
313 | }; | 313 | }; |
314 | 314 | ||
315 | 315 | ||
316 | 316 | ||
317 | static int playpaq_wm8510_init(struct snd_soc_pcm_runtime *rtd) | 317 | static int playpaq_wm8510_init(struct snd_soc_pcm_runtime *rtd) |
318 | { | 318 | { |
319 | struct snd_soc_codec *codec = rtd->codec; | 319 | struct snd_soc_codec *codec = rtd->codec; |
320 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 320 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
321 | int i; | 321 | int i; |
322 | 322 | ||
323 | /* | 323 | /* |
324 | * Add DAPM widgets | 324 | * Add DAPM widgets |
325 | */ | 325 | */ |
326 | for (i = 0; i < ARRAY_SIZE(playpaq_dapm_widgets); i++) | 326 | for (i = 0; i < ARRAY_SIZE(playpaq_dapm_widgets); i++) |
327 | snd_soc_dapm_new_control(dapm, &playpaq_dapm_widgets[i]); | 327 | snd_soc_dapm_new_control(dapm, &playpaq_dapm_widgets[i]); |
328 | 328 | ||
329 | 329 | ||
330 | 330 | ||
331 | /* | 331 | /* |
332 | * Setup audio path interconnects | 332 | * Setup audio path interconnects |
333 | */ | 333 | */ |
334 | snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon)); | 334 | snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon)); |
335 | 335 | ||
336 | 336 | ||
337 | 337 | ||
338 | /* always connected pins */ | 338 | /* always connected pins */ |
339 | snd_soc_dapm_enable_pin(dapm, "Int Mic"); | 339 | snd_soc_dapm_enable_pin(dapm, "Int Mic"); |
340 | snd_soc_dapm_enable_pin(dapm, "Ext Spk"); | 340 | snd_soc_dapm_enable_pin(dapm, "Ext Spk"); |
341 | snd_soc_dapm_sync(dapm); | ||
342 | 341 | ||
343 | 342 | ||
344 | 343 | ||
345 | /* Make CSB show PLL rate */ | 344 | /* Make CSB show PLL rate */ |
346 | snd_soc_dai_set_clkdiv(rtd->codec_dai, WM8510_OPCLKDIV, | 345 | snd_soc_dai_set_clkdiv(rtd->codec_dai, WM8510_OPCLKDIV, |
347 | WM8510_OPCLKDIV_1 | 4); | 346 | WM8510_OPCLKDIV_1 | 4); |
348 | 347 | ||
349 | return 0; | 348 | return 0; |
350 | } | 349 | } |
351 | 350 | ||
352 | 351 | ||
353 | 352 | ||
354 | static struct snd_soc_dai_link playpaq_wm8510_dai = { | 353 | static struct snd_soc_dai_link playpaq_wm8510_dai = { |
355 | .name = "WM8510", | 354 | .name = "WM8510", |
356 | .stream_name = "WM8510 PCM", | 355 | .stream_name = "WM8510 PCM", |
357 | .cpu_dai_name= "atmel-ssc-dai.0", | 356 | .cpu_dai_name= "atmel-ssc-dai.0", |
358 | .platform_name = "atmel-pcm-audio", | 357 | .platform_name = "atmel-pcm-audio", |
359 | .codec_name = "wm8510-codec.0-0x1a", | 358 | .codec_name = "wm8510-codec.0-0x1a", |
360 | .codec_dai_name = "wm8510-hifi", | 359 | .codec_dai_name = "wm8510-hifi", |
361 | .init = playpaq_wm8510_init, | 360 | .init = playpaq_wm8510_init, |
362 | .ops = &playpaq_wm8510_ops, | 361 | .ops = &playpaq_wm8510_ops, |
363 | }; | 362 | }; |
364 | 363 | ||
365 | 364 | ||
366 | 365 | ||
367 | static struct snd_soc_card snd_soc_playpaq = { | 366 | static struct snd_soc_card snd_soc_playpaq = { |
368 | .name = "LRS_PlayPaq_WM8510", | 367 | .name = "LRS_PlayPaq_WM8510", |
369 | .dai_link = &playpaq_wm8510_dai, | 368 | .dai_link = &playpaq_wm8510_dai, |
370 | .num_links = 1, | 369 | .num_links = 1, |
371 | }; | 370 | }; |
372 | 371 | ||
373 | static struct platform_device *playpaq_snd_device; | 372 | static struct platform_device *playpaq_snd_device; |
374 | 373 | ||
375 | 374 | ||
376 | static int __init playpaq_asoc_init(void) | 375 | static int __init playpaq_asoc_init(void) |
377 | { | 376 | { |
378 | int ret = 0; | 377 | int ret = 0; |
379 | 378 | ||
380 | /* | 379 | /* |
381 | * Configure MCLK for WM8510 | 380 | * Configure MCLK for WM8510 |
382 | */ | 381 | */ |
383 | _gclk0 = clk_get(NULL, "gclk0"); | 382 | _gclk0 = clk_get(NULL, "gclk0"); |
384 | if (IS_ERR(_gclk0)) { | 383 | if (IS_ERR(_gclk0)) { |
385 | _gclk0 = NULL; | 384 | _gclk0 = NULL; |
386 | ret = PTR_ERR(_gclk0); | 385 | ret = PTR_ERR(_gclk0); |
387 | goto err_gclk0; | 386 | goto err_gclk0; |
388 | } | 387 | } |
389 | _pll0 = clk_get(NULL, "pll0"); | 388 | _pll0 = clk_get(NULL, "pll0"); |
390 | if (IS_ERR(_pll0)) { | 389 | if (IS_ERR(_pll0)) { |
391 | _pll0 = NULL; | 390 | _pll0 = NULL; |
392 | ret = PTR_ERR(_pll0); | 391 | ret = PTR_ERR(_pll0); |
393 | goto err_pll0; | 392 | goto err_pll0; |
394 | } | 393 | } |
395 | ret = clk_set_parent(_gclk0, _pll0); | 394 | ret = clk_set_parent(_gclk0, _pll0); |
396 | if (ret) { | 395 | if (ret) { |
397 | pr_warning("snd-soc-playpaq: " | 396 | pr_warning("snd-soc-playpaq: " |
398 | "Failed to set PLL0 as parent for DAC clock\n"); | 397 | "Failed to set PLL0 as parent for DAC clock\n"); |
399 | goto err_set_clk; | 398 | goto err_set_clk; |
400 | } | 399 | } |
401 | clk_set_rate(CODEC_CLK, 12000000); | 400 | clk_set_rate(CODEC_CLK, 12000000); |
402 | clk_enable(CODEC_CLK); | 401 | clk_enable(CODEC_CLK); |
403 | 402 | ||
404 | #if defined CONFIG_AT32_ENHANCED_PORTMUX | 403 | #if defined CONFIG_AT32_ENHANCED_PORTMUX |
405 | at32_select_periph(MCLK_PIN, MCLK_PERIPH, 0); | 404 | at32_select_periph(MCLK_PIN, MCLK_PERIPH, 0); |
406 | #endif | 405 | #endif |
407 | 406 | ||
408 | 407 | ||
409 | /* | 408 | /* |
410 | * Create and register platform device | 409 | * Create and register platform device |
411 | */ | 410 | */ |
412 | playpaq_snd_device = platform_device_alloc("soc-audio", 0); | 411 | playpaq_snd_device = platform_device_alloc("soc-audio", 0); |
413 | if (playpaq_snd_device == NULL) { | 412 | if (playpaq_snd_device == NULL) { |
414 | ret = -ENOMEM; | 413 | ret = -ENOMEM; |
415 | goto err_device_alloc; | 414 | goto err_device_alloc; |
416 | } | 415 | } |
417 | 416 | ||
418 | platform_set_drvdata(playpaq_snd_device, &snd_soc_playpaq); | 417 | platform_set_drvdata(playpaq_snd_device, &snd_soc_playpaq); |
419 | 418 | ||
420 | ret = platform_device_add(playpaq_snd_device); | 419 | ret = platform_device_add(playpaq_snd_device); |
421 | if (ret) { | 420 | if (ret) { |
422 | pr_warning("playpaq_wm8510: platform_device_add failed (%d)\n", | 421 | pr_warning("playpaq_wm8510: platform_device_add failed (%d)\n", |
423 | ret); | 422 | ret); |
424 | goto err_device_add; | 423 | goto err_device_add; |
425 | } | 424 | } |
426 | 425 | ||
427 | return 0; | 426 | return 0; |
428 | 427 | ||
429 | 428 | ||
430 | err_device_add: | 429 | err_device_add: |
431 | if (playpaq_snd_device != NULL) { | 430 | if (playpaq_snd_device != NULL) { |
432 | platform_device_put(playpaq_snd_device); | 431 | platform_device_put(playpaq_snd_device); |
433 | playpaq_snd_device = NULL; | 432 | playpaq_snd_device = NULL; |
434 | } | 433 | } |
435 | err_device_alloc: | 434 | err_device_alloc: |
436 | err_set_clk: | 435 | err_set_clk: |
437 | if (_pll0 != NULL) { | 436 | if (_pll0 != NULL) { |
438 | clk_put(_pll0); | 437 | clk_put(_pll0); |
439 | _pll0 = NULL; | 438 | _pll0 = NULL; |
440 | } | 439 | } |
441 | err_pll0: | 440 | err_pll0: |
442 | if (_gclk0 != NULL) { | 441 | if (_gclk0 != NULL) { |
443 | clk_put(_gclk0); | 442 | clk_put(_gclk0); |
444 | _gclk0 = NULL; | 443 | _gclk0 = NULL; |
445 | } | 444 | } |
446 | return ret; | 445 | return ret; |
447 | } | 446 | } |
448 | 447 | ||
449 | 448 | ||
450 | static void __exit playpaq_asoc_exit(void) | 449 | static void __exit playpaq_asoc_exit(void) |
451 | { | 450 | { |
452 | if (_gclk0 != NULL) { | 451 | if (_gclk0 != NULL) { |
453 | clk_put(_gclk0); | 452 | clk_put(_gclk0); |
454 | _gclk0 = NULL; | 453 | _gclk0 = NULL; |
455 | } | 454 | } |
456 | if (_pll0 != NULL) { | 455 | if (_pll0 != NULL) { |
457 | clk_put(_pll0); | 456 | clk_put(_pll0); |
458 | _pll0 = NULL; | 457 | _pll0 = NULL; |
459 | } | 458 | } |
460 | 459 | ||
461 | #if defined CONFIG_AT32_ENHANCED_PORTMUX | 460 | #if defined CONFIG_AT32_ENHANCED_PORTMUX |
462 | at32_free_pin(MCLK_PIN); | 461 | at32_free_pin(MCLK_PIN); |
463 | #endif | 462 | #endif |
464 | 463 | ||
465 | platform_device_unregister(playpaq_snd_device); | 464 | platform_device_unregister(playpaq_snd_device); |
466 | playpaq_snd_device = NULL; | 465 | playpaq_snd_device = NULL; |
467 | } | 466 | } |
468 | 467 | ||
469 | module_init(playpaq_asoc_init); | 468 | module_init(playpaq_asoc_init); |
470 | module_exit(playpaq_asoc_exit); | 469 | module_exit(playpaq_asoc_exit); |
471 | 470 | ||
472 | MODULE_AUTHOR("Geoffrey Wossum <gwossum@acm.org>"); | 471 | MODULE_AUTHOR("Geoffrey Wossum <gwossum@acm.org>"); |
473 | MODULE_DESCRIPTION("ASoC machine driver for LRS PlayPaq"); | 472 | MODULE_DESCRIPTION("ASoC machine driver for LRS PlayPaq"); |
474 | MODULE_LICENSE("GPL"); | 473 | MODULE_LICENSE("GPL"); |
475 | 474 |
sound/soc/atmel/sam9g20_wm8731.c
1 | /* | 1 | /* |
2 | * sam9g20_wm8731 -- SoC audio for AT91SAM9G20-based | 2 | * sam9g20_wm8731 -- SoC audio for AT91SAM9G20-based |
3 | * ATMEL AT91SAM9G20ek board. | 3 | * ATMEL AT91SAM9G20ek board. |
4 | * | 4 | * |
5 | * Copyright (C) 2005 SAN People | 5 | * Copyright (C) 2005 SAN People |
6 | * Copyright (C) 2008 Atmel | 6 | * Copyright (C) 2008 Atmel |
7 | * | 7 | * |
8 | * Authors: Sedji Gaouaou <sedji.gaouaou@atmel.com> | 8 | * Authors: Sedji Gaouaou <sedji.gaouaou@atmel.com> |
9 | * | 9 | * |
10 | * Based on ati_b1_wm8731.c by: | 10 | * Based on ati_b1_wm8731.c by: |
11 | * Frank Mandarino <fmandarino@endrelia.com> | 11 | * Frank Mandarino <fmandarino@endrelia.com> |
12 | * Copyright 2006 Endrelia Technologies Inc. | 12 | * Copyright 2006 Endrelia Technologies Inc. |
13 | * Based on corgi.c by: | 13 | * Based on corgi.c by: |
14 | * Copyright 2005 Wolfson Microelectronics PLC. | 14 | * Copyright 2005 Wolfson Microelectronics PLC. |
15 | * Copyright 2005 Openedhand Ltd. | 15 | * Copyright 2005 Openedhand Ltd. |
16 | * | 16 | * |
17 | * This program is free software; you can redistribute it and/or modify | 17 | * This program is free software; you can redistribute it and/or modify |
18 | * it under the terms of the GNU General Public License as published by | 18 | * it under the terms of the GNU General Public License as published by |
19 | * the Free Software Foundation; either version 2 of the License, or | 19 | * the Free Software Foundation; either version 2 of the License, or |
20 | * (at your option) any later version. | 20 | * (at your option) any later version. |
21 | * | 21 | * |
22 | * This program is distributed in the hope that it will be useful, | 22 | * This program is distributed in the hope that it will be useful, |
23 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 23 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
24 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 24 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
25 | * GNU General Public License for more details. | 25 | * GNU General Public License for more details. |
26 | * | 26 | * |
27 | * You should have received a copy of the GNU General Public License | 27 | * You should have received a copy of the GNU General Public License |
28 | * along with this program; if not, write to the Free Software | 28 | * along with this program; if not, write to the Free Software |
29 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 29 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
30 | */ | 30 | */ |
31 | 31 | ||
32 | #include <linux/module.h> | 32 | #include <linux/module.h> |
33 | #include <linux/moduleparam.h> | 33 | #include <linux/moduleparam.h> |
34 | #include <linux/kernel.h> | 34 | #include <linux/kernel.h> |
35 | #include <linux/clk.h> | 35 | #include <linux/clk.h> |
36 | #include <linux/timer.h> | 36 | #include <linux/timer.h> |
37 | #include <linux/interrupt.h> | 37 | #include <linux/interrupt.h> |
38 | #include <linux/platform_device.h> | 38 | #include <linux/platform_device.h> |
39 | #include <linux/i2c.h> | 39 | #include <linux/i2c.h> |
40 | 40 | ||
41 | #include <linux/atmel-ssc.h> | 41 | #include <linux/atmel-ssc.h> |
42 | 42 | ||
43 | #include <sound/core.h> | 43 | #include <sound/core.h> |
44 | #include <sound/pcm.h> | 44 | #include <sound/pcm.h> |
45 | #include <sound/pcm_params.h> | 45 | #include <sound/pcm_params.h> |
46 | #include <sound/soc.h> | 46 | #include <sound/soc.h> |
47 | 47 | ||
48 | #include <asm/mach-types.h> | 48 | #include <asm/mach-types.h> |
49 | #include <mach/hardware.h> | 49 | #include <mach/hardware.h> |
50 | #include <mach/gpio.h> | 50 | #include <mach/gpio.h> |
51 | 51 | ||
52 | #include "../codecs/wm8731.h" | 52 | #include "../codecs/wm8731.h" |
53 | #include "atmel-pcm.h" | 53 | #include "atmel-pcm.h" |
54 | #include "atmel_ssc_dai.h" | 54 | #include "atmel_ssc_dai.h" |
55 | 55 | ||
56 | #define MCLK_RATE 12000000 | 56 | #define MCLK_RATE 12000000 |
57 | 57 | ||
58 | /* | 58 | /* |
59 | * As shipped the board does not have inputs. However, it is relatively | 59 | * As shipped the board does not have inputs. However, it is relatively |
60 | * straightforward to modify the board to hook them up so support is left | 60 | * straightforward to modify the board to hook them up so support is left |
61 | * in the driver. | 61 | * in the driver. |
62 | */ | 62 | */ |
63 | #undef ENABLE_MIC_INPUT | 63 | #undef ENABLE_MIC_INPUT |
64 | 64 | ||
65 | static struct clk *mclk; | 65 | static struct clk *mclk; |
66 | 66 | ||
67 | static int at91sam9g20ek_hw_params(struct snd_pcm_substream *substream, | 67 | static int at91sam9g20ek_hw_params(struct snd_pcm_substream *substream, |
68 | struct snd_pcm_hw_params *params) | 68 | struct snd_pcm_hw_params *params) |
69 | { | 69 | { |
70 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 70 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
71 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 71 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
72 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 72 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
73 | int ret; | 73 | int ret; |
74 | 74 | ||
75 | /* set codec DAI configuration */ | 75 | /* set codec DAI configuration */ |
76 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | | 76 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | |
77 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); | 77 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); |
78 | if (ret < 0) | 78 | if (ret < 0) |
79 | return ret; | 79 | return ret; |
80 | 80 | ||
81 | /* set cpu DAI configuration */ | 81 | /* set cpu DAI configuration */ |
82 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | | 82 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | |
83 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); | 83 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); |
84 | if (ret < 0) | 84 | if (ret < 0) |
85 | return ret; | 85 | return ret; |
86 | 86 | ||
87 | return 0; | 87 | return 0; |
88 | } | 88 | } |
89 | 89 | ||
90 | static struct snd_soc_ops at91sam9g20ek_ops = { | 90 | static struct snd_soc_ops at91sam9g20ek_ops = { |
91 | .hw_params = at91sam9g20ek_hw_params, | 91 | .hw_params = at91sam9g20ek_hw_params, |
92 | }; | 92 | }; |
93 | 93 | ||
94 | static int at91sam9g20ek_set_bias_level(struct snd_soc_card *card, | 94 | static int at91sam9g20ek_set_bias_level(struct snd_soc_card *card, |
95 | struct snd_soc_dapm_context *dapm, | 95 | struct snd_soc_dapm_context *dapm, |
96 | enum snd_soc_bias_level level) | 96 | enum snd_soc_bias_level level) |
97 | { | 97 | { |
98 | static int mclk_on; | 98 | static int mclk_on; |
99 | int ret = 0; | 99 | int ret = 0; |
100 | 100 | ||
101 | switch (level) { | 101 | switch (level) { |
102 | case SND_SOC_BIAS_ON: | 102 | case SND_SOC_BIAS_ON: |
103 | case SND_SOC_BIAS_PREPARE: | 103 | case SND_SOC_BIAS_PREPARE: |
104 | if (!mclk_on) | 104 | if (!mclk_on) |
105 | ret = clk_enable(mclk); | 105 | ret = clk_enable(mclk); |
106 | if (ret == 0) | 106 | if (ret == 0) |
107 | mclk_on = 1; | 107 | mclk_on = 1; |
108 | break; | 108 | break; |
109 | 109 | ||
110 | case SND_SOC_BIAS_OFF: | 110 | case SND_SOC_BIAS_OFF: |
111 | case SND_SOC_BIAS_STANDBY: | 111 | case SND_SOC_BIAS_STANDBY: |
112 | if (mclk_on) | 112 | if (mclk_on) |
113 | clk_disable(mclk); | 113 | clk_disable(mclk); |
114 | mclk_on = 0; | 114 | mclk_on = 0; |
115 | break; | 115 | break; |
116 | } | 116 | } |
117 | 117 | ||
118 | return ret; | 118 | return ret; |
119 | } | 119 | } |
120 | 120 | ||
121 | static const struct snd_soc_dapm_widget at91sam9g20ek_dapm_widgets[] = { | 121 | static const struct snd_soc_dapm_widget at91sam9g20ek_dapm_widgets[] = { |
122 | SND_SOC_DAPM_MIC("Int Mic", NULL), | 122 | SND_SOC_DAPM_MIC("Int Mic", NULL), |
123 | SND_SOC_DAPM_SPK("Ext Spk", NULL), | 123 | SND_SOC_DAPM_SPK("Ext Spk", NULL), |
124 | }; | 124 | }; |
125 | 125 | ||
126 | static const struct snd_soc_dapm_route intercon[] = { | 126 | static const struct snd_soc_dapm_route intercon[] = { |
127 | 127 | ||
128 | /* speaker connected to LHPOUT */ | 128 | /* speaker connected to LHPOUT */ |
129 | {"Ext Spk", NULL, "LHPOUT"}, | 129 | {"Ext Spk", NULL, "LHPOUT"}, |
130 | 130 | ||
131 | /* mic is connected to Mic Jack, with WM8731 Mic Bias */ | 131 | /* mic is connected to Mic Jack, with WM8731 Mic Bias */ |
132 | {"MICIN", NULL, "Mic Bias"}, | 132 | {"MICIN", NULL, "Mic Bias"}, |
133 | {"Mic Bias", NULL, "Int Mic"}, | 133 | {"Mic Bias", NULL, "Int Mic"}, |
134 | }; | 134 | }; |
135 | 135 | ||
136 | /* | 136 | /* |
137 | * Logic for a wm8731 as connected on a at91sam9g20ek board. | 137 | * Logic for a wm8731 as connected on a at91sam9g20ek board. |
138 | */ | 138 | */ |
139 | static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd) | 139 | static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd) |
140 | { | 140 | { |
141 | struct snd_soc_codec *codec = rtd->codec; | 141 | struct snd_soc_codec *codec = rtd->codec; |
142 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 142 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
143 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 143 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
144 | int ret; | 144 | int ret; |
145 | 145 | ||
146 | printk(KERN_DEBUG | 146 | printk(KERN_DEBUG |
147 | "at91sam9g20ek_wm8731 " | 147 | "at91sam9g20ek_wm8731 " |
148 | ": at91sam9g20ek_wm8731_init() called\n"); | 148 | ": at91sam9g20ek_wm8731_init() called\n"); |
149 | 149 | ||
150 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_MCLK, | 150 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_MCLK, |
151 | MCLK_RATE, SND_SOC_CLOCK_IN); | 151 | MCLK_RATE, SND_SOC_CLOCK_IN); |
152 | if (ret < 0) { | 152 | if (ret < 0) { |
153 | printk(KERN_ERR "Failed to set WM8731 SYSCLK: %d\n", ret); | 153 | printk(KERN_ERR "Failed to set WM8731 SYSCLK: %d\n", ret); |
154 | return ret; | 154 | return ret; |
155 | } | 155 | } |
156 | 156 | ||
157 | /* Add specific widgets */ | 157 | /* Add specific widgets */ |
158 | snd_soc_dapm_new_controls(dapm, at91sam9g20ek_dapm_widgets, | 158 | snd_soc_dapm_new_controls(dapm, at91sam9g20ek_dapm_widgets, |
159 | ARRAY_SIZE(at91sam9g20ek_dapm_widgets)); | 159 | ARRAY_SIZE(at91sam9g20ek_dapm_widgets)); |
160 | /* Set up specific audio path interconnects */ | 160 | /* Set up specific audio path interconnects */ |
161 | snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon)); | 161 | snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon)); |
162 | 162 | ||
163 | /* not connected */ | 163 | /* not connected */ |
164 | snd_soc_dapm_nc_pin(dapm, "RLINEIN"); | 164 | snd_soc_dapm_nc_pin(dapm, "RLINEIN"); |
165 | snd_soc_dapm_nc_pin(dapm, "LLINEIN"); | 165 | snd_soc_dapm_nc_pin(dapm, "LLINEIN"); |
166 | 166 | ||
167 | #ifdef ENABLE_MIC_INPUT | 167 | #ifdef ENABLE_MIC_INPUT |
168 | snd_soc_dapm_enable_pin(dapm, "Int Mic"); | 168 | snd_soc_dapm_enable_pin(dapm, "Int Mic"); |
169 | #else | 169 | #else |
170 | snd_soc_dapm_nc_pin(dapm, "Int Mic"); | 170 | snd_soc_dapm_nc_pin(dapm, "Int Mic"); |
171 | #endif | 171 | #endif |
172 | 172 | ||
173 | /* always connected */ | 173 | /* always connected */ |
174 | snd_soc_dapm_enable_pin(dapm, "Ext Spk"); | 174 | snd_soc_dapm_enable_pin(dapm, "Ext Spk"); |
175 | 175 | ||
176 | snd_soc_dapm_sync(dapm); | ||
177 | |||
178 | return 0; | 176 | return 0; |
179 | } | 177 | } |
180 | 178 | ||
181 | static struct snd_soc_dai_link at91sam9g20ek_dai = { | 179 | static struct snd_soc_dai_link at91sam9g20ek_dai = { |
182 | .name = "WM8731", | 180 | .name = "WM8731", |
183 | .stream_name = "WM8731 PCM", | 181 | .stream_name = "WM8731 PCM", |
184 | .cpu_dai_name = "atmel-ssc-dai.0", | 182 | .cpu_dai_name = "atmel-ssc-dai.0", |
185 | .codec_dai_name = "wm8731-hifi", | 183 | .codec_dai_name = "wm8731-hifi", |
186 | .init = at91sam9g20ek_wm8731_init, | 184 | .init = at91sam9g20ek_wm8731_init, |
187 | .platform_name = "atmel-pcm-audio", | 185 | .platform_name = "atmel-pcm-audio", |
188 | .codec_name = "wm8731.0-001b", | 186 | .codec_name = "wm8731.0-001b", |
189 | .ops = &at91sam9g20ek_ops, | 187 | .ops = &at91sam9g20ek_ops, |
190 | }; | 188 | }; |
191 | 189 | ||
192 | static struct snd_soc_card snd_soc_at91sam9g20ek = { | 190 | static struct snd_soc_card snd_soc_at91sam9g20ek = { |
193 | .name = "AT91SAMG20-EK", | 191 | .name = "AT91SAMG20-EK", |
194 | .dai_link = &at91sam9g20ek_dai, | 192 | .dai_link = &at91sam9g20ek_dai, |
195 | .num_links = 1, | 193 | .num_links = 1, |
196 | .set_bias_level = at91sam9g20ek_set_bias_level, | 194 | .set_bias_level = at91sam9g20ek_set_bias_level, |
197 | }; | 195 | }; |
198 | 196 | ||
199 | static struct platform_device *at91sam9g20ek_snd_device; | 197 | static struct platform_device *at91sam9g20ek_snd_device; |
200 | 198 | ||
201 | static int __init at91sam9g20ek_init(void) | 199 | static int __init at91sam9g20ek_init(void) |
202 | { | 200 | { |
203 | struct clk *pllb; | 201 | struct clk *pllb; |
204 | int ret; | 202 | int ret; |
205 | 203 | ||
206 | if (!(machine_is_at91sam9g20ek() || machine_is_at91sam9g20ek_2mmc())) | 204 | if (!(machine_is_at91sam9g20ek() || machine_is_at91sam9g20ek_2mmc())) |
207 | return -ENODEV; | 205 | return -ENODEV; |
208 | 206 | ||
209 | ret = atmel_ssc_set_audio(0); | 207 | ret = atmel_ssc_set_audio(0); |
210 | if (ret != 0) { | 208 | if (ret != 0) { |
211 | pr_err("Failed to set SSC 0 for audio: %d\n", ret); | 209 | pr_err("Failed to set SSC 0 for audio: %d\n", ret); |
212 | return ret; | 210 | return ret; |
213 | } | 211 | } |
214 | 212 | ||
215 | /* | 213 | /* |
216 | * Codec MCLK is supplied by PCK0 - set it up. | 214 | * Codec MCLK is supplied by PCK0 - set it up. |
217 | */ | 215 | */ |
218 | mclk = clk_get(NULL, "pck0"); | 216 | mclk = clk_get(NULL, "pck0"); |
219 | if (IS_ERR(mclk)) { | 217 | if (IS_ERR(mclk)) { |
220 | printk(KERN_ERR "ASoC: Failed to get MCLK\n"); | 218 | printk(KERN_ERR "ASoC: Failed to get MCLK\n"); |
221 | ret = PTR_ERR(mclk); | 219 | ret = PTR_ERR(mclk); |
222 | goto err; | 220 | goto err; |
223 | } | 221 | } |
224 | 222 | ||
225 | pllb = clk_get(NULL, "pllb"); | 223 | pllb = clk_get(NULL, "pllb"); |
226 | if (IS_ERR(pllb)) { | 224 | if (IS_ERR(pllb)) { |
227 | printk(KERN_ERR "ASoC: Failed to get PLLB\n"); | 225 | printk(KERN_ERR "ASoC: Failed to get PLLB\n"); |
228 | ret = PTR_ERR(pllb); | 226 | ret = PTR_ERR(pllb); |
229 | goto err_mclk; | 227 | goto err_mclk; |
230 | } | 228 | } |
231 | ret = clk_set_parent(mclk, pllb); | 229 | ret = clk_set_parent(mclk, pllb); |
232 | clk_put(pllb); | 230 | clk_put(pllb); |
233 | if (ret != 0) { | 231 | if (ret != 0) { |
234 | printk(KERN_ERR "ASoC: Failed to set MCLK parent\n"); | 232 | printk(KERN_ERR "ASoC: Failed to set MCLK parent\n"); |
235 | goto err_mclk; | 233 | goto err_mclk; |
236 | } | 234 | } |
237 | 235 | ||
238 | clk_set_rate(mclk, MCLK_RATE); | 236 | clk_set_rate(mclk, MCLK_RATE); |
239 | 237 | ||
240 | at91sam9g20ek_snd_device = platform_device_alloc("soc-audio", -1); | 238 | at91sam9g20ek_snd_device = platform_device_alloc("soc-audio", -1); |
241 | if (!at91sam9g20ek_snd_device) { | 239 | if (!at91sam9g20ek_snd_device) { |
242 | printk(KERN_ERR "ASoC: Platform device allocation failed\n"); | 240 | printk(KERN_ERR "ASoC: Platform device allocation failed\n"); |
243 | ret = -ENOMEM; | 241 | ret = -ENOMEM; |
244 | goto err_mclk; | 242 | goto err_mclk; |
245 | } | 243 | } |
246 | 244 | ||
247 | platform_set_drvdata(at91sam9g20ek_snd_device, | 245 | platform_set_drvdata(at91sam9g20ek_snd_device, |
248 | &snd_soc_at91sam9g20ek); | 246 | &snd_soc_at91sam9g20ek); |
249 | 247 | ||
250 | ret = platform_device_add(at91sam9g20ek_snd_device); | 248 | ret = platform_device_add(at91sam9g20ek_snd_device); |
251 | if (ret) { | 249 | if (ret) { |
252 | printk(KERN_ERR "ASoC: Platform device allocation failed\n"); | 250 | printk(KERN_ERR "ASoC: Platform device allocation failed\n"); |
253 | goto err_device_add; | 251 | goto err_device_add; |
254 | } | 252 | } |
255 | 253 | ||
256 | return ret; | 254 | return ret; |
257 | 255 | ||
258 | err_device_add: | 256 | err_device_add: |
259 | platform_device_put(at91sam9g20ek_snd_device); | 257 | platform_device_put(at91sam9g20ek_snd_device); |
260 | err_mclk: | 258 | err_mclk: |
261 | clk_put(mclk); | 259 | clk_put(mclk); |
262 | mclk = NULL; | 260 | mclk = NULL; |
263 | err: | 261 | err: |
264 | return ret; | 262 | return ret; |
265 | } | 263 | } |
266 | 264 | ||
267 | static void __exit at91sam9g20ek_exit(void) | 265 | static void __exit at91sam9g20ek_exit(void) |
268 | { | 266 | { |
269 | platform_device_unregister(at91sam9g20ek_snd_device); | 267 | platform_device_unregister(at91sam9g20ek_snd_device); |
270 | at91sam9g20ek_snd_device = NULL; | 268 | at91sam9g20ek_snd_device = NULL; |
271 | clk_put(mclk); | 269 | clk_put(mclk); |
272 | mclk = NULL; | 270 | mclk = NULL; |
273 | } | 271 | } |
274 | 272 | ||
275 | module_init(at91sam9g20ek_init); | 273 | module_init(at91sam9g20ek_init); |
276 | module_exit(at91sam9g20ek_exit); | 274 | module_exit(at91sam9g20ek_exit); |
277 | 275 | ||
278 | /* Module information */ | 276 | /* Module information */ |
279 | MODULE_AUTHOR("Sedji Gaouaou <sedji.gaouaou@atmel.com>"); | 277 | MODULE_AUTHOR("Sedji Gaouaou <sedji.gaouaou@atmel.com>"); |
280 | MODULE_DESCRIPTION("ALSA SoC AT91SAM9G20EK_WM8731"); | 278 | MODULE_DESCRIPTION("ALSA SoC AT91SAM9G20EK_WM8731"); |
281 | MODULE_LICENSE("GPL"); | 279 | MODULE_LICENSE("GPL"); |
282 | 280 |
sound/soc/atmel/snd-soc-afeb9260.c
1 | /* | 1 | /* |
2 | * afeb9260.c -- SoC audio for AFEB9260 | 2 | * afeb9260.c -- SoC audio for AFEB9260 |
3 | * | 3 | * |
4 | * Copyright (C) 2009 Sergey Lapin <slapin@ossfans.org> | 4 | * Copyright (C) 2009 Sergey Lapin <slapin@ossfans.org> |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU General Public License | 7 | * modify it under the terms of the GNU General Public License |
8 | * version 2 as published by the Free Software Foundation. | 8 | * version 2 as published by the Free Software Foundation. |
9 | * | 9 | * |
10 | * This program is distributed in the hope that it will be useful, but | 10 | * This program is distributed in the hope that it will be useful, but |
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | * General Public License for more details. | 13 | * General Public License for more details. |
14 | * | 14 | * |
15 | * You should have received a copy of the GNU General Public License | 15 | * You should have received a copy of the GNU General Public License |
16 | * along with this program; if not, write to the Free Software | 16 | * along with this program; if not, write to the Free Software |
17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | 17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA |
18 | * 02110-1301 USA | 18 | * 02110-1301 USA |
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <linux/module.h> | 22 | #include <linux/module.h> |
23 | #include <linux/moduleparam.h> | 23 | #include <linux/moduleparam.h> |
24 | #include <linux/kernel.h> | 24 | #include <linux/kernel.h> |
25 | #include <linux/clk.h> | 25 | #include <linux/clk.h> |
26 | #include <linux/platform_device.h> | 26 | #include <linux/platform_device.h> |
27 | 27 | ||
28 | #include <linux/atmel-ssc.h> | 28 | #include <linux/atmel-ssc.h> |
29 | #include <sound/core.h> | 29 | #include <sound/core.h> |
30 | #include <sound/pcm.h> | 30 | #include <sound/pcm.h> |
31 | #include <sound/pcm_params.h> | 31 | #include <sound/pcm_params.h> |
32 | #include <sound/soc.h> | 32 | #include <sound/soc.h> |
33 | 33 | ||
34 | #include <asm/mach-types.h> | 34 | #include <asm/mach-types.h> |
35 | #include <mach/hardware.h> | 35 | #include <mach/hardware.h> |
36 | #include <linux/gpio.h> | 36 | #include <linux/gpio.h> |
37 | 37 | ||
38 | #include "../codecs/tlv320aic23.h" | 38 | #include "../codecs/tlv320aic23.h" |
39 | #include "atmel-pcm.h" | 39 | #include "atmel-pcm.h" |
40 | #include "atmel_ssc_dai.h" | 40 | #include "atmel_ssc_dai.h" |
41 | 41 | ||
42 | #define CODEC_CLOCK 12000000 | 42 | #define CODEC_CLOCK 12000000 |
43 | 43 | ||
44 | static int afeb9260_hw_params(struct snd_pcm_substream *substream, | 44 | static int afeb9260_hw_params(struct snd_pcm_substream *substream, |
45 | struct snd_pcm_hw_params *params) | 45 | struct snd_pcm_hw_params *params) |
46 | { | 46 | { |
47 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 47 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
48 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 48 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
49 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 49 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
50 | int err; | 50 | int err; |
51 | 51 | ||
52 | /* Set codec DAI configuration */ | 52 | /* Set codec DAI configuration */ |
53 | err = snd_soc_dai_set_fmt(codec_dai, | 53 | err = snd_soc_dai_set_fmt(codec_dai, |
54 | SND_SOC_DAIFMT_I2S| | 54 | SND_SOC_DAIFMT_I2S| |
55 | SND_SOC_DAIFMT_NB_IF | | 55 | SND_SOC_DAIFMT_NB_IF | |
56 | SND_SOC_DAIFMT_CBM_CFM); | 56 | SND_SOC_DAIFMT_CBM_CFM); |
57 | if (err < 0) { | 57 | if (err < 0) { |
58 | printk(KERN_ERR "can't set codec DAI configuration\n"); | 58 | printk(KERN_ERR "can't set codec DAI configuration\n"); |
59 | return err; | 59 | return err; |
60 | } | 60 | } |
61 | 61 | ||
62 | /* Set cpu DAI configuration */ | 62 | /* Set cpu DAI configuration */ |
63 | err = snd_soc_dai_set_fmt(cpu_dai, | 63 | err = snd_soc_dai_set_fmt(cpu_dai, |
64 | SND_SOC_DAIFMT_I2S | | 64 | SND_SOC_DAIFMT_I2S | |
65 | SND_SOC_DAIFMT_NB_IF | | 65 | SND_SOC_DAIFMT_NB_IF | |
66 | SND_SOC_DAIFMT_CBM_CFM); | 66 | SND_SOC_DAIFMT_CBM_CFM); |
67 | if (err < 0) { | 67 | if (err < 0) { |
68 | printk(KERN_ERR "can't set cpu DAI configuration\n"); | 68 | printk(KERN_ERR "can't set cpu DAI configuration\n"); |
69 | return err; | 69 | return err; |
70 | } | 70 | } |
71 | 71 | ||
72 | /* Set the codec system clock for DAC and ADC */ | 72 | /* Set the codec system clock for DAC and ADC */ |
73 | err = | 73 | err = |
74 | snd_soc_dai_set_sysclk(codec_dai, 0, CODEC_CLOCK, SND_SOC_CLOCK_IN); | 74 | snd_soc_dai_set_sysclk(codec_dai, 0, CODEC_CLOCK, SND_SOC_CLOCK_IN); |
75 | 75 | ||
76 | if (err < 0) { | 76 | if (err < 0) { |
77 | printk(KERN_ERR "can't set codec system clock\n"); | 77 | printk(KERN_ERR "can't set codec system clock\n"); |
78 | return err; | 78 | return err; |
79 | } | 79 | } |
80 | 80 | ||
81 | return err; | 81 | return err; |
82 | } | 82 | } |
83 | 83 | ||
84 | static struct snd_soc_ops afeb9260_ops = { | 84 | static struct snd_soc_ops afeb9260_ops = { |
85 | .hw_params = afeb9260_hw_params, | 85 | .hw_params = afeb9260_hw_params, |
86 | }; | 86 | }; |
87 | 87 | ||
88 | static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = { | 88 | static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = { |
89 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | 89 | SND_SOC_DAPM_HP("Headphone Jack", NULL), |
90 | SND_SOC_DAPM_LINE("Line In", NULL), | 90 | SND_SOC_DAPM_LINE("Line In", NULL), |
91 | SND_SOC_DAPM_MIC("Mic Jack", NULL), | 91 | SND_SOC_DAPM_MIC("Mic Jack", NULL), |
92 | }; | 92 | }; |
93 | 93 | ||
94 | static const struct snd_soc_dapm_route audio_map[] = { | 94 | static const struct snd_soc_dapm_route audio_map[] = { |
95 | {"Headphone Jack", NULL, "LHPOUT"}, | 95 | {"Headphone Jack", NULL, "LHPOUT"}, |
96 | {"Headphone Jack", NULL, "RHPOUT"}, | 96 | {"Headphone Jack", NULL, "RHPOUT"}, |
97 | 97 | ||
98 | {"LLINEIN", NULL, "Line In"}, | 98 | {"LLINEIN", NULL, "Line In"}, |
99 | {"RLINEIN", NULL, "Line In"}, | 99 | {"RLINEIN", NULL, "Line In"}, |
100 | 100 | ||
101 | {"MICIN", NULL, "Mic Jack"}, | 101 | {"MICIN", NULL, "Mic Jack"}, |
102 | }; | 102 | }; |
103 | 103 | ||
104 | static int afeb9260_tlv320aic23_init(struct snd_soc_pcm_runtime *rtd) | 104 | static int afeb9260_tlv320aic23_init(struct snd_soc_pcm_runtime *rtd) |
105 | { | 105 | { |
106 | struct snd_soc_codec *codec = rtd->codec; | 106 | struct snd_soc_codec *codec = rtd->codec; |
107 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 107 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
108 | 108 | ||
109 | /* Add afeb9260 specific widgets */ | 109 | /* Add afeb9260 specific widgets */ |
110 | snd_soc_dapm_new_controls(dapm, tlv320aic23_dapm_widgets, | 110 | snd_soc_dapm_new_controls(dapm, tlv320aic23_dapm_widgets, |
111 | ARRAY_SIZE(tlv320aic23_dapm_widgets)); | 111 | ARRAY_SIZE(tlv320aic23_dapm_widgets)); |
112 | 112 | ||
113 | /* Set up afeb9260 specific audio path audio_map */ | 113 | /* Set up afeb9260 specific audio path audio_map */ |
114 | snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); | 114 | snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); |
115 | 115 | ||
116 | snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); | 116 | snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); |
117 | snd_soc_dapm_enable_pin(dapm, "Line In"); | 117 | snd_soc_dapm_enable_pin(dapm, "Line In"); |
118 | snd_soc_dapm_enable_pin(dapm, "Mic Jack"); | 118 | snd_soc_dapm_enable_pin(dapm, "Mic Jack"); |
119 | 119 | ||
120 | snd_soc_dapm_sync(dapm); | ||
121 | |||
122 | return 0; | 120 | return 0; |
123 | } | 121 | } |
124 | 122 | ||
125 | /* Digital audio interface glue - connects codec <--> CPU */ | 123 | /* Digital audio interface glue - connects codec <--> CPU */ |
126 | static struct snd_soc_dai_link afeb9260_dai = { | 124 | static struct snd_soc_dai_link afeb9260_dai = { |
127 | .name = "TLV320AIC23", | 125 | .name = "TLV320AIC23", |
128 | .stream_name = "AIC23", | 126 | .stream_name = "AIC23", |
129 | .cpu_dai_name = "atmel-ssc-dai.0", | 127 | .cpu_dai_name = "atmel-ssc-dai.0", |
130 | .codec_dai_name = "tlv320aic23-hifi", | 128 | .codec_dai_name = "tlv320aic23-hifi", |
131 | .platform_name = "atmel_pcm-audio", | 129 | .platform_name = "atmel_pcm-audio", |
132 | .codec_name = "tlv320aic23-codec.0-001a", | 130 | .codec_name = "tlv320aic23-codec.0-001a", |
133 | .init = afeb9260_tlv320aic23_init, | 131 | .init = afeb9260_tlv320aic23_init, |
134 | .ops = &afeb9260_ops, | 132 | .ops = &afeb9260_ops, |
135 | }; | 133 | }; |
136 | 134 | ||
137 | /* Audio machine driver */ | 135 | /* Audio machine driver */ |
138 | static struct snd_soc_card snd_soc_machine_afeb9260 = { | 136 | static struct snd_soc_card snd_soc_machine_afeb9260 = { |
139 | .name = "AFEB9260", | 137 | .name = "AFEB9260", |
140 | .dai_link = &afeb9260_dai, | 138 | .dai_link = &afeb9260_dai, |
141 | .num_links = 1, | 139 | .num_links = 1, |
142 | }; | 140 | }; |
143 | 141 | ||
144 | static struct platform_device *afeb9260_snd_device; | 142 | static struct platform_device *afeb9260_snd_device; |
145 | 143 | ||
146 | static int __init afeb9260_soc_init(void) | 144 | static int __init afeb9260_soc_init(void) |
147 | { | 145 | { |
148 | int err; | 146 | int err; |
149 | struct device *dev; | 147 | struct device *dev; |
150 | 148 | ||
151 | if (!(machine_is_afeb9260())) | 149 | if (!(machine_is_afeb9260())) |
152 | return -ENODEV; | 150 | return -ENODEV; |
153 | 151 | ||
154 | 152 | ||
155 | afeb9260_snd_device = platform_device_alloc("soc-audio", -1); | 153 | afeb9260_snd_device = platform_device_alloc("soc-audio", -1); |
156 | if (!afeb9260_snd_device) { | 154 | if (!afeb9260_snd_device) { |
157 | printk(KERN_ERR "ASoC: Platform device allocation failed\n"); | 155 | printk(KERN_ERR "ASoC: Platform device allocation failed\n"); |
158 | return -ENOMEM; | 156 | return -ENOMEM; |
159 | } | 157 | } |
160 | 158 | ||
161 | platform_set_drvdata(afeb9260_snd_device, &snd_soc_machine_afeb9260); | 159 | platform_set_drvdata(afeb9260_snd_device, &snd_soc_machine_afeb9260); |
162 | err = platform_device_add(afeb9260_snd_device); | 160 | err = platform_device_add(afeb9260_snd_device); |
163 | if (err) | 161 | if (err) |
164 | goto err1; | 162 | goto err1; |
165 | 163 | ||
166 | dev = &afeb9260_snd_device->dev; | 164 | dev = &afeb9260_snd_device->dev; |
167 | 165 | ||
168 | return 0; | 166 | return 0; |
169 | err1: | 167 | err1: |
170 | platform_device_put(afeb9260_snd_device); | 168 | platform_device_put(afeb9260_snd_device); |
171 | return err; | 169 | return err; |
172 | } | 170 | } |
173 | 171 | ||
174 | static void __exit afeb9260_soc_exit(void) | 172 | static void __exit afeb9260_soc_exit(void) |
175 | { | 173 | { |
176 | platform_device_unregister(afeb9260_snd_device); | 174 | platform_device_unregister(afeb9260_snd_device); |
177 | } | 175 | } |
178 | 176 | ||
179 | module_init(afeb9260_soc_init); | 177 | module_init(afeb9260_soc_init); |
180 | module_exit(afeb9260_soc_exit); | 178 | module_exit(afeb9260_soc_exit); |
181 | 179 | ||
182 | MODULE_AUTHOR("Sergey Lapin <slapin@ossfans.org>"); | 180 | MODULE_AUTHOR("Sergey Lapin <slapin@ossfans.org>"); |
183 | MODULE_DESCRIPTION("ALSA SoC for AFEB9260"); | 181 | MODULE_DESCRIPTION("ALSA SoC for AFEB9260"); |
184 | MODULE_LICENSE("GPL"); | 182 | MODULE_LICENSE("GPL"); |
185 | 183 | ||
186 | 184 |
sound/soc/davinci/davinci-evm.c
1 | /* | 1 | /* |
2 | * ASoC driver for TI DAVINCI EVM platform | 2 | * ASoC driver for TI DAVINCI EVM platform |
3 | * | 3 | * |
4 | * Author: Vladimir Barinov, <vbarinov@embeddedalley.com> | 4 | * Author: Vladimir Barinov, <vbarinov@embeddedalley.com> |
5 | * Copyright: (C) 2007 MontaVista Software, Inc., <source@mvista.com> | 5 | * Copyright: (C) 2007 MontaVista Software, Inc., <source@mvista.com> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License version 2 as | 8 | * it under the terms of the GNU General Public License version 2 as |
9 | * published by the Free Software Foundation. | 9 | * published by the Free Software Foundation. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
13 | #include <linux/moduleparam.h> | 13 | #include <linux/moduleparam.h> |
14 | #include <linux/timer.h> | 14 | #include <linux/timer.h> |
15 | #include <linux/interrupt.h> | 15 | #include <linux/interrupt.h> |
16 | #include <linux/platform_device.h> | 16 | #include <linux/platform_device.h> |
17 | #include <linux/i2c.h> | 17 | #include <linux/i2c.h> |
18 | #include <sound/core.h> | 18 | #include <sound/core.h> |
19 | #include <sound/pcm.h> | 19 | #include <sound/pcm.h> |
20 | #include <sound/soc.h> | 20 | #include <sound/soc.h> |
21 | 21 | ||
22 | #include <asm/dma.h> | 22 | #include <asm/dma.h> |
23 | #include <asm/mach-types.h> | 23 | #include <asm/mach-types.h> |
24 | 24 | ||
25 | #include <mach/asp.h> | 25 | #include <mach/asp.h> |
26 | #include <mach/edma.h> | 26 | #include <mach/edma.h> |
27 | #include <mach/mux.h> | 27 | #include <mach/mux.h> |
28 | 28 | ||
29 | #include "davinci-pcm.h" | 29 | #include "davinci-pcm.h" |
30 | #include "davinci-i2s.h" | 30 | #include "davinci-i2s.h" |
31 | #include "davinci-mcasp.h" | 31 | #include "davinci-mcasp.h" |
32 | 32 | ||
33 | #define AUDIO_FORMAT (SND_SOC_DAIFMT_DSP_B | \ | 33 | #define AUDIO_FORMAT (SND_SOC_DAIFMT_DSP_B | \ |
34 | SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF) | 34 | SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF) |
35 | static int evm_hw_params(struct snd_pcm_substream *substream, | 35 | static int evm_hw_params(struct snd_pcm_substream *substream, |
36 | struct snd_pcm_hw_params *params) | 36 | struct snd_pcm_hw_params *params) |
37 | { | 37 | { |
38 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 38 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
39 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 39 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
40 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 40 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
41 | int ret = 0; | 41 | int ret = 0; |
42 | unsigned sysclk; | 42 | unsigned sysclk; |
43 | 43 | ||
44 | /* ASP1 on DM355 EVM is clocked by an external oscillator */ | 44 | /* ASP1 on DM355 EVM is clocked by an external oscillator */ |
45 | if (machine_is_davinci_dm355_evm() || machine_is_davinci_dm6467_evm() || | 45 | if (machine_is_davinci_dm355_evm() || machine_is_davinci_dm6467_evm() || |
46 | machine_is_davinci_dm365_evm()) | 46 | machine_is_davinci_dm365_evm()) |
47 | sysclk = 27000000; | 47 | sysclk = 27000000; |
48 | 48 | ||
49 | /* ASP0 in DM6446 EVM is clocked by U55, as configured by | 49 | /* ASP0 in DM6446 EVM is clocked by U55, as configured by |
50 | * board-dm644x-evm.c using GPIOs from U18. There are six | 50 | * board-dm644x-evm.c using GPIOs from U18. There are six |
51 | * options; here we "know" we use a 48 KHz sample rate. | 51 | * options; here we "know" we use a 48 KHz sample rate. |
52 | */ | 52 | */ |
53 | else if (machine_is_davinci_evm()) | 53 | else if (machine_is_davinci_evm()) |
54 | sysclk = 12288000; | 54 | sysclk = 12288000; |
55 | 55 | ||
56 | else if (machine_is_davinci_da830_evm() || | 56 | else if (machine_is_davinci_da830_evm() || |
57 | machine_is_davinci_da850_evm()) | 57 | machine_is_davinci_da850_evm()) |
58 | sysclk = 24576000; | 58 | sysclk = 24576000; |
59 | 59 | ||
60 | else | 60 | else |
61 | return -EINVAL; | 61 | return -EINVAL; |
62 | 62 | ||
63 | /* set codec DAI configuration */ | 63 | /* set codec DAI configuration */ |
64 | ret = snd_soc_dai_set_fmt(codec_dai, AUDIO_FORMAT); | 64 | ret = snd_soc_dai_set_fmt(codec_dai, AUDIO_FORMAT); |
65 | if (ret < 0) | 65 | if (ret < 0) |
66 | return ret; | 66 | return ret; |
67 | 67 | ||
68 | /* set cpu DAI configuration */ | 68 | /* set cpu DAI configuration */ |
69 | ret = snd_soc_dai_set_fmt(cpu_dai, AUDIO_FORMAT); | 69 | ret = snd_soc_dai_set_fmt(cpu_dai, AUDIO_FORMAT); |
70 | if (ret < 0) | 70 | if (ret < 0) |
71 | return ret; | 71 | return ret; |
72 | 72 | ||
73 | /* set the codec system clock */ | 73 | /* set the codec system clock */ |
74 | ret = snd_soc_dai_set_sysclk(codec_dai, 0, sysclk, SND_SOC_CLOCK_OUT); | 74 | ret = snd_soc_dai_set_sysclk(codec_dai, 0, sysclk, SND_SOC_CLOCK_OUT); |
75 | if (ret < 0) | 75 | if (ret < 0) |
76 | return ret; | 76 | return ret; |
77 | 77 | ||
78 | return 0; | 78 | return 0; |
79 | } | 79 | } |
80 | 80 | ||
81 | static int evm_spdif_hw_params(struct snd_pcm_substream *substream, | 81 | static int evm_spdif_hw_params(struct snd_pcm_substream *substream, |
82 | struct snd_pcm_hw_params *params) | 82 | struct snd_pcm_hw_params *params) |
83 | { | 83 | { |
84 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 84 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
85 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 85 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
86 | 86 | ||
87 | /* set cpu DAI configuration */ | 87 | /* set cpu DAI configuration */ |
88 | return snd_soc_dai_set_fmt(cpu_dai, AUDIO_FORMAT); | 88 | return snd_soc_dai_set_fmt(cpu_dai, AUDIO_FORMAT); |
89 | } | 89 | } |
90 | 90 | ||
91 | static struct snd_soc_ops evm_ops = { | 91 | static struct snd_soc_ops evm_ops = { |
92 | .hw_params = evm_hw_params, | 92 | .hw_params = evm_hw_params, |
93 | }; | 93 | }; |
94 | 94 | ||
95 | static struct snd_soc_ops evm_spdif_ops = { | 95 | static struct snd_soc_ops evm_spdif_ops = { |
96 | .hw_params = evm_spdif_hw_params, | 96 | .hw_params = evm_spdif_hw_params, |
97 | }; | 97 | }; |
98 | 98 | ||
99 | /* davinci-evm machine dapm widgets */ | 99 | /* davinci-evm machine dapm widgets */ |
100 | static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { | 100 | static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { |
101 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | 101 | SND_SOC_DAPM_HP("Headphone Jack", NULL), |
102 | SND_SOC_DAPM_LINE("Line Out", NULL), | 102 | SND_SOC_DAPM_LINE("Line Out", NULL), |
103 | SND_SOC_DAPM_MIC("Mic Jack", NULL), | 103 | SND_SOC_DAPM_MIC("Mic Jack", NULL), |
104 | SND_SOC_DAPM_LINE("Line In", NULL), | 104 | SND_SOC_DAPM_LINE("Line In", NULL), |
105 | }; | 105 | }; |
106 | 106 | ||
107 | /* davinci-evm machine audio_mapnections to the codec pins */ | 107 | /* davinci-evm machine audio_mapnections to the codec pins */ |
108 | static const struct snd_soc_dapm_route audio_map[] = { | 108 | static const struct snd_soc_dapm_route audio_map[] = { |
109 | /* Headphone connected to HPLOUT, HPROUT */ | 109 | /* Headphone connected to HPLOUT, HPROUT */ |
110 | {"Headphone Jack", NULL, "HPLOUT"}, | 110 | {"Headphone Jack", NULL, "HPLOUT"}, |
111 | {"Headphone Jack", NULL, "HPROUT"}, | 111 | {"Headphone Jack", NULL, "HPROUT"}, |
112 | 112 | ||
113 | /* Line Out connected to LLOUT, RLOUT */ | 113 | /* Line Out connected to LLOUT, RLOUT */ |
114 | {"Line Out", NULL, "LLOUT"}, | 114 | {"Line Out", NULL, "LLOUT"}, |
115 | {"Line Out", NULL, "RLOUT"}, | 115 | {"Line Out", NULL, "RLOUT"}, |
116 | 116 | ||
117 | /* Mic connected to (MIC3L | MIC3R) */ | 117 | /* Mic connected to (MIC3L | MIC3R) */ |
118 | {"MIC3L", NULL, "Mic Bias 2V"}, | 118 | {"MIC3L", NULL, "Mic Bias 2V"}, |
119 | {"MIC3R", NULL, "Mic Bias 2V"}, | 119 | {"MIC3R", NULL, "Mic Bias 2V"}, |
120 | {"Mic Bias 2V", NULL, "Mic Jack"}, | 120 | {"Mic Bias 2V", NULL, "Mic Jack"}, |
121 | 121 | ||
122 | /* Line In connected to (LINE1L | LINE2L), (LINE1R | LINE2R) */ | 122 | /* Line In connected to (LINE1L | LINE2L), (LINE1R | LINE2R) */ |
123 | {"LINE1L", NULL, "Line In"}, | 123 | {"LINE1L", NULL, "Line In"}, |
124 | {"LINE2L", NULL, "Line In"}, | 124 | {"LINE2L", NULL, "Line In"}, |
125 | {"LINE1R", NULL, "Line In"}, | 125 | {"LINE1R", NULL, "Line In"}, |
126 | {"LINE2R", NULL, "Line In"}, | 126 | {"LINE2R", NULL, "Line In"}, |
127 | }; | 127 | }; |
128 | 128 | ||
129 | /* Logic for a aic3x as connected on a davinci-evm */ | 129 | /* Logic for a aic3x as connected on a davinci-evm */ |
130 | static int evm_aic3x_init(struct snd_soc_pcm_runtime *rtd) | 130 | static int evm_aic3x_init(struct snd_soc_pcm_runtime *rtd) |
131 | { | 131 | { |
132 | struct snd_soc_codec *codec = rtd->codec; | 132 | struct snd_soc_codec *codec = rtd->codec; |
133 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 133 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
134 | 134 | ||
135 | /* Add davinci-evm specific widgets */ | 135 | /* Add davinci-evm specific widgets */ |
136 | snd_soc_dapm_new_controls(dapm, aic3x_dapm_widgets, | 136 | snd_soc_dapm_new_controls(dapm, aic3x_dapm_widgets, |
137 | ARRAY_SIZE(aic3x_dapm_widgets)); | 137 | ARRAY_SIZE(aic3x_dapm_widgets)); |
138 | 138 | ||
139 | /* Set up davinci-evm specific audio path audio_map */ | 139 | /* Set up davinci-evm specific audio path audio_map */ |
140 | snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); | 140 | snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); |
141 | 141 | ||
142 | /* not connected */ | 142 | /* not connected */ |
143 | snd_soc_dapm_disable_pin(dapm, "MONO_LOUT"); | 143 | snd_soc_dapm_disable_pin(dapm, "MONO_LOUT"); |
144 | snd_soc_dapm_disable_pin(dapm, "HPLCOM"); | 144 | snd_soc_dapm_disable_pin(dapm, "HPLCOM"); |
145 | snd_soc_dapm_disable_pin(dapm, "HPRCOM"); | 145 | snd_soc_dapm_disable_pin(dapm, "HPRCOM"); |
146 | 146 | ||
147 | /* always connected */ | 147 | /* always connected */ |
148 | snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); | 148 | snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); |
149 | snd_soc_dapm_enable_pin(dapm, "Line Out"); | 149 | snd_soc_dapm_enable_pin(dapm, "Line Out"); |
150 | snd_soc_dapm_enable_pin(dapm, "Mic Jack"); | 150 | snd_soc_dapm_enable_pin(dapm, "Mic Jack"); |
151 | snd_soc_dapm_enable_pin(dapm, "Line In"); | 151 | snd_soc_dapm_enable_pin(dapm, "Line In"); |
152 | 152 | ||
153 | snd_soc_dapm_sync(dapm); | ||
154 | |||
155 | return 0; | 153 | return 0; |
156 | } | 154 | } |
157 | 155 | ||
158 | /* davinci-evm digital audio interface glue - connects codec <--> CPU */ | 156 | /* davinci-evm digital audio interface glue - connects codec <--> CPU */ |
159 | static struct snd_soc_dai_link dm6446_evm_dai = { | 157 | static struct snd_soc_dai_link dm6446_evm_dai = { |
160 | .name = "TLV320AIC3X", | 158 | .name = "TLV320AIC3X", |
161 | .stream_name = "AIC3X", | 159 | .stream_name = "AIC3X", |
162 | .cpu_dai_name = "davinci-mcbsp", | 160 | .cpu_dai_name = "davinci-mcbsp", |
163 | .codec_dai_name = "tlv320aic3x-hifi", | 161 | .codec_dai_name = "tlv320aic3x-hifi", |
164 | .codec_name = "tlv320aic3x-codec.1-001b", | 162 | .codec_name = "tlv320aic3x-codec.1-001b", |
165 | .platform_name = "davinci-pcm-audio", | 163 | .platform_name = "davinci-pcm-audio", |
166 | .init = evm_aic3x_init, | 164 | .init = evm_aic3x_init, |
167 | .ops = &evm_ops, | 165 | .ops = &evm_ops, |
168 | }; | 166 | }; |
169 | 167 | ||
170 | static struct snd_soc_dai_link dm355_evm_dai = { | 168 | static struct snd_soc_dai_link dm355_evm_dai = { |
171 | .name = "TLV320AIC3X", | 169 | .name = "TLV320AIC3X", |
172 | .stream_name = "AIC3X", | 170 | .stream_name = "AIC3X", |
173 | .cpu_dai_name = "davinci-mcbsp.1", | 171 | .cpu_dai_name = "davinci-mcbsp.1", |
174 | .codec_dai_name = "tlv320aic3x-hifi", | 172 | .codec_dai_name = "tlv320aic3x-hifi", |
175 | .codec_name = "tlv320aic3x-codec.1-001b", | 173 | .codec_name = "tlv320aic3x-codec.1-001b", |
176 | .platform_name = "davinci-pcm-audio", | 174 | .platform_name = "davinci-pcm-audio", |
177 | .init = evm_aic3x_init, | 175 | .init = evm_aic3x_init, |
178 | .ops = &evm_ops, | 176 | .ops = &evm_ops, |
179 | }; | 177 | }; |
180 | 178 | ||
181 | static struct snd_soc_dai_link dm365_evm_dai = { | 179 | static struct snd_soc_dai_link dm365_evm_dai = { |
182 | #ifdef CONFIG_SND_DM365_AIC3X_CODEC | 180 | #ifdef CONFIG_SND_DM365_AIC3X_CODEC |
183 | .name = "TLV320AIC3X", | 181 | .name = "TLV320AIC3X", |
184 | .stream_name = "AIC3X", | 182 | .stream_name = "AIC3X", |
185 | .cpu_dai_name = "davinci-mcbsp", | 183 | .cpu_dai_name = "davinci-mcbsp", |
186 | .codec_dai_name = "tlv320aic3x-hifi", | 184 | .codec_dai_name = "tlv320aic3x-hifi", |
187 | .init = evm_aic3x_init, | 185 | .init = evm_aic3x_init, |
188 | .codec_name = "tlv320aic3x-codec.1-0018", | 186 | .codec_name = "tlv320aic3x-codec.1-0018", |
189 | .ops = &evm_ops, | 187 | .ops = &evm_ops, |
190 | #elif defined(CONFIG_SND_DM365_VOICE_CODEC) | 188 | #elif defined(CONFIG_SND_DM365_VOICE_CODEC) |
191 | .name = "Voice Codec - CQ93VC", | 189 | .name = "Voice Codec - CQ93VC", |
192 | .stream_name = "CQ93", | 190 | .stream_name = "CQ93", |
193 | .cpu_dai_name = "davinci-vcif", | 191 | .cpu_dai_name = "davinci-vcif", |
194 | .codec_dai_name = "cq93vc-hifi", | 192 | .codec_dai_name = "cq93vc-hifi", |
195 | .codec_name = "cq93vc-codec", | 193 | .codec_name = "cq93vc-codec", |
196 | #endif | 194 | #endif |
197 | .platform_name = "davinci-pcm-audio", | 195 | .platform_name = "davinci-pcm-audio", |
198 | }; | 196 | }; |
199 | 197 | ||
200 | static struct snd_soc_dai_link dm6467_evm_dai[] = { | 198 | static struct snd_soc_dai_link dm6467_evm_dai[] = { |
201 | { | 199 | { |
202 | .name = "TLV320AIC3X", | 200 | .name = "TLV320AIC3X", |
203 | .stream_name = "AIC3X", | 201 | .stream_name = "AIC3X", |
204 | .cpu_dai_name= "davinci-mcasp.0", | 202 | .cpu_dai_name= "davinci-mcasp.0", |
205 | .codec_dai_name = "tlv320aic3x-hifi", | 203 | .codec_dai_name = "tlv320aic3x-hifi", |
206 | .platform_name ="davinci-pcm-audio", | 204 | .platform_name ="davinci-pcm-audio", |
207 | .codec_name = "tlv320aic3x-codec.0-001a", | 205 | .codec_name = "tlv320aic3x-codec.0-001a", |
208 | .init = evm_aic3x_init, | 206 | .init = evm_aic3x_init, |
209 | .ops = &evm_ops, | 207 | .ops = &evm_ops, |
210 | }, | 208 | }, |
211 | { | 209 | { |
212 | .name = "McASP", | 210 | .name = "McASP", |
213 | .stream_name = "spdif", | 211 | .stream_name = "spdif", |
214 | .cpu_dai_name= "davinci-mcasp.1", | 212 | .cpu_dai_name= "davinci-mcasp.1", |
215 | .codec_dai_name = "dit-hifi", | 213 | .codec_dai_name = "dit-hifi", |
216 | .codec_name = "spdif_dit", | 214 | .codec_name = "spdif_dit", |
217 | .platform_name = "davinci-pcm-audio", | 215 | .platform_name = "davinci-pcm-audio", |
218 | .ops = &evm_spdif_ops, | 216 | .ops = &evm_spdif_ops, |
219 | }, | 217 | }, |
220 | }; | 218 | }; |
221 | 219 | ||
222 | static struct snd_soc_dai_link da830_evm_dai = { | 220 | static struct snd_soc_dai_link da830_evm_dai = { |
223 | .name = "TLV320AIC3X", | 221 | .name = "TLV320AIC3X", |
224 | .stream_name = "AIC3X", | 222 | .stream_name = "AIC3X", |
225 | .cpu_dai_name = "davinci-mcasp.1", | 223 | .cpu_dai_name = "davinci-mcasp.1", |
226 | .codec_dai_name = "tlv320aic3x-hifi", | 224 | .codec_dai_name = "tlv320aic3x-hifi", |
227 | .codec_name = "tlv320aic3x-codec.1-0018", | 225 | .codec_name = "tlv320aic3x-codec.1-0018", |
228 | .platform_name = "davinci-pcm-audio", | 226 | .platform_name = "davinci-pcm-audio", |
229 | .init = evm_aic3x_init, | 227 | .init = evm_aic3x_init, |
230 | .ops = &evm_ops, | 228 | .ops = &evm_ops, |
231 | }; | 229 | }; |
232 | 230 | ||
233 | static struct snd_soc_dai_link da850_evm_dai = { | 231 | static struct snd_soc_dai_link da850_evm_dai = { |
234 | .name = "TLV320AIC3X", | 232 | .name = "TLV320AIC3X", |
235 | .stream_name = "AIC3X", | 233 | .stream_name = "AIC3X", |
236 | .cpu_dai_name= "davinci-mcasp.0", | 234 | .cpu_dai_name= "davinci-mcasp.0", |
237 | .codec_dai_name = "tlv320aic3x-hifi", | 235 | .codec_dai_name = "tlv320aic3x-hifi", |
238 | .codec_name = "tlv320aic3x-codec.1-0018", | 236 | .codec_name = "tlv320aic3x-codec.1-0018", |
239 | .platform_name = "davinci-pcm-audio", | 237 | .platform_name = "davinci-pcm-audio", |
240 | .init = evm_aic3x_init, | 238 | .init = evm_aic3x_init, |
241 | .ops = &evm_ops, | 239 | .ops = &evm_ops, |
242 | }; | 240 | }; |
243 | 241 | ||
244 | /* davinci dm6446 evm audio machine driver */ | 242 | /* davinci dm6446 evm audio machine driver */ |
245 | static struct snd_soc_card dm6446_snd_soc_card_evm = { | 243 | static struct snd_soc_card dm6446_snd_soc_card_evm = { |
246 | .name = "DaVinci DM6446 EVM", | 244 | .name = "DaVinci DM6446 EVM", |
247 | .dai_link = &dm6446_evm_dai, | 245 | .dai_link = &dm6446_evm_dai, |
248 | .num_links = 1, | 246 | .num_links = 1, |
249 | }; | 247 | }; |
250 | 248 | ||
251 | /* davinci dm355 evm audio machine driver */ | 249 | /* davinci dm355 evm audio machine driver */ |
252 | static struct snd_soc_card dm355_snd_soc_card_evm = { | 250 | static struct snd_soc_card dm355_snd_soc_card_evm = { |
253 | .name = "DaVinci DM355 EVM", | 251 | .name = "DaVinci DM355 EVM", |
254 | .dai_link = &dm355_evm_dai, | 252 | .dai_link = &dm355_evm_dai, |
255 | .num_links = 1, | 253 | .num_links = 1, |
256 | }; | 254 | }; |
257 | 255 | ||
258 | /* davinci dm365 evm audio machine driver */ | 256 | /* davinci dm365 evm audio machine driver */ |
259 | static struct snd_soc_card dm365_snd_soc_card_evm = { | 257 | static struct snd_soc_card dm365_snd_soc_card_evm = { |
260 | .name = "DaVinci DM365 EVM", | 258 | .name = "DaVinci DM365 EVM", |
261 | .dai_link = &dm365_evm_dai, | 259 | .dai_link = &dm365_evm_dai, |
262 | .num_links = 1, | 260 | .num_links = 1, |
263 | }; | 261 | }; |
264 | 262 | ||
265 | /* davinci dm6467 evm audio machine driver */ | 263 | /* davinci dm6467 evm audio machine driver */ |
266 | static struct snd_soc_card dm6467_snd_soc_card_evm = { | 264 | static struct snd_soc_card dm6467_snd_soc_card_evm = { |
267 | .name = "DaVinci DM6467 EVM", | 265 | .name = "DaVinci DM6467 EVM", |
268 | .dai_link = dm6467_evm_dai, | 266 | .dai_link = dm6467_evm_dai, |
269 | .num_links = ARRAY_SIZE(dm6467_evm_dai), | 267 | .num_links = ARRAY_SIZE(dm6467_evm_dai), |
270 | }; | 268 | }; |
271 | 269 | ||
272 | static struct snd_soc_card da830_snd_soc_card = { | 270 | static struct snd_soc_card da830_snd_soc_card = { |
273 | .name = "DA830/OMAP-L137 EVM", | 271 | .name = "DA830/OMAP-L137 EVM", |
274 | .dai_link = &da830_evm_dai, | 272 | .dai_link = &da830_evm_dai, |
275 | .num_links = 1, | 273 | .num_links = 1, |
276 | }; | 274 | }; |
277 | 275 | ||
278 | static struct snd_soc_card da850_snd_soc_card = { | 276 | static struct snd_soc_card da850_snd_soc_card = { |
279 | .name = "DA850/OMAP-L138 EVM", | 277 | .name = "DA850/OMAP-L138 EVM", |
280 | .dai_link = &da850_evm_dai, | 278 | .dai_link = &da850_evm_dai, |
281 | .num_links = 1, | 279 | .num_links = 1, |
282 | }; | 280 | }; |
283 | 281 | ||
284 | static struct platform_device *evm_snd_device; | 282 | static struct platform_device *evm_snd_device; |
285 | 283 | ||
286 | static int __init evm_init(void) | 284 | static int __init evm_init(void) |
287 | { | 285 | { |
288 | struct snd_soc_card *evm_snd_dev_data; | 286 | struct snd_soc_card *evm_snd_dev_data; |
289 | int index; | 287 | int index; |
290 | int ret; | 288 | int ret; |
291 | 289 | ||
292 | if (machine_is_davinci_evm()) { | 290 | if (machine_is_davinci_evm()) { |
293 | evm_snd_dev_data = &dm6446_snd_soc_card_evm; | 291 | evm_snd_dev_data = &dm6446_snd_soc_card_evm; |
294 | index = 0; | 292 | index = 0; |
295 | } else if (machine_is_davinci_dm355_evm()) { | 293 | } else if (machine_is_davinci_dm355_evm()) { |
296 | evm_snd_dev_data = &dm355_snd_soc_card_evm; | 294 | evm_snd_dev_data = &dm355_snd_soc_card_evm; |
297 | index = 1; | 295 | index = 1; |
298 | } else if (machine_is_davinci_dm365_evm()) { | 296 | } else if (machine_is_davinci_dm365_evm()) { |
299 | evm_snd_dev_data = &dm365_snd_soc_card_evm; | 297 | evm_snd_dev_data = &dm365_snd_soc_card_evm; |
300 | index = 0; | 298 | index = 0; |
301 | } else if (machine_is_davinci_dm6467_evm()) { | 299 | } else if (machine_is_davinci_dm6467_evm()) { |
302 | evm_snd_dev_data = &dm6467_snd_soc_card_evm; | 300 | evm_snd_dev_data = &dm6467_snd_soc_card_evm; |
303 | index = 0; | 301 | index = 0; |
304 | } else if (machine_is_davinci_da830_evm()) { | 302 | } else if (machine_is_davinci_da830_evm()) { |
305 | evm_snd_dev_data = &da830_snd_soc_card; | 303 | evm_snd_dev_data = &da830_snd_soc_card; |
306 | index = 1; | 304 | index = 1; |
307 | } else if (machine_is_davinci_da850_evm()) { | 305 | } else if (machine_is_davinci_da850_evm()) { |
308 | evm_snd_dev_data = &da850_snd_soc_card; | 306 | evm_snd_dev_data = &da850_snd_soc_card; |
309 | index = 0; | 307 | index = 0; |
310 | } else | 308 | } else |
311 | return -EINVAL; | 309 | return -EINVAL; |
312 | 310 | ||
313 | evm_snd_device = platform_device_alloc("soc-audio", index); | 311 | evm_snd_device = platform_device_alloc("soc-audio", index); |
314 | if (!evm_snd_device) | 312 | if (!evm_snd_device) |
315 | return -ENOMEM; | 313 | return -ENOMEM; |
316 | 314 | ||
317 | platform_set_drvdata(evm_snd_device, evm_snd_dev_data); | 315 | platform_set_drvdata(evm_snd_device, evm_snd_dev_data); |
318 | ret = platform_device_add(evm_snd_device); | 316 | ret = platform_device_add(evm_snd_device); |
319 | if (ret) | 317 | if (ret) |
320 | platform_device_put(evm_snd_device); | 318 | platform_device_put(evm_snd_device); |
321 | 319 | ||
322 | return ret; | 320 | return ret; |
323 | } | 321 | } |
324 | 322 | ||
325 | static void __exit evm_exit(void) | 323 | static void __exit evm_exit(void) |
326 | { | 324 | { |
327 | platform_device_unregister(evm_snd_device); | 325 | platform_device_unregister(evm_snd_device); |
328 | } | 326 | } |
329 | 327 | ||
330 | module_init(evm_init); | 328 | module_init(evm_init); |
331 | module_exit(evm_exit); | 329 | module_exit(evm_exit); |
332 | 330 | ||
333 | MODULE_AUTHOR("Vladimir Barinov"); | 331 | MODULE_AUTHOR("Vladimir Barinov"); |
334 | MODULE_DESCRIPTION("TI DAVINCI EVM ASoC driver"); | 332 | MODULE_DESCRIPTION("TI DAVINCI EVM ASoC driver"); |
335 | MODULE_LICENSE("GPL"); | 333 | MODULE_LICENSE("GPL"); |
336 | 334 |
sound/soc/kirkwood/kirkwood-t5325.c
1 | /* | 1 | /* |
2 | * kirkwood-t5325.c | 2 | * kirkwood-t5325.c |
3 | * | 3 | * |
4 | * (c) 2010 Arnaud Patard <arnaud.patard@rtp-net.org> | 4 | * (c) 2010 Arnaud Patard <arnaud.patard@rtp-net.org> |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify it | 6 | * This program is free software; you can redistribute it and/or modify it |
7 | * under the terms of the GNU General Public License as published by the | 7 | * under the terms of the GNU General Public License as published by the |
8 | * Free Software Foundation; either version 2 of the License, or (at your | 8 | * Free Software Foundation; either version 2 of the License, or (at your |
9 | * option) any later version. | 9 | * option) any later version. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
13 | #include <linux/moduleparam.h> | 13 | #include <linux/moduleparam.h> |
14 | #include <linux/interrupt.h> | 14 | #include <linux/interrupt.h> |
15 | #include <linux/platform_device.h> | 15 | #include <linux/platform_device.h> |
16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
17 | #include <sound/soc.h> | 17 | #include <sound/soc.h> |
18 | #include <mach/kirkwood.h> | 18 | #include <mach/kirkwood.h> |
19 | #include <plat/audio.h> | 19 | #include <plat/audio.h> |
20 | #include <asm/mach-types.h> | 20 | #include <asm/mach-types.h> |
21 | #include "../codecs/alc5623.h" | 21 | #include "../codecs/alc5623.h" |
22 | 22 | ||
23 | static int t5325_hw_params(struct snd_pcm_substream *substream, | 23 | static int t5325_hw_params(struct snd_pcm_substream *substream, |
24 | struct snd_pcm_hw_params *params) | 24 | struct snd_pcm_hw_params *params) |
25 | { | 25 | { |
26 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 26 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
27 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 27 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
28 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 28 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
29 | int ret; | 29 | int ret; |
30 | unsigned int freq, fmt; | 30 | unsigned int freq, fmt; |
31 | 31 | ||
32 | fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS; | 32 | fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS; |
33 | ret = snd_soc_dai_set_fmt(cpu_dai, fmt); | 33 | ret = snd_soc_dai_set_fmt(cpu_dai, fmt); |
34 | if (ret < 0) | 34 | if (ret < 0) |
35 | return ret; | 35 | return ret; |
36 | 36 | ||
37 | ret = snd_soc_dai_set_fmt(codec_dai, fmt); | 37 | ret = snd_soc_dai_set_fmt(codec_dai, fmt); |
38 | if (ret < 0) | 38 | if (ret < 0) |
39 | return ret; | 39 | return ret; |
40 | 40 | ||
41 | freq = params_rate(params) * 256; | 41 | freq = params_rate(params) * 256; |
42 | 42 | ||
43 | return snd_soc_dai_set_sysclk(codec_dai, 0, freq, SND_SOC_CLOCK_IN); | 43 | return snd_soc_dai_set_sysclk(codec_dai, 0, freq, SND_SOC_CLOCK_IN); |
44 | 44 | ||
45 | } | 45 | } |
46 | 46 | ||
47 | static struct snd_soc_ops t5325_ops = { | 47 | static struct snd_soc_ops t5325_ops = { |
48 | .hw_params = t5325_hw_params, | 48 | .hw_params = t5325_hw_params, |
49 | }; | 49 | }; |
50 | 50 | ||
51 | static const struct snd_soc_dapm_widget t5325_dapm_widgets[] = { | 51 | static const struct snd_soc_dapm_widget t5325_dapm_widgets[] = { |
52 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | 52 | SND_SOC_DAPM_HP("Headphone Jack", NULL), |
53 | SND_SOC_DAPM_SPK("Speaker", NULL), | 53 | SND_SOC_DAPM_SPK("Speaker", NULL), |
54 | SND_SOC_DAPM_MIC("Mic Jack", NULL), | 54 | SND_SOC_DAPM_MIC("Mic Jack", NULL), |
55 | }; | 55 | }; |
56 | 56 | ||
57 | static const struct snd_soc_dapm_route t5325_route[] = { | 57 | static const struct snd_soc_dapm_route t5325_route[] = { |
58 | { "Headphone Jack", NULL, "HPL" }, | 58 | { "Headphone Jack", NULL, "HPL" }, |
59 | { "Headphone Jack", NULL, "HPR" }, | 59 | { "Headphone Jack", NULL, "HPR" }, |
60 | 60 | ||
61 | {"Speaker", NULL, "SPKOUT"}, | 61 | {"Speaker", NULL, "SPKOUT"}, |
62 | {"Speaker", NULL, "SPKOUTN"}, | 62 | {"Speaker", NULL, "SPKOUTN"}, |
63 | 63 | ||
64 | { "MIC1", NULL, "Mic Jack" }, | 64 | { "MIC1", NULL, "Mic Jack" }, |
65 | { "MIC2", NULL, "Mic Jack" }, | 65 | { "MIC2", NULL, "Mic Jack" }, |
66 | }; | 66 | }; |
67 | 67 | ||
68 | static int t5325_dai_init(struct snd_soc_pcm_runtime *rtd) | 68 | static int t5325_dai_init(struct snd_soc_pcm_runtime *rtd) |
69 | { | 69 | { |
70 | struct snd_soc_codec *codec = rtd->codec; | 70 | struct snd_soc_codec *codec = rtd->codec; |
71 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 71 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
72 | 72 | ||
73 | snd_soc_dapm_new_controls(dapm, t5325_dapm_widgets, | 73 | snd_soc_dapm_new_controls(dapm, t5325_dapm_widgets, |
74 | ARRAY_SIZE(t5325_dapm_widgets)); | 74 | ARRAY_SIZE(t5325_dapm_widgets)); |
75 | 75 | ||
76 | snd_soc_dapm_add_routes(dapm, t5325_route, ARRAY_SIZE(t5325_route)); | 76 | snd_soc_dapm_add_routes(dapm, t5325_route, ARRAY_SIZE(t5325_route)); |
77 | 77 | ||
78 | snd_soc_dapm_enable_pin(dapm, "Mic Jack"); | 78 | snd_soc_dapm_enable_pin(dapm, "Mic Jack"); |
79 | snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); | 79 | snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); |
80 | snd_soc_dapm_enable_pin(dapm, "Speaker"); | 80 | snd_soc_dapm_enable_pin(dapm, "Speaker"); |
81 | 81 | ||
82 | snd_soc_dapm_sync(dapm); | ||
83 | |||
84 | return 0; | 82 | return 0; |
85 | } | 83 | } |
86 | 84 | ||
87 | static struct snd_soc_dai_link t5325_dai[] = { | 85 | static struct snd_soc_dai_link t5325_dai[] = { |
88 | { | 86 | { |
89 | .name = "ALC5621", | 87 | .name = "ALC5621", |
90 | .stream_name = "ALC5621 HiFi", | 88 | .stream_name = "ALC5621 HiFi", |
91 | .cpu_dai_name = "kirkwood-i2s", | 89 | .cpu_dai_name = "kirkwood-i2s", |
92 | .platform_name = "kirkwood-pcm-audio", | 90 | .platform_name = "kirkwood-pcm-audio", |
93 | .codec_dai_name = "alc5621-hifi", | 91 | .codec_dai_name = "alc5621-hifi", |
94 | .codec_name = "alc562x-codec.0-001a", | 92 | .codec_name = "alc562x-codec.0-001a", |
95 | .ops = &t5325_ops, | 93 | .ops = &t5325_ops, |
96 | .init = t5325_dai_init, | 94 | .init = t5325_dai_init, |
97 | }, | 95 | }, |
98 | }; | 96 | }; |
99 | 97 | ||
100 | 98 | ||
101 | static struct snd_soc_card t5325 = { | 99 | static struct snd_soc_card t5325 = { |
102 | .name = "t5325", | 100 | .name = "t5325", |
103 | .dai_link = t5325_dai, | 101 | .dai_link = t5325_dai, |
104 | .num_links = ARRAY_SIZE(t5325_dai), | 102 | .num_links = ARRAY_SIZE(t5325_dai), |
105 | }; | 103 | }; |
106 | 104 | ||
107 | static struct platform_device *t5325_snd_device; | 105 | static struct platform_device *t5325_snd_device; |
108 | 106 | ||
109 | static int __init t5325_init(void) | 107 | static int __init t5325_init(void) |
110 | { | 108 | { |
111 | int ret; | 109 | int ret; |
112 | 110 | ||
113 | if (!machine_is_t5325()) | 111 | if (!machine_is_t5325()) |
114 | return 0; | 112 | return 0; |
115 | 113 | ||
116 | t5325_snd_device = platform_device_alloc("soc-audio", -1); | 114 | t5325_snd_device = platform_device_alloc("soc-audio", -1); |
117 | if (!t5325_snd_device) | 115 | if (!t5325_snd_device) |
118 | return -ENOMEM; | 116 | return -ENOMEM; |
119 | 117 | ||
120 | platform_set_drvdata(t5325_snd_device, | 118 | platform_set_drvdata(t5325_snd_device, |
121 | &t5325); | 119 | &t5325); |
122 | 120 | ||
123 | ret = platform_device_add(t5325_snd_device); | 121 | ret = platform_device_add(t5325_snd_device); |
124 | if (ret) { | 122 | if (ret) { |
125 | printk(KERN_ERR "%s: platform_device_add failed\n", __func__); | 123 | printk(KERN_ERR "%s: platform_device_add failed\n", __func__); |
126 | platform_device_put(t5325_snd_device); | 124 | platform_device_put(t5325_snd_device); |
127 | } | 125 | } |
128 | 126 | ||
129 | return ret; | 127 | return ret; |
130 | } | 128 | } |
131 | module_init(t5325_init); | 129 | module_init(t5325_init); |
132 | 130 | ||
133 | static void __exit t5325_exit(void) | 131 | static void __exit t5325_exit(void) |
134 | { | 132 | { |
135 | platform_device_unregister(t5325_snd_device); | 133 | platform_device_unregister(t5325_snd_device); |
136 | } | 134 | } |
137 | module_exit(t5325_exit); | 135 | module_exit(t5325_exit); |
138 | 136 | ||
139 | MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>"); | 137 | MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>"); |
140 | MODULE_DESCRIPTION("ALSA SoC t5325 audio client"); | 138 | MODULE_DESCRIPTION("ALSA SoC t5325 audio client"); |
141 | MODULE_LICENSE("GPL"); | 139 | MODULE_LICENSE("GPL"); |
142 | 140 |
sound/soc/mid-x86/mfld_machine.c
1 | /* | 1 | /* |
2 | * mfld_machine.c - ASoc Machine driver for Intel Medfield MID platform | 2 | * mfld_machine.c - ASoc Machine driver for Intel Medfield MID platform |
3 | * | 3 | * |
4 | * Copyright (C) 2010 Intel Corp | 4 | * Copyright (C) 2010 Intel Corp |
5 | * Author: Vinod Koul <vinod.koul@intel.com> | 5 | * Author: Vinod Koul <vinod.koul@intel.com> |
6 | * Author: Harsha Priya <priya.harsha@intel.com> | 6 | * Author: Harsha Priya <priya.harsha@intel.com> |
7 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 7 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU General Public License as published by | 10 | * it under the terms of the GNU General Public License as published by |
11 | * the Free Software Foundation; version 2 of the License. | 11 | * the Free Software Foundation; version 2 of the License. |
12 | * | 12 | * |
13 | * This program is distributed in the hope that it will be useful, but | 13 | * This program is distributed in the hope that it will be useful, but |
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | 14 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
16 | * General Public License for more details. | 16 | * General Public License for more details. |
17 | * | 17 | * |
18 | * You should have received a copy of the GNU General Public License along | 18 | * You should have received a copy of the GNU General Public License along |
19 | * with this program; if not, write to the Free Software Foundation, Inc., | 19 | * with this program; if not, write to the Free Software Foundation, Inc., |
20 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | 20 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. |
21 | * | 21 | * |
22 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 22 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 25 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
26 | 26 | ||
27 | #include <linux/init.h> | 27 | #include <linux/init.h> |
28 | #include <linux/device.h> | 28 | #include <linux/device.h> |
29 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
30 | #include <linux/io.h> | 30 | #include <linux/io.h> |
31 | #include <sound/pcm.h> | 31 | #include <sound/pcm.h> |
32 | #include <sound/pcm_params.h> | 32 | #include <sound/pcm_params.h> |
33 | #include <sound/soc.h> | 33 | #include <sound/soc.h> |
34 | #include <sound/jack.h> | 34 | #include <sound/jack.h> |
35 | #include "../codecs/sn95031.h" | 35 | #include "../codecs/sn95031.h" |
36 | 36 | ||
37 | #define MID_MONO 1 | 37 | #define MID_MONO 1 |
38 | #define MID_STEREO 2 | 38 | #define MID_STEREO 2 |
39 | #define MID_MAX_CAP 5 | 39 | #define MID_MAX_CAP 5 |
40 | #define MFLD_JACK_INSERT 0x04 | 40 | #define MFLD_JACK_INSERT 0x04 |
41 | 41 | ||
42 | enum soc_mic_bias_zones { | 42 | enum soc_mic_bias_zones { |
43 | MFLD_MV_START = 0, | 43 | MFLD_MV_START = 0, |
44 | /* mic bias volutage range for Headphones*/ | 44 | /* mic bias volutage range for Headphones*/ |
45 | MFLD_MV_HP = 400, | 45 | MFLD_MV_HP = 400, |
46 | /* mic bias volutage range for American Headset*/ | 46 | /* mic bias volutage range for American Headset*/ |
47 | MFLD_MV_AM_HS = 650, | 47 | MFLD_MV_AM_HS = 650, |
48 | /* mic bias volutage range for Headset*/ | 48 | /* mic bias volutage range for Headset*/ |
49 | MFLD_MV_HS = 2000, | 49 | MFLD_MV_HS = 2000, |
50 | MFLD_MV_UNDEFINED, | 50 | MFLD_MV_UNDEFINED, |
51 | }; | 51 | }; |
52 | 52 | ||
53 | static unsigned int hs_switch; | 53 | static unsigned int hs_switch; |
54 | static unsigned int lo_dac; | 54 | static unsigned int lo_dac; |
55 | 55 | ||
56 | struct mfld_mc_private { | 56 | struct mfld_mc_private { |
57 | void __iomem *int_base; | 57 | void __iomem *int_base; |
58 | u8 interrupt_status; | 58 | u8 interrupt_status; |
59 | }; | 59 | }; |
60 | 60 | ||
61 | struct snd_soc_jack mfld_jack; | 61 | struct snd_soc_jack mfld_jack; |
62 | 62 | ||
63 | /*Headset jack detection DAPM pins */ | 63 | /*Headset jack detection DAPM pins */ |
64 | static struct snd_soc_jack_pin mfld_jack_pins[] = { | 64 | static struct snd_soc_jack_pin mfld_jack_pins[] = { |
65 | { | 65 | { |
66 | .pin = "Headphones", | 66 | .pin = "Headphones", |
67 | .mask = SND_JACK_HEADPHONE, | 67 | .mask = SND_JACK_HEADPHONE, |
68 | }, | 68 | }, |
69 | { | 69 | { |
70 | .pin = "AMIC1", | 70 | .pin = "AMIC1", |
71 | .mask = SND_JACK_MICROPHONE, | 71 | .mask = SND_JACK_MICROPHONE, |
72 | }, | 72 | }, |
73 | }; | 73 | }; |
74 | 74 | ||
75 | /* jack detection voltage zones */ | 75 | /* jack detection voltage zones */ |
76 | static struct snd_soc_jack_zone mfld_zones[] = { | 76 | static struct snd_soc_jack_zone mfld_zones[] = { |
77 | {MFLD_MV_START, MFLD_MV_AM_HS, SND_JACK_HEADPHONE}, | 77 | {MFLD_MV_START, MFLD_MV_AM_HS, SND_JACK_HEADPHONE}, |
78 | {MFLD_MV_AM_HS, MFLD_MV_HS, SND_JACK_HEADSET}, | 78 | {MFLD_MV_AM_HS, MFLD_MV_HS, SND_JACK_HEADSET}, |
79 | }; | 79 | }; |
80 | 80 | ||
81 | /* sound card controls */ | 81 | /* sound card controls */ |
82 | static const char *headset_switch_text[] = {"Earpiece", "Headset"}; | 82 | static const char *headset_switch_text[] = {"Earpiece", "Headset"}; |
83 | 83 | ||
84 | static const char *lo_text[] = {"Vibra", "Headset", "IHF", "None"}; | 84 | static const char *lo_text[] = {"Vibra", "Headset", "IHF", "None"}; |
85 | 85 | ||
86 | static const struct soc_enum headset_enum = | 86 | static const struct soc_enum headset_enum = |
87 | SOC_ENUM_SINGLE_EXT(2, headset_switch_text); | 87 | SOC_ENUM_SINGLE_EXT(2, headset_switch_text); |
88 | 88 | ||
89 | static const struct soc_enum lo_enum = | 89 | static const struct soc_enum lo_enum = |
90 | SOC_ENUM_SINGLE_EXT(4, lo_text); | 90 | SOC_ENUM_SINGLE_EXT(4, lo_text); |
91 | 91 | ||
92 | static int headset_get_switch(struct snd_kcontrol *kcontrol, | 92 | static int headset_get_switch(struct snd_kcontrol *kcontrol, |
93 | struct snd_ctl_elem_value *ucontrol) | 93 | struct snd_ctl_elem_value *ucontrol) |
94 | { | 94 | { |
95 | ucontrol->value.integer.value[0] = hs_switch; | 95 | ucontrol->value.integer.value[0] = hs_switch; |
96 | return 0; | 96 | return 0; |
97 | } | 97 | } |
98 | 98 | ||
99 | static int headset_set_switch(struct snd_kcontrol *kcontrol, | 99 | static int headset_set_switch(struct snd_kcontrol *kcontrol, |
100 | struct snd_ctl_elem_value *ucontrol) | 100 | struct snd_ctl_elem_value *ucontrol) |
101 | { | 101 | { |
102 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 102 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
103 | 103 | ||
104 | if (ucontrol->value.integer.value[0] == hs_switch) | 104 | if (ucontrol->value.integer.value[0] == hs_switch) |
105 | return 0; | 105 | return 0; |
106 | 106 | ||
107 | if (ucontrol->value.integer.value[0]) { | 107 | if (ucontrol->value.integer.value[0]) { |
108 | pr_debug("hs_set HS path\n"); | 108 | pr_debug("hs_set HS path\n"); |
109 | snd_soc_dapm_enable_pin(&codec->dapm, "Headphones"); | 109 | snd_soc_dapm_enable_pin(&codec->dapm, "Headphones"); |
110 | snd_soc_dapm_disable_pin(&codec->dapm, "EPOUT"); | 110 | snd_soc_dapm_disable_pin(&codec->dapm, "EPOUT"); |
111 | } else { | 111 | } else { |
112 | pr_debug("hs_set EP path\n"); | 112 | pr_debug("hs_set EP path\n"); |
113 | snd_soc_dapm_disable_pin(&codec->dapm, "Headphones"); | 113 | snd_soc_dapm_disable_pin(&codec->dapm, "Headphones"); |
114 | snd_soc_dapm_enable_pin(&codec->dapm, "EPOUT"); | 114 | snd_soc_dapm_enable_pin(&codec->dapm, "EPOUT"); |
115 | } | 115 | } |
116 | snd_soc_dapm_sync(&codec->dapm); | 116 | snd_soc_dapm_sync(&codec->dapm); |
117 | hs_switch = ucontrol->value.integer.value[0]; | 117 | hs_switch = ucontrol->value.integer.value[0]; |
118 | 118 | ||
119 | return 0; | 119 | return 0; |
120 | } | 120 | } |
121 | 121 | ||
122 | static void lo_enable_out_pins(struct snd_soc_codec *codec) | 122 | static void lo_enable_out_pins(struct snd_soc_codec *codec) |
123 | { | 123 | { |
124 | snd_soc_dapm_enable_pin(&codec->dapm, "IHFOUTL"); | 124 | snd_soc_dapm_enable_pin(&codec->dapm, "IHFOUTL"); |
125 | snd_soc_dapm_enable_pin(&codec->dapm, "IHFOUTR"); | 125 | snd_soc_dapm_enable_pin(&codec->dapm, "IHFOUTR"); |
126 | snd_soc_dapm_enable_pin(&codec->dapm, "LINEOUTL"); | 126 | snd_soc_dapm_enable_pin(&codec->dapm, "LINEOUTL"); |
127 | snd_soc_dapm_enable_pin(&codec->dapm, "LINEOUTR"); | 127 | snd_soc_dapm_enable_pin(&codec->dapm, "LINEOUTR"); |
128 | snd_soc_dapm_enable_pin(&codec->dapm, "VIB1OUT"); | 128 | snd_soc_dapm_enable_pin(&codec->dapm, "VIB1OUT"); |
129 | snd_soc_dapm_enable_pin(&codec->dapm, "VIB2OUT"); | 129 | snd_soc_dapm_enable_pin(&codec->dapm, "VIB2OUT"); |
130 | if (hs_switch) { | 130 | if (hs_switch) { |
131 | snd_soc_dapm_enable_pin(&codec->dapm, "Headphones"); | 131 | snd_soc_dapm_enable_pin(&codec->dapm, "Headphones"); |
132 | snd_soc_dapm_disable_pin(&codec->dapm, "EPOUT"); | 132 | snd_soc_dapm_disable_pin(&codec->dapm, "EPOUT"); |
133 | } else { | 133 | } else { |
134 | snd_soc_dapm_disable_pin(&codec->dapm, "Headphones"); | 134 | snd_soc_dapm_disable_pin(&codec->dapm, "Headphones"); |
135 | snd_soc_dapm_enable_pin(&codec->dapm, "EPOUT"); | 135 | snd_soc_dapm_enable_pin(&codec->dapm, "EPOUT"); |
136 | } | 136 | } |
137 | } | 137 | } |
138 | 138 | ||
139 | static int lo_get_switch(struct snd_kcontrol *kcontrol, | 139 | static int lo_get_switch(struct snd_kcontrol *kcontrol, |
140 | struct snd_ctl_elem_value *ucontrol) | 140 | struct snd_ctl_elem_value *ucontrol) |
141 | { | 141 | { |
142 | ucontrol->value.integer.value[0] = lo_dac; | 142 | ucontrol->value.integer.value[0] = lo_dac; |
143 | return 0; | 143 | return 0; |
144 | } | 144 | } |
145 | 145 | ||
146 | static int lo_set_switch(struct snd_kcontrol *kcontrol, | 146 | static int lo_set_switch(struct snd_kcontrol *kcontrol, |
147 | struct snd_ctl_elem_value *ucontrol) | 147 | struct snd_ctl_elem_value *ucontrol) |
148 | { | 148 | { |
149 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 149 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
150 | 150 | ||
151 | if (ucontrol->value.integer.value[0] == lo_dac) | 151 | if (ucontrol->value.integer.value[0] == lo_dac) |
152 | return 0; | 152 | return 0; |
153 | 153 | ||
154 | /* we dont want to work with last state of lineout so just enable all | 154 | /* we dont want to work with last state of lineout so just enable all |
155 | * pins and then disable pins not required | 155 | * pins and then disable pins not required |
156 | */ | 156 | */ |
157 | lo_enable_out_pins(codec); | 157 | lo_enable_out_pins(codec); |
158 | switch (ucontrol->value.integer.value[0]) { | 158 | switch (ucontrol->value.integer.value[0]) { |
159 | case 0: | 159 | case 0: |
160 | pr_debug("set vibra path\n"); | 160 | pr_debug("set vibra path\n"); |
161 | snd_soc_dapm_disable_pin(&codec->dapm, "VIB1OUT"); | 161 | snd_soc_dapm_disable_pin(&codec->dapm, "VIB1OUT"); |
162 | snd_soc_dapm_disable_pin(&codec->dapm, "VIB2OUT"); | 162 | snd_soc_dapm_disable_pin(&codec->dapm, "VIB2OUT"); |
163 | snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0); | 163 | snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0); |
164 | break; | 164 | break; |
165 | 165 | ||
166 | case 1: | 166 | case 1: |
167 | pr_debug("set hs path\n"); | 167 | pr_debug("set hs path\n"); |
168 | snd_soc_dapm_disable_pin(&codec->dapm, "Headphones"); | 168 | snd_soc_dapm_disable_pin(&codec->dapm, "Headphones"); |
169 | snd_soc_dapm_disable_pin(&codec->dapm, "EPOUT"); | 169 | snd_soc_dapm_disable_pin(&codec->dapm, "EPOUT"); |
170 | snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x22); | 170 | snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x22); |
171 | break; | 171 | break; |
172 | 172 | ||
173 | case 2: | 173 | case 2: |
174 | pr_debug("set spkr path\n"); | 174 | pr_debug("set spkr path\n"); |
175 | snd_soc_dapm_disable_pin(&codec->dapm, "IHFOUTL"); | 175 | snd_soc_dapm_disable_pin(&codec->dapm, "IHFOUTL"); |
176 | snd_soc_dapm_disable_pin(&codec->dapm, "IHFOUTR"); | 176 | snd_soc_dapm_disable_pin(&codec->dapm, "IHFOUTR"); |
177 | snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x44); | 177 | snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x44); |
178 | break; | 178 | break; |
179 | 179 | ||
180 | case 3: | 180 | case 3: |
181 | pr_debug("set null path\n"); | 181 | pr_debug("set null path\n"); |
182 | snd_soc_dapm_disable_pin(&codec->dapm, "LINEOUTL"); | 182 | snd_soc_dapm_disable_pin(&codec->dapm, "LINEOUTL"); |
183 | snd_soc_dapm_disable_pin(&codec->dapm, "LINEOUTR"); | 183 | snd_soc_dapm_disable_pin(&codec->dapm, "LINEOUTR"); |
184 | snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x66); | 184 | snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x66); |
185 | break; | 185 | break; |
186 | } | 186 | } |
187 | snd_soc_dapm_sync(&codec->dapm); | 187 | snd_soc_dapm_sync(&codec->dapm); |
188 | lo_dac = ucontrol->value.integer.value[0]; | 188 | lo_dac = ucontrol->value.integer.value[0]; |
189 | return 0; | 189 | return 0; |
190 | } | 190 | } |
191 | 191 | ||
192 | static const struct snd_kcontrol_new mfld_snd_controls[] = { | 192 | static const struct snd_kcontrol_new mfld_snd_controls[] = { |
193 | SOC_ENUM_EXT("Playback Switch", headset_enum, | 193 | SOC_ENUM_EXT("Playback Switch", headset_enum, |
194 | headset_get_switch, headset_set_switch), | 194 | headset_get_switch, headset_set_switch), |
195 | SOC_ENUM_EXT("Lineout Mux", lo_enum, | 195 | SOC_ENUM_EXT("Lineout Mux", lo_enum, |
196 | lo_get_switch, lo_set_switch), | 196 | lo_get_switch, lo_set_switch), |
197 | }; | 197 | }; |
198 | 198 | ||
199 | static const struct snd_soc_dapm_widget mfld_widgets[] = { | 199 | static const struct snd_soc_dapm_widget mfld_widgets[] = { |
200 | SND_SOC_DAPM_HP("Headphones", NULL), | 200 | SND_SOC_DAPM_HP("Headphones", NULL), |
201 | SND_SOC_DAPM_MIC("Mic", NULL), | 201 | SND_SOC_DAPM_MIC("Mic", NULL), |
202 | }; | 202 | }; |
203 | 203 | ||
204 | static const struct snd_soc_dapm_route mfld_map[] = { | 204 | static const struct snd_soc_dapm_route mfld_map[] = { |
205 | {"Headphones", NULL, "HPOUTR"}, | 205 | {"Headphones", NULL, "HPOUTR"}, |
206 | {"Headphones", NULL, "HPOUTL"}, | 206 | {"Headphones", NULL, "HPOUTL"}, |
207 | {"Mic", NULL, "AMIC1"}, | 207 | {"Mic", NULL, "AMIC1"}, |
208 | }; | 208 | }; |
209 | 209 | ||
210 | static void mfld_jack_check(unsigned int intr_status) | 210 | static void mfld_jack_check(unsigned int intr_status) |
211 | { | 211 | { |
212 | struct mfld_jack_data jack_data; | 212 | struct mfld_jack_data jack_data; |
213 | 213 | ||
214 | jack_data.mfld_jack = &mfld_jack; | 214 | jack_data.mfld_jack = &mfld_jack; |
215 | jack_data.intr_id = intr_status; | 215 | jack_data.intr_id = intr_status; |
216 | 216 | ||
217 | sn95031_jack_detection(&jack_data); | 217 | sn95031_jack_detection(&jack_data); |
218 | /* TODO: add american headset detection post gpiolib support */ | 218 | /* TODO: add american headset detection post gpiolib support */ |
219 | } | 219 | } |
220 | 220 | ||
221 | static int mfld_init(struct snd_soc_pcm_runtime *runtime) | 221 | static int mfld_init(struct snd_soc_pcm_runtime *runtime) |
222 | { | 222 | { |
223 | struct snd_soc_codec *codec = runtime->codec; | 223 | struct snd_soc_codec *codec = runtime->codec; |
224 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 224 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
225 | int ret_val; | 225 | int ret_val; |
226 | 226 | ||
227 | /* Add jack sense widgets */ | 227 | /* Add jack sense widgets */ |
228 | snd_soc_dapm_new_controls(dapm, mfld_widgets, ARRAY_SIZE(mfld_widgets)); | 228 | snd_soc_dapm_new_controls(dapm, mfld_widgets, ARRAY_SIZE(mfld_widgets)); |
229 | 229 | ||
230 | /* Set up the map */ | 230 | /* Set up the map */ |
231 | snd_soc_dapm_add_routes(dapm, mfld_map, ARRAY_SIZE(mfld_map)); | 231 | snd_soc_dapm_add_routes(dapm, mfld_map, ARRAY_SIZE(mfld_map)); |
232 | 232 | ||
233 | /* always connected */ | 233 | /* always connected */ |
234 | snd_soc_dapm_enable_pin(dapm, "Headphones"); | 234 | snd_soc_dapm_enable_pin(dapm, "Headphones"); |
235 | snd_soc_dapm_enable_pin(dapm, "Mic"); | 235 | snd_soc_dapm_enable_pin(dapm, "Mic"); |
236 | snd_soc_dapm_sync(dapm); | ||
237 | 236 | ||
238 | ret_val = snd_soc_add_controls(codec, mfld_snd_controls, | 237 | ret_val = snd_soc_add_controls(codec, mfld_snd_controls, |
239 | ARRAY_SIZE(mfld_snd_controls)); | 238 | ARRAY_SIZE(mfld_snd_controls)); |
240 | if (ret_val) { | 239 | if (ret_val) { |
241 | pr_err("soc_add_controls failed %d", ret_val); | 240 | pr_err("soc_add_controls failed %d", ret_val); |
242 | return ret_val; | 241 | return ret_val; |
243 | } | 242 | } |
244 | /* default is earpiece pin, userspace sets it explcitly */ | 243 | /* default is earpiece pin, userspace sets it explcitly */ |
245 | snd_soc_dapm_disable_pin(dapm, "Headphones"); | 244 | snd_soc_dapm_disable_pin(dapm, "Headphones"); |
246 | /* default is lineout NC, userspace sets it explcitly */ | 245 | /* default is lineout NC, userspace sets it explcitly */ |
247 | snd_soc_dapm_disable_pin(dapm, "LINEOUTL"); | 246 | snd_soc_dapm_disable_pin(dapm, "LINEOUTL"); |
248 | snd_soc_dapm_disable_pin(dapm, "LINEOUTR"); | 247 | snd_soc_dapm_disable_pin(dapm, "LINEOUTR"); |
249 | lo_dac = 3; | 248 | lo_dac = 3; |
250 | hs_switch = 0; | 249 | hs_switch = 0; |
251 | /* we dont use linein in this so set to NC */ | 250 | /* we dont use linein in this so set to NC */ |
252 | snd_soc_dapm_disable_pin(dapm, "LINEINL"); | 251 | snd_soc_dapm_disable_pin(dapm, "LINEINL"); |
253 | snd_soc_dapm_disable_pin(dapm, "LINEINR"); | 252 | snd_soc_dapm_disable_pin(dapm, "LINEINR"); |
254 | snd_soc_dapm_sync(dapm); | ||
255 | 253 | ||
256 | /* Headset and button jack detection */ | 254 | /* Headset and button jack detection */ |
257 | ret_val = snd_soc_jack_new(codec, "Intel(R) MID Audio Jack", | 255 | ret_val = snd_soc_jack_new(codec, "Intel(R) MID Audio Jack", |
258 | SND_JACK_HEADSET | SND_JACK_BTN_0 | | 256 | SND_JACK_HEADSET | SND_JACK_BTN_0 | |
259 | SND_JACK_BTN_1, &mfld_jack); | 257 | SND_JACK_BTN_1, &mfld_jack); |
260 | if (ret_val) { | 258 | if (ret_val) { |
261 | pr_err("jack creation failed\n"); | 259 | pr_err("jack creation failed\n"); |
262 | return ret_val; | 260 | return ret_val; |
263 | } | 261 | } |
264 | 262 | ||
265 | ret_val = snd_soc_jack_add_pins(&mfld_jack, | 263 | ret_val = snd_soc_jack_add_pins(&mfld_jack, |
266 | ARRAY_SIZE(mfld_jack_pins), mfld_jack_pins); | 264 | ARRAY_SIZE(mfld_jack_pins), mfld_jack_pins); |
267 | if (ret_val) { | 265 | if (ret_val) { |
268 | pr_err("adding jack pins failed\n"); | 266 | pr_err("adding jack pins failed\n"); |
269 | return ret_val; | 267 | return ret_val; |
270 | } | 268 | } |
271 | ret_val = snd_soc_jack_add_zones(&mfld_jack, | 269 | ret_val = snd_soc_jack_add_zones(&mfld_jack, |
272 | ARRAY_SIZE(mfld_zones), mfld_zones); | 270 | ARRAY_SIZE(mfld_zones), mfld_zones); |
273 | if (ret_val) { | 271 | if (ret_val) { |
274 | pr_err("adding jack zones failed\n"); | 272 | pr_err("adding jack zones failed\n"); |
275 | return ret_val; | 273 | return ret_val; |
276 | } | 274 | } |
277 | 275 | ||
278 | /* we want to check if anything is inserted at boot, | 276 | /* we want to check if anything is inserted at boot, |
279 | * so send a fake event to codec and it will read adc | 277 | * so send a fake event to codec and it will read adc |
280 | * to find if anything is there or not */ | 278 | * to find if anything is there or not */ |
281 | mfld_jack_check(MFLD_JACK_INSERT); | 279 | mfld_jack_check(MFLD_JACK_INSERT); |
282 | return ret_val; | 280 | return ret_val; |
283 | } | 281 | } |
284 | 282 | ||
285 | struct snd_soc_dai_link mfld_msic_dailink[] = { | 283 | struct snd_soc_dai_link mfld_msic_dailink[] = { |
286 | { | 284 | { |
287 | .name = "Medfield Headset", | 285 | .name = "Medfield Headset", |
288 | .stream_name = "Headset", | 286 | .stream_name = "Headset", |
289 | .cpu_dai_name = "Headset-cpu-dai", | 287 | .cpu_dai_name = "Headset-cpu-dai", |
290 | .codec_dai_name = "SN95031 Headset", | 288 | .codec_dai_name = "SN95031 Headset", |
291 | .codec_name = "sn95031", | 289 | .codec_name = "sn95031", |
292 | .platform_name = "sst-platform", | 290 | .platform_name = "sst-platform", |
293 | .init = mfld_init, | 291 | .init = mfld_init, |
294 | }, | 292 | }, |
295 | { | 293 | { |
296 | .name = "Medfield Speaker", | 294 | .name = "Medfield Speaker", |
297 | .stream_name = "Speaker", | 295 | .stream_name = "Speaker", |
298 | .cpu_dai_name = "Speaker-cpu-dai", | 296 | .cpu_dai_name = "Speaker-cpu-dai", |
299 | .codec_dai_name = "SN95031 Speaker", | 297 | .codec_dai_name = "SN95031 Speaker", |
300 | .codec_name = "sn95031", | 298 | .codec_name = "sn95031", |
301 | .platform_name = "sst-platform", | 299 | .platform_name = "sst-platform", |
302 | .init = NULL, | 300 | .init = NULL, |
303 | }, | 301 | }, |
304 | { | 302 | { |
305 | .name = "Medfield Vibra", | 303 | .name = "Medfield Vibra", |
306 | .stream_name = "Vibra1", | 304 | .stream_name = "Vibra1", |
307 | .cpu_dai_name = "Vibra1-cpu-dai", | 305 | .cpu_dai_name = "Vibra1-cpu-dai", |
308 | .codec_dai_name = "SN95031 Vibra1", | 306 | .codec_dai_name = "SN95031 Vibra1", |
309 | .codec_name = "sn95031", | 307 | .codec_name = "sn95031", |
310 | .platform_name = "sst-platform", | 308 | .platform_name = "sst-platform", |
311 | .init = NULL, | 309 | .init = NULL, |
312 | }, | 310 | }, |
313 | { | 311 | { |
314 | .name = "Medfield Haptics", | 312 | .name = "Medfield Haptics", |
315 | .stream_name = "Vibra2", | 313 | .stream_name = "Vibra2", |
316 | .cpu_dai_name = "Vibra2-cpu-dai", | 314 | .cpu_dai_name = "Vibra2-cpu-dai", |
317 | .codec_dai_name = "SN95031 Vibra2", | 315 | .codec_dai_name = "SN95031 Vibra2", |
318 | .codec_name = "sn95031", | 316 | .codec_name = "sn95031", |
319 | .platform_name = "sst-platform", | 317 | .platform_name = "sst-platform", |
320 | .init = NULL, | 318 | .init = NULL, |
321 | }, | 319 | }, |
322 | }; | 320 | }; |
323 | 321 | ||
324 | /* SoC card */ | 322 | /* SoC card */ |
325 | static struct snd_soc_card snd_soc_card_mfld = { | 323 | static struct snd_soc_card snd_soc_card_mfld = { |
326 | .name = "medfield_audio", | 324 | .name = "medfield_audio", |
327 | .dai_link = mfld_msic_dailink, | 325 | .dai_link = mfld_msic_dailink, |
328 | .num_links = ARRAY_SIZE(mfld_msic_dailink), | 326 | .num_links = ARRAY_SIZE(mfld_msic_dailink), |
329 | }; | 327 | }; |
330 | 328 | ||
331 | static irqreturn_t snd_mfld_jack_intr_handler(int irq, void *dev) | 329 | static irqreturn_t snd_mfld_jack_intr_handler(int irq, void *dev) |
332 | { | 330 | { |
333 | struct mfld_mc_private *mc_private = (struct mfld_mc_private *) dev; | 331 | struct mfld_mc_private *mc_private = (struct mfld_mc_private *) dev; |
334 | 332 | ||
335 | memcpy_fromio(&mc_private->interrupt_status, | 333 | memcpy_fromio(&mc_private->interrupt_status, |
336 | ((void *)(mc_private->int_base)), | 334 | ((void *)(mc_private->int_base)), |
337 | sizeof(u8)); | 335 | sizeof(u8)); |
338 | return IRQ_WAKE_THREAD; | 336 | return IRQ_WAKE_THREAD; |
339 | } | 337 | } |
340 | 338 | ||
341 | static irqreturn_t snd_mfld_jack_detection(int irq, void *data) | 339 | static irqreturn_t snd_mfld_jack_detection(int irq, void *data) |
342 | { | 340 | { |
343 | struct mfld_mc_private *mc_drv_ctx = (struct mfld_mc_private *) data; | 341 | struct mfld_mc_private *mc_drv_ctx = (struct mfld_mc_private *) data; |
344 | 342 | ||
345 | if (mfld_jack.codec == NULL) | 343 | if (mfld_jack.codec == NULL) |
346 | return IRQ_HANDLED; | 344 | return IRQ_HANDLED; |
347 | mfld_jack_check(mc_drv_ctx->interrupt_status); | 345 | mfld_jack_check(mc_drv_ctx->interrupt_status); |
348 | 346 | ||
349 | return IRQ_HANDLED; | 347 | return IRQ_HANDLED; |
350 | } | 348 | } |
351 | 349 | ||
352 | static int __devinit snd_mfld_mc_probe(struct platform_device *pdev) | 350 | static int __devinit snd_mfld_mc_probe(struct platform_device *pdev) |
353 | { | 351 | { |
354 | int ret_val = 0, irq; | 352 | int ret_val = 0, irq; |
355 | struct mfld_mc_private *mc_drv_ctx; | 353 | struct mfld_mc_private *mc_drv_ctx; |
356 | struct resource *irq_mem; | 354 | struct resource *irq_mem; |
357 | 355 | ||
358 | pr_debug("snd_mfld_mc_probe called\n"); | 356 | pr_debug("snd_mfld_mc_probe called\n"); |
359 | 357 | ||
360 | /* retrive the irq number */ | 358 | /* retrive the irq number */ |
361 | irq = platform_get_irq(pdev, 0); | 359 | irq = platform_get_irq(pdev, 0); |
362 | 360 | ||
363 | /* audio interrupt base of SRAM location where | 361 | /* audio interrupt base of SRAM location where |
364 | * interrupts are stored by System FW */ | 362 | * interrupts are stored by System FW */ |
365 | mc_drv_ctx = kzalloc(sizeof(*mc_drv_ctx), GFP_ATOMIC); | 363 | mc_drv_ctx = kzalloc(sizeof(*mc_drv_ctx), GFP_ATOMIC); |
366 | if (!mc_drv_ctx) { | 364 | if (!mc_drv_ctx) { |
367 | pr_err("allocation failed\n"); | 365 | pr_err("allocation failed\n"); |
368 | return -ENOMEM; | 366 | return -ENOMEM; |
369 | } | 367 | } |
370 | 368 | ||
371 | irq_mem = platform_get_resource_byname( | 369 | irq_mem = platform_get_resource_byname( |
372 | pdev, IORESOURCE_MEM, "IRQ_BASE"); | 370 | pdev, IORESOURCE_MEM, "IRQ_BASE"); |
373 | if (!irq_mem) { | 371 | if (!irq_mem) { |
374 | pr_err("no mem resource given\n"); | 372 | pr_err("no mem resource given\n"); |
375 | ret_val = -ENODEV; | 373 | ret_val = -ENODEV; |
376 | goto unalloc; | 374 | goto unalloc; |
377 | } | 375 | } |
378 | mc_drv_ctx->int_base = ioremap_nocache(irq_mem->start, | 376 | mc_drv_ctx->int_base = ioremap_nocache(irq_mem->start, |
379 | resource_size(irq_mem)); | 377 | resource_size(irq_mem)); |
380 | if (!mc_drv_ctx->int_base) { | 378 | if (!mc_drv_ctx->int_base) { |
381 | pr_err("Mapping of cache failed\n"); | 379 | pr_err("Mapping of cache failed\n"); |
382 | ret_val = -ENOMEM; | 380 | ret_val = -ENOMEM; |
383 | goto unalloc; | 381 | goto unalloc; |
384 | } | 382 | } |
385 | /* register for interrupt */ | 383 | /* register for interrupt */ |
386 | ret_val = request_threaded_irq(irq, snd_mfld_jack_intr_handler, | 384 | ret_val = request_threaded_irq(irq, snd_mfld_jack_intr_handler, |
387 | snd_mfld_jack_detection, | 385 | snd_mfld_jack_detection, |
388 | IRQF_SHARED, pdev->dev.driver->name, mc_drv_ctx); | 386 | IRQF_SHARED, pdev->dev.driver->name, mc_drv_ctx); |
389 | if (ret_val) { | 387 | if (ret_val) { |
390 | pr_err("cannot register IRQ\n"); | 388 | pr_err("cannot register IRQ\n"); |
391 | goto unalloc; | 389 | goto unalloc; |
392 | } | 390 | } |
393 | /* register the soc card */ | 391 | /* register the soc card */ |
394 | snd_soc_card_mfld.dev = &pdev->dev; | 392 | snd_soc_card_mfld.dev = &pdev->dev; |
395 | ret_val = snd_soc_register_card(&snd_soc_card_mfld); | 393 | ret_val = snd_soc_register_card(&snd_soc_card_mfld); |
396 | if (ret_val) { | 394 | if (ret_val) { |
397 | pr_debug("snd_soc_register_card failed %d\n", ret_val); | 395 | pr_debug("snd_soc_register_card failed %d\n", ret_val); |
398 | goto freeirq; | 396 | goto freeirq; |
399 | } | 397 | } |
400 | platform_set_drvdata(pdev, mc_drv_ctx); | 398 | platform_set_drvdata(pdev, mc_drv_ctx); |
401 | pr_debug("successfully exited probe\n"); | 399 | pr_debug("successfully exited probe\n"); |
402 | return ret_val; | 400 | return ret_val; |
403 | 401 | ||
404 | freeirq: | 402 | freeirq: |
405 | free_irq(irq, mc_drv_ctx); | 403 | free_irq(irq, mc_drv_ctx); |
406 | unalloc: | 404 | unalloc: |
407 | kfree(mc_drv_ctx); | 405 | kfree(mc_drv_ctx); |
408 | return ret_val; | 406 | return ret_val; |
409 | } | 407 | } |
410 | 408 | ||
411 | static int __devexit snd_mfld_mc_remove(struct platform_device *pdev) | 409 | static int __devexit snd_mfld_mc_remove(struct platform_device *pdev) |
412 | { | 410 | { |
413 | struct mfld_mc_private *mc_drv_ctx = platform_get_drvdata(pdev); | 411 | struct mfld_mc_private *mc_drv_ctx = platform_get_drvdata(pdev); |
414 | 412 | ||
415 | pr_debug("snd_mfld_mc_remove called\n"); | 413 | pr_debug("snd_mfld_mc_remove called\n"); |
416 | free_irq(platform_get_irq(pdev, 0), mc_drv_ctx); | 414 | free_irq(platform_get_irq(pdev, 0), mc_drv_ctx); |
417 | snd_soc_unregister_card(&snd_soc_card_mfld); | 415 | snd_soc_unregister_card(&snd_soc_card_mfld); |
418 | kfree(mc_drv_ctx); | 416 | kfree(mc_drv_ctx); |
419 | platform_set_drvdata(pdev, NULL); | 417 | platform_set_drvdata(pdev, NULL); |
420 | return 0; | 418 | return 0; |
421 | } | 419 | } |
422 | 420 | ||
423 | static struct platform_driver snd_mfld_mc_driver = { | 421 | static struct platform_driver snd_mfld_mc_driver = { |
424 | .driver = { | 422 | .driver = { |
425 | .owner = THIS_MODULE, | 423 | .owner = THIS_MODULE, |
426 | .name = "msic_audio", | 424 | .name = "msic_audio", |
427 | }, | 425 | }, |
428 | .probe = snd_mfld_mc_probe, | 426 | .probe = snd_mfld_mc_probe, |
429 | .remove = __devexit_p(snd_mfld_mc_remove), | 427 | .remove = __devexit_p(snd_mfld_mc_remove), |
430 | }; | 428 | }; |
431 | 429 | ||
432 | static int __init snd_mfld_driver_init(void) | 430 | static int __init snd_mfld_driver_init(void) |
433 | { | 431 | { |
434 | pr_debug("snd_mfld_driver_init called\n"); | 432 | pr_debug("snd_mfld_driver_init called\n"); |
435 | return platform_driver_register(&snd_mfld_mc_driver); | 433 | return platform_driver_register(&snd_mfld_mc_driver); |
436 | } | 434 | } |
437 | module_init(snd_mfld_driver_init); | 435 | module_init(snd_mfld_driver_init); |
438 | 436 | ||
439 | static void __exit snd_mfld_driver_exit(void) | 437 | static void __exit snd_mfld_driver_exit(void) |
440 | { | 438 | { |
441 | pr_debug("snd_mfld_driver_exit called\n"); | 439 | pr_debug("snd_mfld_driver_exit called\n"); |
442 | platform_driver_unregister(&snd_mfld_mc_driver); | 440 | platform_driver_unregister(&snd_mfld_mc_driver); |
443 | } | 441 | } |
444 | module_exit(snd_mfld_driver_exit); | 442 | module_exit(snd_mfld_driver_exit); |
445 | 443 | ||
446 | MODULE_DESCRIPTION("ASoC Intel(R) MID Machine driver"); | 444 | MODULE_DESCRIPTION("ASoC Intel(R) MID Machine driver"); |
447 | MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>"); | 445 | MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>"); |
448 | MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>"); | 446 | MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>"); |
449 | MODULE_LICENSE("GPL v2"); | 447 | MODULE_LICENSE("GPL v2"); |
450 | MODULE_ALIAS("platform:msic-audio"); | 448 | MODULE_ALIAS("platform:msic-audio"); |
451 | 449 |
sound/soc/pxa/corgi.c
1 | /* | 1 | /* |
2 | * corgi.c -- SoC audio for Corgi | 2 | * corgi.c -- SoC audio for Corgi |
3 | * | 3 | * |
4 | * Copyright 2005 Wolfson Microelectronics PLC. | 4 | * Copyright 2005 Wolfson Microelectronics PLC. |
5 | * Copyright 2005 Openedhand Ltd. | 5 | * Copyright 2005 Openedhand Ltd. |
6 | * | 6 | * |
7 | * Authors: Liam Girdwood <lrg@slimlogic.co.uk> | 7 | * Authors: Liam Girdwood <lrg@slimlogic.co.uk> |
8 | * Richard Purdie <richard@openedhand.com> | 8 | * Richard Purdie <richard@openedhand.com> |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify it | 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 | 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 | 12 | * Free Software Foundation; either version 2 of the License, or (at your |
13 | * option) any later version. | 13 | * option) any later version. |
14 | */ | 14 | */ |
15 | 15 | ||
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/moduleparam.h> | 17 | #include <linux/moduleparam.h> |
18 | #include <linux/timer.h> | 18 | #include <linux/timer.h> |
19 | #include <linux/i2c.h> | 19 | #include <linux/i2c.h> |
20 | #include <linux/interrupt.h> | 20 | #include <linux/interrupt.h> |
21 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
22 | #include <linux/gpio.h> | 22 | #include <linux/gpio.h> |
23 | #include <sound/core.h> | 23 | #include <sound/core.h> |
24 | #include <sound/pcm.h> | 24 | #include <sound/pcm.h> |
25 | #include <sound/soc.h> | 25 | #include <sound/soc.h> |
26 | 26 | ||
27 | #include <asm/mach-types.h> | 27 | #include <asm/mach-types.h> |
28 | #include <mach/corgi.h> | 28 | #include <mach/corgi.h> |
29 | #include <mach/audio.h> | 29 | #include <mach/audio.h> |
30 | 30 | ||
31 | #include "../codecs/wm8731.h" | 31 | #include "../codecs/wm8731.h" |
32 | #include "pxa2xx-i2s.h" | 32 | #include "pxa2xx-i2s.h" |
33 | 33 | ||
34 | #define CORGI_HP 0 | 34 | #define CORGI_HP 0 |
35 | #define CORGI_MIC 1 | 35 | #define CORGI_MIC 1 |
36 | #define CORGI_LINE 2 | 36 | #define CORGI_LINE 2 |
37 | #define CORGI_HEADSET 3 | 37 | #define CORGI_HEADSET 3 |
38 | #define CORGI_HP_OFF 4 | 38 | #define CORGI_HP_OFF 4 |
39 | #define CORGI_SPK_ON 0 | 39 | #define CORGI_SPK_ON 0 |
40 | #define CORGI_SPK_OFF 1 | 40 | #define CORGI_SPK_OFF 1 |
41 | 41 | ||
42 | /* audio clock in Hz - rounded from 12.235MHz */ | 42 | /* audio clock in Hz - rounded from 12.235MHz */ |
43 | #define CORGI_AUDIO_CLOCK 12288000 | 43 | #define CORGI_AUDIO_CLOCK 12288000 |
44 | 44 | ||
45 | static int corgi_jack_func; | 45 | static int corgi_jack_func; |
46 | static int corgi_spk_func; | 46 | static int corgi_spk_func; |
47 | 47 | ||
48 | static void corgi_ext_control(struct snd_soc_codec *codec) | 48 | static void corgi_ext_control(struct snd_soc_codec *codec) |
49 | { | 49 | { |
50 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 50 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
51 | 51 | ||
52 | /* set up jack connection */ | 52 | /* set up jack connection */ |
53 | switch (corgi_jack_func) { | 53 | switch (corgi_jack_func) { |
54 | case CORGI_HP: | 54 | case CORGI_HP: |
55 | /* set = unmute headphone */ | 55 | /* set = unmute headphone */ |
56 | gpio_set_value(CORGI_GPIO_MUTE_L, 1); | 56 | gpio_set_value(CORGI_GPIO_MUTE_L, 1); |
57 | gpio_set_value(CORGI_GPIO_MUTE_R, 1); | 57 | gpio_set_value(CORGI_GPIO_MUTE_R, 1); |
58 | snd_soc_dapm_disable_pin(dapm, "Mic Jack"); | 58 | snd_soc_dapm_disable_pin(dapm, "Mic Jack"); |
59 | snd_soc_dapm_disable_pin(dapm, "Line Jack"); | 59 | snd_soc_dapm_disable_pin(dapm, "Line Jack"); |
60 | snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); | 60 | snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); |
61 | snd_soc_dapm_disable_pin(dapm, "Headset Jack"); | 61 | snd_soc_dapm_disable_pin(dapm, "Headset Jack"); |
62 | break; | 62 | break; |
63 | case CORGI_MIC: | 63 | case CORGI_MIC: |
64 | /* reset = mute headphone */ | 64 | /* reset = mute headphone */ |
65 | gpio_set_value(CORGI_GPIO_MUTE_L, 0); | 65 | gpio_set_value(CORGI_GPIO_MUTE_L, 0); |
66 | gpio_set_value(CORGI_GPIO_MUTE_R, 0); | 66 | gpio_set_value(CORGI_GPIO_MUTE_R, 0); |
67 | snd_soc_dapm_enable_pin(dapm, "Mic Jack"); | 67 | snd_soc_dapm_enable_pin(dapm, "Mic Jack"); |
68 | snd_soc_dapm_disable_pin(dapm, "Line Jack"); | 68 | snd_soc_dapm_disable_pin(dapm, "Line Jack"); |
69 | snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); | 69 | snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); |
70 | snd_soc_dapm_disable_pin(dapm, "Headset Jack"); | 70 | snd_soc_dapm_disable_pin(dapm, "Headset Jack"); |
71 | break; | 71 | break; |
72 | case CORGI_LINE: | 72 | case CORGI_LINE: |
73 | gpio_set_value(CORGI_GPIO_MUTE_L, 0); | 73 | gpio_set_value(CORGI_GPIO_MUTE_L, 0); |
74 | gpio_set_value(CORGI_GPIO_MUTE_R, 0); | 74 | gpio_set_value(CORGI_GPIO_MUTE_R, 0); |
75 | snd_soc_dapm_disable_pin(dapm, "Mic Jack"); | 75 | snd_soc_dapm_disable_pin(dapm, "Mic Jack"); |
76 | snd_soc_dapm_enable_pin(dapm, "Line Jack"); | 76 | snd_soc_dapm_enable_pin(dapm, "Line Jack"); |
77 | snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); | 77 | snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); |
78 | snd_soc_dapm_disable_pin(dapm, "Headset Jack"); | 78 | snd_soc_dapm_disable_pin(dapm, "Headset Jack"); |
79 | break; | 79 | break; |
80 | case CORGI_HEADSET: | 80 | case CORGI_HEADSET: |
81 | gpio_set_value(CORGI_GPIO_MUTE_L, 0); | 81 | gpio_set_value(CORGI_GPIO_MUTE_L, 0); |
82 | gpio_set_value(CORGI_GPIO_MUTE_R, 1); | 82 | gpio_set_value(CORGI_GPIO_MUTE_R, 1); |
83 | snd_soc_dapm_enable_pin(dapm, "Mic Jack"); | 83 | snd_soc_dapm_enable_pin(dapm, "Mic Jack"); |
84 | snd_soc_dapm_disable_pin(dapm, "Line Jack"); | 84 | snd_soc_dapm_disable_pin(dapm, "Line Jack"); |
85 | snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); | 85 | snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); |
86 | snd_soc_dapm_enable_pin(dapm, "Headset Jack"); | 86 | snd_soc_dapm_enable_pin(dapm, "Headset Jack"); |
87 | break; | 87 | break; |
88 | } | 88 | } |
89 | 89 | ||
90 | if (corgi_spk_func == CORGI_SPK_ON) | 90 | if (corgi_spk_func == CORGI_SPK_ON) |
91 | snd_soc_dapm_enable_pin(dapm, "Ext Spk"); | 91 | snd_soc_dapm_enable_pin(dapm, "Ext Spk"); |
92 | else | 92 | else |
93 | snd_soc_dapm_disable_pin(dapm, "Ext Spk"); | 93 | snd_soc_dapm_disable_pin(dapm, "Ext Spk"); |
94 | 94 | ||
95 | /* signal a DAPM event */ | 95 | /* signal a DAPM event */ |
96 | snd_soc_dapm_sync(dapm); | 96 | snd_soc_dapm_sync(dapm); |
97 | } | 97 | } |
98 | 98 | ||
99 | static int corgi_startup(struct snd_pcm_substream *substream) | 99 | static int corgi_startup(struct snd_pcm_substream *substream) |
100 | { | 100 | { |
101 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 101 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
102 | struct snd_soc_codec *codec = rtd->codec; | 102 | struct snd_soc_codec *codec = rtd->codec; |
103 | 103 | ||
104 | mutex_lock(&codec->mutex); | 104 | mutex_lock(&codec->mutex); |
105 | 105 | ||
106 | /* check the jack status at stream startup */ | 106 | /* check the jack status at stream startup */ |
107 | corgi_ext_control(codec); | 107 | corgi_ext_control(codec); |
108 | 108 | ||
109 | mutex_unlock(&codec->mutex); | 109 | mutex_unlock(&codec->mutex); |
110 | 110 | ||
111 | return 0; | 111 | return 0; |
112 | } | 112 | } |
113 | 113 | ||
114 | /* we need to unmute the HP at shutdown as the mute burns power on corgi */ | 114 | /* we need to unmute the HP at shutdown as the mute burns power on corgi */ |
115 | static void corgi_shutdown(struct snd_pcm_substream *substream) | 115 | static void corgi_shutdown(struct snd_pcm_substream *substream) |
116 | { | 116 | { |
117 | /* set = unmute headphone */ | 117 | /* set = unmute headphone */ |
118 | gpio_set_value(CORGI_GPIO_MUTE_L, 1); | 118 | gpio_set_value(CORGI_GPIO_MUTE_L, 1); |
119 | gpio_set_value(CORGI_GPIO_MUTE_R, 1); | 119 | gpio_set_value(CORGI_GPIO_MUTE_R, 1); |
120 | } | 120 | } |
121 | 121 | ||
122 | static int corgi_hw_params(struct snd_pcm_substream *substream, | 122 | static int corgi_hw_params(struct snd_pcm_substream *substream, |
123 | struct snd_pcm_hw_params *params) | 123 | struct snd_pcm_hw_params *params) |
124 | { | 124 | { |
125 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 125 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
126 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 126 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
127 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 127 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
128 | unsigned int clk = 0; | 128 | unsigned int clk = 0; |
129 | int ret = 0; | 129 | int ret = 0; |
130 | 130 | ||
131 | switch (params_rate(params)) { | 131 | switch (params_rate(params)) { |
132 | case 8000: | 132 | case 8000: |
133 | case 16000: | 133 | case 16000: |
134 | case 48000: | 134 | case 48000: |
135 | case 96000: | 135 | case 96000: |
136 | clk = 12288000; | 136 | clk = 12288000; |
137 | break; | 137 | break; |
138 | case 11025: | 138 | case 11025: |
139 | case 22050: | 139 | case 22050: |
140 | case 44100: | 140 | case 44100: |
141 | clk = 11289600; | 141 | clk = 11289600; |
142 | break; | 142 | break; |
143 | } | 143 | } |
144 | 144 | ||
145 | /* set codec DAI configuration */ | 145 | /* set codec DAI configuration */ |
146 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | | 146 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | |
147 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); | 147 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); |
148 | if (ret < 0) | 148 | if (ret < 0) |
149 | return ret; | 149 | return ret; |
150 | 150 | ||
151 | /* set cpu DAI configuration */ | 151 | /* set cpu DAI configuration */ |
152 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | | 152 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | |
153 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); | 153 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); |
154 | if (ret < 0) | 154 | if (ret < 0) |
155 | return ret; | 155 | return ret; |
156 | 156 | ||
157 | /* set the codec system clock for DAC and ADC */ | 157 | /* set the codec system clock for DAC and ADC */ |
158 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL, clk, | 158 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL, clk, |
159 | SND_SOC_CLOCK_IN); | 159 | SND_SOC_CLOCK_IN); |
160 | if (ret < 0) | 160 | if (ret < 0) |
161 | return ret; | 161 | return ret; |
162 | 162 | ||
163 | /* set the I2S system clock as input (unused) */ | 163 | /* set the I2S system clock as input (unused) */ |
164 | ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0, | 164 | ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0, |
165 | SND_SOC_CLOCK_IN); | 165 | SND_SOC_CLOCK_IN); |
166 | if (ret < 0) | 166 | if (ret < 0) |
167 | return ret; | 167 | return ret; |
168 | 168 | ||
169 | return 0; | 169 | return 0; |
170 | } | 170 | } |
171 | 171 | ||
172 | static struct snd_soc_ops corgi_ops = { | 172 | static struct snd_soc_ops corgi_ops = { |
173 | .startup = corgi_startup, | 173 | .startup = corgi_startup, |
174 | .hw_params = corgi_hw_params, | 174 | .hw_params = corgi_hw_params, |
175 | .shutdown = corgi_shutdown, | 175 | .shutdown = corgi_shutdown, |
176 | }; | 176 | }; |
177 | 177 | ||
178 | static int corgi_get_jack(struct snd_kcontrol *kcontrol, | 178 | static int corgi_get_jack(struct snd_kcontrol *kcontrol, |
179 | struct snd_ctl_elem_value *ucontrol) | 179 | struct snd_ctl_elem_value *ucontrol) |
180 | { | 180 | { |
181 | ucontrol->value.integer.value[0] = corgi_jack_func; | 181 | ucontrol->value.integer.value[0] = corgi_jack_func; |
182 | return 0; | 182 | return 0; |
183 | } | 183 | } |
184 | 184 | ||
185 | static int corgi_set_jack(struct snd_kcontrol *kcontrol, | 185 | static int corgi_set_jack(struct snd_kcontrol *kcontrol, |
186 | struct snd_ctl_elem_value *ucontrol) | 186 | struct snd_ctl_elem_value *ucontrol) |
187 | { | 187 | { |
188 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 188 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
189 | 189 | ||
190 | if (corgi_jack_func == ucontrol->value.integer.value[0]) | 190 | if (corgi_jack_func == ucontrol->value.integer.value[0]) |
191 | return 0; | 191 | return 0; |
192 | 192 | ||
193 | corgi_jack_func = ucontrol->value.integer.value[0]; | 193 | corgi_jack_func = ucontrol->value.integer.value[0]; |
194 | corgi_ext_control(codec); | 194 | corgi_ext_control(codec); |
195 | return 1; | 195 | return 1; |
196 | } | 196 | } |
197 | 197 | ||
198 | static int corgi_get_spk(struct snd_kcontrol *kcontrol, | 198 | static int corgi_get_spk(struct snd_kcontrol *kcontrol, |
199 | struct snd_ctl_elem_value *ucontrol) | 199 | struct snd_ctl_elem_value *ucontrol) |
200 | { | 200 | { |
201 | ucontrol->value.integer.value[0] = corgi_spk_func; | 201 | ucontrol->value.integer.value[0] = corgi_spk_func; |
202 | return 0; | 202 | return 0; |
203 | } | 203 | } |
204 | 204 | ||
205 | static int corgi_set_spk(struct snd_kcontrol *kcontrol, | 205 | static int corgi_set_spk(struct snd_kcontrol *kcontrol, |
206 | struct snd_ctl_elem_value *ucontrol) | 206 | struct snd_ctl_elem_value *ucontrol) |
207 | { | 207 | { |
208 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 208 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
209 | 209 | ||
210 | if (corgi_spk_func == ucontrol->value.integer.value[0]) | 210 | if (corgi_spk_func == ucontrol->value.integer.value[0]) |
211 | return 0; | 211 | return 0; |
212 | 212 | ||
213 | corgi_spk_func = ucontrol->value.integer.value[0]; | 213 | corgi_spk_func = ucontrol->value.integer.value[0]; |
214 | corgi_ext_control(codec); | 214 | corgi_ext_control(codec); |
215 | return 1; | 215 | return 1; |
216 | } | 216 | } |
217 | 217 | ||
218 | static int corgi_amp_event(struct snd_soc_dapm_widget *w, | 218 | static int corgi_amp_event(struct snd_soc_dapm_widget *w, |
219 | struct snd_kcontrol *k, int event) | 219 | struct snd_kcontrol *k, int event) |
220 | { | 220 | { |
221 | gpio_set_value(CORGI_GPIO_APM_ON, SND_SOC_DAPM_EVENT_ON(event)); | 221 | gpio_set_value(CORGI_GPIO_APM_ON, SND_SOC_DAPM_EVENT_ON(event)); |
222 | return 0; | 222 | return 0; |
223 | } | 223 | } |
224 | 224 | ||
225 | static int corgi_mic_event(struct snd_soc_dapm_widget *w, | 225 | static int corgi_mic_event(struct snd_soc_dapm_widget *w, |
226 | struct snd_kcontrol *k, int event) | 226 | struct snd_kcontrol *k, int event) |
227 | { | 227 | { |
228 | gpio_set_value(CORGI_GPIO_MIC_BIAS, SND_SOC_DAPM_EVENT_ON(event)); | 228 | gpio_set_value(CORGI_GPIO_MIC_BIAS, SND_SOC_DAPM_EVENT_ON(event)); |
229 | return 0; | 229 | return 0; |
230 | } | 230 | } |
231 | 231 | ||
232 | /* corgi machine dapm widgets */ | 232 | /* corgi machine dapm widgets */ |
233 | static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = { | 233 | static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = { |
234 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | 234 | SND_SOC_DAPM_HP("Headphone Jack", NULL), |
235 | SND_SOC_DAPM_MIC("Mic Jack", corgi_mic_event), | 235 | SND_SOC_DAPM_MIC("Mic Jack", corgi_mic_event), |
236 | SND_SOC_DAPM_SPK("Ext Spk", corgi_amp_event), | 236 | SND_SOC_DAPM_SPK("Ext Spk", corgi_amp_event), |
237 | SND_SOC_DAPM_LINE("Line Jack", NULL), | 237 | SND_SOC_DAPM_LINE("Line Jack", NULL), |
238 | SND_SOC_DAPM_HP("Headset Jack", NULL), | 238 | SND_SOC_DAPM_HP("Headset Jack", NULL), |
239 | }; | 239 | }; |
240 | 240 | ||
241 | /* Corgi machine audio map (connections to the codec pins) */ | 241 | /* Corgi machine audio map (connections to the codec pins) */ |
242 | static const struct snd_soc_dapm_route audio_map[] = { | 242 | static const struct snd_soc_dapm_route audio_map[] = { |
243 | 243 | ||
244 | /* headset Jack - in = micin, out = LHPOUT*/ | 244 | /* headset Jack - in = micin, out = LHPOUT*/ |
245 | {"Headset Jack", NULL, "LHPOUT"}, | 245 | {"Headset Jack", NULL, "LHPOUT"}, |
246 | 246 | ||
247 | /* headphone connected to LHPOUT1, RHPOUT1 */ | 247 | /* headphone connected to LHPOUT1, RHPOUT1 */ |
248 | {"Headphone Jack", NULL, "LHPOUT"}, | 248 | {"Headphone Jack", NULL, "LHPOUT"}, |
249 | {"Headphone Jack", NULL, "RHPOUT"}, | 249 | {"Headphone Jack", NULL, "RHPOUT"}, |
250 | 250 | ||
251 | /* speaker connected to LOUT, ROUT */ | 251 | /* speaker connected to LOUT, ROUT */ |
252 | {"Ext Spk", NULL, "ROUT"}, | 252 | {"Ext Spk", NULL, "ROUT"}, |
253 | {"Ext Spk", NULL, "LOUT"}, | 253 | {"Ext Spk", NULL, "LOUT"}, |
254 | 254 | ||
255 | /* mic is connected to MICIN (via right channel of headphone jack) */ | 255 | /* mic is connected to MICIN (via right channel of headphone jack) */ |
256 | {"MICIN", NULL, "Mic Jack"}, | 256 | {"MICIN", NULL, "Mic Jack"}, |
257 | 257 | ||
258 | /* Same as the above but no mic bias for line signals */ | 258 | /* Same as the above but no mic bias for line signals */ |
259 | {"MICIN", NULL, "Line Jack"}, | 259 | {"MICIN", NULL, "Line Jack"}, |
260 | }; | 260 | }; |
261 | 261 | ||
262 | static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset", | 262 | static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset", |
263 | "Off"}; | 263 | "Off"}; |
264 | static const char *spk_function[] = {"On", "Off"}; | 264 | static const char *spk_function[] = {"On", "Off"}; |
265 | static const struct soc_enum corgi_enum[] = { | 265 | static const struct soc_enum corgi_enum[] = { |
266 | SOC_ENUM_SINGLE_EXT(5, jack_function), | 266 | SOC_ENUM_SINGLE_EXT(5, jack_function), |
267 | SOC_ENUM_SINGLE_EXT(2, spk_function), | 267 | SOC_ENUM_SINGLE_EXT(2, spk_function), |
268 | }; | 268 | }; |
269 | 269 | ||
270 | static const struct snd_kcontrol_new wm8731_corgi_controls[] = { | 270 | static const struct snd_kcontrol_new wm8731_corgi_controls[] = { |
271 | SOC_ENUM_EXT("Jack Function", corgi_enum[0], corgi_get_jack, | 271 | SOC_ENUM_EXT("Jack Function", corgi_enum[0], corgi_get_jack, |
272 | corgi_set_jack), | 272 | corgi_set_jack), |
273 | SOC_ENUM_EXT("Speaker Function", corgi_enum[1], corgi_get_spk, | 273 | SOC_ENUM_EXT("Speaker Function", corgi_enum[1], corgi_get_spk, |
274 | corgi_set_spk), | 274 | corgi_set_spk), |
275 | }; | 275 | }; |
276 | 276 | ||
277 | /* | 277 | /* |
278 | * Logic for a wm8731 as connected on a Sharp SL-C7x0 Device | 278 | * Logic for a wm8731 as connected on a Sharp SL-C7x0 Device |
279 | */ | 279 | */ |
280 | static int corgi_wm8731_init(struct snd_soc_pcm_runtime *rtd) | 280 | static int corgi_wm8731_init(struct snd_soc_pcm_runtime *rtd) |
281 | { | 281 | { |
282 | struct snd_soc_codec *codec = rtd->codec; | 282 | struct snd_soc_codec *codec = rtd->codec; |
283 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 283 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
284 | int err; | 284 | int err; |
285 | 285 | ||
286 | snd_soc_dapm_nc_pin(dapm, "LLINEIN"); | 286 | snd_soc_dapm_nc_pin(dapm, "LLINEIN"); |
287 | snd_soc_dapm_nc_pin(dapm, "RLINEIN"); | 287 | snd_soc_dapm_nc_pin(dapm, "RLINEIN"); |
288 | 288 | ||
289 | /* Add corgi specific controls */ | 289 | /* Add corgi specific controls */ |
290 | err = snd_soc_add_controls(codec, wm8731_corgi_controls, | 290 | err = snd_soc_add_controls(codec, wm8731_corgi_controls, |
291 | ARRAY_SIZE(wm8731_corgi_controls)); | 291 | ARRAY_SIZE(wm8731_corgi_controls)); |
292 | if (err < 0) | 292 | if (err < 0) |
293 | return err; | 293 | return err; |
294 | 294 | ||
295 | /* Add corgi specific widgets */ | 295 | /* Add corgi specific widgets */ |
296 | snd_soc_dapm_new_controls(dapm, wm8731_dapm_widgets, | 296 | snd_soc_dapm_new_controls(dapm, wm8731_dapm_widgets, |
297 | ARRAY_SIZE(wm8731_dapm_widgets)); | 297 | ARRAY_SIZE(wm8731_dapm_widgets)); |
298 | 298 | ||
299 | /* Set up corgi specific audio path audio_map */ | 299 | /* Set up corgi specific audio path audio_map */ |
300 | snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); | 300 | snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); |
301 | 301 | ||
302 | snd_soc_dapm_sync(dapm); | ||
303 | return 0; | 302 | return 0; |
304 | } | 303 | } |
305 | 304 | ||
306 | /* corgi digital audio interface glue - connects codec <--> CPU */ | 305 | /* corgi digital audio interface glue - connects codec <--> CPU */ |
307 | static struct snd_soc_dai_link corgi_dai = { | 306 | static struct snd_soc_dai_link corgi_dai = { |
308 | .name = "WM8731", | 307 | .name = "WM8731", |
309 | .stream_name = "WM8731", | 308 | .stream_name = "WM8731", |
310 | .cpu_dai_name = "pxa2xx-i2s", | 309 | .cpu_dai_name = "pxa2xx-i2s", |
311 | .codec_dai_name = "wm8731-hifi", | 310 | .codec_dai_name = "wm8731-hifi", |
312 | .platform_name = "pxa-pcm-audio", | 311 | .platform_name = "pxa-pcm-audio", |
313 | .codec_name = "wm8731.0-001b", | 312 | .codec_name = "wm8731.0-001b", |
314 | .init = corgi_wm8731_init, | 313 | .init = corgi_wm8731_init, |
315 | .ops = &corgi_ops, | 314 | .ops = &corgi_ops, |
316 | }; | 315 | }; |
317 | 316 | ||
318 | /* corgi audio machine driver */ | 317 | /* corgi audio machine driver */ |
319 | static struct snd_soc_card snd_soc_corgi = { | 318 | static struct snd_soc_card snd_soc_corgi = { |
320 | .name = "Corgi", | 319 | .name = "Corgi", |
321 | .dai_link = &corgi_dai, | 320 | .dai_link = &corgi_dai, |
322 | .num_links = 1, | 321 | .num_links = 1, |
323 | }; | 322 | }; |
324 | 323 | ||
325 | static struct platform_device *corgi_snd_device; | 324 | static struct platform_device *corgi_snd_device; |
326 | 325 | ||
327 | static int __init corgi_init(void) | 326 | static int __init corgi_init(void) |
328 | { | 327 | { |
329 | int ret; | 328 | int ret; |
330 | 329 | ||
331 | if (!(machine_is_corgi() || machine_is_shepherd() || | 330 | if (!(machine_is_corgi() || machine_is_shepherd() || |
332 | machine_is_husky())) | 331 | machine_is_husky())) |
333 | return -ENODEV; | 332 | return -ENODEV; |
334 | 333 | ||
335 | corgi_snd_device = platform_device_alloc("soc-audio", -1); | 334 | corgi_snd_device = platform_device_alloc("soc-audio", -1); |
336 | if (!corgi_snd_device) | 335 | if (!corgi_snd_device) |
337 | return -ENOMEM; | 336 | return -ENOMEM; |
338 | 337 | ||
339 | platform_set_drvdata(corgi_snd_device, &snd_soc_corgi); | 338 | platform_set_drvdata(corgi_snd_device, &snd_soc_corgi); |
340 | ret = platform_device_add(corgi_snd_device); | 339 | ret = platform_device_add(corgi_snd_device); |
341 | 340 | ||
342 | if (ret) | 341 | if (ret) |
343 | platform_device_put(corgi_snd_device); | 342 | platform_device_put(corgi_snd_device); |
344 | 343 | ||
345 | return ret; | 344 | return ret; |
346 | } | 345 | } |
347 | 346 | ||
348 | static void __exit corgi_exit(void) | 347 | static void __exit corgi_exit(void) |
349 | { | 348 | { |
350 | platform_device_unregister(corgi_snd_device); | 349 | platform_device_unregister(corgi_snd_device); |
351 | } | 350 | } |
352 | 351 | ||
353 | module_init(corgi_init); | 352 | module_init(corgi_init); |
354 | module_exit(corgi_exit); | 353 | module_exit(corgi_exit); |
355 | 354 | ||
356 | /* Module information */ | 355 | /* Module information */ |
357 | MODULE_AUTHOR("Richard Purdie"); | 356 | MODULE_AUTHOR("Richard Purdie"); |
358 | MODULE_DESCRIPTION("ALSA SoC Corgi"); | 357 | MODULE_DESCRIPTION("ALSA SoC Corgi"); |
359 | MODULE_LICENSE("GPL"); | 358 | MODULE_LICENSE("GPL"); |
360 | 359 |
sound/soc/pxa/e740_wm9705.c
1 | /* | 1 | /* |
2 | * e740-wm9705.c -- SoC audio for e740 | 2 | * e740-wm9705.c -- SoC audio for e740 |
3 | * | 3 | * |
4 | * Copyright 2007 (c) Ian Molton <spyro@f2s.com> | 4 | * Copyright 2007 (c) Ian Molton <spyro@f2s.com> |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify it | 6 | * This program is free software; you can redistribute it and/or modify it |
7 | * under the terms of the GNU General Public License as published by the | 7 | * under the terms of the GNU General Public License as published by the |
8 | * Free Software Foundation; version 2 ONLY. | 8 | * Free Software Foundation; version 2 ONLY. |
9 | * | 9 | * |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
13 | #include <linux/moduleparam.h> | 13 | #include <linux/moduleparam.h> |
14 | #include <linux/gpio.h> | 14 | #include <linux/gpio.h> |
15 | 15 | ||
16 | #include <sound/core.h> | 16 | #include <sound/core.h> |
17 | #include <sound/pcm.h> | 17 | #include <sound/pcm.h> |
18 | #include <sound/soc.h> | 18 | #include <sound/soc.h> |
19 | 19 | ||
20 | #include <mach/audio.h> | 20 | #include <mach/audio.h> |
21 | #include <mach/eseries-gpio.h> | 21 | #include <mach/eseries-gpio.h> |
22 | 22 | ||
23 | #include <asm/mach-types.h> | 23 | #include <asm/mach-types.h> |
24 | 24 | ||
25 | #include "../codecs/wm9705.h" | 25 | #include "../codecs/wm9705.h" |
26 | #include "pxa2xx-ac97.h" | 26 | #include "pxa2xx-ac97.h" |
27 | 27 | ||
28 | 28 | ||
29 | #define E740_AUDIO_OUT 1 | 29 | #define E740_AUDIO_OUT 1 |
30 | #define E740_AUDIO_IN 2 | 30 | #define E740_AUDIO_IN 2 |
31 | 31 | ||
32 | static int e740_audio_power; | 32 | static int e740_audio_power; |
33 | 33 | ||
34 | static void e740_sync_audio_power(int status) | 34 | static void e740_sync_audio_power(int status) |
35 | { | 35 | { |
36 | gpio_set_value(GPIO_E740_WM9705_nAVDD2, !status); | 36 | gpio_set_value(GPIO_E740_WM9705_nAVDD2, !status); |
37 | gpio_set_value(GPIO_E740_AMP_ON, (status & E740_AUDIO_OUT) ? 1 : 0); | 37 | gpio_set_value(GPIO_E740_AMP_ON, (status & E740_AUDIO_OUT) ? 1 : 0); |
38 | gpio_set_value(GPIO_E740_MIC_ON, (status & E740_AUDIO_IN) ? 1 : 0); | 38 | gpio_set_value(GPIO_E740_MIC_ON, (status & E740_AUDIO_IN) ? 1 : 0); |
39 | } | 39 | } |
40 | 40 | ||
41 | static int e740_mic_amp_event(struct snd_soc_dapm_widget *w, | 41 | static int e740_mic_amp_event(struct snd_soc_dapm_widget *w, |
42 | struct snd_kcontrol *kcontrol, int event) | 42 | struct snd_kcontrol *kcontrol, int event) |
43 | { | 43 | { |
44 | if (event & SND_SOC_DAPM_PRE_PMU) | 44 | if (event & SND_SOC_DAPM_PRE_PMU) |
45 | e740_audio_power |= E740_AUDIO_IN; | 45 | e740_audio_power |= E740_AUDIO_IN; |
46 | else if (event & SND_SOC_DAPM_POST_PMD) | 46 | else if (event & SND_SOC_DAPM_POST_PMD) |
47 | e740_audio_power &= ~E740_AUDIO_IN; | 47 | e740_audio_power &= ~E740_AUDIO_IN; |
48 | 48 | ||
49 | e740_sync_audio_power(e740_audio_power); | 49 | e740_sync_audio_power(e740_audio_power); |
50 | 50 | ||
51 | return 0; | 51 | return 0; |
52 | } | 52 | } |
53 | 53 | ||
54 | static int e740_output_amp_event(struct snd_soc_dapm_widget *w, | 54 | static int e740_output_amp_event(struct snd_soc_dapm_widget *w, |
55 | struct snd_kcontrol *kcontrol, int event) | 55 | struct snd_kcontrol *kcontrol, int event) |
56 | { | 56 | { |
57 | if (event & SND_SOC_DAPM_PRE_PMU) | 57 | if (event & SND_SOC_DAPM_PRE_PMU) |
58 | e740_audio_power |= E740_AUDIO_OUT; | 58 | e740_audio_power |= E740_AUDIO_OUT; |
59 | else if (event & SND_SOC_DAPM_POST_PMD) | 59 | else if (event & SND_SOC_DAPM_POST_PMD) |
60 | e740_audio_power &= ~E740_AUDIO_OUT; | 60 | e740_audio_power &= ~E740_AUDIO_OUT; |
61 | 61 | ||
62 | e740_sync_audio_power(e740_audio_power); | 62 | e740_sync_audio_power(e740_audio_power); |
63 | 63 | ||
64 | return 0; | 64 | return 0; |
65 | } | 65 | } |
66 | 66 | ||
67 | static const struct snd_soc_dapm_widget e740_dapm_widgets[] = { | 67 | static const struct snd_soc_dapm_widget e740_dapm_widgets[] = { |
68 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | 68 | SND_SOC_DAPM_HP("Headphone Jack", NULL), |
69 | SND_SOC_DAPM_SPK("Speaker", NULL), | 69 | SND_SOC_DAPM_SPK("Speaker", NULL), |
70 | SND_SOC_DAPM_MIC("Mic (Internal)", NULL), | 70 | SND_SOC_DAPM_MIC("Mic (Internal)", NULL), |
71 | SND_SOC_DAPM_PGA_E("Output Amp", SND_SOC_NOPM, 0, 0, NULL, 0, | 71 | SND_SOC_DAPM_PGA_E("Output Amp", SND_SOC_NOPM, 0, 0, NULL, 0, |
72 | e740_output_amp_event, SND_SOC_DAPM_PRE_PMU | | 72 | e740_output_amp_event, SND_SOC_DAPM_PRE_PMU | |
73 | SND_SOC_DAPM_POST_PMD), | 73 | SND_SOC_DAPM_POST_PMD), |
74 | SND_SOC_DAPM_PGA_E("Mic Amp", SND_SOC_NOPM, 0, 0, NULL, 0, | 74 | SND_SOC_DAPM_PGA_E("Mic Amp", SND_SOC_NOPM, 0, 0, NULL, 0, |
75 | e740_mic_amp_event, SND_SOC_DAPM_PRE_PMU | | 75 | e740_mic_amp_event, SND_SOC_DAPM_PRE_PMU | |
76 | SND_SOC_DAPM_POST_PMD), | 76 | SND_SOC_DAPM_POST_PMD), |
77 | }; | 77 | }; |
78 | 78 | ||
79 | static const struct snd_soc_dapm_route audio_map[] = { | 79 | static const struct snd_soc_dapm_route audio_map[] = { |
80 | {"Output Amp", NULL, "LOUT"}, | 80 | {"Output Amp", NULL, "LOUT"}, |
81 | {"Output Amp", NULL, "ROUT"}, | 81 | {"Output Amp", NULL, "ROUT"}, |
82 | {"Output Amp", NULL, "MONOOUT"}, | 82 | {"Output Amp", NULL, "MONOOUT"}, |
83 | 83 | ||
84 | {"Speaker", NULL, "Output Amp"}, | 84 | {"Speaker", NULL, "Output Amp"}, |
85 | {"Headphone Jack", NULL, "Output Amp"}, | 85 | {"Headphone Jack", NULL, "Output Amp"}, |
86 | 86 | ||
87 | {"MIC1", NULL, "Mic Amp"}, | 87 | {"MIC1", NULL, "Mic Amp"}, |
88 | {"Mic Amp", NULL, "Mic (Internal)"}, | 88 | {"Mic Amp", NULL, "Mic (Internal)"}, |
89 | }; | 89 | }; |
90 | 90 | ||
91 | static int e740_ac97_init(struct snd_soc_pcm_runtime *rtd) | 91 | static int e740_ac97_init(struct snd_soc_pcm_runtime *rtd) |
92 | { | 92 | { |
93 | struct snd_soc_codec *codec = rtd->codec; | 93 | struct snd_soc_codec *codec = rtd->codec; |
94 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 94 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
95 | 95 | ||
96 | snd_soc_dapm_nc_pin(dapm, "HPOUTL"); | 96 | snd_soc_dapm_nc_pin(dapm, "HPOUTL"); |
97 | snd_soc_dapm_nc_pin(dapm, "HPOUTR"); | 97 | snd_soc_dapm_nc_pin(dapm, "HPOUTR"); |
98 | snd_soc_dapm_nc_pin(dapm, "PHONE"); | 98 | snd_soc_dapm_nc_pin(dapm, "PHONE"); |
99 | snd_soc_dapm_nc_pin(dapm, "LINEINL"); | 99 | snd_soc_dapm_nc_pin(dapm, "LINEINL"); |
100 | snd_soc_dapm_nc_pin(dapm, "LINEINR"); | 100 | snd_soc_dapm_nc_pin(dapm, "LINEINR"); |
101 | snd_soc_dapm_nc_pin(dapm, "CDINL"); | 101 | snd_soc_dapm_nc_pin(dapm, "CDINL"); |
102 | snd_soc_dapm_nc_pin(dapm, "CDINR"); | 102 | snd_soc_dapm_nc_pin(dapm, "CDINR"); |
103 | snd_soc_dapm_nc_pin(dapm, "PCBEEP"); | 103 | snd_soc_dapm_nc_pin(dapm, "PCBEEP"); |
104 | snd_soc_dapm_nc_pin(dapm, "MIC2"); | 104 | snd_soc_dapm_nc_pin(dapm, "MIC2"); |
105 | 105 | ||
106 | snd_soc_dapm_new_controls(dapm, e740_dapm_widgets, | 106 | snd_soc_dapm_new_controls(dapm, e740_dapm_widgets, |
107 | ARRAY_SIZE(e740_dapm_widgets)); | 107 | ARRAY_SIZE(e740_dapm_widgets)); |
108 | 108 | ||
109 | snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); | 109 | snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); |
110 | 110 | ||
111 | snd_soc_dapm_sync(dapm); | ||
112 | |||
113 | return 0; | 111 | return 0; |
114 | } | 112 | } |
115 | 113 | ||
116 | static struct snd_soc_dai_link e740_dai[] = { | 114 | static struct snd_soc_dai_link e740_dai[] = { |
117 | { | 115 | { |
118 | .name = "AC97", | 116 | .name = "AC97", |
119 | .stream_name = "AC97 HiFi", | 117 | .stream_name = "AC97 HiFi", |
120 | .cpu_dai_name = "pxa2xx-ac97", | 118 | .cpu_dai_name = "pxa2xx-ac97", |
121 | .codec_dai_name = "wm9705-hifi", | 119 | .codec_dai_name = "wm9705-hifi", |
122 | .platform_name = "pxa-pcm-audio", | 120 | .platform_name = "pxa-pcm-audio", |
123 | .codec_name = "wm9705-codec", | 121 | .codec_name = "wm9705-codec", |
124 | .init = e740_ac97_init, | 122 | .init = e740_ac97_init, |
125 | }, | 123 | }, |
126 | { | 124 | { |
127 | .name = "AC97 Aux", | 125 | .name = "AC97 Aux", |
128 | .stream_name = "AC97 Aux", | 126 | .stream_name = "AC97 Aux", |
129 | .cpu_dai_name = "pxa2xx-ac97-aux", | 127 | .cpu_dai_name = "pxa2xx-ac97-aux", |
130 | .codec_dai_name = "wm9705-aux", | 128 | .codec_dai_name = "wm9705-aux", |
131 | .platform_name = "pxa-pcm-audio", | 129 | .platform_name = "pxa-pcm-audio", |
132 | .codec_name = "wm9705-codec", | 130 | .codec_name = "wm9705-codec", |
133 | }, | 131 | }, |
134 | }; | 132 | }; |
135 | 133 | ||
136 | static struct snd_soc_card e740 = { | 134 | static struct snd_soc_card e740 = { |
137 | .name = "Toshiba e740", | 135 | .name = "Toshiba e740", |
138 | .dai_link = e740_dai, | 136 | .dai_link = e740_dai, |
139 | .num_links = ARRAY_SIZE(e740_dai), | 137 | .num_links = ARRAY_SIZE(e740_dai), |
140 | }; | 138 | }; |
141 | 139 | ||
142 | static struct platform_device *e740_snd_device; | 140 | static struct platform_device *e740_snd_device; |
143 | 141 | ||
144 | static int __init e740_init(void) | 142 | static int __init e740_init(void) |
145 | { | 143 | { |
146 | int ret; | 144 | int ret; |
147 | 145 | ||
148 | if (!machine_is_e740()) | 146 | if (!machine_is_e740()) |
149 | return -ENODEV; | 147 | return -ENODEV; |
150 | 148 | ||
151 | ret = gpio_request(GPIO_E740_MIC_ON, "Mic amp"); | 149 | ret = gpio_request(GPIO_E740_MIC_ON, "Mic amp"); |
152 | if (ret) | 150 | if (ret) |
153 | return ret; | 151 | return ret; |
154 | 152 | ||
155 | ret = gpio_request(GPIO_E740_AMP_ON, "Output amp"); | 153 | ret = gpio_request(GPIO_E740_AMP_ON, "Output amp"); |
156 | if (ret) | 154 | if (ret) |
157 | goto free_mic_amp_gpio; | 155 | goto free_mic_amp_gpio; |
158 | 156 | ||
159 | ret = gpio_request(GPIO_E740_WM9705_nAVDD2, "Audio power"); | 157 | ret = gpio_request(GPIO_E740_WM9705_nAVDD2, "Audio power"); |
160 | if (ret) | 158 | if (ret) |
161 | goto free_op_amp_gpio; | 159 | goto free_op_amp_gpio; |
162 | 160 | ||
163 | /* Disable audio */ | 161 | /* Disable audio */ |
164 | ret = gpio_direction_output(GPIO_E740_MIC_ON, 0); | 162 | ret = gpio_direction_output(GPIO_E740_MIC_ON, 0); |
165 | if (ret) | 163 | if (ret) |
166 | goto free_apwr_gpio; | 164 | goto free_apwr_gpio; |
167 | ret = gpio_direction_output(GPIO_E740_AMP_ON, 0); | 165 | ret = gpio_direction_output(GPIO_E740_AMP_ON, 0); |
168 | if (ret) | 166 | if (ret) |
169 | goto free_apwr_gpio; | 167 | goto free_apwr_gpio; |
170 | ret = gpio_direction_output(GPIO_E740_WM9705_nAVDD2, 1); | 168 | ret = gpio_direction_output(GPIO_E740_WM9705_nAVDD2, 1); |
171 | if (ret) | 169 | if (ret) |
172 | goto free_apwr_gpio; | 170 | goto free_apwr_gpio; |
173 | 171 | ||
174 | e740_snd_device = platform_device_alloc("soc-audio", -1); | 172 | e740_snd_device = platform_device_alloc("soc-audio", -1); |
175 | if (!e740_snd_device) { | 173 | if (!e740_snd_device) { |
176 | ret = -ENOMEM; | 174 | ret = -ENOMEM; |
177 | goto free_apwr_gpio; | 175 | goto free_apwr_gpio; |
178 | } | 176 | } |
179 | 177 | ||
180 | platform_set_drvdata(e740_snd_device, &e740); | 178 | platform_set_drvdata(e740_snd_device, &e740); |
181 | ret = platform_device_add(e740_snd_device); | 179 | ret = platform_device_add(e740_snd_device); |
182 | 180 | ||
183 | if (!ret) | 181 | if (!ret) |
184 | return 0; | 182 | return 0; |
185 | 183 | ||
186 | /* Fail gracefully */ | 184 | /* Fail gracefully */ |
187 | platform_device_put(e740_snd_device); | 185 | platform_device_put(e740_snd_device); |
188 | free_apwr_gpio: | 186 | free_apwr_gpio: |
189 | gpio_free(GPIO_E740_WM9705_nAVDD2); | 187 | gpio_free(GPIO_E740_WM9705_nAVDD2); |
190 | free_op_amp_gpio: | 188 | free_op_amp_gpio: |
191 | gpio_free(GPIO_E740_AMP_ON); | 189 | gpio_free(GPIO_E740_AMP_ON); |
192 | free_mic_amp_gpio: | 190 | free_mic_amp_gpio: |
193 | gpio_free(GPIO_E740_MIC_ON); | 191 | gpio_free(GPIO_E740_MIC_ON); |
194 | 192 | ||
195 | return ret; | 193 | return ret; |
196 | } | 194 | } |
197 | 195 | ||
198 | static void __exit e740_exit(void) | 196 | static void __exit e740_exit(void) |
199 | { | 197 | { |
200 | platform_device_unregister(e740_snd_device); | 198 | platform_device_unregister(e740_snd_device); |
201 | gpio_free(GPIO_E740_WM9705_nAVDD2); | 199 | gpio_free(GPIO_E740_WM9705_nAVDD2); |
202 | gpio_free(GPIO_E740_AMP_ON); | 200 | gpio_free(GPIO_E740_AMP_ON); |
203 | gpio_free(GPIO_E740_MIC_ON); | 201 | gpio_free(GPIO_E740_MIC_ON); |
204 | } | 202 | } |
205 | 203 | ||
206 | module_init(e740_init); | 204 | module_init(e740_init); |
207 | module_exit(e740_exit); | 205 | module_exit(e740_exit); |
208 | 206 | ||
209 | /* Module information */ | 207 | /* Module information */ |
210 | MODULE_AUTHOR("Ian Molton <spyro@f2s.com>"); | 208 | MODULE_AUTHOR("Ian Molton <spyro@f2s.com>"); |
211 | MODULE_DESCRIPTION("ALSA SoC driver for e740"); | 209 | MODULE_DESCRIPTION("ALSA SoC driver for e740"); |
212 | MODULE_LICENSE("GPL v2"); | 210 | MODULE_LICENSE("GPL v2"); |
213 | 211 |
sound/soc/pxa/e750_wm9705.c
1 | /* | 1 | /* |
2 | * e750-wm9705.c -- SoC audio for e750 | 2 | * e750-wm9705.c -- SoC audio for e750 |
3 | * | 3 | * |
4 | * Copyright 2007 (c) Ian Molton <spyro@f2s.com> | 4 | * Copyright 2007 (c) Ian Molton <spyro@f2s.com> |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify it | 6 | * This program is free software; you can redistribute it and/or modify it |
7 | * under the terms of the GNU General Public License as published by the | 7 | * under the terms of the GNU General Public License as published by the |
8 | * Free Software Foundation; version 2 ONLY. | 8 | * Free Software Foundation; version 2 ONLY. |
9 | * | 9 | * |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
13 | #include <linux/moduleparam.h> | 13 | #include <linux/moduleparam.h> |
14 | #include <linux/gpio.h> | 14 | #include <linux/gpio.h> |
15 | 15 | ||
16 | #include <sound/core.h> | 16 | #include <sound/core.h> |
17 | #include <sound/pcm.h> | 17 | #include <sound/pcm.h> |
18 | #include <sound/soc.h> | 18 | #include <sound/soc.h> |
19 | 19 | ||
20 | #include <mach/audio.h> | 20 | #include <mach/audio.h> |
21 | #include <mach/eseries-gpio.h> | 21 | #include <mach/eseries-gpio.h> |
22 | 22 | ||
23 | #include <asm/mach-types.h> | 23 | #include <asm/mach-types.h> |
24 | 24 | ||
25 | #include "../codecs/wm9705.h" | 25 | #include "../codecs/wm9705.h" |
26 | #include "pxa2xx-ac97.h" | 26 | #include "pxa2xx-ac97.h" |
27 | 27 | ||
28 | static int e750_spk_amp_event(struct snd_soc_dapm_widget *w, | 28 | static int e750_spk_amp_event(struct snd_soc_dapm_widget *w, |
29 | struct snd_kcontrol *kcontrol, int event) | 29 | struct snd_kcontrol *kcontrol, int event) |
30 | { | 30 | { |
31 | if (event & SND_SOC_DAPM_PRE_PMU) | 31 | if (event & SND_SOC_DAPM_PRE_PMU) |
32 | gpio_set_value(GPIO_E750_SPK_AMP_OFF, 0); | 32 | gpio_set_value(GPIO_E750_SPK_AMP_OFF, 0); |
33 | else if (event & SND_SOC_DAPM_POST_PMD) | 33 | else if (event & SND_SOC_DAPM_POST_PMD) |
34 | gpio_set_value(GPIO_E750_SPK_AMP_OFF, 1); | 34 | gpio_set_value(GPIO_E750_SPK_AMP_OFF, 1); |
35 | 35 | ||
36 | return 0; | 36 | return 0; |
37 | } | 37 | } |
38 | 38 | ||
39 | static int e750_hp_amp_event(struct snd_soc_dapm_widget *w, | 39 | static int e750_hp_amp_event(struct snd_soc_dapm_widget *w, |
40 | struct snd_kcontrol *kcontrol, int event) | 40 | struct snd_kcontrol *kcontrol, int event) |
41 | { | 41 | { |
42 | if (event & SND_SOC_DAPM_PRE_PMU) | 42 | if (event & SND_SOC_DAPM_PRE_PMU) |
43 | gpio_set_value(GPIO_E750_HP_AMP_OFF, 0); | 43 | gpio_set_value(GPIO_E750_HP_AMP_OFF, 0); |
44 | else if (event & SND_SOC_DAPM_POST_PMD) | 44 | else if (event & SND_SOC_DAPM_POST_PMD) |
45 | gpio_set_value(GPIO_E750_HP_AMP_OFF, 1); | 45 | gpio_set_value(GPIO_E750_HP_AMP_OFF, 1); |
46 | 46 | ||
47 | return 0; | 47 | return 0; |
48 | } | 48 | } |
49 | 49 | ||
50 | static const struct snd_soc_dapm_widget e750_dapm_widgets[] = { | 50 | static const struct snd_soc_dapm_widget e750_dapm_widgets[] = { |
51 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | 51 | SND_SOC_DAPM_HP("Headphone Jack", NULL), |
52 | SND_SOC_DAPM_SPK("Speaker", NULL), | 52 | SND_SOC_DAPM_SPK("Speaker", NULL), |
53 | SND_SOC_DAPM_MIC("Mic (Internal)", NULL), | 53 | SND_SOC_DAPM_MIC("Mic (Internal)", NULL), |
54 | SND_SOC_DAPM_PGA_E("Headphone Amp", SND_SOC_NOPM, 0, 0, NULL, 0, | 54 | SND_SOC_DAPM_PGA_E("Headphone Amp", SND_SOC_NOPM, 0, 0, NULL, 0, |
55 | e750_hp_amp_event, SND_SOC_DAPM_PRE_PMU | | 55 | e750_hp_amp_event, SND_SOC_DAPM_PRE_PMU | |
56 | SND_SOC_DAPM_POST_PMD), | 56 | SND_SOC_DAPM_POST_PMD), |
57 | SND_SOC_DAPM_PGA_E("Speaker Amp", SND_SOC_NOPM, 0, 0, NULL, 0, | 57 | SND_SOC_DAPM_PGA_E("Speaker Amp", SND_SOC_NOPM, 0, 0, NULL, 0, |
58 | e750_spk_amp_event, SND_SOC_DAPM_PRE_PMU | | 58 | e750_spk_amp_event, SND_SOC_DAPM_PRE_PMU | |
59 | SND_SOC_DAPM_POST_PMD), | 59 | SND_SOC_DAPM_POST_PMD), |
60 | }; | 60 | }; |
61 | 61 | ||
62 | static const struct snd_soc_dapm_route audio_map[] = { | 62 | static const struct snd_soc_dapm_route audio_map[] = { |
63 | {"Headphone Amp", NULL, "HPOUTL"}, | 63 | {"Headphone Amp", NULL, "HPOUTL"}, |
64 | {"Headphone Amp", NULL, "HPOUTR"}, | 64 | {"Headphone Amp", NULL, "HPOUTR"}, |
65 | {"Headphone Jack", NULL, "Headphone Amp"}, | 65 | {"Headphone Jack", NULL, "Headphone Amp"}, |
66 | 66 | ||
67 | {"Speaker Amp", NULL, "MONOOUT"}, | 67 | {"Speaker Amp", NULL, "MONOOUT"}, |
68 | {"Speaker", NULL, "Speaker Amp"}, | 68 | {"Speaker", NULL, "Speaker Amp"}, |
69 | 69 | ||
70 | {"MIC1", NULL, "Mic (Internal)"}, | 70 | {"MIC1", NULL, "Mic (Internal)"}, |
71 | }; | 71 | }; |
72 | 72 | ||
73 | static int e750_ac97_init(struct snd_soc_pcm_runtime *rtd) | 73 | static int e750_ac97_init(struct snd_soc_pcm_runtime *rtd) |
74 | { | 74 | { |
75 | struct snd_soc_codec *codec = rtd->codec; | 75 | struct snd_soc_codec *codec = rtd->codec; |
76 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 76 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
77 | 77 | ||
78 | snd_soc_dapm_nc_pin(dapm, "LOUT"); | 78 | snd_soc_dapm_nc_pin(dapm, "LOUT"); |
79 | snd_soc_dapm_nc_pin(dapm, "ROUT"); | 79 | snd_soc_dapm_nc_pin(dapm, "ROUT"); |
80 | snd_soc_dapm_nc_pin(dapm, "PHONE"); | 80 | snd_soc_dapm_nc_pin(dapm, "PHONE"); |
81 | snd_soc_dapm_nc_pin(dapm, "LINEINL"); | 81 | snd_soc_dapm_nc_pin(dapm, "LINEINL"); |
82 | snd_soc_dapm_nc_pin(dapm, "LINEINR"); | 82 | snd_soc_dapm_nc_pin(dapm, "LINEINR"); |
83 | snd_soc_dapm_nc_pin(dapm, "CDINL"); | 83 | snd_soc_dapm_nc_pin(dapm, "CDINL"); |
84 | snd_soc_dapm_nc_pin(dapm, "CDINR"); | 84 | snd_soc_dapm_nc_pin(dapm, "CDINR"); |
85 | snd_soc_dapm_nc_pin(dapm, "PCBEEP"); | 85 | snd_soc_dapm_nc_pin(dapm, "PCBEEP"); |
86 | snd_soc_dapm_nc_pin(dapm, "MIC2"); | 86 | snd_soc_dapm_nc_pin(dapm, "MIC2"); |
87 | 87 | ||
88 | snd_soc_dapm_new_controls(dapm, e750_dapm_widgets, | 88 | snd_soc_dapm_new_controls(dapm, e750_dapm_widgets, |
89 | ARRAY_SIZE(e750_dapm_widgets)); | 89 | ARRAY_SIZE(e750_dapm_widgets)); |
90 | 90 | ||
91 | snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); | 91 | snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); |
92 | 92 | ||
93 | snd_soc_dapm_sync(dapm); | ||
94 | |||
95 | return 0; | 93 | return 0; |
96 | } | 94 | } |
97 | 95 | ||
98 | static struct snd_soc_dai_link e750_dai[] = { | 96 | static struct snd_soc_dai_link e750_dai[] = { |
99 | { | 97 | { |
100 | .name = "AC97", | 98 | .name = "AC97", |
101 | .stream_name = "AC97 HiFi", | 99 | .stream_name = "AC97 HiFi", |
102 | .cpu_dai_name = "pxa2xx-ac97", | 100 | .cpu_dai_name = "pxa2xx-ac97", |
103 | .codec_dai_name = "wm9705-hifi", | 101 | .codec_dai_name = "wm9705-hifi", |
104 | .platform_name = "pxa-pcm-audio", | 102 | .platform_name = "pxa-pcm-audio", |
105 | .codec_name = "wm9705-codec", | 103 | .codec_name = "wm9705-codec", |
106 | .init = e750_ac97_init, | 104 | .init = e750_ac97_init, |
107 | /* use ops to check startup state */ | 105 | /* use ops to check startup state */ |
108 | }, | 106 | }, |
109 | { | 107 | { |
110 | .name = "AC97 Aux", | 108 | .name = "AC97 Aux", |
111 | .stream_name = "AC97 Aux", | 109 | .stream_name = "AC97 Aux", |
112 | .cpu_dai_name = "pxa2xx-ac97-aux", | 110 | .cpu_dai_name = "pxa2xx-ac97-aux", |
113 | .codec_dai_name ="wm9705-aux", | 111 | .codec_dai_name ="wm9705-aux", |
114 | .platform_name = "pxa-pcm-audio", | 112 | .platform_name = "pxa-pcm-audio", |
115 | .codec_name = "wm9705-codec", | 113 | .codec_name = "wm9705-codec", |
116 | }, | 114 | }, |
117 | }; | 115 | }; |
118 | 116 | ||
119 | static struct snd_soc_card e750 = { | 117 | static struct snd_soc_card e750 = { |
120 | .name = "Toshiba e750", | 118 | .name = "Toshiba e750", |
121 | .dai_link = e750_dai, | 119 | .dai_link = e750_dai, |
122 | .num_links = ARRAY_SIZE(e750_dai), | 120 | .num_links = ARRAY_SIZE(e750_dai), |
123 | }; | 121 | }; |
124 | 122 | ||
125 | static struct platform_device *e750_snd_device; | 123 | static struct platform_device *e750_snd_device; |
126 | 124 | ||
127 | static int __init e750_init(void) | 125 | static int __init e750_init(void) |
128 | { | 126 | { |
129 | int ret; | 127 | int ret; |
130 | 128 | ||
131 | if (!machine_is_e750()) | 129 | if (!machine_is_e750()) |
132 | return -ENODEV; | 130 | return -ENODEV; |
133 | 131 | ||
134 | ret = gpio_request(GPIO_E750_HP_AMP_OFF, "Headphone amp"); | 132 | ret = gpio_request(GPIO_E750_HP_AMP_OFF, "Headphone amp"); |
135 | if (ret) | 133 | if (ret) |
136 | return ret; | 134 | return ret; |
137 | 135 | ||
138 | ret = gpio_request(GPIO_E750_SPK_AMP_OFF, "Speaker amp"); | 136 | ret = gpio_request(GPIO_E750_SPK_AMP_OFF, "Speaker amp"); |
139 | if (ret) | 137 | if (ret) |
140 | goto free_hp_amp_gpio; | 138 | goto free_hp_amp_gpio; |
141 | 139 | ||
142 | ret = gpio_direction_output(GPIO_E750_HP_AMP_OFF, 1); | 140 | ret = gpio_direction_output(GPIO_E750_HP_AMP_OFF, 1); |
143 | if (ret) | 141 | if (ret) |
144 | goto free_spk_amp_gpio; | 142 | goto free_spk_amp_gpio; |
145 | 143 | ||
146 | ret = gpio_direction_output(GPIO_E750_SPK_AMP_OFF, 1); | 144 | ret = gpio_direction_output(GPIO_E750_SPK_AMP_OFF, 1); |
147 | if (ret) | 145 | if (ret) |
148 | goto free_spk_amp_gpio; | 146 | goto free_spk_amp_gpio; |
149 | 147 | ||
150 | e750_snd_device = platform_device_alloc("soc-audio", -1); | 148 | e750_snd_device = platform_device_alloc("soc-audio", -1); |
151 | if (!e750_snd_device) { | 149 | if (!e750_snd_device) { |
152 | ret = -ENOMEM; | 150 | ret = -ENOMEM; |
153 | goto free_spk_amp_gpio; | 151 | goto free_spk_amp_gpio; |
154 | } | 152 | } |
155 | 153 | ||
156 | platform_set_drvdata(e750_snd_device, &e750); | 154 | platform_set_drvdata(e750_snd_device, &e750); |
157 | ret = platform_device_add(e750_snd_device); | 155 | ret = platform_device_add(e750_snd_device); |
158 | 156 | ||
159 | if (!ret) | 157 | if (!ret) |
160 | return 0; | 158 | return 0; |
161 | 159 | ||
162 | /* Fail gracefully */ | 160 | /* Fail gracefully */ |
163 | platform_device_put(e750_snd_device); | 161 | platform_device_put(e750_snd_device); |
164 | free_spk_amp_gpio: | 162 | free_spk_amp_gpio: |
165 | gpio_free(GPIO_E750_SPK_AMP_OFF); | 163 | gpio_free(GPIO_E750_SPK_AMP_OFF); |
166 | free_hp_amp_gpio: | 164 | free_hp_amp_gpio: |
167 | gpio_free(GPIO_E750_HP_AMP_OFF); | 165 | gpio_free(GPIO_E750_HP_AMP_OFF); |
168 | 166 | ||
169 | return ret; | 167 | return ret; |
170 | } | 168 | } |
171 | 169 | ||
172 | static void __exit e750_exit(void) | 170 | static void __exit e750_exit(void) |
173 | { | 171 | { |
174 | platform_device_unregister(e750_snd_device); | 172 | platform_device_unregister(e750_snd_device); |
175 | gpio_free(GPIO_E750_SPK_AMP_OFF); | 173 | gpio_free(GPIO_E750_SPK_AMP_OFF); |
176 | gpio_free(GPIO_E750_HP_AMP_OFF); | 174 | gpio_free(GPIO_E750_HP_AMP_OFF); |
177 | } | 175 | } |
178 | 176 | ||
179 | module_init(e750_init); | 177 | module_init(e750_init); |
180 | module_exit(e750_exit); | 178 | module_exit(e750_exit); |
181 | 179 | ||
182 | /* Module information */ | 180 | /* Module information */ |
183 | MODULE_AUTHOR("Ian Molton <spyro@f2s.com>"); | 181 | MODULE_AUTHOR("Ian Molton <spyro@f2s.com>"); |
184 | MODULE_DESCRIPTION("ALSA SoC driver for e750"); | 182 | MODULE_DESCRIPTION("ALSA SoC driver for e750"); |
185 | MODULE_LICENSE("GPL v2"); | 183 | MODULE_LICENSE("GPL v2"); |
186 | 184 |
sound/soc/pxa/e800_wm9712.c
1 | /* | 1 | /* |
2 | * e800-wm9712.c -- SoC audio for e800 | 2 | * e800-wm9712.c -- SoC audio for e800 |
3 | * | 3 | * |
4 | * Copyright 2007 (c) Ian Molton <spyro@f2s.com> | 4 | * Copyright 2007 (c) Ian Molton <spyro@f2s.com> |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify it | 6 | * This program is free software; you can redistribute it and/or modify it |
7 | * under the terms of the GNU General Public License as published by the | 7 | * under the terms of the GNU General Public License as published by the |
8 | * Free Software Foundation; version 2 ONLY. | 8 | * Free Software Foundation; version 2 ONLY. |
9 | * | 9 | * |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
13 | #include <linux/moduleparam.h> | 13 | #include <linux/moduleparam.h> |
14 | #include <linux/gpio.h> | 14 | #include <linux/gpio.h> |
15 | 15 | ||
16 | #include <sound/core.h> | 16 | #include <sound/core.h> |
17 | #include <sound/pcm.h> | 17 | #include <sound/pcm.h> |
18 | #include <sound/soc.h> | 18 | #include <sound/soc.h> |
19 | 19 | ||
20 | #include <asm/mach-types.h> | 20 | #include <asm/mach-types.h> |
21 | #include <mach/audio.h> | 21 | #include <mach/audio.h> |
22 | #include <mach/eseries-gpio.h> | 22 | #include <mach/eseries-gpio.h> |
23 | 23 | ||
24 | #include "../codecs/wm9712.h" | 24 | #include "../codecs/wm9712.h" |
25 | #include "pxa2xx-ac97.h" | 25 | #include "pxa2xx-ac97.h" |
26 | 26 | ||
27 | static int e800_spk_amp_event(struct snd_soc_dapm_widget *w, | 27 | static int e800_spk_amp_event(struct snd_soc_dapm_widget *w, |
28 | struct snd_kcontrol *kcontrol, int event) | 28 | struct snd_kcontrol *kcontrol, int event) |
29 | { | 29 | { |
30 | if (event & SND_SOC_DAPM_PRE_PMU) | 30 | if (event & SND_SOC_DAPM_PRE_PMU) |
31 | gpio_set_value(GPIO_E800_SPK_AMP_ON, 1); | 31 | gpio_set_value(GPIO_E800_SPK_AMP_ON, 1); |
32 | else if (event & SND_SOC_DAPM_POST_PMD) | 32 | else if (event & SND_SOC_DAPM_POST_PMD) |
33 | gpio_set_value(GPIO_E800_SPK_AMP_ON, 0); | 33 | gpio_set_value(GPIO_E800_SPK_AMP_ON, 0); |
34 | 34 | ||
35 | return 0; | 35 | return 0; |
36 | } | 36 | } |
37 | 37 | ||
38 | static int e800_hp_amp_event(struct snd_soc_dapm_widget *w, | 38 | static int e800_hp_amp_event(struct snd_soc_dapm_widget *w, |
39 | struct snd_kcontrol *kcontrol, int event) | 39 | struct snd_kcontrol *kcontrol, int event) |
40 | { | 40 | { |
41 | if (event & SND_SOC_DAPM_PRE_PMU) | 41 | if (event & SND_SOC_DAPM_PRE_PMU) |
42 | gpio_set_value(GPIO_E800_HP_AMP_OFF, 0); | 42 | gpio_set_value(GPIO_E800_HP_AMP_OFF, 0); |
43 | else if (event & SND_SOC_DAPM_POST_PMD) | 43 | else if (event & SND_SOC_DAPM_POST_PMD) |
44 | gpio_set_value(GPIO_E800_HP_AMP_OFF, 1); | 44 | gpio_set_value(GPIO_E800_HP_AMP_OFF, 1); |
45 | 45 | ||
46 | return 0; | 46 | return 0; |
47 | } | 47 | } |
48 | 48 | ||
49 | static const struct snd_soc_dapm_widget e800_dapm_widgets[] = { | 49 | static const struct snd_soc_dapm_widget e800_dapm_widgets[] = { |
50 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | 50 | SND_SOC_DAPM_HP("Headphone Jack", NULL), |
51 | SND_SOC_DAPM_MIC("Mic (Internal1)", NULL), | 51 | SND_SOC_DAPM_MIC("Mic (Internal1)", NULL), |
52 | SND_SOC_DAPM_MIC("Mic (Internal2)", NULL), | 52 | SND_SOC_DAPM_MIC("Mic (Internal2)", NULL), |
53 | SND_SOC_DAPM_SPK("Speaker", NULL), | 53 | SND_SOC_DAPM_SPK("Speaker", NULL), |
54 | SND_SOC_DAPM_PGA_E("Headphone Amp", SND_SOC_NOPM, 0, 0, NULL, 0, | 54 | SND_SOC_DAPM_PGA_E("Headphone Amp", SND_SOC_NOPM, 0, 0, NULL, 0, |
55 | e800_hp_amp_event, SND_SOC_DAPM_PRE_PMU | | 55 | e800_hp_amp_event, SND_SOC_DAPM_PRE_PMU | |
56 | SND_SOC_DAPM_POST_PMD), | 56 | SND_SOC_DAPM_POST_PMD), |
57 | SND_SOC_DAPM_PGA_E("Speaker Amp", SND_SOC_NOPM, 0, 0, NULL, 0, | 57 | SND_SOC_DAPM_PGA_E("Speaker Amp", SND_SOC_NOPM, 0, 0, NULL, 0, |
58 | e800_spk_amp_event, SND_SOC_DAPM_PRE_PMU | | 58 | e800_spk_amp_event, SND_SOC_DAPM_PRE_PMU | |
59 | SND_SOC_DAPM_POST_PMD), | 59 | SND_SOC_DAPM_POST_PMD), |
60 | }; | 60 | }; |
61 | 61 | ||
62 | static const struct snd_soc_dapm_route audio_map[] = { | 62 | static const struct snd_soc_dapm_route audio_map[] = { |
63 | {"Headphone Jack", NULL, "HPOUTL"}, | 63 | {"Headphone Jack", NULL, "HPOUTL"}, |
64 | {"Headphone Jack", NULL, "HPOUTR"}, | 64 | {"Headphone Jack", NULL, "HPOUTR"}, |
65 | {"Headphone Jack", NULL, "Headphone Amp"}, | 65 | {"Headphone Jack", NULL, "Headphone Amp"}, |
66 | 66 | ||
67 | {"Speaker Amp", NULL, "MONOOUT"}, | 67 | {"Speaker Amp", NULL, "MONOOUT"}, |
68 | {"Speaker", NULL, "Speaker Amp"}, | 68 | {"Speaker", NULL, "Speaker Amp"}, |
69 | 69 | ||
70 | {"MIC1", NULL, "Mic (Internal1)"}, | 70 | {"MIC1", NULL, "Mic (Internal1)"}, |
71 | {"MIC2", NULL, "Mic (Internal2)"}, | 71 | {"MIC2", NULL, "Mic (Internal2)"}, |
72 | }; | 72 | }; |
73 | 73 | ||
74 | static int e800_ac97_init(struct snd_soc_pcm_runtime *rtd) | 74 | static int e800_ac97_init(struct snd_soc_pcm_runtime *rtd) |
75 | { | 75 | { |
76 | struct snd_soc_codec *codec = rtd->codec; | 76 | struct snd_soc_codec *codec = rtd->codec; |
77 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 77 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
78 | 78 | ||
79 | snd_soc_dapm_new_controls(dapm, e800_dapm_widgets, | 79 | snd_soc_dapm_new_controls(dapm, e800_dapm_widgets, |
80 | ARRAY_SIZE(e800_dapm_widgets)); | 80 | ARRAY_SIZE(e800_dapm_widgets)); |
81 | 81 | ||
82 | snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); | 82 | snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); |
83 | snd_soc_dapm_sync(dapm); | ||
84 | 83 | ||
85 | return 0; | 84 | return 0; |
86 | } | 85 | } |
87 | 86 | ||
88 | static struct snd_soc_dai_link e800_dai[] = { | 87 | static struct snd_soc_dai_link e800_dai[] = { |
89 | { | 88 | { |
90 | .name = "AC97", | 89 | .name = "AC97", |
91 | .stream_name = "AC97 HiFi", | 90 | .stream_name = "AC97 HiFi", |
92 | .cpu_dai_name = "pxa2xx-ac97", | 91 | .cpu_dai_name = "pxa2xx-ac97", |
93 | .codec_dai_name = "wm9712-hifi", | 92 | .codec_dai_name = "wm9712-hifi", |
94 | .platform_name = "pxa-pcm-audio", | 93 | .platform_name = "pxa-pcm-audio", |
95 | .codec_name = "wm9712-codec", | 94 | .codec_name = "wm9712-codec", |
96 | .init = e800_ac97_init, | 95 | .init = e800_ac97_init, |
97 | }, | 96 | }, |
98 | { | 97 | { |
99 | .name = "AC97 Aux", | 98 | .name = "AC97 Aux", |
100 | .stream_name = "AC97 Aux", | 99 | .stream_name = "AC97 Aux", |
101 | .cpu_dai_name = "pxa2xx-ac97-aux", | 100 | .cpu_dai_name = "pxa2xx-ac97-aux", |
102 | .codec_dai_name ="wm9712-aux", | 101 | .codec_dai_name ="wm9712-aux", |
103 | .platform_name = "pxa-pcm-audio", | 102 | .platform_name = "pxa-pcm-audio", |
104 | .codec_name = "wm9712-codec", | 103 | .codec_name = "wm9712-codec", |
105 | }, | 104 | }, |
106 | }; | 105 | }; |
107 | 106 | ||
108 | static struct snd_soc_card e800 = { | 107 | static struct snd_soc_card e800 = { |
109 | .name = "Toshiba e800", | 108 | .name = "Toshiba e800", |
110 | .dai_link = e800_dai, | 109 | .dai_link = e800_dai, |
111 | .num_links = ARRAY_SIZE(e800_dai), | 110 | .num_links = ARRAY_SIZE(e800_dai), |
112 | }; | 111 | }; |
113 | 112 | ||
114 | static struct platform_device *e800_snd_device; | 113 | static struct platform_device *e800_snd_device; |
115 | 114 | ||
116 | static int __init e800_init(void) | 115 | static int __init e800_init(void) |
117 | { | 116 | { |
118 | int ret; | 117 | int ret; |
119 | 118 | ||
120 | if (!machine_is_e800()) | 119 | if (!machine_is_e800()) |
121 | return -ENODEV; | 120 | return -ENODEV; |
122 | 121 | ||
123 | ret = gpio_request(GPIO_E800_HP_AMP_OFF, "Headphone amp"); | 122 | ret = gpio_request(GPIO_E800_HP_AMP_OFF, "Headphone amp"); |
124 | if (ret) | 123 | if (ret) |
125 | return ret; | 124 | return ret; |
126 | 125 | ||
127 | ret = gpio_request(GPIO_E800_SPK_AMP_ON, "Speaker amp"); | 126 | ret = gpio_request(GPIO_E800_SPK_AMP_ON, "Speaker amp"); |
128 | if (ret) | 127 | if (ret) |
129 | goto free_hp_amp_gpio; | 128 | goto free_hp_amp_gpio; |
130 | 129 | ||
131 | ret = gpio_direction_output(GPIO_E800_HP_AMP_OFF, 1); | 130 | ret = gpio_direction_output(GPIO_E800_HP_AMP_OFF, 1); |
132 | if (ret) | 131 | if (ret) |
133 | goto free_spk_amp_gpio; | 132 | goto free_spk_amp_gpio; |
134 | 133 | ||
135 | ret = gpio_direction_output(GPIO_E800_SPK_AMP_ON, 1); | 134 | ret = gpio_direction_output(GPIO_E800_SPK_AMP_ON, 1); |
136 | if (ret) | 135 | if (ret) |
137 | goto free_spk_amp_gpio; | 136 | goto free_spk_amp_gpio; |
138 | 137 | ||
139 | e800_snd_device = platform_device_alloc("soc-audio", -1); | 138 | e800_snd_device = platform_device_alloc("soc-audio", -1); |
140 | if (!e800_snd_device) | 139 | if (!e800_snd_device) |
141 | return -ENOMEM; | 140 | return -ENOMEM; |
142 | 141 | ||
143 | platform_set_drvdata(e800_snd_device, &e800); | 142 | platform_set_drvdata(e800_snd_device, &e800); |
144 | ret = platform_device_add(e800_snd_device); | 143 | ret = platform_device_add(e800_snd_device); |
145 | 144 | ||
146 | if (!ret) | 145 | if (!ret) |
147 | return 0; | 146 | return 0; |
148 | 147 | ||
149 | /* Fail gracefully */ | 148 | /* Fail gracefully */ |
150 | platform_device_put(e800_snd_device); | 149 | platform_device_put(e800_snd_device); |
151 | free_spk_amp_gpio: | 150 | free_spk_amp_gpio: |
152 | gpio_free(GPIO_E800_SPK_AMP_ON); | 151 | gpio_free(GPIO_E800_SPK_AMP_ON); |
153 | free_hp_amp_gpio: | 152 | free_hp_amp_gpio: |
154 | gpio_free(GPIO_E800_HP_AMP_OFF); | 153 | gpio_free(GPIO_E800_HP_AMP_OFF); |
155 | 154 | ||
156 | return ret; | 155 | return ret; |
157 | } | 156 | } |
158 | 157 | ||
159 | static void __exit e800_exit(void) | 158 | static void __exit e800_exit(void) |
160 | { | 159 | { |
161 | platform_device_unregister(e800_snd_device); | 160 | platform_device_unregister(e800_snd_device); |
162 | gpio_free(GPIO_E800_SPK_AMP_ON); | 161 | gpio_free(GPIO_E800_SPK_AMP_ON); |
163 | gpio_free(GPIO_E800_HP_AMP_OFF); | 162 | gpio_free(GPIO_E800_HP_AMP_OFF); |
164 | } | 163 | } |
165 | 164 | ||
166 | module_init(e800_init); | 165 | module_init(e800_init); |
167 | module_exit(e800_exit); | 166 | module_exit(e800_exit); |
168 | 167 | ||
169 | /* Module information */ | 168 | /* Module information */ |
170 | MODULE_AUTHOR("Ian Molton <spyro@f2s.com>"); | 169 | MODULE_AUTHOR("Ian Molton <spyro@f2s.com>"); |
171 | MODULE_DESCRIPTION("ALSA SoC driver for e800"); | 170 | MODULE_DESCRIPTION("ALSA SoC driver for e800"); |
172 | MODULE_LICENSE("GPL v2"); | 171 | MODULE_LICENSE("GPL v2"); |
173 | 172 |
sound/soc/pxa/magician.c
1 | /* | 1 | /* |
2 | * SoC audio for HTC Magician | 2 | * SoC audio for HTC Magician |
3 | * | 3 | * |
4 | * Copyright (c) 2006 Philipp Zabel <philipp.zabel@gmail.com> | 4 | * Copyright (c) 2006 Philipp Zabel <philipp.zabel@gmail.com> |
5 | * | 5 | * |
6 | * based on spitz.c, | 6 | * based on spitz.c, |
7 | * Authors: Liam Girdwood <lrg@slimlogic.co.uk> | 7 | * Authors: Liam Girdwood <lrg@slimlogic.co.uk> |
8 | * Richard Purdie <richard@openedhand.com> | 8 | * Richard Purdie <richard@openedhand.com> |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify it | 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 | 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 | 12 | * Free Software Foundation; either version 2 of the License, or (at your |
13 | * option) any later version. | 13 | * option) any later version. |
14 | * | 14 | * |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
18 | #include <linux/timer.h> | 18 | #include <linux/timer.h> |
19 | #include <linux/interrupt.h> | 19 | #include <linux/interrupt.h> |
20 | #include <linux/platform_device.h> | 20 | #include <linux/platform_device.h> |
21 | #include <linux/delay.h> | 21 | #include <linux/delay.h> |
22 | #include <linux/gpio.h> | 22 | #include <linux/gpio.h> |
23 | #include <linux/i2c.h> | 23 | #include <linux/i2c.h> |
24 | 24 | ||
25 | #include <sound/core.h> | 25 | #include <sound/core.h> |
26 | #include <sound/pcm.h> | 26 | #include <sound/pcm.h> |
27 | #include <sound/pcm_params.h> | 27 | #include <sound/pcm_params.h> |
28 | #include <sound/soc.h> | 28 | #include <sound/soc.h> |
29 | #include <sound/uda1380.h> | 29 | #include <sound/uda1380.h> |
30 | 30 | ||
31 | #include <mach/magician.h> | 31 | #include <mach/magician.h> |
32 | #include <asm/mach-types.h> | 32 | #include <asm/mach-types.h> |
33 | #include "../codecs/uda1380.h" | 33 | #include "../codecs/uda1380.h" |
34 | #include "pxa2xx-i2s.h" | 34 | #include "pxa2xx-i2s.h" |
35 | #include "pxa-ssp.h" | 35 | #include "pxa-ssp.h" |
36 | 36 | ||
37 | #define MAGICIAN_MIC 0 | 37 | #define MAGICIAN_MIC 0 |
38 | #define MAGICIAN_MIC_EXT 1 | 38 | #define MAGICIAN_MIC_EXT 1 |
39 | 39 | ||
40 | static int magician_hp_switch; | 40 | static int magician_hp_switch; |
41 | static int magician_spk_switch = 1; | 41 | static int magician_spk_switch = 1; |
42 | static int magician_in_sel = MAGICIAN_MIC; | 42 | static int magician_in_sel = MAGICIAN_MIC; |
43 | 43 | ||
44 | static void magician_ext_control(struct snd_soc_codec *codec) | 44 | static void magician_ext_control(struct snd_soc_codec *codec) |
45 | { | 45 | { |
46 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 46 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
47 | 47 | ||
48 | if (magician_spk_switch) | 48 | if (magician_spk_switch) |
49 | snd_soc_dapm_enable_pin(dapm, "Speaker"); | 49 | snd_soc_dapm_enable_pin(dapm, "Speaker"); |
50 | else | 50 | else |
51 | snd_soc_dapm_disable_pin(dapm, "Speaker"); | 51 | snd_soc_dapm_disable_pin(dapm, "Speaker"); |
52 | if (magician_hp_switch) | 52 | if (magician_hp_switch) |
53 | snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); | 53 | snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); |
54 | else | 54 | else |
55 | snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); | 55 | snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); |
56 | 56 | ||
57 | switch (magician_in_sel) { | 57 | switch (magician_in_sel) { |
58 | case MAGICIAN_MIC: | 58 | case MAGICIAN_MIC: |
59 | snd_soc_dapm_disable_pin(dapm, "Headset Mic"); | 59 | snd_soc_dapm_disable_pin(dapm, "Headset Mic"); |
60 | snd_soc_dapm_enable_pin(dapm, "Call Mic"); | 60 | snd_soc_dapm_enable_pin(dapm, "Call Mic"); |
61 | break; | 61 | break; |
62 | case MAGICIAN_MIC_EXT: | 62 | case MAGICIAN_MIC_EXT: |
63 | snd_soc_dapm_disable_pin(dapm, "Call Mic"); | 63 | snd_soc_dapm_disable_pin(dapm, "Call Mic"); |
64 | snd_soc_dapm_enable_pin(dapm, "Headset Mic"); | 64 | snd_soc_dapm_enable_pin(dapm, "Headset Mic"); |
65 | break; | 65 | break; |
66 | } | 66 | } |
67 | 67 | ||
68 | snd_soc_dapm_sync(dapm); | 68 | snd_soc_dapm_sync(dapm); |
69 | } | 69 | } |
70 | 70 | ||
71 | static int magician_startup(struct snd_pcm_substream *substream) | 71 | static int magician_startup(struct snd_pcm_substream *substream) |
72 | { | 72 | { |
73 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 73 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
74 | struct snd_soc_codec *codec = rtd->codec; | 74 | struct snd_soc_codec *codec = rtd->codec; |
75 | 75 | ||
76 | mutex_lock(&codec->mutex); | 76 | mutex_lock(&codec->mutex); |
77 | 77 | ||
78 | /* check the jack status at stream startup */ | 78 | /* check the jack status at stream startup */ |
79 | magician_ext_control(codec); | 79 | magician_ext_control(codec); |
80 | 80 | ||
81 | mutex_unlock(&codec->mutex); | 81 | mutex_unlock(&codec->mutex); |
82 | 82 | ||
83 | return 0; | 83 | return 0; |
84 | } | 84 | } |
85 | 85 | ||
86 | /* | 86 | /* |
87 | * Magician uses SSP port for playback. | 87 | * Magician uses SSP port for playback. |
88 | */ | 88 | */ |
89 | static int magician_playback_hw_params(struct snd_pcm_substream *substream, | 89 | static int magician_playback_hw_params(struct snd_pcm_substream *substream, |
90 | struct snd_pcm_hw_params *params) | 90 | struct snd_pcm_hw_params *params) |
91 | { | 91 | { |
92 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 92 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
93 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 93 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
94 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 94 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
95 | unsigned int acps, acds, width; | 95 | unsigned int acps, acds, width; |
96 | unsigned int div4 = PXA_SSP_CLK_SCDB_4; | 96 | unsigned int div4 = PXA_SSP_CLK_SCDB_4; |
97 | int ret = 0; | 97 | int ret = 0; |
98 | 98 | ||
99 | width = snd_pcm_format_physical_width(params_format(params)); | 99 | width = snd_pcm_format_physical_width(params_format(params)); |
100 | 100 | ||
101 | /* | 101 | /* |
102 | * rate = SSPSCLK / (2 * width(16 or 32)) | 102 | * rate = SSPSCLK / (2 * width(16 or 32)) |
103 | * SSPSCLK = (ACPS / ACDS) / SSPSCLKDIV(div4 or div1) | 103 | * SSPSCLK = (ACPS / ACDS) / SSPSCLKDIV(div4 or div1) |
104 | */ | 104 | */ |
105 | switch (params_rate(params)) { | 105 | switch (params_rate(params)) { |
106 | case 8000: | 106 | case 8000: |
107 | /* off by a factor of 2: bug in the PXA27x audio clock? */ | 107 | /* off by a factor of 2: bug in the PXA27x audio clock? */ |
108 | acps = 32842000; | 108 | acps = 32842000; |
109 | switch (width) { | 109 | switch (width) { |
110 | case 16: | 110 | case 16: |
111 | /* 513156 Hz ~= _2_ * 8000 Hz * 32 (+0.23%) */ | 111 | /* 513156 Hz ~= _2_ * 8000 Hz * 32 (+0.23%) */ |
112 | acds = PXA_SSP_CLK_AUDIO_DIV_16; | 112 | acds = PXA_SSP_CLK_AUDIO_DIV_16; |
113 | break; | 113 | break; |
114 | default: /* 32 */ | 114 | default: /* 32 */ |
115 | /* 1026312 Hz ~= _2_ * 8000 Hz * 64 (+0.23%) */ | 115 | /* 1026312 Hz ~= _2_ * 8000 Hz * 64 (+0.23%) */ |
116 | acds = PXA_SSP_CLK_AUDIO_DIV_8; | 116 | acds = PXA_SSP_CLK_AUDIO_DIV_8; |
117 | } | 117 | } |
118 | break; | 118 | break; |
119 | case 11025: | 119 | case 11025: |
120 | acps = 5622000; | 120 | acps = 5622000; |
121 | switch (width) { | 121 | switch (width) { |
122 | case 16: | 122 | case 16: |
123 | /* 351375 Hz ~= 11025 Hz * 32 (-0.41%) */ | 123 | /* 351375 Hz ~= 11025 Hz * 32 (-0.41%) */ |
124 | acds = PXA_SSP_CLK_AUDIO_DIV_4; | 124 | acds = PXA_SSP_CLK_AUDIO_DIV_4; |
125 | break; | 125 | break; |
126 | default: /* 32 */ | 126 | default: /* 32 */ |
127 | /* 702750 Hz ~= 11025 Hz * 64 (-0.41%) */ | 127 | /* 702750 Hz ~= 11025 Hz * 64 (-0.41%) */ |
128 | acds = PXA_SSP_CLK_AUDIO_DIV_2; | 128 | acds = PXA_SSP_CLK_AUDIO_DIV_2; |
129 | } | 129 | } |
130 | break; | 130 | break; |
131 | case 22050: | 131 | case 22050: |
132 | acps = 5622000; | 132 | acps = 5622000; |
133 | switch (width) { | 133 | switch (width) { |
134 | case 16: | 134 | case 16: |
135 | /* 702750 Hz ~= 22050 Hz * 32 (-0.41%) */ | 135 | /* 702750 Hz ~= 22050 Hz * 32 (-0.41%) */ |
136 | acds = PXA_SSP_CLK_AUDIO_DIV_2; | 136 | acds = PXA_SSP_CLK_AUDIO_DIV_2; |
137 | break; | 137 | break; |
138 | default: /* 32 */ | 138 | default: /* 32 */ |
139 | /* 1405500 Hz ~= 22050 Hz * 64 (-0.41%) */ | 139 | /* 1405500 Hz ~= 22050 Hz * 64 (-0.41%) */ |
140 | acds = PXA_SSP_CLK_AUDIO_DIV_1; | 140 | acds = PXA_SSP_CLK_AUDIO_DIV_1; |
141 | } | 141 | } |
142 | break; | 142 | break; |
143 | case 44100: | 143 | case 44100: |
144 | acps = 5622000; | 144 | acps = 5622000; |
145 | switch (width) { | 145 | switch (width) { |
146 | case 16: | 146 | case 16: |
147 | /* 1405500 Hz ~= 44100 Hz * 32 (-0.41%) */ | 147 | /* 1405500 Hz ~= 44100 Hz * 32 (-0.41%) */ |
148 | acds = PXA_SSP_CLK_AUDIO_DIV_2; | 148 | acds = PXA_SSP_CLK_AUDIO_DIV_2; |
149 | break; | 149 | break; |
150 | default: /* 32 */ | 150 | default: /* 32 */ |
151 | /* 2811000 Hz ~= 44100 Hz * 64 (-0.41%) */ | 151 | /* 2811000 Hz ~= 44100 Hz * 64 (-0.41%) */ |
152 | acds = PXA_SSP_CLK_AUDIO_DIV_1; | 152 | acds = PXA_SSP_CLK_AUDIO_DIV_1; |
153 | } | 153 | } |
154 | break; | 154 | break; |
155 | case 48000: | 155 | case 48000: |
156 | acps = 12235000; | 156 | acps = 12235000; |
157 | switch (width) { | 157 | switch (width) { |
158 | case 16: | 158 | case 16: |
159 | /* 1529375 Hz ~= 48000 Hz * 32 (-0.44%) */ | 159 | /* 1529375 Hz ~= 48000 Hz * 32 (-0.44%) */ |
160 | acds = PXA_SSP_CLK_AUDIO_DIV_2; | 160 | acds = PXA_SSP_CLK_AUDIO_DIV_2; |
161 | break; | 161 | break; |
162 | default: /* 32 */ | 162 | default: /* 32 */ |
163 | /* 3058750 Hz ~= 48000 Hz * 64 (-0.44%) */ | 163 | /* 3058750 Hz ~= 48000 Hz * 64 (-0.44%) */ |
164 | acds = PXA_SSP_CLK_AUDIO_DIV_1; | 164 | acds = PXA_SSP_CLK_AUDIO_DIV_1; |
165 | } | 165 | } |
166 | break; | 166 | break; |
167 | case 96000: | 167 | case 96000: |
168 | default: | 168 | default: |
169 | acps = 12235000; | 169 | acps = 12235000; |
170 | switch (width) { | 170 | switch (width) { |
171 | case 16: | 171 | case 16: |
172 | /* 3058750 Hz ~= 96000 Hz * 32 (-0.44%) */ | 172 | /* 3058750 Hz ~= 96000 Hz * 32 (-0.44%) */ |
173 | acds = PXA_SSP_CLK_AUDIO_DIV_1; | 173 | acds = PXA_SSP_CLK_AUDIO_DIV_1; |
174 | break; | 174 | break; |
175 | default: /* 32 */ | 175 | default: /* 32 */ |
176 | /* 6117500 Hz ~= 96000 Hz * 64 (-0.44%) */ | 176 | /* 6117500 Hz ~= 96000 Hz * 64 (-0.44%) */ |
177 | acds = PXA_SSP_CLK_AUDIO_DIV_2; | 177 | acds = PXA_SSP_CLK_AUDIO_DIV_2; |
178 | div4 = PXA_SSP_CLK_SCDB_1; | 178 | div4 = PXA_SSP_CLK_SCDB_1; |
179 | break; | 179 | break; |
180 | } | 180 | } |
181 | break; | 181 | break; |
182 | } | 182 | } |
183 | 183 | ||
184 | /* set codec DAI configuration */ | 184 | /* set codec DAI configuration */ |
185 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_MSB | | 185 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_MSB | |
186 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); | 186 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); |
187 | if (ret < 0) | 187 | if (ret < 0) |
188 | return ret; | 188 | return ret; |
189 | 189 | ||
190 | /* set cpu DAI configuration */ | 190 | /* set cpu DAI configuration */ |
191 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A | | 191 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A | |
192 | SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_CBS_CFS); | 192 | SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_CBS_CFS); |
193 | if (ret < 0) | 193 | if (ret < 0) |
194 | return ret; | 194 | return ret; |
195 | 195 | ||
196 | ret = snd_soc_dai_set_tdm_slot(cpu_dai, 1, 0, 1, width); | 196 | ret = snd_soc_dai_set_tdm_slot(cpu_dai, 1, 0, 1, width); |
197 | if (ret < 0) | 197 | if (ret < 0) |
198 | return ret; | 198 | return ret; |
199 | 199 | ||
200 | /* set audio clock as clock source */ | 200 | /* set audio clock as clock source */ |
201 | ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_AUDIO, 0, | 201 | ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_AUDIO, 0, |
202 | SND_SOC_CLOCK_OUT); | 202 | SND_SOC_CLOCK_OUT); |
203 | if (ret < 0) | 203 | if (ret < 0) |
204 | return ret; | 204 | return ret; |
205 | 205 | ||
206 | /* set the SSP audio system clock ACDS divider */ | 206 | /* set the SSP audio system clock ACDS divider */ |
207 | ret = snd_soc_dai_set_clkdiv(cpu_dai, | 207 | ret = snd_soc_dai_set_clkdiv(cpu_dai, |
208 | PXA_SSP_AUDIO_DIV_ACDS, acds); | 208 | PXA_SSP_AUDIO_DIV_ACDS, acds); |
209 | if (ret < 0) | 209 | if (ret < 0) |
210 | return ret; | 210 | return ret; |
211 | 211 | ||
212 | /* set the SSP audio system clock SCDB divider4 */ | 212 | /* set the SSP audio system clock SCDB divider4 */ |
213 | ret = snd_soc_dai_set_clkdiv(cpu_dai, | 213 | ret = snd_soc_dai_set_clkdiv(cpu_dai, |
214 | PXA_SSP_AUDIO_DIV_SCDB, div4); | 214 | PXA_SSP_AUDIO_DIV_SCDB, div4); |
215 | if (ret < 0) | 215 | if (ret < 0) |
216 | return ret; | 216 | return ret; |
217 | 217 | ||
218 | /* set SSP audio pll clock */ | 218 | /* set SSP audio pll clock */ |
219 | ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, acps); | 219 | ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, acps); |
220 | if (ret < 0) | 220 | if (ret < 0) |
221 | return ret; | 221 | return ret; |
222 | 222 | ||
223 | return 0; | 223 | return 0; |
224 | } | 224 | } |
225 | 225 | ||
226 | /* | 226 | /* |
227 | * Magician uses I2S for capture. | 227 | * Magician uses I2S for capture. |
228 | */ | 228 | */ |
229 | static int magician_capture_hw_params(struct snd_pcm_substream *substream, | 229 | static int magician_capture_hw_params(struct snd_pcm_substream *substream, |
230 | struct snd_pcm_hw_params *params) | 230 | struct snd_pcm_hw_params *params) |
231 | { | 231 | { |
232 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 232 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
233 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 233 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
234 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 234 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
235 | int ret = 0; | 235 | int ret = 0; |
236 | 236 | ||
237 | /* set codec DAI configuration */ | 237 | /* set codec DAI configuration */ |
238 | ret = snd_soc_dai_set_fmt(codec_dai, | 238 | ret = snd_soc_dai_set_fmt(codec_dai, |
239 | SND_SOC_DAIFMT_MSB | SND_SOC_DAIFMT_NB_NF | | 239 | SND_SOC_DAIFMT_MSB | SND_SOC_DAIFMT_NB_NF | |
240 | SND_SOC_DAIFMT_CBS_CFS); | 240 | SND_SOC_DAIFMT_CBS_CFS); |
241 | if (ret < 0) | 241 | if (ret < 0) |
242 | return ret; | 242 | return ret; |
243 | 243 | ||
244 | /* set cpu DAI configuration */ | 244 | /* set cpu DAI configuration */ |
245 | ret = snd_soc_dai_set_fmt(cpu_dai, | 245 | ret = snd_soc_dai_set_fmt(cpu_dai, |
246 | SND_SOC_DAIFMT_MSB | SND_SOC_DAIFMT_NB_NF | | 246 | SND_SOC_DAIFMT_MSB | SND_SOC_DAIFMT_NB_NF | |
247 | SND_SOC_DAIFMT_CBS_CFS); | 247 | SND_SOC_DAIFMT_CBS_CFS); |
248 | if (ret < 0) | 248 | if (ret < 0) |
249 | return ret; | 249 | return ret; |
250 | 250 | ||
251 | /* set the I2S system clock as output */ | 251 | /* set the I2S system clock as output */ |
252 | ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0, | 252 | ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0, |
253 | SND_SOC_CLOCK_OUT); | 253 | SND_SOC_CLOCK_OUT); |
254 | if (ret < 0) | 254 | if (ret < 0) |
255 | return ret; | 255 | return ret; |
256 | 256 | ||
257 | return 0; | 257 | return 0; |
258 | } | 258 | } |
259 | 259 | ||
260 | static struct snd_soc_ops magician_capture_ops = { | 260 | static struct snd_soc_ops magician_capture_ops = { |
261 | .startup = magician_startup, | 261 | .startup = magician_startup, |
262 | .hw_params = magician_capture_hw_params, | 262 | .hw_params = magician_capture_hw_params, |
263 | }; | 263 | }; |
264 | 264 | ||
265 | static struct snd_soc_ops magician_playback_ops = { | 265 | static struct snd_soc_ops magician_playback_ops = { |
266 | .startup = magician_startup, | 266 | .startup = magician_startup, |
267 | .hw_params = magician_playback_hw_params, | 267 | .hw_params = magician_playback_hw_params, |
268 | }; | 268 | }; |
269 | 269 | ||
270 | static int magician_get_hp(struct snd_kcontrol *kcontrol, | 270 | static int magician_get_hp(struct snd_kcontrol *kcontrol, |
271 | struct snd_ctl_elem_value *ucontrol) | 271 | struct snd_ctl_elem_value *ucontrol) |
272 | { | 272 | { |
273 | ucontrol->value.integer.value[0] = magician_hp_switch; | 273 | ucontrol->value.integer.value[0] = magician_hp_switch; |
274 | return 0; | 274 | return 0; |
275 | } | 275 | } |
276 | 276 | ||
277 | static int magician_set_hp(struct snd_kcontrol *kcontrol, | 277 | static int magician_set_hp(struct snd_kcontrol *kcontrol, |
278 | struct snd_ctl_elem_value *ucontrol) | 278 | struct snd_ctl_elem_value *ucontrol) |
279 | { | 279 | { |
280 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 280 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
281 | 281 | ||
282 | if (magician_hp_switch == ucontrol->value.integer.value[0]) | 282 | if (magician_hp_switch == ucontrol->value.integer.value[0]) |
283 | return 0; | 283 | return 0; |
284 | 284 | ||
285 | magician_hp_switch = ucontrol->value.integer.value[0]; | 285 | magician_hp_switch = ucontrol->value.integer.value[0]; |
286 | magician_ext_control(codec); | 286 | magician_ext_control(codec); |
287 | return 1; | 287 | return 1; |
288 | } | 288 | } |
289 | 289 | ||
290 | static int magician_get_spk(struct snd_kcontrol *kcontrol, | 290 | static int magician_get_spk(struct snd_kcontrol *kcontrol, |
291 | struct snd_ctl_elem_value *ucontrol) | 291 | struct snd_ctl_elem_value *ucontrol) |
292 | { | 292 | { |
293 | ucontrol->value.integer.value[0] = magician_spk_switch; | 293 | ucontrol->value.integer.value[0] = magician_spk_switch; |
294 | return 0; | 294 | return 0; |
295 | } | 295 | } |
296 | 296 | ||
297 | static int magician_set_spk(struct snd_kcontrol *kcontrol, | 297 | static int magician_set_spk(struct snd_kcontrol *kcontrol, |
298 | struct snd_ctl_elem_value *ucontrol) | 298 | struct snd_ctl_elem_value *ucontrol) |
299 | { | 299 | { |
300 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 300 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
301 | 301 | ||
302 | if (magician_spk_switch == ucontrol->value.integer.value[0]) | 302 | if (magician_spk_switch == ucontrol->value.integer.value[0]) |
303 | return 0; | 303 | return 0; |
304 | 304 | ||
305 | magician_spk_switch = ucontrol->value.integer.value[0]; | 305 | magician_spk_switch = ucontrol->value.integer.value[0]; |
306 | magician_ext_control(codec); | 306 | magician_ext_control(codec); |
307 | return 1; | 307 | return 1; |
308 | } | 308 | } |
309 | 309 | ||
310 | static int magician_get_input(struct snd_kcontrol *kcontrol, | 310 | static int magician_get_input(struct snd_kcontrol *kcontrol, |
311 | struct snd_ctl_elem_value *ucontrol) | 311 | struct snd_ctl_elem_value *ucontrol) |
312 | { | 312 | { |
313 | ucontrol->value.integer.value[0] = magician_in_sel; | 313 | ucontrol->value.integer.value[0] = magician_in_sel; |
314 | return 0; | 314 | return 0; |
315 | } | 315 | } |
316 | 316 | ||
317 | static int magician_set_input(struct snd_kcontrol *kcontrol, | 317 | static int magician_set_input(struct snd_kcontrol *kcontrol, |
318 | struct snd_ctl_elem_value *ucontrol) | 318 | struct snd_ctl_elem_value *ucontrol) |
319 | { | 319 | { |
320 | if (magician_in_sel == ucontrol->value.integer.value[0]) | 320 | if (magician_in_sel == ucontrol->value.integer.value[0]) |
321 | return 0; | 321 | return 0; |
322 | 322 | ||
323 | magician_in_sel = ucontrol->value.integer.value[0]; | 323 | magician_in_sel = ucontrol->value.integer.value[0]; |
324 | 324 | ||
325 | switch (magician_in_sel) { | 325 | switch (magician_in_sel) { |
326 | case MAGICIAN_MIC: | 326 | case MAGICIAN_MIC: |
327 | gpio_set_value(EGPIO_MAGICIAN_IN_SEL1, 1); | 327 | gpio_set_value(EGPIO_MAGICIAN_IN_SEL1, 1); |
328 | break; | 328 | break; |
329 | case MAGICIAN_MIC_EXT: | 329 | case MAGICIAN_MIC_EXT: |
330 | gpio_set_value(EGPIO_MAGICIAN_IN_SEL1, 0); | 330 | gpio_set_value(EGPIO_MAGICIAN_IN_SEL1, 0); |
331 | } | 331 | } |
332 | 332 | ||
333 | return 1; | 333 | return 1; |
334 | } | 334 | } |
335 | 335 | ||
336 | static int magician_spk_power(struct snd_soc_dapm_widget *w, | 336 | static int magician_spk_power(struct snd_soc_dapm_widget *w, |
337 | struct snd_kcontrol *k, int event) | 337 | struct snd_kcontrol *k, int event) |
338 | { | 338 | { |
339 | gpio_set_value(EGPIO_MAGICIAN_SPK_POWER, SND_SOC_DAPM_EVENT_ON(event)); | 339 | gpio_set_value(EGPIO_MAGICIAN_SPK_POWER, SND_SOC_DAPM_EVENT_ON(event)); |
340 | return 0; | 340 | return 0; |
341 | } | 341 | } |
342 | 342 | ||
343 | static int magician_hp_power(struct snd_soc_dapm_widget *w, | 343 | static int magician_hp_power(struct snd_soc_dapm_widget *w, |
344 | struct snd_kcontrol *k, int event) | 344 | struct snd_kcontrol *k, int event) |
345 | { | 345 | { |
346 | gpio_set_value(EGPIO_MAGICIAN_EP_POWER, SND_SOC_DAPM_EVENT_ON(event)); | 346 | gpio_set_value(EGPIO_MAGICIAN_EP_POWER, SND_SOC_DAPM_EVENT_ON(event)); |
347 | return 0; | 347 | return 0; |
348 | } | 348 | } |
349 | 349 | ||
350 | static int magician_mic_bias(struct snd_soc_dapm_widget *w, | 350 | static int magician_mic_bias(struct snd_soc_dapm_widget *w, |
351 | struct snd_kcontrol *k, int event) | 351 | struct snd_kcontrol *k, int event) |
352 | { | 352 | { |
353 | gpio_set_value(EGPIO_MAGICIAN_MIC_POWER, SND_SOC_DAPM_EVENT_ON(event)); | 353 | gpio_set_value(EGPIO_MAGICIAN_MIC_POWER, SND_SOC_DAPM_EVENT_ON(event)); |
354 | return 0; | 354 | return 0; |
355 | } | 355 | } |
356 | 356 | ||
357 | /* magician machine dapm widgets */ | 357 | /* magician machine dapm widgets */ |
358 | static const struct snd_soc_dapm_widget uda1380_dapm_widgets[] = { | 358 | static const struct snd_soc_dapm_widget uda1380_dapm_widgets[] = { |
359 | SND_SOC_DAPM_HP("Headphone Jack", magician_hp_power), | 359 | SND_SOC_DAPM_HP("Headphone Jack", magician_hp_power), |
360 | SND_SOC_DAPM_SPK("Speaker", magician_spk_power), | 360 | SND_SOC_DAPM_SPK("Speaker", magician_spk_power), |
361 | SND_SOC_DAPM_MIC("Call Mic", magician_mic_bias), | 361 | SND_SOC_DAPM_MIC("Call Mic", magician_mic_bias), |
362 | SND_SOC_DAPM_MIC("Headset Mic", magician_mic_bias), | 362 | SND_SOC_DAPM_MIC("Headset Mic", magician_mic_bias), |
363 | }; | 363 | }; |
364 | 364 | ||
365 | /* magician machine audio_map */ | 365 | /* magician machine audio_map */ |
366 | static const struct snd_soc_dapm_route audio_map[] = { | 366 | static const struct snd_soc_dapm_route audio_map[] = { |
367 | 367 | ||
368 | /* Headphone connected to VOUTL, VOUTR */ | 368 | /* Headphone connected to VOUTL, VOUTR */ |
369 | {"Headphone Jack", NULL, "VOUTL"}, | 369 | {"Headphone Jack", NULL, "VOUTL"}, |
370 | {"Headphone Jack", NULL, "VOUTR"}, | 370 | {"Headphone Jack", NULL, "VOUTR"}, |
371 | 371 | ||
372 | /* Speaker connected to VOUTL, VOUTR */ | 372 | /* Speaker connected to VOUTL, VOUTR */ |
373 | {"Speaker", NULL, "VOUTL"}, | 373 | {"Speaker", NULL, "VOUTL"}, |
374 | {"Speaker", NULL, "VOUTR"}, | 374 | {"Speaker", NULL, "VOUTR"}, |
375 | 375 | ||
376 | /* Mics are connected to VINM */ | 376 | /* Mics are connected to VINM */ |
377 | {"VINM", NULL, "Headset Mic"}, | 377 | {"VINM", NULL, "Headset Mic"}, |
378 | {"VINM", NULL, "Call Mic"}, | 378 | {"VINM", NULL, "Call Mic"}, |
379 | }; | 379 | }; |
380 | 380 | ||
381 | static const char *input_select[] = {"Call Mic", "Headset Mic"}; | 381 | static const char *input_select[] = {"Call Mic", "Headset Mic"}; |
382 | static const struct soc_enum magician_in_sel_enum = | 382 | static const struct soc_enum magician_in_sel_enum = |
383 | SOC_ENUM_SINGLE_EXT(2, input_select); | 383 | SOC_ENUM_SINGLE_EXT(2, input_select); |
384 | 384 | ||
385 | static const struct snd_kcontrol_new uda1380_magician_controls[] = { | 385 | static const struct snd_kcontrol_new uda1380_magician_controls[] = { |
386 | SOC_SINGLE_BOOL_EXT("Headphone Switch", | 386 | SOC_SINGLE_BOOL_EXT("Headphone Switch", |
387 | (unsigned long)&magician_hp_switch, | 387 | (unsigned long)&magician_hp_switch, |
388 | magician_get_hp, magician_set_hp), | 388 | magician_get_hp, magician_set_hp), |
389 | SOC_SINGLE_BOOL_EXT("Speaker Switch", | 389 | SOC_SINGLE_BOOL_EXT("Speaker Switch", |
390 | (unsigned long)&magician_spk_switch, | 390 | (unsigned long)&magician_spk_switch, |
391 | magician_get_spk, magician_set_spk), | 391 | magician_get_spk, magician_set_spk), |
392 | SOC_ENUM_EXT("Input Select", magician_in_sel_enum, | 392 | SOC_ENUM_EXT("Input Select", magician_in_sel_enum, |
393 | magician_get_input, magician_set_input), | 393 | magician_get_input, magician_set_input), |
394 | }; | 394 | }; |
395 | 395 | ||
396 | /* | 396 | /* |
397 | * Logic for a uda1380 as connected on a HTC Magician | 397 | * Logic for a uda1380 as connected on a HTC Magician |
398 | */ | 398 | */ |
399 | static int magician_uda1380_init(struct snd_soc_pcm_runtime *rtd) | 399 | static int magician_uda1380_init(struct snd_soc_pcm_runtime *rtd) |
400 | { | 400 | { |
401 | struct snd_soc_codec *codec = rtd->codec; | 401 | struct snd_soc_codec *codec = rtd->codec; |
402 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 402 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
403 | int err; | 403 | int err; |
404 | 404 | ||
405 | /* NC codec pins */ | 405 | /* NC codec pins */ |
406 | snd_soc_dapm_nc_pin(dapm, "VOUTLHP"); | 406 | snd_soc_dapm_nc_pin(dapm, "VOUTLHP"); |
407 | snd_soc_dapm_nc_pin(dapm, "VOUTRHP"); | 407 | snd_soc_dapm_nc_pin(dapm, "VOUTRHP"); |
408 | 408 | ||
409 | /* FIXME: is anything connected here? */ | 409 | /* FIXME: is anything connected here? */ |
410 | snd_soc_dapm_nc_pin(dapm, "VINL"); | 410 | snd_soc_dapm_nc_pin(dapm, "VINL"); |
411 | snd_soc_dapm_nc_pin(dapm, "VINR"); | 411 | snd_soc_dapm_nc_pin(dapm, "VINR"); |
412 | 412 | ||
413 | /* Add magician specific controls */ | 413 | /* Add magician specific controls */ |
414 | err = snd_soc_add_controls(codec, uda1380_magician_controls, | 414 | err = snd_soc_add_controls(codec, uda1380_magician_controls, |
415 | ARRAY_SIZE(uda1380_magician_controls)); | 415 | ARRAY_SIZE(uda1380_magician_controls)); |
416 | if (err < 0) | 416 | if (err < 0) |
417 | return err; | 417 | return err; |
418 | 418 | ||
419 | /* Add magician specific widgets */ | 419 | /* Add magician specific widgets */ |
420 | snd_soc_dapm_new_controls(dapm, uda1380_dapm_widgets, | 420 | snd_soc_dapm_new_controls(dapm, uda1380_dapm_widgets, |
421 | ARRAY_SIZE(uda1380_dapm_widgets)); | 421 | ARRAY_SIZE(uda1380_dapm_widgets)); |
422 | 422 | ||
423 | /* Set up magician specific audio path interconnects */ | 423 | /* Set up magician specific audio path interconnects */ |
424 | snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); | 424 | snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); |
425 | 425 | ||
426 | snd_soc_dapm_sync(dapm); | ||
427 | return 0; | 426 | return 0; |
428 | } | 427 | } |
429 | 428 | ||
430 | /* magician digital audio interface glue - connects codec <--> CPU */ | 429 | /* magician digital audio interface glue - connects codec <--> CPU */ |
431 | static struct snd_soc_dai_link magician_dai[] = { | 430 | static struct snd_soc_dai_link magician_dai[] = { |
432 | { | 431 | { |
433 | .name = "uda1380", | 432 | .name = "uda1380", |
434 | .stream_name = "UDA1380 Playback", | 433 | .stream_name = "UDA1380 Playback", |
435 | .cpu_dai_name = "pxa-ssp-dai.0", | 434 | .cpu_dai_name = "pxa-ssp-dai.0", |
436 | .codec_dai_name = "uda1380-hifi-playback", | 435 | .codec_dai_name = "uda1380-hifi-playback", |
437 | .platform_name = "pxa-pcm-audio", | 436 | .platform_name = "pxa-pcm-audio", |
438 | .codec_name = "uda1380-codec.0-0018", | 437 | .codec_name = "uda1380-codec.0-0018", |
439 | .init = magician_uda1380_init, | 438 | .init = magician_uda1380_init, |
440 | .ops = &magician_playback_ops, | 439 | .ops = &magician_playback_ops, |
441 | }, | 440 | }, |
442 | { | 441 | { |
443 | .name = "uda1380", | 442 | .name = "uda1380", |
444 | .stream_name = "UDA1380 Capture", | 443 | .stream_name = "UDA1380 Capture", |
445 | .cpu_dai_name = "pxa2xx-i2s", | 444 | .cpu_dai_name = "pxa2xx-i2s", |
446 | .codec_dai_name = "uda1380-hifi-capture", | 445 | .codec_dai_name = "uda1380-hifi-capture", |
447 | .platform_name = "pxa-pcm-audio", | 446 | .platform_name = "pxa-pcm-audio", |
448 | .codec_name = "uda1380-codec.0-0018", | 447 | .codec_name = "uda1380-codec.0-0018", |
449 | .ops = &magician_capture_ops, | 448 | .ops = &magician_capture_ops, |
450 | } | 449 | } |
451 | }; | 450 | }; |
452 | 451 | ||
453 | /* magician audio machine driver */ | 452 | /* magician audio machine driver */ |
454 | static struct snd_soc_card snd_soc_card_magician = { | 453 | static struct snd_soc_card snd_soc_card_magician = { |
455 | .name = "Magician", | 454 | .name = "Magician", |
456 | .dai_link = magician_dai, | 455 | .dai_link = magician_dai, |
457 | .num_links = ARRAY_SIZE(magician_dai), | 456 | .num_links = ARRAY_SIZE(magician_dai), |
458 | 457 | ||
459 | }; | 458 | }; |
460 | 459 | ||
461 | static struct platform_device *magician_snd_device; | 460 | static struct platform_device *magician_snd_device; |
462 | 461 | ||
463 | /* | 462 | /* |
464 | * FIXME: move into magician board file once merged into the pxa tree | 463 | * FIXME: move into magician board file once merged into the pxa tree |
465 | */ | 464 | */ |
466 | static struct uda1380_platform_data uda1380_info = { | 465 | static struct uda1380_platform_data uda1380_info = { |
467 | .gpio_power = EGPIO_MAGICIAN_CODEC_POWER, | 466 | .gpio_power = EGPIO_MAGICIAN_CODEC_POWER, |
468 | .gpio_reset = EGPIO_MAGICIAN_CODEC_RESET, | 467 | .gpio_reset = EGPIO_MAGICIAN_CODEC_RESET, |
469 | .dac_clk = UDA1380_DAC_CLK_WSPLL, | 468 | .dac_clk = UDA1380_DAC_CLK_WSPLL, |
470 | }; | 469 | }; |
471 | 470 | ||
472 | static struct i2c_board_info i2c_board_info[] = { | 471 | static struct i2c_board_info i2c_board_info[] = { |
473 | { | 472 | { |
474 | I2C_BOARD_INFO("uda1380", 0x18), | 473 | I2C_BOARD_INFO("uda1380", 0x18), |
475 | .platform_data = &uda1380_info, | 474 | .platform_data = &uda1380_info, |
476 | }, | 475 | }, |
477 | }; | 476 | }; |
478 | 477 | ||
479 | static int __init magician_init(void) | 478 | static int __init magician_init(void) |
480 | { | 479 | { |
481 | int ret; | 480 | int ret; |
482 | struct i2c_adapter *adapter; | 481 | struct i2c_adapter *adapter; |
483 | struct i2c_client *client; | 482 | struct i2c_client *client; |
484 | 483 | ||
485 | if (!machine_is_magician()) | 484 | if (!machine_is_magician()) |
486 | return -ENODEV; | 485 | return -ENODEV; |
487 | 486 | ||
488 | adapter = i2c_get_adapter(0); | 487 | adapter = i2c_get_adapter(0); |
489 | if (!adapter) | 488 | if (!adapter) |
490 | return -ENODEV; | 489 | return -ENODEV; |
491 | client = i2c_new_device(adapter, i2c_board_info); | 490 | client = i2c_new_device(adapter, i2c_board_info); |
492 | i2c_put_adapter(adapter); | 491 | i2c_put_adapter(adapter); |
493 | if (!client) | 492 | if (!client) |
494 | return -ENODEV; | 493 | return -ENODEV; |
495 | 494 | ||
496 | ret = gpio_request(EGPIO_MAGICIAN_SPK_POWER, "SPK_POWER"); | 495 | ret = gpio_request(EGPIO_MAGICIAN_SPK_POWER, "SPK_POWER"); |
497 | if (ret) | 496 | if (ret) |
498 | goto err_request_spk; | 497 | goto err_request_spk; |
499 | ret = gpio_request(EGPIO_MAGICIAN_EP_POWER, "EP_POWER"); | 498 | ret = gpio_request(EGPIO_MAGICIAN_EP_POWER, "EP_POWER"); |
500 | if (ret) | 499 | if (ret) |
501 | goto err_request_ep; | 500 | goto err_request_ep; |
502 | ret = gpio_request(EGPIO_MAGICIAN_MIC_POWER, "MIC_POWER"); | 501 | ret = gpio_request(EGPIO_MAGICIAN_MIC_POWER, "MIC_POWER"); |
503 | if (ret) | 502 | if (ret) |
504 | goto err_request_mic; | 503 | goto err_request_mic; |
505 | ret = gpio_request(EGPIO_MAGICIAN_IN_SEL0, "IN_SEL0"); | 504 | ret = gpio_request(EGPIO_MAGICIAN_IN_SEL0, "IN_SEL0"); |
506 | if (ret) | 505 | if (ret) |
507 | goto err_request_in_sel0; | 506 | goto err_request_in_sel0; |
508 | ret = gpio_request(EGPIO_MAGICIAN_IN_SEL1, "IN_SEL1"); | 507 | ret = gpio_request(EGPIO_MAGICIAN_IN_SEL1, "IN_SEL1"); |
509 | if (ret) | 508 | if (ret) |
510 | goto err_request_in_sel1; | 509 | goto err_request_in_sel1; |
511 | 510 | ||
512 | gpio_set_value(EGPIO_MAGICIAN_IN_SEL0, 0); | 511 | gpio_set_value(EGPIO_MAGICIAN_IN_SEL0, 0); |
513 | 512 | ||
514 | magician_snd_device = platform_device_alloc("soc-audio", -1); | 513 | magician_snd_device = platform_device_alloc("soc-audio", -1); |
515 | if (!magician_snd_device) { | 514 | if (!magician_snd_device) { |
516 | ret = -ENOMEM; | 515 | ret = -ENOMEM; |
517 | goto err_pdev; | 516 | goto err_pdev; |
518 | } | 517 | } |
519 | 518 | ||
520 | platform_set_drvdata(magician_snd_device, &snd_soc_card_magician); | 519 | platform_set_drvdata(magician_snd_device, &snd_soc_card_magician); |
521 | ret = platform_device_add(magician_snd_device); | 520 | ret = platform_device_add(magician_snd_device); |
522 | if (ret) { | 521 | if (ret) { |
523 | platform_device_put(magician_snd_device); | 522 | platform_device_put(magician_snd_device); |
524 | goto err_pdev; | 523 | goto err_pdev; |
525 | } | 524 | } |
526 | 525 | ||
527 | return 0; | 526 | return 0; |
528 | 527 | ||
529 | err_pdev: | 528 | err_pdev: |
530 | gpio_free(EGPIO_MAGICIAN_IN_SEL1); | 529 | gpio_free(EGPIO_MAGICIAN_IN_SEL1); |
531 | err_request_in_sel1: | 530 | err_request_in_sel1: |
532 | gpio_free(EGPIO_MAGICIAN_IN_SEL0); | 531 | gpio_free(EGPIO_MAGICIAN_IN_SEL0); |
533 | err_request_in_sel0: | 532 | err_request_in_sel0: |
534 | gpio_free(EGPIO_MAGICIAN_MIC_POWER); | 533 | gpio_free(EGPIO_MAGICIAN_MIC_POWER); |
535 | err_request_mic: | 534 | err_request_mic: |
536 | gpio_free(EGPIO_MAGICIAN_EP_POWER); | 535 | gpio_free(EGPIO_MAGICIAN_EP_POWER); |
537 | err_request_ep: | 536 | err_request_ep: |
538 | gpio_free(EGPIO_MAGICIAN_SPK_POWER); | 537 | gpio_free(EGPIO_MAGICIAN_SPK_POWER); |
539 | err_request_spk: | 538 | err_request_spk: |
540 | return ret; | 539 | return ret; |
541 | } | 540 | } |
542 | 541 | ||
543 | static void __exit magician_exit(void) | 542 | static void __exit magician_exit(void) |
544 | { | 543 | { |
545 | platform_device_unregister(magician_snd_device); | 544 | platform_device_unregister(magician_snd_device); |
546 | 545 | ||
547 | gpio_set_value(EGPIO_MAGICIAN_SPK_POWER, 0); | 546 | gpio_set_value(EGPIO_MAGICIAN_SPK_POWER, 0); |
548 | gpio_set_value(EGPIO_MAGICIAN_EP_POWER, 0); | 547 | gpio_set_value(EGPIO_MAGICIAN_EP_POWER, 0); |
549 | gpio_set_value(EGPIO_MAGICIAN_MIC_POWER, 0); | 548 | gpio_set_value(EGPIO_MAGICIAN_MIC_POWER, 0); |
550 | 549 | ||
551 | gpio_free(EGPIO_MAGICIAN_IN_SEL1); | 550 | gpio_free(EGPIO_MAGICIAN_IN_SEL1); |
552 | gpio_free(EGPIO_MAGICIAN_IN_SEL0); | 551 | gpio_free(EGPIO_MAGICIAN_IN_SEL0); |
553 | gpio_free(EGPIO_MAGICIAN_MIC_POWER); | 552 | gpio_free(EGPIO_MAGICIAN_MIC_POWER); |
554 | gpio_free(EGPIO_MAGICIAN_EP_POWER); | 553 | gpio_free(EGPIO_MAGICIAN_EP_POWER); |
555 | gpio_free(EGPIO_MAGICIAN_SPK_POWER); | 554 | gpio_free(EGPIO_MAGICIAN_SPK_POWER); |
556 | } | 555 | } |
557 | 556 | ||
558 | module_init(magician_init); | 557 | module_init(magician_init); |
559 | module_exit(magician_exit); | 558 | module_exit(magician_exit); |
560 | 559 | ||
561 | MODULE_AUTHOR("Philipp Zabel"); | 560 | MODULE_AUTHOR("Philipp Zabel"); |
562 | MODULE_DESCRIPTION("ALSA SoC Magician"); | 561 | MODULE_DESCRIPTION("ALSA SoC Magician"); |
563 | MODULE_LICENSE("GPL"); | 562 | MODULE_LICENSE("GPL"); |
564 | 563 |
sound/soc/pxa/mioa701_wm9713.c
1 | /* | 1 | /* |
2 | * Handles the Mitac mioa701 SoC system | 2 | * Handles the Mitac mioa701 SoC system |
3 | * | 3 | * |
4 | * Copyright (C) 2008 Robert Jarzmik | 4 | * Copyright (C) 2008 Robert Jarzmik |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by | 7 | * it under the terms of the GNU General Public License as published by |
8 | * the Free Software Foundation in version 2 of the License. | 8 | * the Free Software Foundation in version 2 of the License. |
9 | * | 9 | * |
10 | * This program is distributed in the hope that it will be useful, | 10 | * This program is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | * GNU General Public License for more details. | 13 | * GNU General Public License for more details. |
14 | * | 14 | * |
15 | * You should have received a copy of the GNU General Public License | 15 | * You should have received a copy of the GNU General Public License |
16 | * along with this program; if not, write to the Free Software | 16 | * along with this program; if not, write to the Free Software |
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
18 | * | 18 | * |
19 | * This is a little schema of the sound interconnections : | 19 | * This is a little schema of the sound interconnections : |
20 | * | 20 | * |
21 | * Sagem X200 Wolfson WM9713 | 21 | * Sagem X200 Wolfson WM9713 |
22 | * +--------+ +-------------------+ Rear Speaker | 22 | * +--------+ +-------------------+ Rear Speaker |
23 | * | | | | /-+ | 23 | * | | | | /-+ |
24 | * | +--->----->---+MONOIN SPKL+--->----+-+ | | 24 | * | +--->----->---+MONOIN SPKL+--->----+-+ | |
25 | * | GSM | | | | | | | 25 | * | GSM | | | | | | |
26 | * | +--->----->---+PCBEEP SPKR+--->----+-+ | | 26 | * | +--->----->---+PCBEEP SPKR+--->----+-+ | |
27 | * | CHIP | | | \-+ | 27 | * | CHIP | | | \-+ |
28 | * | +---<-----<---+MONO | | 28 | * | +---<-----<---+MONO | |
29 | * | | | | Front Speaker | 29 | * | | | | Front Speaker |
30 | * +--------+ | | /-+ | 30 | * +--------+ | | /-+ |
31 | * | HPL+--->----+-+ | | 31 | * | HPL+--->----+-+ | |
32 | * | | | | | | 32 | * | | | | | |
33 | * | OUT3+--->----+-+ | | 33 | * | OUT3+--->----+-+ | |
34 | * | | \-+ | 34 | * | | \-+ |
35 | * | | | 35 | * | | |
36 | * | | Front Micro | 36 | * | | Front Micro |
37 | * | | + | 37 | * | | + |
38 | * | MIC1+-----<--+o+ | 38 | * | MIC1+-----<--+o+ |
39 | * | | + | 39 | * | | + |
40 | * +-------------------+ --- | 40 | * +-------------------+ --- |
41 | */ | 41 | */ |
42 | 42 | ||
43 | #include <linux/module.h> | 43 | #include <linux/module.h> |
44 | #include <linux/moduleparam.h> | 44 | #include <linux/moduleparam.h> |
45 | #include <linux/platform_device.h> | 45 | #include <linux/platform_device.h> |
46 | 46 | ||
47 | #include <asm/mach-types.h> | 47 | #include <asm/mach-types.h> |
48 | #include <mach/audio.h> | 48 | #include <mach/audio.h> |
49 | 49 | ||
50 | #include <sound/core.h> | 50 | #include <sound/core.h> |
51 | #include <sound/pcm.h> | 51 | #include <sound/pcm.h> |
52 | #include <sound/soc.h> | 52 | #include <sound/soc.h> |
53 | #include <sound/initval.h> | 53 | #include <sound/initval.h> |
54 | #include <sound/ac97_codec.h> | 54 | #include <sound/ac97_codec.h> |
55 | 55 | ||
56 | #include "pxa2xx-ac97.h" | 56 | #include "pxa2xx-ac97.h" |
57 | #include "../codecs/wm9713.h" | 57 | #include "../codecs/wm9713.h" |
58 | 58 | ||
59 | #define ARRAY_AND_SIZE(x) (x), ARRAY_SIZE(x) | 59 | #define ARRAY_AND_SIZE(x) (x), ARRAY_SIZE(x) |
60 | 60 | ||
61 | #define AC97_GPIO_PULL 0x58 | 61 | #define AC97_GPIO_PULL 0x58 |
62 | 62 | ||
63 | /* Use GPIO8 for rear speaker amplifier */ | 63 | /* Use GPIO8 for rear speaker amplifier */ |
64 | static int rear_amp_power(struct snd_soc_codec *codec, int power) | 64 | static int rear_amp_power(struct snd_soc_codec *codec, int power) |
65 | { | 65 | { |
66 | unsigned short reg; | 66 | unsigned short reg; |
67 | 67 | ||
68 | if (power) { | 68 | if (power) { |
69 | reg = snd_soc_read(codec, AC97_GPIO_CFG); | 69 | reg = snd_soc_read(codec, AC97_GPIO_CFG); |
70 | snd_soc_write(codec, AC97_GPIO_CFG, reg | 0x0100); | 70 | snd_soc_write(codec, AC97_GPIO_CFG, reg | 0x0100); |
71 | reg = snd_soc_read(codec, AC97_GPIO_PULL); | 71 | reg = snd_soc_read(codec, AC97_GPIO_PULL); |
72 | snd_soc_write(codec, AC97_GPIO_PULL, reg | (1<<15)); | 72 | snd_soc_write(codec, AC97_GPIO_PULL, reg | (1<<15)); |
73 | } else { | 73 | } else { |
74 | reg = snd_soc_read(codec, AC97_GPIO_CFG); | 74 | reg = snd_soc_read(codec, AC97_GPIO_CFG); |
75 | snd_soc_write(codec, AC97_GPIO_CFG, reg & ~0x0100); | 75 | snd_soc_write(codec, AC97_GPIO_CFG, reg & ~0x0100); |
76 | reg = snd_soc_read(codec, AC97_GPIO_PULL); | 76 | reg = snd_soc_read(codec, AC97_GPIO_PULL); |
77 | snd_soc_write(codec, AC97_GPIO_PULL, reg & ~(1<<15)); | 77 | snd_soc_write(codec, AC97_GPIO_PULL, reg & ~(1<<15)); |
78 | } | 78 | } |
79 | 79 | ||
80 | return 0; | 80 | return 0; |
81 | } | 81 | } |
82 | 82 | ||
83 | static int rear_amp_event(struct snd_soc_dapm_widget *widget, | 83 | static int rear_amp_event(struct snd_soc_dapm_widget *widget, |
84 | struct snd_kcontrol *kctl, int event) | 84 | struct snd_kcontrol *kctl, int event) |
85 | { | 85 | { |
86 | struct snd_soc_codec *codec = widget->codec; | 86 | struct snd_soc_codec *codec = widget->codec; |
87 | 87 | ||
88 | return rear_amp_power(codec, SND_SOC_DAPM_EVENT_ON(event)); | 88 | return rear_amp_power(codec, SND_SOC_DAPM_EVENT_ON(event)); |
89 | } | 89 | } |
90 | 90 | ||
91 | /* mioa701 machine dapm widgets */ | 91 | /* mioa701 machine dapm widgets */ |
92 | static const struct snd_soc_dapm_widget mioa701_dapm_widgets[] = { | 92 | static const struct snd_soc_dapm_widget mioa701_dapm_widgets[] = { |
93 | SND_SOC_DAPM_SPK("Front Speaker", NULL), | 93 | SND_SOC_DAPM_SPK("Front Speaker", NULL), |
94 | SND_SOC_DAPM_SPK("Rear Speaker", rear_amp_event), | 94 | SND_SOC_DAPM_SPK("Rear Speaker", rear_amp_event), |
95 | SND_SOC_DAPM_MIC("Headset", NULL), | 95 | SND_SOC_DAPM_MIC("Headset", NULL), |
96 | SND_SOC_DAPM_LINE("GSM Line Out", NULL), | 96 | SND_SOC_DAPM_LINE("GSM Line Out", NULL), |
97 | SND_SOC_DAPM_LINE("GSM Line In", NULL), | 97 | SND_SOC_DAPM_LINE("GSM Line In", NULL), |
98 | SND_SOC_DAPM_MIC("Headset Mic", NULL), | 98 | SND_SOC_DAPM_MIC("Headset Mic", NULL), |
99 | SND_SOC_DAPM_MIC("Front Mic", NULL), | 99 | SND_SOC_DAPM_MIC("Front Mic", NULL), |
100 | }; | 100 | }; |
101 | 101 | ||
102 | static const struct snd_soc_dapm_route audio_map[] = { | 102 | static const struct snd_soc_dapm_route audio_map[] = { |
103 | /* Call Mic */ | 103 | /* Call Mic */ |
104 | {"Mic Bias", NULL, "Front Mic"}, | 104 | {"Mic Bias", NULL, "Front Mic"}, |
105 | {"MIC1", NULL, "Mic Bias"}, | 105 | {"MIC1", NULL, "Mic Bias"}, |
106 | 106 | ||
107 | /* Headset Mic */ | 107 | /* Headset Mic */ |
108 | {"LINEL", NULL, "Headset Mic"}, | 108 | {"LINEL", NULL, "Headset Mic"}, |
109 | {"LINER", NULL, "Headset Mic"}, | 109 | {"LINER", NULL, "Headset Mic"}, |
110 | 110 | ||
111 | /* GSM Module */ | 111 | /* GSM Module */ |
112 | {"MONOIN", NULL, "GSM Line Out"}, | 112 | {"MONOIN", NULL, "GSM Line Out"}, |
113 | {"PCBEEP", NULL, "GSM Line Out"}, | 113 | {"PCBEEP", NULL, "GSM Line Out"}, |
114 | {"GSM Line In", NULL, "MONO"}, | 114 | {"GSM Line In", NULL, "MONO"}, |
115 | 115 | ||
116 | /* headphone connected to HPL, HPR */ | 116 | /* headphone connected to HPL, HPR */ |
117 | {"Headset", NULL, "HPL"}, | 117 | {"Headset", NULL, "HPL"}, |
118 | {"Headset", NULL, "HPR"}, | 118 | {"Headset", NULL, "HPR"}, |
119 | 119 | ||
120 | /* front speaker connected to HPL, OUT3 */ | 120 | /* front speaker connected to HPL, OUT3 */ |
121 | {"Front Speaker", NULL, "HPL"}, | 121 | {"Front Speaker", NULL, "HPL"}, |
122 | {"Front Speaker", NULL, "OUT3"}, | 122 | {"Front Speaker", NULL, "OUT3"}, |
123 | 123 | ||
124 | /* rear speaker connected to SPKL, SPKR */ | 124 | /* rear speaker connected to SPKL, SPKR */ |
125 | {"Rear Speaker", NULL, "SPKL"}, | 125 | {"Rear Speaker", NULL, "SPKL"}, |
126 | {"Rear Speaker", NULL, "SPKR"}, | 126 | {"Rear Speaker", NULL, "SPKR"}, |
127 | }; | 127 | }; |
128 | 128 | ||
129 | static int mioa701_wm9713_init(struct snd_soc_pcm_runtime *rtd) | 129 | static int mioa701_wm9713_init(struct snd_soc_pcm_runtime *rtd) |
130 | { | 130 | { |
131 | struct snd_soc_codec *codec = rtd->codec; | 131 | struct snd_soc_codec *codec = rtd->codec; |
132 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 132 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
133 | unsigned short reg; | 133 | unsigned short reg; |
134 | 134 | ||
135 | /* Add mioa701 specific widgets */ | 135 | /* Add mioa701 specific widgets */ |
136 | snd_soc_dapm_new_controls(dapm, ARRAY_AND_SIZE(mioa701_dapm_widgets)); | 136 | snd_soc_dapm_new_controls(dapm, ARRAY_AND_SIZE(mioa701_dapm_widgets)); |
137 | 137 | ||
138 | /* Set up mioa701 specific audio path audio_mapnects */ | 138 | /* Set up mioa701 specific audio path audio_mapnects */ |
139 | snd_soc_dapm_add_routes(dapm, ARRAY_AND_SIZE(audio_map)); | 139 | snd_soc_dapm_add_routes(dapm, ARRAY_AND_SIZE(audio_map)); |
140 | 140 | ||
141 | /* Prepare GPIO8 for rear speaker amplifier */ | 141 | /* Prepare GPIO8 for rear speaker amplifier */ |
142 | reg = codec->driver->read(codec, AC97_GPIO_CFG); | 142 | reg = codec->driver->read(codec, AC97_GPIO_CFG); |
143 | codec->driver->write(codec, AC97_GPIO_CFG, reg | 0x0100); | 143 | codec->driver->write(codec, AC97_GPIO_CFG, reg | 0x0100); |
144 | 144 | ||
145 | /* Prepare MIC input */ | 145 | /* Prepare MIC input */ |
146 | reg = codec->driver->read(codec, AC97_3D_CONTROL); | 146 | reg = codec->driver->read(codec, AC97_3D_CONTROL); |
147 | codec->driver->write(codec, AC97_3D_CONTROL, reg | 0xc000); | 147 | codec->driver->write(codec, AC97_3D_CONTROL, reg | 0xc000); |
148 | 148 | ||
149 | snd_soc_dapm_enable_pin(dapm, "Front Speaker"); | 149 | snd_soc_dapm_enable_pin(dapm, "Front Speaker"); |
150 | snd_soc_dapm_enable_pin(dapm, "Rear Speaker"); | 150 | snd_soc_dapm_enable_pin(dapm, "Rear Speaker"); |
151 | snd_soc_dapm_enable_pin(dapm, "Front Mic"); | 151 | snd_soc_dapm_enable_pin(dapm, "Front Mic"); |
152 | snd_soc_dapm_enable_pin(dapm, "GSM Line In"); | 152 | snd_soc_dapm_enable_pin(dapm, "GSM Line In"); |
153 | snd_soc_dapm_enable_pin(dapm, "GSM Line Out"); | 153 | snd_soc_dapm_enable_pin(dapm, "GSM Line Out"); |
154 | snd_soc_dapm_sync(dapm); | ||
155 | 154 | ||
156 | return 0; | 155 | return 0; |
157 | } | 156 | } |
158 | 157 | ||
159 | static struct snd_soc_ops mioa701_ops; | 158 | static struct snd_soc_ops mioa701_ops; |
160 | 159 | ||
161 | static struct snd_soc_dai_link mioa701_dai[] = { | 160 | static struct snd_soc_dai_link mioa701_dai[] = { |
162 | { | 161 | { |
163 | .name = "AC97", | 162 | .name = "AC97", |
164 | .stream_name = "AC97 HiFi", | 163 | .stream_name = "AC97 HiFi", |
165 | .cpu_dai_name = "pxa2xx-ac97", | 164 | .cpu_dai_name = "pxa2xx-ac97", |
166 | .codec_dai_name = "wm9713-hifi", | 165 | .codec_dai_name = "wm9713-hifi", |
167 | .codec_name = "wm9713-codec", | 166 | .codec_name = "wm9713-codec", |
168 | .init = mioa701_wm9713_init, | 167 | .init = mioa701_wm9713_init, |
169 | .platform_name = "pxa-pcm-audio", | 168 | .platform_name = "pxa-pcm-audio", |
170 | .ops = &mioa701_ops, | 169 | .ops = &mioa701_ops, |
171 | }, | 170 | }, |
172 | { | 171 | { |
173 | .name = "AC97 Aux", | 172 | .name = "AC97 Aux", |
174 | .stream_name = "AC97 Aux", | 173 | .stream_name = "AC97 Aux", |
175 | .cpu_dai_name = "pxa2xx-ac97-aux", | 174 | .cpu_dai_name = "pxa2xx-ac97-aux", |
176 | .codec_dai_name ="wm9713-aux", | 175 | .codec_dai_name ="wm9713-aux", |
177 | .codec_name = "wm9713-codec", | 176 | .codec_name = "wm9713-codec", |
178 | .platform_name = "pxa-pcm-audio", | 177 | .platform_name = "pxa-pcm-audio", |
179 | .ops = &mioa701_ops, | 178 | .ops = &mioa701_ops, |
180 | }, | 179 | }, |
181 | }; | 180 | }; |
182 | 181 | ||
183 | static struct snd_soc_card mioa701 = { | 182 | static struct snd_soc_card mioa701 = { |
184 | .name = "MioA701", | 183 | .name = "MioA701", |
185 | .dai_link = mioa701_dai, | 184 | .dai_link = mioa701_dai, |
186 | .num_links = ARRAY_SIZE(mioa701_dai), | 185 | .num_links = ARRAY_SIZE(mioa701_dai), |
187 | }; | 186 | }; |
188 | 187 | ||
189 | static struct platform_device *mioa701_snd_device; | 188 | static struct platform_device *mioa701_snd_device; |
190 | 189 | ||
191 | static int mioa701_wm9713_probe(struct platform_device *pdev) | 190 | static int mioa701_wm9713_probe(struct platform_device *pdev) |
192 | { | 191 | { |
193 | int ret; | 192 | int ret; |
194 | 193 | ||
195 | if (!machine_is_mioa701()) | 194 | if (!machine_is_mioa701()) |
196 | return -ENODEV; | 195 | return -ENODEV; |
197 | 196 | ||
198 | dev_warn(&pdev->dev, "Be warned that incorrect mixers/muxes setup will" | 197 | dev_warn(&pdev->dev, "Be warned that incorrect mixers/muxes setup will" |
199 | "lead to overheating and possible destruction of your device." | 198 | "lead to overheating and possible destruction of your device." |
200 | "Do not use without a good knowledge of mio's board design!\n"); | 199 | "Do not use without a good knowledge of mio's board design!\n"); |
201 | 200 | ||
202 | mioa701_snd_device = platform_device_alloc("soc-audio", -1); | 201 | mioa701_snd_device = platform_device_alloc("soc-audio", -1); |
203 | if (!mioa701_snd_device) | 202 | if (!mioa701_snd_device) |
204 | return -ENOMEM; | 203 | return -ENOMEM; |
205 | 204 | ||
206 | platform_set_drvdata(mioa701_snd_device, &mioa701); | 205 | platform_set_drvdata(mioa701_snd_device, &mioa701); |
207 | 206 | ||
208 | ret = platform_device_add(mioa701_snd_device); | 207 | ret = platform_device_add(mioa701_snd_device); |
209 | if (!ret) | 208 | if (!ret) |
210 | return 0; | 209 | return 0; |
211 | 210 | ||
212 | platform_device_put(mioa701_snd_device); | 211 | platform_device_put(mioa701_snd_device); |
213 | return ret; | 212 | return ret; |
214 | } | 213 | } |
215 | 214 | ||
216 | static int __devexit mioa701_wm9713_remove(struct platform_device *pdev) | 215 | static int __devexit mioa701_wm9713_remove(struct platform_device *pdev) |
217 | { | 216 | { |
218 | platform_device_unregister(mioa701_snd_device); | 217 | platform_device_unregister(mioa701_snd_device); |
219 | return 0; | 218 | return 0; |
220 | } | 219 | } |
221 | 220 | ||
222 | static struct platform_driver mioa701_wm9713_driver = { | 221 | static struct platform_driver mioa701_wm9713_driver = { |
223 | .probe = mioa701_wm9713_probe, | 222 | .probe = mioa701_wm9713_probe, |
224 | .remove = __devexit_p(mioa701_wm9713_remove), | 223 | .remove = __devexit_p(mioa701_wm9713_remove), |
225 | .driver = { | 224 | .driver = { |
226 | .name = "mioa701-wm9713", | 225 | .name = "mioa701-wm9713", |
227 | .owner = THIS_MODULE, | 226 | .owner = THIS_MODULE, |
228 | }, | 227 | }, |
229 | }; | 228 | }; |
230 | 229 | ||
231 | static int __init mioa701_asoc_init(void) | 230 | static int __init mioa701_asoc_init(void) |
232 | { | 231 | { |
233 | return platform_driver_register(&mioa701_wm9713_driver); | 232 | return platform_driver_register(&mioa701_wm9713_driver); |
234 | } | 233 | } |
235 | 234 | ||
236 | static void __exit mioa701_asoc_exit(void) | 235 | static void __exit mioa701_asoc_exit(void) |
237 | { | 236 | { |
238 | platform_driver_unregister(&mioa701_wm9713_driver); | 237 | platform_driver_unregister(&mioa701_wm9713_driver); |
239 | } | 238 | } |
240 | 239 | ||
241 | module_init(mioa701_asoc_init); | 240 | module_init(mioa701_asoc_init); |
242 | module_exit(mioa701_asoc_exit); | 241 | module_exit(mioa701_asoc_exit); |
243 | 242 | ||
244 | /* Module information */ | 243 | /* Module information */ |
245 | MODULE_AUTHOR("Robert Jarzmik (rjarzmik@free.fr)"); | 244 | MODULE_AUTHOR("Robert Jarzmik (rjarzmik@free.fr)"); |
246 | MODULE_DESCRIPTION("ALSA SoC WM9713 MIO A701"); | 245 | MODULE_DESCRIPTION("ALSA SoC WM9713 MIO A701"); |
247 | MODULE_LICENSE("GPL"); | 246 | MODULE_LICENSE("GPL"); |
248 | 247 |
sound/soc/pxa/palm27x.c
1 | /* | 1 | /* |
2 | * linux/sound/soc/pxa/palm27x.c | 2 | * linux/sound/soc/pxa/palm27x.c |
3 | * | 3 | * |
4 | * SoC Audio driver for Palm T|X, T5 and LifeDrive | 4 | * SoC Audio driver for Palm T|X, T5 and LifeDrive |
5 | * | 5 | * |
6 | * based on tosa.c | 6 | * based on tosa.c |
7 | * | 7 | * |
8 | * Copyright (C) 2008 Marek Vasut <marek.vasut@gmail.com> | 8 | * Copyright (C) 2008 Marek Vasut <marek.vasut@gmail.com> |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 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 | 11 | * it under the terms of the GNU General Public License version 2 as |
12 | * published by the Free Software Foundation. | 12 | * published by the Free Software Foundation. |
13 | * | 13 | * |
14 | */ | 14 | */ |
15 | 15 | ||
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/moduleparam.h> | 17 | #include <linux/moduleparam.h> |
18 | #include <linux/device.h> | 18 | #include <linux/device.h> |
19 | #include <linux/gpio.h> | 19 | #include <linux/gpio.h> |
20 | 20 | ||
21 | #include <sound/core.h> | 21 | #include <sound/core.h> |
22 | #include <sound/pcm.h> | 22 | #include <sound/pcm.h> |
23 | #include <sound/soc.h> | 23 | #include <sound/soc.h> |
24 | #include <sound/jack.h> | 24 | #include <sound/jack.h> |
25 | 25 | ||
26 | #include <asm/mach-types.h> | 26 | #include <asm/mach-types.h> |
27 | #include <mach/audio.h> | 27 | #include <mach/audio.h> |
28 | #include <mach/palmasoc.h> | 28 | #include <mach/palmasoc.h> |
29 | 29 | ||
30 | #include "../codecs/wm9712.h" | 30 | #include "../codecs/wm9712.h" |
31 | #include "pxa2xx-ac97.h" | 31 | #include "pxa2xx-ac97.h" |
32 | 32 | ||
33 | static struct snd_soc_jack hs_jack; | 33 | static struct snd_soc_jack hs_jack; |
34 | 34 | ||
35 | /* Headphones jack detection DAPM pins */ | 35 | /* Headphones jack detection DAPM pins */ |
36 | static struct snd_soc_jack_pin hs_jack_pins[] = { | 36 | static struct snd_soc_jack_pin hs_jack_pins[] = { |
37 | { | 37 | { |
38 | .pin = "Headphone Jack", | 38 | .pin = "Headphone Jack", |
39 | .mask = SND_JACK_HEADPHONE, | 39 | .mask = SND_JACK_HEADPHONE, |
40 | }, | 40 | }, |
41 | }; | 41 | }; |
42 | 42 | ||
43 | /* Headphones jack detection gpios */ | 43 | /* Headphones jack detection gpios */ |
44 | static struct snd_soc_jack_gpio hs_jack_gpios[] = { | 44 | static struct snd_soc_jack_gpio hs_jack_gpios[] = { |
45 | [0] = { | 45 | [0] = { |
46 | /* gpio is set on per-platform basis */ | 46 | /* gpio is set on per-platform basis */ |
47 | .name = "hp-gpio", | 47 | .name = "hp-gpio", |
48 | .report = SND_JACK_HEADPHONE, | 48 | .report = SND_JACK_HEADPHONE, |
49 | .debounce_time = 200, | 49 | .debounce_time = 200, |
50 | }, | 50 | }, |
51 | }; | 51 | }; |
52 | 52 | ||
53 | /* Palm27x machine dapm widgets */ | 53 | /* Palm27x machine dapm widgets */ |
54 | static const struct snd_soc_dapm_widget palm27x_dapm_widgets[] = { | 54 | static const struct snd_soc_dapm_widget palm27x_dapm_widgets[] = { |
55 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | 55 | SND_SOC_DAPM_HP("Headphone Jack", NULL), |
56 | SND_SOC_DAPM_SPK("Ext. Speaker", NULL), | 56 | SND_SOC_DAPM_SPK("Ext. Speaker", NULL), |
57 | SND_SOC_DAPM_MIC("Ext. Microphone", NULL), | 57 | SND_SOC_DAPM_MIC("Ext. Microphone", NULL), |
58 | }; | 58 | }; |
59 | 59 | ||
60 | /* PalmTX audio map */ | 60 | /* PalmTX audio map */ |
61 | static const struct snd_soc_dapm_route audio_map[] = { | 61 | static const struct snd_soc_dapm_route audio_map[] = { |
62 | /* headphone connected to HPOUTL, HPOUTR */ | 62 | /* headphone connected to HPOUTL, HPOUTR */ |
63 | {"Headphone Jack", NULL, "HPOUTL"}, | 63 | {"Headphone Jack", NULL, "HPOUTL"}, |
64 | {"Headphone Jack", NULL, "HPOUTR"}, | 64 | {"Headphone Jack", NULL, "HPOUTR"}, |
65 | 65 | ||
66 | /* ext speaker connected to ROUT2, LOUT2 */ | 66 | /* ext speaker connected to ROUT2, LOUT2 */ |
67 | {"Ext. Speaker", NULL, "LOUT2"}, | 67 | {"Ext. Speaker", NULL, "LOUT2"}, |
68 | {"Ext. Speaker", NULL, "ROUT2"}, | 68 | {"Ext. Speaker", NULL, "ROUT2"}, |
69 | 69 | ||
70 | /* mic connected to MIC1 */ | 70 | /* mic connected to MIC1 */ |
71 | {"Ext. Microphone", NULL, "MIC1"}, | 71 | {"Ext. Microphone", NULL, "MIC1"}, |
72 | }; | 72 | }; |
73 | 73 | ||
74 | static struct snd_soc_card palm27x_asoc; | 74 | static struct snd_soc_card palm27x_asoc; |
75 | 75 | ||
76 | static int palm27x_ac97_init(struct snd_soc_pcm_runtime *rtd) | 76 | static int palm27x_ac97_init(struct snd_soc_pcm_runtime *rtd) |
77 | { | 77 | { |
78 | struct snd_soc_codec *codec = rtd->codec; | 78 | struct snd_soc_codec *codec = rtd->codec; |
79 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 79 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
80 | int err; | 80 | int err; |
81 | 81 | ||
82 | /* add palm27x specific widgets */ | 82 | /* add palm27x specific widgets */ |
83 | err = snd_soc_dapm_new_controls(dapm, palm27x_dapm_widgets, | 83 | err = snd_soc_dapm_new_controls(dapm, palm27x_dapm_widgets, |
84 | ARRAY_SIZE(palm27x_dapm_widgets)); | 84 | ARRAY_SIZE(palm27x_dapm_widgets)); |
85 | if (err) | 85 | if (err) |
86 | return err; | 86 | return err; |
87 | 87 | ||
88 | /* set up palm27x specific audio path audio_map */ | 88 | /* set up palm27x specific audio path audio_map */ |
89 | err = snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); | 89 | err = snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); |
90 | if (err) | 90 | if (err) |
91 | return err; | 91 | return err; |
92 | 92 | ||
93 | /* connected pins */ | 93 | /* connected pins */ |
94 | if (machine_is_palmld()) | 94 | if (machine_is_palmld()) |
95 | snd_soc_dapm_enable_pin(dapm, "MIC1"); | 95 | snd_soc_dapm_enable_pin(dapm, "MIC1"); |
96 | snd_soc_dapm_enable_pin(dapm, "HPOUTL"); | 96 | snd_soc_dapm_enable_pin(dapm, "HPOUTL"); |
97 | snd_soc_dapm_enable_pin(dapm, "HPOUTR"); | 97 | snd_soc_dapm_enable_pin(dapm, "HPOUTR"); |
98 | snd_soc_dapm_enable_pin(dapm, "LOUT2"); | 98 | snd_soc_dapm_enable_pin(dapm, "LOUT2"); |
99 | snd_soc_dapm_enable_pin(dapm, "ROUT2"); | 99 | snd_soc_dapm_enable_pin(dapm, "ROUT2"); |
100 | 100 | ||
101 | /* not connected pins */ | 101 | /* not connected pins */ |
102 | snd_soc_dapm_nc_pin(dapm, "OUT3"); | 102 | snd_soc_dapm_nc_pin(dapm, "OUT3"); |
103 | snd_soc_dapm_nc_pin(dapm, "MONOOUT"); | 103 | snd_soc_dapm_nc_pin(dapm, "MONOOUT"); |
104 | snd_soc_dapm_nc_pin(dapm, "LINEINL"); | 104 | snd_soc_dapm_nc_pin(dapm, "LINEINL"); |
105 | snd_soc_dapm_nc_pin(dapm, "LINEINR"); | 105 | snd_soc_dapm_nc_pin(dapm, "LINEINR"); |
106 | snd_soc_dapm_nc_pin(dapm, "PCBEEP"); | 106 | snd_soc_dapm_nc_pin(dapm, "PCBEEP"); |
107 | snd_soc_dapm_nc_pin(dapm, "PHONE"); | 107 | snd_soc_dapm_nc_pin(dapm, "PHONE"); |
108 | snd_soc_dapm_nc_pin(dapm, "MIC2"); | 108 | snd_soc_dapm_nc_pin(dapm, "MIC2"); |
109 | 109 | ||
110 | err = snd_soc_dapm_sync(dapm); | ||
111 | if (err) | ||
112 | return err; | ||
113 | |||
114 | /* Jack detection API stuff */ | 110 | /* Jack detection API stuff */ |
115 | err = snd_soc_jack_new(codec, "Headphone Jack", | 111 | err = snd_soc_jack_new(codec, "Headphone Jack", |
116 | SND_JACK_HEADPHONE, &hs_jack); | 112 | SND_JACK_HEADPHONE, &hs_jack); |
117 | if (err) | 113 | if (err) |
118 | return err; | 114 | return err; |
119 | 115 | ||
120 | err = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins), | 116 | err = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins), |
121 | hs_jack_pins); | 117 | hs_jack_pins); |
122 | if (err) | 118 | if (err) |
123 | return err; | 119 | return err; |
124 | 120 | ||
125 | err = snd_soc_jack_add_gpios(&hs_jack, ARRAY_SIZE(hs_jack_gpios), | 121 | err = snd_soc_jack_add_gpios(&hs_jack, ARRAY_SIZE(hs_jack_gpios), |
126 | hs_jack_gpios); | 122 | hs_jack_gpios); |
127 | 123 | ||
128 | return err; | 124 | return err; |
129 | } | 125 | } |
130 | 126 | ||
131 | static struct snd_soc_dai_link palm27x_dai[] = { | 127 | static struct snd_soc_dai_link palm27x_dai[] = { |
132 | { | 128 | { |
133 | .name = "AC97 HiFi", | 129 | .name = "AC97 HiFi", |
134 | .stream_name = "AC97 HiFi", | 130 | .stream_name = "AC97 HiFi", |
135 | .cpu_dai_name = "pxa2xx-ac97", | 131 | .cpu_dai_name = "pxa2xx-ac97", |
136 | .codec_dai_name = "wm9712-hifi", | 132 | .codec_dai_name = "wm9712-hifi", |
137 | .codec_name = "wm9712-codec", | 133 | .codec_name = "wm9712-codec", |
138 | .platform_name = "pxa-pcm-audio", | 134 | .platform_name = "pxa-pcm-audio", |
139 | .init = palm27x_ac97_init, | 135 | .init = palm27x_ac97_init, |
140 | }, | 136 | }, |
141 | { | 137 | { |
142 | .name = "AC97 Aux", | 138 | .name = "AC97 Aux", |
143 | .stream_name = "AC97 Aux", | 139 | .stream_name = "AC97 Aux", |
144 | .cpu_dai_name = "pxa2xx-ac97-aux", | 140 | .cpu_dai_name = "pxa2xx-ac97-aux", |
145 | .codec_dai_name = "wm9712-aux", | 141 | .codec_dai_name = "wm9712-aux", |
146 | .codec_name = "wm9712-codec", | 142 | .codec_name = "wm9712-codec", |
147 | .platform_name = "pxa-pcm-audio", | 143 | .platform_name = "pxa-pcm-audio", |
148 | }, | 144 | }, |
149 | }; | 145 | }; |
150 | 146 | ||
151 | static struct snd_soc_card palm27x_asoc = { | 147 | static struct snd_soc_card palm27x_asoc = { |
152 | .name = "Palm/PXA27x", | 148 | .name = "Palm/PXA27x", |
153 | .dai_link = palm27x_dai, | 149 | .dai_link = palm27x_dai, |
154 | .num_links = ARRAY_SIZE(palm27x_dai), | 150 | .num_links = ARRAY_SIZE(palm27x_dai), |
155 | }; | 151 | }; |
156 | 152 | ||
157 | static struct platform_device *palm27x_snd_device; | 153 | static struct platform_device *palm27x_snd_device; |
158 | 154 | ||
159 | static int palm27x_asoc_probe(struct platform_device *pdev) | 155 | static int palm27x_asoc_probe(struct platform_device *pdev) |
160 | { | 156 | { |
161 | int ret; | 157 | int ret; |
162 | 158 | ||
163 | if (!(machine_is_palmtx() || machine_is_palmt5() || | 159 | if (!(machine_is_palmtx() || machine_is_palmt5() || |
164 | machine_is_palmld() || machine_is_palmte2())) | 160 | machine_is_palmld() || machine_is_palmte2())) |
165 | return -ENODEV; | 161 | return -ENODEV; |
166 | 162 | ||
167 | if (!pdev->dev.platform_data) { | 163 | if (!pdev->dev.platform_data) { |
168 | dev_err(&pdev->dev, "please supply platform_data\n"); | 164 | dev_err(&pdev->dev, "please supply platform_data\n"); |
169 | return -ENODEV; | 165 | return -ENODEV; |
170 | } | 166 | } |
171 | 167 | ||
172 | hs_jack_gpios[0].gpio = ((struct palm27x_asoc_info *) | 168 | hs_jack_gpios[0].gpio = ((struct palm27x_asoc_info *) |
173 | (pdev->dev.platform_data))->jack_gpio; | 169 | (pdev->dev.platform_data))->jack_gpio; |
174 | 170 | ||
175 | palm27x_snd_device = platform_device_alloc("soc-audio", -1); | 171 | palm27x_snd_device = platform_device_alloc("soc-audio", -1); |
176 | if (!palm27x_snd_device) | 172 | if (!palm27x_snd_device) |
177 | return -ENOMEM; | 173 | return -ENOMEM; |
178 | 174 | ||
179 | platform_set_drvdata(palm27x_snd_device, &palm27x_asoc); | 175 | platform_set_drvdata(palm27x_snd_device, &palm27x_asoc); |
180 | ret = platform_device_add(palm27x_snd_device); | 176 | ret = platform_device_add(palm27x_snd_device); |
181 | 177 | ||
182 | if (ret != 0) | 178 | if (ret != 0) |
183 | goto put_device; | 179 | goto put_device; |
184 | 180 | ||
185 | return 0; | 181 | return 0; |
186 | 182 | ||
187 | put_device: | 183 | put_device: |
188 | platform_device_put(palm27x_snd_device); | 184 | platform_device_put(palm27x_snd_device); |
189 | 185 | ||
190 | return ret; | 186 | return ret; |
191 | } | 187 | } |
192 | 188 | ||
193 | static int __devexit palm27x_asoc_remove(struct platform_device *pdev) | 189 | static int __devexit palm27x_asoc_remove(struct platform_device *pdev) |
194 | { | 190 | { |
195 | platform_device_unregister(palm27x_snd_device); | 191 | platform_device_unregister(palm27x_snd_device); |
196 | return 0; | 192 | return 0; |
197 | } | 193 | } |
198 | 194 | ||
199 | static struct platform_driver palm27x_wm9712_driver = { | 195 | static struct platform_driver palm27x_wm9712_driver = { |
200 | .probe = palm27x_asoc_probe, | 196 | .probe = palm27x_asoc_probe, |
201 | .remove = __devexit_p(palm27x_asoc_remove), | 197 | .remove = __devexit_p(palm27x_asoc_remove), |
202 | .driver = { | 198 | .driver = { |
203 | .name = "palm27x-asoc", | 199 | .name = "palm27x-asoc", |
204 | .owner = THIS_MODULE, | 200 | .owner = THIS_MODULE, |
205 | }, | 201 | }, |
206 | }; | 202 | }; |
207 | 203 | ||
208 | static int __init palm27x_asoc_init(void) | 204 | static int __init palm27x_asoc_init(void) |
209 | { | 205 | { |
210 | return platform_driver_register(&palm27x_wm9712_driver); | 206 | return platform_driver_register(&palm27x_wm9712_driver); |
211 | } | 207 | } |
212 | 208 | ||
213 | static void __exit palm27x_asoc_exit(void) | 209 | static void __exit palm27x_asoc_exit(void) |
214 | { | 210 | { |
215 | platform_driver_unregister(&palm27x_wm9712_driver); | 211 | platform_driver_unregister(&palm27x_wm9712_driver); |
216 | } | 212 | } |
217 | 213 | ||
218 | module_init(palm27x_asoc_init); | 214 | module_init(palm27x_asoc_init); |
219 | module_exit(palm27x_asoc_exit); | 215 | module_exit(palm27x_asoc_exit); |
220 | 216 | ||
221 | /* Module information */ | 217 | /* Module information */ |
222 | MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>"); | 218 | MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>"); |
223 | MODULE_DESCRIPTION("ALSA SoC Palm T|X, T5 and LifeDrive"); | 219 | MODULE_DESCRIPTION("ALSA SoC Palm T|X, T5 and LifeDrive"); |
224 | MODULE_LICENSE("GPL"); | 220 | MODULE_LICENSE("GPL"); |
225 | 221 |
sound/soc/pxa/saarb.c
1 | /* | 1 | /* |
2 | * saarb.c -- SoC audio for saarb | 2 | * saarb.c -- SoC audio for saarb |
3 | * | 3 | * |
4 | * Copyright (C) 2010 Marvell International Ltd. | 4 | * Copyright (C) 2010 Marvell International Ltd. |
5 | * Haojian Zhuang <haojian.zhuang@marvell.com> | 5 | * Haojian Zhuang <haojian.zhuang@marvell.com> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License version 2 as | 8 | * it under the terms of the GNU General Public License version 2 as |
9 | * published by the Free Software Foundation. | 9 | * published by the Free Software Foundation. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
13 | #include <linux/moduleparam.h> | 13 | #include <linux/moduleparam.h> |
14 | #include <linux/device.h> | 14 | #include <linux/device.h> |
15 | #include <linux/clk.h> | 15 | #include <linux/clk.h> |
16 | #include <linux/i2c.h> | 16 | #include <linux/i2c.h> |
17 | #include <sound/core.h> | 17 | #include <sound/core.h> |
18 | #include <sound/pcm.h> | 18 | #include <sound/pcm.h> |
19 | #include <sound/pcm_params.h> | 19 | #include <sound/pcm_params.h> |
20 | #include <sound/soc.h> | 20 | #include <sound/soc.h> |
21 | #include <sound/jack.h> | 21 | #include <sound/jack.h> |
22 | 22 | ||
23 | #include <asm/mach-types.h> | 23 | #include <asm/mach-types.h> |
24 | 24 | ||
25 | #include "../codecs/88pm860x-codec.h" | 25 | #include "../codecs/88pm860x-codec.h" |
26 | #include "pxa-ssp.h" | 26 | #include "pxa-ssp.h" |
27 | 27 | ||
28 | static int saarb_pm860x_init(struct snd_soc_pcm_runtime *rtd); | 28 | static int saarb_pm860x_init(struct snd_soc_pcm_runtime *rtd); |
29 | 29 | ||
30 | static struct platform_device *saarb_snd_device; | 30 | static struct platform_device *saarb_snd_device; |
31 | 31 | ||
32 | static struct snd_soc_jack hs_jack, mic_jack; | 32 | static struct snd_soc_jack hs_jack, mic_jack; |
33 | 33 | ||
34 | static struct snd_soc_jack_pin hs_jack_pins[] = { | 34 | static struct snd_soc_jack_pin hs_jack_pins[] = { |
35 | { .pin = "Headset Stereophone", .mask = SND_JACK_HEADPHONE, }, | 35 | { .pin = "Headset Stereophone", .mask = SND_JACK_HEADPHONE, }, |
36 | }; | 36 | }; |
37 | 37 | ||
38 | static struct snd_soc_jack_pin mic_jack_pins[] = { | 38 | static struct snd_soc_jack_pin mic_jack_pins[] = { |
39 | { .pin = "Headset Mic 2", .mask = SND_JACK_MICROPHONE, }, | 39 | { .pin = "Headset Mic 2", .mask = SND_JACK_MICROPHONE, }, |
40 | }; | 40 | }; |
41 | 41 | ||
42 | /* saarb machine dapm widgets */ | 42 | /* saarb machine dapm widgets */ |
43 | static const struct snd_soc_dapm_widget saarb_dapm_widgets[] = { | 43 | static const struct snd_soc_dapm_widget saarb_dapm_widgets[] = { |
44 | SND_SOC_DAPM_HP("Headphone Stereophone", NULL), | 44 | SND_SOC_DAPM_HP("Headphone Stereophone", NULL), |
45 | SND_SOC_DAPM_LINE("Lineout Out 1", NULL), | 45 | SND_SOC_DAPM_LINE("Lineout Out 1", NULL), |
46 | SND_SOC_DAPM_LINE("Lineout Out 2", NULL), | 46 | SND_SOC_DAPM_LINE("Lineout Out 2", NULL), |
47 | SND_SOC_DAPM_SPK("Ext Speaker", NULL), | 47 | SND_SOC_DAPM_SPK("Ext Speaker", NULL), |
48 | SND_SOC_DAPM_MIC("Ext Mic 1", NULL), | 48 | SND_SOC_DAPM_MIC("Ext Mic 1", NULL), |
49 | SND_SOC_DAPM_MIC("Headset Mic", NULL), | 49 | SND_SOC_DAPM_MIC("Headset Mic", NULL), |
50 | SND_SOC_DAPM_MIC("Ext Mic 3", NULL), | 50 | SND_SOC_DAPM_MIC("Ext Mic 3", NULL), |
51 | }; | 51 | }; |
52 | 52 | ||
53 | /* saarb machine audio map */ | 53 | /* saarb machine audio map */ |
54 | static const struct snd_soc_dapm_route audio_map[] = { | 54 | static const struct snd_soc_dapm_route audio_map[] = { |
55 | {"Headset Stereophone", NULL, "HS1"}, | 55 | {"Headset Stereophone", NULL, "HS1"}, |
56 | {"Headset Stereophone", NULL, "HS2"}, | 56 | {"Headset Stereophone", NULL, "HS2"}, |
57 | 57 | ||
58 | {"Ext Speaker", NULL, "LSP"}, | 58 | {"Ext Speaker", NULL, "LSP"}, |
59 | {"Ext Speaker", NULL, "LSN"}, | 59 | {"Ext Speaker", NULL, "LSN"}, |
60 | 60 | ||
61 | {"Lineout Out 1", NULL, "LINEOUT1"}, | 61 | {"Lineout Out 1", NULL, "LINEOUT1"}, |
62 | {"Lineout Out 2", NULL, "LINEOUT2"}, | 62 | {"Lineout Out 2", NULL, "LINEOUT2"}, |
63 | 63 | ||
64 | {"MIC1P", NULL, "Mic1 Bias"}, | 64 | {"MIC1P", NULL, "Mic1 Bias"}, |
65 | {"MIC1N", NULL, "Mic1 Bias"}, | 65 | {"MIC1N", NULL, "Mic1 Bias"}, |
66 | {"Mic1 Bias", NULL, "Ext Mic 1"}, | 66 | {"Mic1 Bias", NULL, "Ext Mic 1"}, |
67 | 67 | ||
68 | {"MIC2P", NULL, "Mic1 Bias"}, | 68 | {"MIC2P", NULL, "Mic1 Bias"}, |
69 | {"MIC2N", NULL, "Mic1 Bias"}, | 69 | {"MIC2N", NULL, "Mic1 Bias"}, |
70 | {"Mic1 Bias", NULL, "Headset Mic 2"}, | 70 | {"Mic1 Bias", NULL, "Headset Mic 2"}, |
71 | 71 | ||
72 | {"MIC3P", NULL, "Mic3 Bias"}, | 72 | {"MIC3P", NULL, "Mic3 Bias"}, |
73 | {"MIC3N", NULL, "Mic3 Bias"}, | 73 | {"MIC3N", NULL, "Mic3 Bias"}, |
74 | {"Mic3 Bias", NULL, "Ext Mic 3"}, | 74 | {"Mic3 Bias", NULL, "Ext Mic 3"}, |
75 | }; | 75 | }; |
76 | 76 | ||
77 | static int saarb_i2s_hw_params(struct snd_pcm_substream *substream, | 77 | static int saarb_i2s_hw_params(struct snd_pcm_substream *substream, |
78 | struct snd_pcm_hw_params *params) | 78 | struct snd_pcm_hw_params *params) |
79 | { | 79 | { |
80 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 80 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
81 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 81 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
82 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 82 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
83 | int width = snd_pcm_format_physical_width(params_format(params)); | 83 | int width = snd_pcm_format_physical_width(params_format(params)); |
84 | int ret; | 84 | int ret; |
85 | 85 | ||
86 | ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_NET_PLL, 0, | 86 | ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_NET_PLL, 0, |
87 | PM860X_CLK_DIR_OUT); | 87 | PM860X_CLK_DIR_OUT); |
88 | if (ret < 0) | 88 | if (ret < 0) |
89 | return ret; | 89 | return ret; |
90 | 90 | ||
91 | ret = snd_soc_dai_set_sysclk(codec_dai, 0, 0, PM860X_CLK_DIR_OUT); | 91 | ret = snd_soc_dai_set_sysclk(codec_dai, 0, 0, PM860X_CLK_DIR_OUT); |
92 | if (ret < 0) | 92 | if (ret < 0) |
93 | return ret; | 93 | return ret; |
94 | 94 | ||
95 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | | 95 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | |
96 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); | 96 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); |
97 | if (ret < 0) | 97 | if (ret < 0) |
98 | return ret; | 98 | return ret; |
99 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | | 99 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | |
100 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); | 100 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); |
101 | if (ret < 0) | 101 | if (ret < 0) |
102 | return ret; | 102 | return ret; |
103 | 103 | ||
104 | ret = snd_soc_dai_set_tdm_slot(cpu_dai, 3, 3, 2, width); | 104 | ret = snd_soc_dai_set_tdm_slot(cpu_dai, 3, 3, 2, width); |
105 | 105 | ||
106 | return ret; | 106 | return ret; |
107 | } | 107 | } |
108 | 108 | ||
109 | static struct snd_soc_ops saarb_i2s_ops = { | 109 | static struct snd_soc_ops saarb_i2s_ops = { |
110 | .hw_params = saarb_i2s_hw_params, | 110 | .hw_params = saarb_i2s_hw_params, |
111 | }; | 111 | }; |
112 | 112 | ||
113 | static struct snd_soc_dai_link saarb_dai[] = { | 113 | static struct snd_soc_dai_link saarb_dai[] = { |
114 | { | 114 | { |
115 | .name = "88PM860x I2S", | 115 | .name = "88PM860x I2S", |
116 | .stream_name = "I2S Audio", | 116 | .stream_name = "I2S Audio", |
117 | .cpu_dai_name = "pxa-ssp-dai.1", | 117 | .cpu_dai_name = "pxa-ssp-dai.1", |
118 | .codec_dai_name = "88pm860x-i2s", | 118 | .codec_dai_name = "88pm860x-i2s", |
119 | .platform_name = "pxa-pcm-audio", | 119 | .platform_name = "pxa-pcm-audio", |
120 | .codec_name = "88pm860x-codec", | 120 | .codec_name = "88pm860x-codec", |
121 | .init = saarb_pm860x_init, | 121 | .init = saarb_pm860x_init, |
122 | .ops = &saarb_i2s_ops, | 122 | .ops = &saarb_i2s_ops, |
123 | }, | 123 | }, |
124 | }; | 124 | }; |
125 | 125 | ||
126 | static struct snd_soc_card snd_soc_card_saarb = { | 126 | static struct snd_soc_card snd_soc_card_saarb = { |
127 | .name = "Saarb", | 127 | .name = "Saarb", |
128 | .dai_link = saarb_dai, | 128 | .dai_link = saarb_dai, |
129 | .num_links = ARRAY_SIZE(saarb_dai), | 129 | .num_links = ARRAY_SIZE(saarb_dai), |
130 | }; | 130 | }; |
131 | 131 | ||
132 | static int saarb_pm860x_init(struct snd_soc_pcm_runtime *rtd) | 132 | static int saarb_pm860x_init(struct snd_soc_pcm_runtime *rtd) |
133 | { | 133 | { |
134 | struct snd_soc_codec *codec = rtd->codec; | 134 | struct snd_soc_codec *codec = rtd->codec; |
135 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 135 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
136 | int ret; | 136 | int ret; |
137 | 137 | ||
138 | snd_soc_dapm_new_controls(dapm, saarb_dapm_widgets, | 138 | snd_soc_dapm_new_controls(dapm, saarb_dapm_widgets, |
139 | ARRAY_SIZE(saarb_dapm_widgets)); | 139 | ARRAY_SIZE(saarb_dapm_widgets)); |
140 | snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); | 140 | snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); |
141 | 141 | ||
142 | /* connected pins */ | 142 | /* connected pins */ |
143 | snd_soc_dapm_enable_pin(dapm, "Ext Speaker"); | 143 | snd_soc_dapm_enable_pin(dapm, "Ext Speaker"); |
144 | snd_soc_dapm_enable_pin(dapm, "Ext Mic 1"); | 144 | snd_soc_dapm_enable_pin(dapm, "Ext Mic 1"); |
145 | snd_soc_dapm_enable_pin(dapm, "Ext Mic 3"); | 145 | snd_soc_dapm_enable_pin(dapm, "Ext Mic 3"); |
146 | snd_soc_dapm_disable_pin(dapm, "Headset Mic 2"); | 146 | snd_soc_dapm_disable_pin(dapm, "Headset Mic 2"); |
147 | snd_soc_dapm_disable_pin(dapm, "Headset Stereophone"); | 147 | snd_soc_dapm_disable_pin(dapm, "Headset Stereophone"); |
148 | 148 | ||
149 | ret = snd_soc_dapm_sync(dapm); | ||
150 | if (ret) | ||
151 | return ret; | ||
152 | |||
153 | /* Headset jack detection */ | 149 | /* Headset jack detection */ |
154 | snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE | 150 | snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE |
155 | | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2, | 151 | | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2, |
156 | &hs_jack); | 152 | &hs_jack); |
157 | snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins), | 153 | snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins), |
158 | hs_jack_pins); | 154 | hs_jack_pins); |
159 | snd_soc_jack_new(codec, "Microphone Jack", SND_JACK_MICROPHONE, | 155 | snd_soc_jack_new(codec, "Microphone Jack", SND_JACK_MICROPHONE, |
160 | &mic_jack); | 156 | &mic_jack); |
161 | snd_soc_jack_add_pins(&mic_jack, ARRAY_SIZE(mic_jack_pins), | 157 | snd_soc_jack_add_pins(&mic_jack, ARRAY_SIZE(mic_jack_pins), |
162 | mic_jack_pins); | 158 | mic_jack_pins); |
163 | 159 | ||
164 | /* headphone, microphone detection & headset short detection */ | 160 | /* headphone, microphone detection & headset short detection */ |
165 | pm860x_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADPHONE, | 161 | pm860x_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADPHONE, |
166 | SND_JACK_BTN_0, SND_JACK_BTN_1, SND_JACK_BTN_2); | 162 | SND_JACK_BTN_0, SND_JACK_BTN_1, SND_JACK_BTN_2); |
167 | pm860x_mic_jack_detect(codec, &hs_jack, SND_JACK_MICROPHONE); | 163 | pm860x_mic_jack_detect(codec, &hs_jack, SND_JACK_MICROPHONE); |
168 | return 0; | 164 | return 0; |
169 | } | 165 | } |
170 | 166 | ||
171 | static int __init saarb_init(void) | 167 | static int __init saarb_init(void) |
172 | { | 168 | { |
173 | int ret; | 169 | int ret; |
174 | 170 | ||
175 | if (!machine_is_saarb()) | 171 | if (!machine_is_saarb()) |
176 | return -ENODEV; | 172 | return -ENODEV; |
177 | saarb_snd_device = platform_device_alloc("soc-audio", -1); | 173 | saarb_snd_device = platform_device_alloc("soc-audio", -1); |
178 | if (!saarb_snd_device) | 174 | if (!saarb_snd_device) |
179 | return -ENOMEM; | 175 | return -ENOMEM; |
180 | 176 | ||
181 | platform_set_drvdata(saarb_snd_device, &snd_soc_card_saarb); | 177 | platform_set_drvdata(saarb_snd_device, &snd_soc_card_saarb); |
182 | 178 | ||
183 | ret = platform_device_add(saarb_snd_device); | 179 | ret = platform_device_add(saarb_snd_device); |
184 | if (ret) | 180 | if (ret) |
185 | platform_device_put(saarb_snd_device); | 181 | platform_device_put(saarb_snd_device); |
186 | 182 | ||
187 | return ret; | 183 | return ret; |
188 | } | 184 | } |
189 | 185 | ||
190 | static void __exit saarb_exit(void) | 186 | static void __exit saarb_exit(void) |
191 | { | 187 | { |
192 | platform_device_unregister(saarb_snd_device); | 188 | platform_device_unregister(saarb_snd_device); |
193 | } | 189 | } |
194 | 190 | ||
195 | module_init(saarb_init); | 191 | module_init(saarb_init); |
196 | module_exit(saarb_exit); | 192 | module_exit(saarb_exit); |
197 | 193 | ||
198 | MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>"); | 194 | MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>"); |
199 | MODULE_DESCRIPTION("ALSA SoC 88PM860x Saarb"); | 195 | MODULE_DESCRIPTION("ALSA SoC 88PM860x Saarb"); |
200 | MODULE_LICENSE("GPL"); | 196 | MODULE_LICENSE("GPL"); |
201 | 197 |
sound/soc/pxa/tavorevb3.c
1 | /* | 1 | /* |
2 | * tavorevb3.c -- SoC audio for Tavor EVB3 | 2 | * tavorevb3.c -- SoC audio for Tavor EVB3 |
3 | * | 3 | * |
4 | * Copyright (C) 2010 Marvell International Ltd. | 4 | * Copyright (C) 2010 Marvell International Ltd. |
5 | * Haojian Zhuang <haojian.zhuang@marvell.com> | 5 | * Haojian Zhuang <haojian.zhuang@marvell.com> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License version 2 as | 8 | * it under the terms of the GNU General Public License version 2 as |
9 | * published by the Free Software Foundation. | 9 | * published by the Free Software Foundation. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
13 | #include <linux/moduleparam.h> | 13 | #include <linux/moduleparam.h> |
14 | #include <linux/device.h> | 14 | #include <linux/device.h> |
15 | #include <linux/clk.h> | 15 | #include <linux/clk.h> |
16 | #include <linux/i2c.h> | 16 | #include <linux/i2c.h> |
17 | #include <sound/core.h> | 17 | #include <sound/core.h> |
18 | #include <sound/pcm.h> | 18 | #include <sound/pcm.h> |
19 | #include <sound/pcm_params.h> | 19 | #include <sound/pcm_params.h> |
20 | #include <sound/soc.h> | 20 | #include <sound/soc.h> |
21 | #include <sound/jack.h> | 21 | #include <sound/jack.h> |
22 | 22 | ||
23 | #include <asm/mach-types.h> | 23 | #include <asm/mach-types.h> |
24 | 24 | ||
25 | #include "../codecs/88pm860x-codec.h" | 25 | #include "../codecs/88pm860x-codec.h" |
26 | #include "pxa-ssp.h" | 26 | #include "pxa-ssp.h" |
27 | 27 | ||
28 | static int evb3_pm860x_init(struct snd_soc_pcm_runtime *rtd); | 28 | static int evb3_pm860x_init(struct snd_soc_pcm_runtime *rtd); |
29 | 29 | ||
30 | static struct platform_device *evb3_snd_device; | 30 | static struct platform_device *evb3_snd_device; |
31 | 31 | ||
32 | static struct snd_soc_jack hs_jack, mic_jack; | 32 | static struct snd_soc_jack hs_jack, mic_jack; |
33 | 33 | ||
34 | static struct snd_soc_jack_pin hs_jack_pins[] = { | 34 | static struct snd_soc_jack_pin hs_jack_pins[] = { |
35 | { .pin = "Headset Stereophone", .mask = SND_JACK_HEADPHONE, }, | 35 | { .pin = "Headset Stereophone", .mask = SND_JACK_HEADPHONE, }, |
36 | }; | 36 | }; |
37 | 37 | ||
38 | static struct snd_soc_jack_pin mic_jack_pins[] = { | 38 | static struct snd_soc_jack_pin mic_jack_pins[] = { |
39 | { .pin = "Headset Mic 2", .mask = SND_JACK_MICROPHONE, }, | 39 | { .pin = "Headset Mic 2", .mask = SND_JACK_MICROPHONE, }, |
40 | }; | 40 | }; |
41 | 41 | ||
42 | /* tavorevb3 machine dapm widgets */ | 42 | /* tavorevb3 machine dapm widgets */ |
43 | static const struct snd_soc_dapm_widget evb3_dapm_widgets[] = { | 43 | static const struct snd_soc_dapm_widget evb3_dapm_widgets[] = { |
44 | SND_SOC_DAPM_HP("Headset Stereophone", NULL), | 44 | SND_SOC_DAPM_HP("Headset Stereophone", NULL), |
45 | SND_SOC_DAPM_LINE("Lineout Out 1", NULL), | 45 | SND_SOC_DAPM_LINE("Lineout Out 1", NULL), |
46 | SND_SOC_DAPM_LINE("Lineout Out 2", NULL), | 46 | SND_SOC_DAPM_LINE("Lineout Out 2", NULL), |
47 | SND_SOC_DAPM_SPK("Ext Speaker", NULL), | 47 | SND_SOC_DAPM_SPK("Ext Speaker", NULL), |
48 | SND_SOC_DAPM_MIC("Ext Mic 1", NULL), | 48 | SND_SOC_DAPM_MIC("Ext Mic 1", NULL), |
49 | SND_SOC_DAPM_MIC("Headset Mic 2", NULL), | 49 | SND_SOC_DAPM_MIC("Headset Mic 2", NULL), |
50 | SND_SOC_DAPM_MIC("Ext Mic 3", NULL), | 50 | SND_SOC_DAPM_MIC("Ext Mic 3", NULL), |
51 | }; | 51 | }; |
52 | 52 | ||
53 | /* tavorevb3 machine audio map */ | 53 | /* tavorevb3 machine audio map */ |
54 | static const struct snd_soc_dapm_route audio_map[] = { | 54 | static const struct snd_soc_dapm_route audio_map[] = { |
55 | {"Headset Stereophone", NULL, "HS1"}, | 55 | {"Headset Stereophone", NULL, "HS1"}, |
56 | {"Headset Stereophone", NULL, "HS2"}, | 56 | {"Headset Stereophone", NULL, "HS2"}, |
57 | 57 | ||
58 | {"Ext Speaker", NULL, "LSP"}, | 58 | {"Ext Speaker", NULL, "LSP"}, |
59 | {"Ext Speaker", NULL, "LSN"}, | 59 | {"Ext Speaker", NULL, "LSN"}, |
60 | 60 | ||
61 | {"Lineout Out 1", NULL, "LINEOUT1"}, | 61 | {"Lineout Out 1", NULL, "LINEOUT1"}, |
62 | {"Lineout Out 2", NULL, "LINEOUT2"}, | 62 | {"Lineout Out 2", NULL, "LINEOUT2"}, |
63 | 63 | ||
64 | {"MIC1P", NULL, "Mic1 Bias"}, | 64 | {"MIC1P", NULL, "Mic1 Bias"}, |
65 | {"MIC1N", NULL, "Mic1 Bias"}, | 65 | {"MIC1N", NULL, "Mic1 Bias"}, |
66 | {"Mic1 Bias", NULL, "Ext Mic 1"}, | 66 | {"Mic1 Bias", NULL, "Ext Mic 1"}, |
67 | 67 | ||
68 | {"MIC2P", NULL, "Mic1 Bias"}, | 68 | {"MIC2P", NULL, "Mic1 Bias"}, |
69 | {"MIC2N", NULL, "Mic1 Bias"}, | 69 | {"MIC2N", NULL, "Mic1 Bias"}, |
70 | {"Mic1 Bias", NULL, "Headset Mic 2"}, | 70 | {"Mic1 Bias", NULL, "Headset Mic 2"}, |
71 | 71 | ||
72 | {"MIC3P", NULL, "Mic3 Bias"}, | 72 | {"MIC3P", NULL, "Mic3 Bias"}, |
73 | {"MIC3N", NULL, "Mic3 Bias"}, | 73 | {"MIC3N", NULL, "Mic3 Bias"}, |
74 | {"Mic3 Bias", NULL, "Ext Mic 3"}, | 74 | {"Mic3 Bias", NULL, "Ext Mic 3"}, |
75 | }; | 75 | }; |
76 | 76 | ||
77 | static int evb3_i2s_hw_params(struct snd_pcm_substream *substream, | 77 | static int evb3_i2s_hw_params(struct snd_pcm_substream *substream, |
78 | struct snd_pcm_hw_params *params) | 78 | struct snd_pcm_hw_params *params) |
79 | { | 79 | { |
80 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 80 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
81 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 81 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
82 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 82 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
83 | int width = snd_pcm_format_physical_width(params_format(params)); | 83 | int width = snd_pcm_format_physical_width(params_format(params)); |
84 | int ret; | 84 | int ret; |
85 | 85 | ||
86 | ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_NET_PLL, 0, | 86 | ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_NET_PLL, 0, |
87 | PM860X_CLK_DIR_OUT); | 87 | PM860X_CLK_DIR_OUT); |
88 | if (ret < 0) | 88 | if (ret < 0) |
89 | return ret; | 89 | return ret; |
90 | 90 | ||
91 | ret = snd_soc_dai_set_sysclk(codec_dai, 0, 0, PM860X_CLK_DIR_OUT); | 91 | ret = snd_soc_dai_set_sysclk(codec_dai, 0, 0, PM860X_CLK_DIR_OUT); |
92 | if (ret < 0) | 92 | if (ret < 0) |
93 | return ret; | 93 | return ret; |
94 | 94 | ||
95 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | | 95 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | |
96 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); | 96 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); |
97 | if (ret < 0) | 97 | if (ret < 0) |
98 | return ret; | 98 | return ret; |
99 | 99 | ||
100 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | | 100 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | |
101 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); | 101 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); |
102 | if (ret < 0) | 102 | if (ret < 0) |
103 | return ret; | 103 | return ret; |
104 | 104 | ||
105 | ret = snd_soc_dai_set_tdm_slot(cpu_dai, 3, 3, 2, width); | 105 | ret = snd_soc_dai_set_tdm_slot(cpu_dai, 3, 3, 2, width); |
106 | return ret; | 106 | return ret; |
107 | } | 107 | } |
108 | 108 | ||
109 | static struct snd_soc_ops evb3_i2s_ops = { | 109 | static struct snd_soc_ops evb3_i2s_ops = { |
110 | .hw_params = evb3_i2s_hw_params, | 110 | .hw_params = evb3_i2s_hw_params, |
111 | }; | 111 | }; |
112 | 112 | ||
113 | static struct snd_soc_dai_link evb3_dai[] = { | 113 | static struct snd_soc_dai_link evb3_dai[] = { |
114 | { | 114 | { |
115 | .name = "88PM860x I2S", | 115 | .name = "88PM860x I2S", |
116 | .stream_name = "I2S Audio", | 116 | .stream_name = "I2S Audio", |
117 | .cpu_dai_name = "pxa-ssp-dai.1", | 117 | .cpu_dai_name = "pxa-ssp-dai.1", |
118 | .codec_dai_name = "88pm860x-i2s", | 118 | .codec_dai_name = "88pm860x-i2s", |
119 | .platform_name = "pxa-pcm-audio", | 119 | .platform_name = "pxa-pcm-audio", |
120 | .codec_name = "88pm860x-codec", | 120 | .codec_name = "88pm860x-codec", |
121 | .init = evb3_pm860x_init, | 121 | .init = evb3_pm860x_init, |
122 | .ops = &evb3_i2s_ops, | 122 | .ops = &evb3_i2s_ops, |
123 | }, | 123 | }, |
124 | }; | 124 | }; |
125 | 125 | ||
126 | static struct snd_soc_card snd_soc_card_evb3 = { | 126 | static struct snd_soc_card snd_soc_card_evb3 = { |
127 | .name = "Tavor EVB3", | 127 | .name = "Tavor EVB3", |
128 | .dai_link = evb3_dai, | 128 | .dai_link = evb3_dai, |
129 | .num_links = ARRAY_SIZE(evb3_dai), | 129 | .num_links = ARRAY_SIZE(evb3_dai), |
130 | }; | 130 | }; |
131 | 131 | ||
132 | static int evb3_pm860x_init(struct snd_soc_pcm_runtime *rtd) | 132 | static int evb3_pm860x_init(struct snd_soc_pcm_runtime *rtd) |
133 | { | 133 | { |
134 | struct snd_soc_codec *codec = rtd->codec; | 134 | struct snd_soc_codec *codec = rtd->codec; |
135 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 135 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
136 | int ret; | 136 | int ret; |
137 | 137 | ||
138 | snd_soc_dapm_new_controls(dapm, evb3_dapm_widgets, | 138 | snd_soc_dapm_new_controls(dapm, evb3_dapm_widgets, |
139 | ARRAY_SIZE(evb3_dapm_widgets)); | 139 | ARRAY_SIZE(evb3_dapm_widgets)); |
140 | snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); | 140 | snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); |
141 | 141 | ||
142 | /* connected pins */ | 142 | /* connected pins */ |
143 | snd_soc_dapm_enable_pin(dapm, "Ext Speaker"); | 143 | snd_soc_dapm_enable_pin(dapm, "Ext Speaker"); |
144 | snd_soc_dapm_enable_pin(dapm, "Ext Mic 1"); | 144 | snd_soc_dapm_enable_pin(dapm, "Ext Mic 1"); |
145 | snd_soc_dapm_enable_pin(dapm, "Ext Mic 3"); | 145 | snd_soc_dapm_enable_pin(dapm, "Ext Mic 3"); |
146 | snd_soc_dapm_disable_pin(dapm, "Headset Mic 2"); | 146 | snd_soc_dapm_disable_pin(dapm, "Headset Mic 2"); |
147 | snd_soc_dapm_disable_pin(dapm, "Headset Stereophone"); | 147 | snd_soc_dapm_disable_pin(dapm, "Headset Stereophone"); |
148 | 148 | ||
149 | ret = snd_soc_dapm_sync(dapm); | ||
150 | if (ret) | ||
151 | return ret; | ||
152 | |||
153 | /* Headset jack detection */ | 149 | /* Headset jack detection */ |
154 | snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE | 150 | snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE |
155 | | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2, | 151 | | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2, |
156 | &hs_jack); | 152 | &hs_jack); |
157 | snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins), | 153 | snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins), |
158 | hs_jack_pins); | 154 | hs_jack_pins); |
159 | snd_soc_jack_new(codec, "Microphone Jack", SND_JACK_MICROPHONE, | 155 | snd_soc_jack_new(codec, "Microphone Jack", SND_JACK_MICROPHONE, |
160 | &mic_jack); | 156 | &mic_jack); |
161 | snd_soc_jack_add_pins(&mic_jack, ARRAY_SIZE(mic_jack_pins), | 157 | snd_soc_jack_add_pins(&mic_jack, ARRAY_SIZE(mic_jack_pins), |
162 | mic_jack_pins); | 158 | mic_jack_pins); |
163 | 159 | ||
164 | /* headphone, microphone detection & headset short detection */ | 160 | /* headphone, microphone detection & headset short detection */ |
165 | pm860x_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADPHONE, | 161 | pm860x_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADPHONE, |
166 | SND_JACK_BTN_0, SND_JACK_BTN_1, SND_JACK_BTN_2); | 162 | SND_JACK_BTN_0, SND_JACK_BTN_1, SND_JACK_BTN_2); |
167 | pm860x_mic_jack_detect(codec, &hs_jack, SND_JACK_MICROPHONE); | 163 | pm860x_mic_jack_detect(codec, &hs_jack, SND_JACK_MICROPHONE); |
168 | return 0; | 164 | return 0; |
169 | } | 165 | } |
170 | 166 | ||
171 | static int __init tavorevb3_init(void) | 167 | static int __init tavorevb3_init(void) |
172 | { | 168 | { |
173 | int ret; | 169 | int ret; |
174 | 170 | ||
175 | if (!machine_is_tavorevb3()) | 171 | if (!machine_is_tavorevb3()) |
176 | return -ENODEV; | 172 | return -ENODEV; |
177 | evb3_snd_device = platform_device_alloc("soc-audio", -1); | 173 | evb3_snd_device = platform_device_alloc("soc-audio", -1); |
178 | if (!evb3_snd_device) | 174 | if (!evb3_snd_device) |
179 | return -ENOMEM; | 175 | return -ENOMEM; |
180 | 176 | ||
181 | platform_set_drvdata(evb3_snd_device, &snd_soc_card_evb3); | 177 | platform_set_drvdata(evb3_snd_device, &snd_soc_card_evb3); |
182 | 178 | ||
183 | ret = platform_device_add(evb3_snd_device); | 179 | ret = platform_device_add(evb3_snd_device); |
184 | if (ret) | 180 | if (ret) |
185 | platform_device_put(evb3_snd_device); | 181 | platform_device_put(evb3_snd_device); |
186 | 182 | ||
187 | return ret; | 183 | return ret; |
188 | } | 184 | } |
189 | 185 | ||
190 | static void __exit tavorevb3_exit(void) | 186 | static void __exit tavorevb3_exit(void) |
191 | { | 187 | { |
192 | platform_device_unregister(evb3_snd_device); | 188 | platform_device_unregister(evb3_snd_device); |
193 | } | 189 | } |
194 | 190 | ||
195 | module_init(tavorevb3_init); | 191 | module_init(tavorevb3_init); |
196 | module_exit(tavorevb3_exit); | 192 | module_exit(tavorevb3_exit); |
197 | 193 | ||
198 | MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>"); | 194 | MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>"); |
199 | MODULE_DESCRIPTION("ALSA SoC 88PM860x Tavor EVB3"); | 195 | MODULE_DESCRIPTION("ALSA SoC 88PM860x Tavor EVB3"); |
200 | MODULE_LICENSE("GPL"); | 196 | MODULE_LICENSE("GPL"); |
201 | 197 |
sound/soc/pxa/tosa.c
1 | /* | 1 | /* |
2 | * tosa.c -- SoC audio for Tosa | 2 | * tosa.c -- SoC audio for Tosa |
3 | * | 3 | * |
4 | * Copyright 2005 Wolfson Microelectronics PLC. | 4 | * Copyright 2005 Wolfson Microelectronics PLC. |
5 | * Copyright 2005 Openedhand Ltd. | 5 | * Copyright 2005 Openedhand Ltd. |
6 | * | 6 | * |
7 | * Authors: Liam Girdwood <lrg@slimlogic.co.uk> | 7 | * Authors: Liam Girdwood <lrg@slimlogic.co.uk> |
8 | * Richard Purdie <richard@openedhand.com> | 8 | * Richard Purdie <richard@openedhand.com> |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify it | 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 | 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 | 12 | * Free Software Foundation; either version 2 of the License, or (at your |
13 | * option) any later version. | 13 | * option) any later version. |
14 | * | 14 | * |
15 | * GPIO's | 15 | * GPIO's |
16 | * 1 - Jack Insertion | 16 | * 1 - Jack Insertion |
17 | * 5 - Hookswitch (headset answer/hang up switch) | 17 | * 5 - Hookswitch (headset answer/hang up switch) |
18 | * | 18 | * |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <linux/module.h> | 21 | #include <linux/module.h> |
22 | #include <linux/moduleparam.h> | 22 | #include <linux/moduleparam.h> |
23 | #include <linux/device.h> | 23 | #include <linux/device.h> |
24 | #include <linux/gpio.h> | 24 | #include <linux/gpio.h> |
25 | 25 | ||
26 | #include <sound/core.h> | 26 | #include <sound/core.h> |
27 | #include <sound/pcm.h> | 27 | #include <sound/pcm.h> |
28 | #include <sound/soc.h> | 28 | #include <sound/soc.h> |
29 | 29 | ||
30 | #include <asm/mach-types.h> | 30 | #include <asm/mach-types.h> |
31 | #include <mach/tosa.h> | 31 | #include <mach/tosa.h> |
32 | #include <mach/audio.h> | 32 | #include <mach/audio.h> |
33 | 33 | ||
34 | #include "../codecs/wm9712.h" | 34 | #include "../codecs/wm9712.h" |
35 | #include "pxa2xx-ac97.h" | 35 | #include "pxa2xx-ac97.h" |
36 | 36 | ||
37 | static struct snd_soc_card tosa; | 37 | static struct snd_soc_card tosa; |
38 | 38 | ||
39 | #define TOSA_HP 0 | 39 | #define TOSA_HP 0 |
40 | #define TOSA_MIC_INT 1 | 40 | #define TOSA_MIC_INT 1 |
41 | #define TOSA_HEADSET 2 | 41 | #define TOSA_HEADSET 2 |
42 | #define TOSA_HP_OFF 3 | 42 | #define TOSA_HP_OFF 3 |
43 | #define TOSA_SPK_ON 0 | 43 | #define TOSA_SPK_ON 0 |
44 | #define TOSA_SPK_OFF 1 | 44 | #define TOSA_SPK_OFF 1 |
45 | 45 | ||
46 | static int tosa_jack_func; | 46 | static int tosa_jack_func; |
47 | static int tosa_spk_func; | 47 | static int tosa_spk_func; |
48 | 48 | ||
49 | static void tosa_ext_control(struct snd_soc_codec *codec) | 49 | static void tosa_ext_control(struct snd_soc_codec *codec) |
50 | { | 50 | { |
51 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 51 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
52 | 52 | ||
53 | /* set up jack connection */ | 53 | /* set up jack connection */ |
54 | switch (tosa_jack_func) { | 54 | switch (tosa_jack_func) { |
55 | case TOSA_HP: | 55 | case TOSA_HP: |
56 | snd_soc_dapm_disable_pin(dapm, "Mic (Internal)"); | 56 | snd_soc_dapm_disable_pin(dapm, "Mic (Internal)"); |
57 | snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); | 57 | snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); |
58 | snd_soc_dapm_disable_pin(dapm, "Headset Jack"); | 58 | snd_soc_dapm_disable_pin(dapm, "Headset Jack"); |
59 | break; | 59 | break; |
60 | case TOSA_MIC_INT: | 60 | case TOSA_MIC_INT: |
61 | snd_soc_dapm_enable_pin(dapm, "Mic (Internal)"); | 61 | snd_soc_dapm_enable_pin(dapm, "Mic (Internal)"); |
62 | snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); | 62 | snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); |
63 | snd_soc_dapm_disable_pin(dapm, "Headset Jack"); | 63 | snd_soc_dapm_disable_pin(dapm, "Headset Jack"); |
64 | break; | 64 | break; |
65 | case TOSA_HEADSET: | 65 | case TOSA_HEADSET: |
66 | snd_soc_dapm_disable_pin(dapm, "Mic (Internal)"); | 66 | snd_soc_dapm_disable_pin(dapm, "Mic (Internal)"); |
67 | snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); | 67 | snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); |
68 | snd_soc_dapm_enable_pin(dapm, "Headset Jack"); | 68 | snd_soc_dapm_enable_pin(dapm, "Headset Jack"); |
69 | break; | 69 | break; |
70 | } | 70 | } |
71 | 71 | ||
72 | if (tosa_spk_func == TOSA_SPK_ON) | 72 | if (tosa_spk_func == TOSA_SPK_ON) |
73 | snd_soc_dapm_enable_pin(dapm, "Speaker"); | 73 | snd_soc_dapm_enable_pin(dapm, "Speaker"); |
74 | else | 74 | else |
75 | snd_soc_dapm_disable_pin(dapm, "Speaker"); | 75 | snd_soc_dapm_disable_pin(dapm, "Speaker"); |
76 | 76 | ||
77 | snd_soc_dapm_sync(dapm); | 77 | snd_soc_dapm_sync(dapm); |
78 | } | 78 | } |
79 | 79 | ||
80 | static int tosa_startup(struct snd_pcm_substream *substream) | 80 | static int tosa_startup(struct snd_pcm_substream *substream) |
81 | { | 81 | { |
82 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 82 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
83 | struct snd_soc_codec *codec = rtd->codec; | 83 | struct snd_soc_codec *codec = rtd->codec; |
84 | 84 | ||
85 | mutex_lock(&codec->mutex); | 85 | mutex_lock(&codec->mutex); |
86 | 86 | ||
87 | /* check the jack status at stream startup */ | 87 | /* check the jack status at stream startup */ |
88 | tosa_ext_control(codec); | 88 | tosa_ext_control(codec); |
89 | 89 | ||
90 | mutex_unlock(&codec->mutex); | 90 | mutex_unlock(&codec->mutex); |
91 | 91 | ||
92 | return 0; | 92 | return 0; |
93 | } | 93 | } |
94 | 94 | ||
95 | static struct snd_soc_ops tosa_ops = { | 95 | static struct snd_soc_ops tosa_ops = { |
96 | .startup = tosa_startup, | 96 | .startup = tosa_startup, |
97 | }; | 97 | }; |
98 | 98 | ||
99 | static int tosa_get_jack(struct snd_kcontrol *kcontrol, | 99 | static int tosa_get_jack(struct snd_kcontrol *kcontrol, |
100 | struct snd_ctl_elem_value *ucontrol) | 100 | struct snd_ctl_elem_value *ucontrol) |
101 | { | 101 | { |
102 | ucontrol->value.integer.value[0] = tosa_jack_func; | 102 | ucontrol->value.integer.value[0] = tosa_jack_func; |
103 | return 0; | 103 | return 0; |
104 | } | 104 | } |
105 | 105 | ||
106 | static int tosa_set_jack(struct snd_kcontrol *kcontrol, | 106 | static int tosa_set_jack(struct snd_kcontrol *kcontrol, |
107 | struct snd_ctl_elem_value *ucontrol) | 107 | struct snd_ctl_elem_value *ucontrol) |
108 | { | 108 | { |
109 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 109 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
110 | 110 | ||
111 | if (tosa_jack_func == ucontrol->value.integer.value[0]) | 111 | if (tosa_jack_func == ucontrol->value.integer.value[0]) |
112 | return 0; | 112 | return 0; |
113 | 113 | ||
114 | tosa_jack_func = ucontrol->value.integer.value[0]; | 114 | tosa_jack_func = ucontrol->value.integer.value[0]; |
115 | tosa_ext_control(codec); | 115 | tosa_ext_control(codec); |
116 | return 1; | 116 | return 1; |
117 | } | 117 | } |
118 | 118 | ||
119 | static int tosa_get_spk(struct snd_kcontrol *kcontrol, | 119 | static int tosa_get_spk(struct snd_kcontrol *kcontrol, |
120 | struct snd_ctl_elem_value *ucontrol) | 120 | struct snd_ctl_elem_value *ucontrol) |
121 | { | 121 | { |
122 | ucontrol->value.integer.value[0] = tosa_spk_func; | 122 | ucontrol->value.integer.value[0] = tosa_spk_func; |
123 | return 0; | 123 | return 0; |
124 | } | 124 | } |
125 | 125 | ||
126 | static int tosa_set_spk(struct snd_kcontrol *kcontrol, | 126 | static int tosa_set_spk(struct snd_kcontrol *kcontrol, |
127 | struct snd_ctl_elem_value *ucontrol) | 127 | struct snd_ctl_elem_value *ucontrol) |
128 | { | 128 | { |
129 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 129 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
130 | 130 | ||
131 | if (tosa_spk_func == ucontrol->value.integer.value[0]) | 131 | if (tosa_spk_func == ucontrol->value.integer.value[0]) |
132 | return 0; | 132 | return 0; |
133 | 133 | ||
134 | tosa_spk_func = ucontrol->value.integer.value[0]; | 134 | tosa_spk_func = ucontrol->value.integer.value[0]; |
135 | tosa_ext_control(codec); | 135 | tosa_ext_control(codec); |
136 | return 1; | 136 | return 1; |
137 | } | 137 | } |
138 | 138 | ||
139 | /* tosa dapm event handlers */ | 139 | /* tosa dapm event handlers */ |
140 | static int tosa_hp_event(struct snd_soc_dapm_widget *w, | 140 | static int tosa_hp_event(struct snd_soc_dapm_widget *w, |
141 | struct snd_kcontrol *k, int event) | 141 | struct snd_kcontrol *k, int event) |
142 | { | 142 | { |
143 | gpio_set_value(TOSA_GPIO_L_MUTE, SND_SOC_DAPM_EVENT_ON(event) ? 1 :0); | 143 | gpio_set_value(TOSA_GPIO_L_MUTE, SND_SOC_DAPM_EVENT_ON(event) ? 1 :0); |
144 | return 0; | 144 | return 0; |
145 | } | 145 | } |
146 | 146 | ||
147 | /* tosa machine dapm widgets */ | 147 | /* tosa machine dapm widgets */ |
148 | static const struct snd_soc_dapm_widget tosa_dapm_widgets[] = { | 148 | static const struct snd_soc_dapm_widget tosa_dapm_widgets[] = { |
149 | SND_SOC_DAPM_HP("Headphone Jack", tosa_hp_event), | 149 | SND_SOC_DAPM_HP("Headphone Jack", tosa_hp_event), |
150 | SND_SOC_DAPM_HP("Headset Jack", NULL), | 150 | SND_SOC_DAPM_HP("Headset Jack", NULL), |
151 | SND_SOC_DAPM_MIC("Mic (Internal)", NULL), | 151 | SND_SOC_DAPM_MIC("Mic (Internal)", NULL), |
152 | SND_SOC_DAPM_SPK("Speaker", NULL), | 152 | SND_SOC_DAPM_SPK("Speaker", NULL), |
153 | }; | 153 | }; |
154 | 154 | ||
155 | /* tosa audio map */ | 155 | /* tosa audio map */ |
156 | static const struct snd_soc_dapm_route audio_map[] = { | 156 | static const struct snd_soc_dapm_route audio_map[] = { |
157 | 157 | ||
158 | /* headphone connected to HPOUTL, HPOUTR */ | 158 | /* headphone connected to HPOUTL, HPOUTR */ |
159 | {"Headphone Jack", NULL, "HPOUTL"}, | 159 | {"Headphone Jack", NULL, "HPOUTL"}, |
160 | {"Headphone Jack", NULL, "HPOUTR"}, | 160 | {"Headphone Jack", NULL, "HPOUTR"}, |
161 | 161 | ||
162 | /* ext speaker connected to LOUT2, ROUT2 */ | 162 | /* ext speaker connected to LOUT2, ROUT2 */ |
163 | {"Speaker", NULL, "LOUT2"}, | 163 | {"Speaker", NULL, "LOUT2"}, |
164 | {"Speaker", NULL, "ROUT2"}, | 164 | {"Speaker", NULL, "ROUT2"}, |
165 | 165 | ||
166 | /* internal mic is connected to mic1, mic2 differential - with bias */ | 166 | /* internal mic is connected to mic1, mic2 differential - with bias */ |
167 | {"MIC1", NULL, "Mic Bias"}, | 167 | {"MIC1", NULL, "Mic Bias"}, |
168 | {"MIC2", NULL, "Mic Bias"}, | 168 | {"MIC2", NULL, "Mic Bias"}, |
169 | {"Mic Bias", NULL, "Mic (Internal)"}, | 169 | {"Mic Bias", NULL, "Mic (Internal)"}, |
170 | 170 | ||
171 | /* headset is connected to HPOUTR, and LINEINR with bias */ | 171 | /* headset is connected to HPOUTR, and LINEINR with bias */ |
172 | {"Headset Jack", NULL, "HPOUTR"}, | 172 | {"Headset Jack", NULL, "HPOUTR"}, |
173 | {"LINEINR", NULL, "Mic Bias"}, | 173 | {"LINEINR", NULL, "Mic Bias"}, |
174 | {"Mic Bias", NULL, "Headset Jack"}, | 174 | {"Mic Bias", NULL, "Headset Jack"}, |
175 | }; | 175 | }; |
176 | 176 | ||
177 | static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset", | 177 | static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset", |
178 | "Off"}; | 178 | "Off"}; |
179 | static const char *spk_function[] = {"On", "Off"}; | 179 | static const char *spk_function[] = {"On", "Off"}; |
180 | static const struct soc_enum tosa_enum[] = { | 180 | static const struct soc_enum tosa_enum[] = { |
181 | SOC_ENUM_SINGLE_EXT(5, jack_function), | 181 | SOC_ENUM_SINGLE_EXT(5, jack_function), |
182 | SOC_ENUM_SINGLE_EXT(2, spk_function), | 182 | SOC_ENUM_SINGLE_EXT(2, spk_function), |
183 | }; | 183 | }; |
184 | 184 | ||
185 | static const struct snd_kcontrol_new tosa_controls[] = { | 185 | static const struct snd_kcontrol_new tosa_controls[] = { |
186 | SOC_ENUM_EXT("Jack Function", tosa_enum[0], tosa_get_jack, | 186 | SOC_ENUM_EXT("Jack Function", tosa_enum[0], tosa_get_jack, |
187 | tosa_set_jack), | 187 | tosa_set_jack), |
188 | SOC_ENUM_EXT("Speaker Function", tosa_enum[1], tosa_get_spk, | 188 | SOC_ENUM_EXT("Speaker Function", tosa_enum[1], tosa_get_spk, |
189 | tosa_set_spk), | 189 | tosa_set_spk), |
190 | }; | 190 | }; |
191 | 191 | ||
192 | static int tosa_ac97_init(struct snd_soc_pcm_runtime *rtd) | 192 | static int tosa_ac97_init(struct snd_soc_pcm_runtime *rtd) |
193 | { | 193 | { |
194 | struct snd_soc_codec *codec = rtd->codec; | 194 | struct snd_soc_codec *codec = rtd->codec; |
195 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 195 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
196 | int err; | 196 | int err; |
197 | 197 | ||
198 | snd_soc_dapm_nc_pin(dapm, "OUT3"); | 198 | snd_soc_dapm_nc_pin(dapm, "OUT3"); |
199 | snd_soc_dapm_nc_pin(dapm, "MONOOUT"); | 199 | snd_soc_dapm_nc_pin(dapm, "MONOOUT"); |
200 | 200 | ||
201 | /* add tosa specific controls */ | 201 | /* add tosa specific controls */ |
202 | err = snd_soc_add_controls(codec, tosa_controls, | 202 | err = snd_soc_add_controls(codec, tosa_controls, |
203 | ARRAY_SIZE(tosa_controls)); | 203 | ARRAY_SIZE(tosa_controls)); |
204 | if (err < 0) | 204 | if (err < 0) |
205 | return err; | 205 | return err; |
206 | 206 | ||
207 | /* add tosa specific widgets */ | 207 | /* add tosa specific widgets */ |
208 | snd_soc_dapm_new_controls(dapm, tosa_dapm_widgets, | 208 | snd_soc_dapm_new_controls(dapm, tosa_dapm_widgets, |
209 | ARRAY_SIZE(tosa_dapm_widgets)); | 209 | ARRAY_SIZE(tosa_dapm_widgets)); |
210 | 210 | ||
211 | /* set up tosa specific audio path audio_map */ | 211 | /* set up tosa specific audio path audio_map */ |
212 | snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); | 212 | snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); |
213 | 213 | ||
214 | snd_soc_dapm_sync(dapm); | ||
215 | return 0; | 214 | return 0; |
216 | } | 215 | } |
217 | 216 | ||
218 | static struct snd_soc_dai_link tosa_dai[] = { | 217 | static struct snd_soc_dai_link tosa_dai[] = { |
219 | { | 218 | { |
220 | .name = "AC97", | 219 | .name = "AC97", |
221 | .stream_name = "AC97 HiFi", | 220 | .stream_name = "AC97 HiFi", |
222 | .cpu_dai_name = "pxa2xx-ac97", | 221 | .cpu_dai_name = "pxa2xx-ac97", |
223 | .codec_dai_name = "wm9712-hifi", | 222 | .codec_dai_name = "wm9712-hifi", |
224 | .platform_name = "pxa-pcm-audio", | 223 | .platform_name = "pxa-pcm-audio", |
225 | .codec_name = "wm9712-codec", | 224 | .codec_name = "wm9712-codec", |
226 | .init = tosa_ac97_init, | 225 | .init = tosa_ac97_init, |
227 | .ops = &tosa_ops, | 226 | .ops = &tosa_ops, |
228 | }, | 227 | }, |
229 | { | 228 | { |
230 | .name = "AC97 Aux", | 229 | .name = "AC97 Aux", |
231 | .stream_name = "AC97 Aux", | 230 | .stream_name = "AC97 Aux", |
232 | .cpu_dai_name = "pxa2xx-ac97-aux", | 231 | .cpu_dai_name = "pxa2xx-ac97-aux", |
233 | .codec_dai_name = "wm9712-aux", | 232 | .codec_dai_name = "wm9712-aux", |
234 | .platform_name = "pxa-pcm-audio", | 233 | .platform_name = "pxa-pcm-audio", |
235 | .codec_name = "wm9712-codec", | 234 | .codec_name = "wm9712-codec", |
236 | .ops = &tosa_ops, | 235 | .ops = &tosa_ops, |
237 | }, | 236 | }, |
238 | }; | 237 | }; |
239 | 238 | ||
240 | static int tosa_probe(struct snd_soc_card *card) | 239 | static int tosa_probe(struct snd_soc_card *card) |
241 | { | 240 | { |
242 | int ret; | 241 | int ret; |
243 | 242 | ||
244 | ret = gpio_request(TOSA_GPIO_L_MUTE, "Headphone Jack"); | 243 | ret = gpio_request(TOSA_GPIO_L_MUTE, "Headphone Jack"); |
245 | if (ret) | 244 | if (ret) |
246 | return ret; | 245 | return ret; |
247 | ret = gpio_direction_output(TOSA_GPIO_L_MUTE, 0); | 246 | ret = gpio_direction_output(TOSA_GPIO_L_MUTE, 0); |
248 | if (ret) | 247 | if (ret) |
249 | gpio_free(TOSA_GPIO_L_MUTE); | 248 | gpio_free(TOSA_GPIO_L_MUTE); |
250 | 249 | ||
251 | return ret; | 250 | return ret; |
252 | } | 251 | } |
253 | 252 | ||
254 | static int tosa_remove(struct snd_soc_card *card) | 253 | static int tosa_remove(struct snd_soc_card *card) |
255 | { | 254 | { |
256 | gpio_free(TOSA_GPIO_L_MUTE); | 255 | gpio_free(TOSA_GPIO_L_MUTE); |
257 | return 0; | 256 | return 0; |
258 | } | 257 | } |
259 | 258 | ||
260 | static struct snd_soc_card tosa = { | 259 | static struct snd_soc_card tosa = { |
261 | .name = "Tosa", | 260 | .name = "Tosa", |
262 | .dai_link = tosa_dai, | 261 | .dai_link = tosa_dai, |
263 | .num_links = ARRAY_SIZE(tosa_dai), | 262 | .num_links = ARRAY_SIZE(tosa_dai), |
264 | .probe = tosa_probe, | 263 | .probe = tosa_probe, |
265 | .remove = tosa_remove, | 264 | .remove = tosa_remove, |
266 | }; | 265 | }; |
267 | 266 | ||
268 | static struct platform_device *tosa_snd_device; | 267 | static struct platform_device *tosa_snd_device; |
269 | 268 | ||
270 | static int __init tosa_init(void) | 269 | static int __init tosa_init(void) |
271 | { | 270 | { |
272 | int ret; | 271 | int ret; |
273 | 272 | ||
274 | if (!machine_is_tosa()) | 273 | if (!machine_is_tosa()) |
275 | return -ENODEV; | 274 | return -ENODEV; |
276 | 275 | ||
277 | tosa_snd_device = platform_device_alloc("soc-audio", -1); | 276 | tosa_snd_device = platform_device_alloc("soc-audio", -1); |
278 | if (!tosa_snd_device) { | 277 | if (!tosa_snd_device) { |
279 | ret = -ENOMEM; | 278 | ret = -ENOMEM; |
280 | goto err_alloc; | 279 | goto err_alloc; |
281 | } | 280 | } |
282 | 281 | ||
283 | platform_set_drvdata(tosa_snd_device, &tosa); | 282 | platform_set_drvdata(tosa_snd_device, &tosa); |
284 | ret = platform_device_add(tosa_snd_device); | 283 | ret = platform_device_add(tosa_snd_device); |
285 | 284 | ||
286 | if (!ret) | 285 | if (!ret) |
287 | return 0; | 286 | return 0; |
288 | 287 | ||
289 | platform_device_put(tosa_snd_device); | 288 | platform_device_put(tosa_snd_device); |
290 | 289 | ||
291 | err_alloc: | 290 | err_alloc: |
292 | return ret; | 291 | return ret; |
293 | } | 292 | } |
294 | 293 | ||
295 | static void __exit tosa_exit(void) | 294 | static void __exit tosa_exit(void) |
296 | { | 295 | { |
297 | platform_device_unregister(tosa_snd_device); | 296 | platform_device_unregister(tosa_snd_device); |
298 | } | 297 | } |
299 | 298 | ||
300 | module_init(tosa_init); | 299 | module_init(tosa_init); |
301 | module_exit(tosa_exit); | 300 | module_exit(tosa_exit); |
302 | 301 | ||
303 | /* Module information */ | 302 | /* Module information */ |
304 | MODULE_AUTHOR("Richard Purdie"); | 303 | MODULE_AUTHOR("Richard Purdie"); |
305 | MODULE_DESCRIPTION("ALSA SoC Tosa"); | 304 | MODULE_DESCRIPTION("ALSA SoC Tosa"); |
306 | MODULE_LICENSE("GPL"); | 305 | MODULE_LICENSE("GPL"); |
307 | 306 |
sound/soc/pxa/z2.c
1 | /* | 1 | /* |
2 | * linux/sound/soc/pxa/z2.c | 2 | * linux/sound/soc/pxa/z2.c |
3 | * | 3 | * |
4 | * SoC Audio driver for Aeronix Zipit Z2 | 4 | * SoC Audio driver for Aeronix Zipit Z2 |
5 | * | 5 | * |
6 | * Copyright (C) 2009 Ken McGuire <kenm@desertweyr.com> | 6 | * Copyright (C) 2009 Ken McGuire <kenm@desertweyr.com> |
7 | * Copyright (C) 2010 Marek Vasut <marek.vasut@gmail.com> | 7 | * Copyright (C) 2010 Marek Vasut <marek.vasut@gmail.com> |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or modify | 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 | 10 | * it under the terms of the GNU General Public License version 2 as |
11 | * published by the Free Software Foundation. | 11 | * published by the Free Software Foundation. |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/moduleparam.h> | 15 | #include <linux/moduleparam.h> |
16 | #include <linux/timer.h> | 16 | #include <linux/timer.h> |
17 | #include <linux/interrupt.h> | 17 | #include <linux/interrupt.h> |
18 | #include <linux/platform_device.h> | 18 | #include <linux/platform_device.h> |
19 | #include <linux/gpio.h> | 19 | #include <linux/gpio.h> |
20 | 20 | ||
21 | #include <sound/core.h> | 21 | #include <sound/core.h> |
22 | #include <sound/pcm.h> | 22 | #include <sound/pcm.h> |
23 | #include <sound/soc.h> | 23 | #include <sound/soc.h> |
24 | #include <sound/jack.h> | 24 | #include <sound/jack.h> |
25 | 25 | ||
26 | #include <asm/mach-types.h> | 26 | #include <asm/mach-types.h> |
27 | #include <mach/hardware.h> | 27 | #include <mach/hardware.h> |
28 | #include <mach/audio.h> | 28 | #include <mach/audio.h> |
29 | #include <mach/z2.h> | 29 | #include <mach/z2.h> |
30 | 30 | ||
31 | #include "../codecs/wm8750.h" | 31 | #include "../codecs/wm8750.h" |
32 | #include "pxa2xx-i2s.h" | 32 | #include "pxa2xx-i2s.h" |
33 | 33 | ||
34 | static struct snd_soc_card snd_soc_z2; | 34 | static struct snd_soc_card snd_soc_z2; |
35 | 35 | ||
36 | static int z2_hw_params(struct snd_pcm_substream *substream, | 36 | static int z2_hw_params(struct snd_pcm_substream *substream, |
37 | struct snd_pcm_hw_params *params) | 37 | struct snd_pcm_hw_params *params) |
38 | { | 38 | { |
39 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 39 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
40 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 40 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
41 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 41 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
42 | unsigned int clk = 0; | 42 | unsigned int clk = 0; |
43 | int ret = 0; | 43 | int ret = 0; |
44 | 44 | ||
45 | switch (params_rate(params)) { | 45 | switch (params_rate(params)) { |
46 | case 8000: | 46 | case 8000: |
47 | case 16000: | 47 | case 16000: |
48 | case 48000: | 48 | case 48000: |
49 | case 96000: | 49 | case 96000: |
50 | clk = 12288000; | 50 | clk = 12288000; |
51 | break; | 51 | break; |
52 | case 11025: | 52 | case 11025: |
53 | case 22050: | 53 | case 22050: |
54 | case 44100: | 54 | case 44100: |
55 | clk = 11289600; | 55 | clk = 11289600; |
56 | break; | 56 | break; |
57 | } | 57 | } |
58 | 58 | ||
59 | /* set codec DAI configuration */ | 59 | /* set codec DAI configuration */ |
60 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | | 60 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | |
61 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); | 61 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); |
62 | if (ret < 0) | 62 | if (ret < 0) |
63 | return ret; | 63 | return ret; |
64 | 64 | ||
65 | /* set cpu DAI configuration */ | 65 | /* set cpu DAI configuration */ |
66 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | | 66 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | |
67 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); | 67 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); |
68 | if (ret < 0) | 68 | if (ret < 0) |
69 | return ret; | 69 | return ret; |
70 | 70 | ||
71 | /* set the codec system clock for DAC and ADC */ | 71 | /* set the codec system clock for DAC and ADC */ |
72 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk, | 72 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk, |
73 | SND_SOC_CLOCK_IN); | 73 | SND_SOC_CLOCK_IN); |
74 | if (ret < 0) | 74 | if (ret < 0) |
75 | return ret; | 75 | return ret; |
76 | 76 | ||
77 | /* set the I2S system clock as input (unused) */ | 77 | /* set the I2S system clock as input (unused) */ |
78 | ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0, | 78 | ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0, |
79 | SND_SOC_CLOCK_IN); | 79 | SND_SOC_CLOCK_IN); |
80 | if (ret < 0) | 80 | if (ret < 0) |
81 | return ret; | 81 | return ret; |
82 | 82 | ||
83 | return 0; | 83 | return 0; |
84 | } | 84 | } |
85 | 85 | ||
86 | static struct snd_soc_jack hs_jack; | 86 | static struct snd_soc_jack hs_jack; |
87 | 87 | ||
88 | /* Headset jack detection DAPM pins */ | 88 | /* Headset jack detection DAPM pins */ |
89 | static struct snd_soc_jack_pin hs_jack_pins[] = { | 89 | static struct snd_soc_jack_pin hs_jack_pins[] = { |
90 | { | 90 | { |
91 | .pin = "Mic Jack", | 91 | .pin = "Mic Jack", |
92 | .mask = SND_JACK_MICROPHONE, | 92 | .mask = SND_JACK_MICROPHONE, |
93 | }, | 93 | }, |
94 | { | 94 | { |
95 | .pin = "Headphone Jack", | 95 | .pin = "Headphone Jack", |
96 | .mask = SND_JACK_HEADPHONE, | 96 | .mask = SND_JACK_HEADPHONE, |
97 | }, | 97 | }, |
98 | { | 98 | { |
99 | .pin = "Ext Spk", | 99 | .pin = "Ext Spk", |
100 | .mask = SND_JACK_HEADPHONE, | 100 | .mask = SND_JACK_HEADPHONE, |
101 | .invert = 1 | 101 | .invert = 1 |
102 | }, | 102 | }, |
103 | }; | 103 | }; |
104 | 104 | ||
105 | /* Headset jack detection gpios */ | 105 | /* Headset jack detection gpios */ |
106 | static struct snd_soc_jack_gpio hs_jack_gpios[] = { | 106 | static struct snd_soc_jack_gpio hs_jack_gpios[] = { |
107 | { | 107 | { |
108 | .gpio = GPIO37_ZIPITZ2_HEADSET_DETECT, | 108 | .gpio = GPIO37_ZIPITZ2_HEADSET_DETECT, |
109 | .name = "hsdet-gpio", | 109 | .name = "hsdet-gpio", |
110 | .report = SND_JACK_HEADSET, | 110 | .report = SND_JACK_HEADSET, |
111 | .debounce_time = 200, | 111 | .debounce_time = 200, |
112 | .invert = 1, | 112 | .invert = 1, |
113 | }, | 113 | }, |
114 | }; | 114 | }; |
115 | 115 | ||
116 | /* z2 machine dapm widgets */ | 116 | /* z2 machine dapm widgets */ |
117 | static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = { | 117 | static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = { |
118 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | 118 | SND_SOC_DAPM_HP("Headphone Jack", NULL), |
119 | SND_SOC_DAPM_MIC("Mic Jack", NULL), | 119 | SND_SOC_DAPM_MIC("Mic Jack", NULL), |
120 | SND_SOC_DAPM_SPK("Ext Spk", NULL), | 120 | SND_SOC_DAPM_SPK("Ext Spk", NULL), |
121 | 121 | ||
122 | /* headset is a mic and mono headphone */ | 122 | /* headset is a mic and mono headphone */ |
123 | SND_SOC_DAPM_HP("Headset Jack", NULL), | 123 | SND_SOC_DAPM_HP("Headset Jack", NULL), |
124 | }; | 124 | }; |
125 | 125 | ||
126 | /* Z2 machine audio_map */ | 126 | /* Z2 machine audio_map */ |
127 | static const struct snd_soc_dapm_route audio_map[] = { | 127 | static const struct snd_soc_dapm_route audio_map[] = { |
128 | 128 | ||
129 | /* headphone connected to LOUT1, ROUT1 */ | 129 | /* headphone connected to LOUT1, ROUT1 */ |
130 | {"Headphone Jack", NULL, "LOUT1"}, | 130 | {"Headphone Jack", NULL, "LOUT1"}, |
131 | {"Headphone Jack", NULL, "ROUT1"}, | 131 | {"Headphone Jack", NULL, "ROUT1"}, |
132 | 132 | ||
133 | /* ext speaker connected to LOUT2, ROUT2 */ | 133 | /* ext speaker connected to LOUT2, ROUT2 */ |
134 | {"Ext Spk", NULL , "ROUT2"}, | 134 | {"Ext Spk", NULL , "ROUT2"}, |
135 | {"Ext Spk", NULL , "LOUT2"}, | 135 | {"Ext Spk", NULL , "LOUT2"}, |
136 | 136 | ||
137 | /* mic is connected to R input 2 - with bias */ | 137 | /* mic is connected to R input 2 - with bias */ |
138 | {"RINPUT2", NULL, "Mic Bias"}, | 138 | {"RINPUT2", NULL, "Mic Bias"}, |
139 | {"Mic Bias", NULL, "Mic Jack"}, | 139 | {"Mic Bias", NULL, "Mic Jack"}, |
140 | }; | 140 | }; |
141 | 141 | ||
142 | /* | 142 | /* |
143 | * Logic for a wm8750 as connected on a Z2 Device | 143 | * Logic for a wm8750 as connected on a Z2 Device |
144 | */ | 144 | */ |
145 | static int z2_wm8750_init(struct snd_soc_pcm_runtime *rtd) | 145 | static int z2_wm8750_init(struct snd_soc_pcm_runtime *rtd) |
146 | { | 146 | { |
147 | struct snd_soc_codec *codec = rtd->codec; | 147 | struct snd_soc_codec *codec = rtd->codec; |
148 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 148 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
149 | int ret; | 149 | int ret; |
150 | 150 | ||
151 | /* NC codec pins */ | 151 | /* NC codec pins */ |
152 | snd_soc_dapm_disable_pin(dapm, "LINPUT3"); | 152 | snd_soc_dapm_disable_pin(dapm, "LINPUT3"); |
153 | snd_soc_dapm_disable_pin(dapm, "RINPUT3"); | 153 | snd_soc_dapm_disable_pin(dapm, "RINPUT3"); |
154 | snd_soc_dapm_disable_pin(dapm, "OUT3"); | 154 | snd_soc_dapm_disable_pin(dapm, "OUT3"); |
155 | snd_soc_dapm_disable_pin(dapm, "MONO1"); | 155 | snd_soc_dapm_disable_pin(dapm, "MONO1"); |
156 | 156 | ||
157 | /* Add z2 specific widgets */ | 157 | /* Add z2 specific widgets */ |
158 | snd_soc_dapm_new_controls(dapm, wm8750_dapm_widgets, | 158 | snd_soc_dapm_new_controls(dapm, wm8750_dapm_widgets, |
159 | ARRAY_SIZE(wm8750_dapm_widgets)); | 159 | ARRAY_SIZE(wm8750_dapm_widgets)); |
160 | 160 | ||
161 | /* Set up z2 specific audio paths */ | 161 | /* Set up z2 specific audio paths */ |
162 | snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); | 162 | snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); |
163 | 163 | ||
164 | ret = snd_soc_dapm_sync(dapm); | ||
165 | if (ret) | ||
166 | goto err; | ||
167 | |||
168 | /* Jack detection API stuff */ | 164 | /* Jack detection API stuff */ |
169 | ret = snd_soc_jack_new(codec, "Headset Jack", SND_JACK_HEADSET, | 165 | ret = snd_soc_jack_new(codec, "Headset Jack", SND_JACK_HEADSET, |
170 | &hs_jack); | 166 | &hs_jack); |
171 | if (ret) | 167 | if (ret) |
172 | goto err; | 168 | goto err; |
173 | 169 | ||
174 | ret = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins), | 170 | ret = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins), |
175 | hs_jack_pins); | 171 | hs_jack_pins); |
176 | if (ret) | 172 | if (ret) |
177 | goto err; | 173 | goto err; |
178 | 174 | ||
179 | ret = snd_soc_jack_add_gpios(&hs_jack, ARRAY_SIZE(hs_jack_gpios), | 175 | ret = snd_soc_jack_add_gpios(&hs_jack, ARRAY_SIZE(hs_jack_gpios), |
180 | hs_jack_gpios); | 176 | hs_jack_gpios); |
181 | if (ret) | 177 | if (ret) |
182 | goto err; | 178 | goto err; |
183 | 179 | ||
184 | return 0; | 180 | return 0; |
185 | 181 | ||
186 | err: | 182 | err: |
187 | return ret; | 183 | return ret; |
188 | } | 184 | } |
189 | 185 | ||
190 | static struct snd_soc_ops z2_ops = { | 186 | static struct snd_soc_ops z2_ops = { |
191 | .hw_params = z2_hw_params, | 187 | .hw_params = z2_hw_params, |
192 | }; | 188 | }; |
193 | 189 | ||
194 | /* z2 digital audio interface glue - connects codec <--> CPU */ | 190 | /* z2 digital audio interface glue - connects codec <--> CPU */ |
195 | static struct snd_soc_dai_link z2_dai = { | 191 | static struct snd_soc_dai_link z2_dai = { |
196 | .name = "wm8750", | 192 | .name = "wm8750", |
197 | .stream_name = "WM8750", | 193 | .stream_name = "WM8750", |
198 | .cpu_dai_name = "pxa2xx-i2s", | 194 | .cpu_dai_name = "pxa2xx-i2s", |
199 | .codec_dai_name = "wm8750-hifi", | 195 | .codec_dai_name = "wm8750-hifi", |
200 | .platform_name = "pxa-pcm-audio", | 196 | .platform_name = "pxa-pcm-audio", |
201 | .codec_name = "wm8750.0-001b", | 197 | .codec_name = "wm8750.0-001b", |
202 | .init = z2_wm8750_init, | 198 | .init = z2_wm8750_init, |
203 | .ops = &z2_ops, | 199 | .ops = &z2_ops, |
204 | }; | 200 | }; |
205 | 201 | ||
206 | /* z2 audio machine driver */ | 202 | /* z2 audio machine driver */ |
207 | static struct snd_soc_card snd_soc_z2 = { | 203 | static struct snd_soc_card snd_soc_z2 = { |
208 | .name = "Z2", | 204 | .name = "Z2", |
209 | .dai_link = &z2_dai, | 205 | .dai_link = &z2_dai, |
210 | .num_links = 1, | 206 | .num_links = 1, |
211 | }; | 207 | }; |
212 | 208 | ||
213 | static struct platform_device *z2_snd_device; | 209 | static struct platform_device *z2_snd_device; |
214 | 210 | ||
215 | static int __init z2_init(void) | 211 | static int __init z2_init(void) |
216 | { | 212 | { |
217 | int ret; | 213 | int ret; |
218 | 214 | ||
219 | if (!machine_is_zipit2()) | 215 | if (!machine_is_zipit2()) |
220 | return -ENODEV; | 216 | return -ENODEV; |
221 | 217 | ||
222 | z2_snd_device = platform_device_alloc("soc-audio", -1); | 218 | z2_snd_device = platform_device_alloc("soc-audio", -1); |
223 | if (!z2_snd_device) | 219 | if (!z2_snd_device) |
224 | return -ENOMEM; | 220 | return -ENOMEM; |
225 | 221 | ||
226 | platform_set_drvdata(z2_snd_device, &snd_soc_z2); | 222 | platform_set_drvdata(z2_snd_device, &snd_soc_z2); |
227 | ret = platform_device_add(z2_snd_device); | 223 | ret = platform_device_add(z2_snd_device); |
228 | 224 | ||
229 | if (ret) | 225 | if (ret) |
230 | platform_device_put(z2_snd_device); | 226 | platform_device_put(z2_snd_device); |
231 | 227 | ||
232 | return ret; | 228 | return ret; |
233 | } | 229 | } |
234 | 230 | ||
235 | static void __exit z2_exit(void) | 231 | static void __exit z2_exit(void) |
236 | { | 232 | { |
237 | platform_device_unregister(z2_snd_device); | 233 | platform_device_unregister(z2_snd_device); |
238 | } | 234 | } |
239 | 235 | ||
240 | module_init(z2_init); | 236 | module_init(z2_init); |
241 | module_exit(z2_exit); | 237 | module_exit(z2_exit); |
242 | 238 | ||
243 | MODULE_AUTHOR("Ken McGuire <kenm@desertweyr.com>, " | 239 | MODULE_AUTHOR("Ken McGuire <kenm@desertweyr.com>, " |
244 | "Marek Vasut <marek.vasut@gmail.com>"); | 240 | "Marek Vasut <marek.vasut@gmail.com>"); |
245 | MODULE_DESCRIPTION("ALSA SoC ZipitZ2"); | 241 | MODULE_DESCRIPTION("ALSA SoC ZipitZ2"); |
246 | MODULE_LICENSE("GPL"); | 242 | MODULE_LICENSE("GPL"); |
247 | 243 |
sound/soc/pxa/zylonite.c
1 | /* | 1 | /* |
2 | * zylonite.c -- SoC audio for Zylonite | 2 | * zylonite.c -- SoC audio for Zylonite |
3 | * | 3 | * |
4 | * Copyright 2008 Wolfson Microelectronics PLC. | 4 | * Copyright 2008 Wolfson Microelectronics PLC. |
5 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | 5 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or | 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 | 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 | 9 | * published by the Free Software Foundation; either version 2 of the |
10 | * License, or (at your option) any later version. | 10 | * License, or (at your option) any later version. |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/moduleparam.h> | 15 | #include <linux/moduleparam.h> |
16 | #include <linux/device.h> | 16 | #include <linux/device.h> |
17 | #include <linux/clk.h> | 17 | #include <linux/clk.h> |
18 | #include <linux/i2c.h> | 18 | #include <linux/i2c.h> |
19 | #include <sound/core.h> | 19 | #include <sound/core.h> |
20 | #include <sound/pcm.h> | 20 | #include <sound/pcm.h> |
21 | #include <sound/pcm_params.h> | 21 | #include <sound/pcm_params.h> |
22 | #include <sound/soc.h> | 22 | #include <sound/soc.h> |
23 | 23 | ||
24 | #include "../codecs/wm9713.h" | 24 | #include "../codecs/wm9713.h" |
25 | #include "pxa2xx-ac97.h" | 25 | #include "pxa2xx-ac97.h" |
26 | #include "pxa-ssp.h" | 26 | #include "pxa-ssp.h" |
27 | 27 | ||
28 | /* | 28 | /* |
29 | * There is a physical switch SW15 on the board which changes the MCLK | 29 | * There is a physical switch SW15 on the board which changes the MCLK |
30 | * for the WM9713 between the standard AC97 master clock and the | 30 | * for the WM9713 between the standard AC97 master clock and the |
31 | * output of the CLK_POUT signal from the PXA. | 31 | * output of the CLK_POUT signal from the PXA. |
32 | */ | 32 | */ |
33 | static int clk_pout; | 33 | static int clk_pout; |
34 | module_param(clk_pout, int, 0); | 34 | module_param(clk_pout, int, 0); |
35 | MODULE_PARM_DESC(clk_pout, "Use CLK_POUT as WM9713 MCLK (SW15 on board)."); | 35 | MODULE_PARM_DESC(clk_pout, "Use CLK_POUT as WM9713 MCLK (SW15 on board)."); |
36 | 36 | ||
37 | static struct clk *pout; | 37 | static struct clk *pout; |
38 | 38 | ||
39 | static struct snd_soc_card zylonite; | 39 | static struct snd_soc_card zylonite; |
40 | 40 | ||
41 | static const struct snd_soc_dapm_widget zylonite_dapm_widgets[] = { | 41 | static const struct snd_soc_dapm_widget zylonite_dapm_widgets[] = { |
42 | SND_SOC_DAPM_HP("Headphone", NULL), | 42 | SND_SOC_DAPM_HP("Headphone", NULL), |
43 | SND_SOC_DAPM_MIC("Headset Microphone", NULL), | 43 | SND_SOC_DAPM_MIC("Headset Microphone", NULL), |
44 | SND_SOC_DAPM_MIC("Handset Microphone", NULL), | 44 | SND_SOC_DAPM_MIC("Handset Microphone", NULL), |
45 | SND_SOC_DAPM_SPK("Multiactor", NULL), | 45 | SND_SOC_DAPM_SPK("Multiactor", NULL), |
46 | SND_SOC_DAPM_SPK("Headset Earpiece", NULL), | 46 | SND_SOC_DAPM_SPK("Headset Earpiece", NULL), |
47 | }; | 47 | }; |
48 | 48 | ||
49 | /* Currently supported audio map */ | 49 | /* Currently supported audio map */ |
50 | static const struct snd_soc_dapm_route audio_map[] = { | 50 | static const struct snd_soc_dapm_route audio_map[] = { |
51 | 51 | ||
52 | /* Headphone output connected to HPL/HPR */ | 52 | /* Headphone output connected to HPL/HPR */ |
53 | { "Headphone", NULL, "HPL" }, | 53 | { "Headphone", NULL, "HPL" }, |
54 | { "Headphone", NULL, "HPR" }, | 54 | { "Headphone", NULL, "HPR" }, |
55 | 55 | ||
56 | /* On-board earpiece */ | 56 | /* On-board earpiece */ |
57 | { "Headset Earpiece", NULL, "OUT3" }, | 57 | { "Headset Earpiece", NULL, "OUT3" }, |
58 | 58 | ||
59 | /* Headphone mic */ | 59 | /* Headphone mic */ |
60 | { "MIC2A", NULL, "Mic Bias" }, | 60 | { "MIC2A", NULL, "Mic Bias" }, |
61 | { "Mic Bias", NULL, "Headset Microphone" }, | 61 | { "Mic Bias", NULL, "Headset Microphone" }, |
62 | 62 | ||
63 | /* On-board mic */ | 63 | /* On-board mic */ |
64 | { "MIC1", NULL, "Mic Bias" }, | 64 | { "MIC1", NULL, "Mic Bias" }, |
65 | { "Mic Bias", NULL, "Handset Microphone" }, | 65 | { "Mic Bias", NULL, "Handset Microphone" }, |
66 | 66 | ||
67 | /* Multiactor differentially connected over SPKL/SPKR */ | 67 | /* Multiactor differentially connected over SPKL/SPKR */ |
68 | { "Multiactor", NULL, "SPKL" }, | 68 | { "Multiactor", NULL, "SPKL" }, |
69 | { "Multiactor", NULL, "SPKR" }, | 69 | { "Multiactor", NULL, "SPKR" }, |
70 | }; | 70 | }; |
71 | 71 | ||
72 | static int zylonite_wm9713_init(struct snd_soc_pcm_runtime *rtd) | 72 | static int zylonite_wm9713_init(struct snd_soc_pcm_runtime *rtd) |
73 | { | 73 | { |
74 | struct snd_soc_codec *codec = rtd->codec; | 74 | struct snd_soc_codec *codec = rtd->codec; |
75 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 75 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
76 | 76 | ||
77 | if (clk_pout) | 77 | if (clk_pout) |
78 | snd_soc_dai_set_pll(rtd->codec_dai, 0, 0, | 78 | snd_soc_dai_set_pll(rtd->codec_dai, 0, 0, |
79 | clk_get_rate(pout), 0); | 79 | clk_get_rate(pout), 0); |
80 | 80 | ||
81 | snd_soc_dapm_new_controls(dapm, zylonite_dapm_widgets, | 81 | snd_soc_dapm_new_controls(dapm, zylonite_dapm_widgets, |
82 | ARRAY_SIZE(zylonite_dapm_widgets)); | 82 | ARRAY_SIZE(zylonite_dapm_widgets)); |
83 | 83 | ||
84 | snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); | 84 | snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); |
85 | 85 | ||
86 | /* Static setup for now */ | 86 | /* Static setup for now */ |
87 | snd_soc_dapm_enable_pin(dapm, "Headphone"); | 87 | snd_soc_dapm_enable_pin(dapm, "Headphone"); |
88 | snd_soc_dapm_enable_pin(dapm, "Headset Earpiece"); | 88 | snd_soc_dapm_enable_pin(dapm, "Headset Earpiece"); |
89 | 89 | ||
90 | snd_soc_dapm_sync(dapm); | ||
91 | return 0; | 90 | return 0; |
92 | } | 91 | } |
93 | 92 | ||
94 | static int zylonite_voice_hw_params(struct snd_pcm_substream *substream, | 93 | static int zylonite_voice_hw_params(struct snd_pcm_substream *substream, |
95 | struct snd_pcm_hw_params *params) | 94 | struct snd_pcm_hw_params *params) |
96 | { | 95 | { |
97 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 96 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
98 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 97 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
99 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 98 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
100 | unsigned int pll_out = 0; | 99 | unsigned int pll_out = 0; |
101 | unsigned int wm9713_div = 0; | 100 | unsigned int wm9713_div = 0; |
102 | int ret = 0; | 101 | int ret = 0; |
103 | int rate = params_rate(params); | 102 | int rate = params_rate(params); |
104 | int width = snd_pcm_format_physical_width(params_format(params)); | 103 | int width = snd_pcm_format_physical_width(params_format(params)); |
105 | 104 | ||
106 | /* Only support ratios that we can generate neatly from the AC97 | 105 | /* Only support ratios that we can generate neatly from the AC97 |
107 | * based master clock - in particular, this excludes 44.1kHz. | 106 | * based master clock - in particular, this excludes 44.1kHz. |
108 | * In most applications the voice DAC will be used for telephony | 107 | * In most applications the voice DAC will be used for telephony |
109 | * data so multiples of 8kHz will be the common case. | 108 | * data so multiples of 8kHz will be the common case. |
110 | */ | 109 | */ |
111 | switch (rate) { | 110 | switch (rate) { |
112 | case 8000: | 111 | case 8000: |
113 | wm9713_div = 12; | 112 | wm9713_div = 12; |
114 | break; | 113 | break; |
115 | case 16000: | 114 | case 16000: |
116 | wm9713_div = 6; | 115 | wm9713_div = 6; |
117 | break; | 116 | break; |
118 | case 48000: | 117 | case 48000: |
119 | wm9713_div = 2; | 118 | wm9713_div = 2; |
120 | break; | 119 | break; |
121 | default: | 120 | default: |
122 | /* Don't support OSS emulation */ | 121 | /* Don't support OSS emulation */ |
123 | return -EINVAL; | 122 | return -EINVAL; |
124 | } | 123 | } |
125 | 124 | ||
126 | /* Add 1 to the width for the leading clock cycle */ | 125 | /* Add 1 to the width for the leading clock cycle */ |
127 | pll_out = rate * (width + 1) * 8; | 126 | pll_out = rate * (width + 1) * 8; |
128 | 127 | ||
129 | ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_AUDIO, 0, 1); | 128 | ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_AUDIO, 0, 1); |
130 | if (ret < 0) | 129 | if (ret < 0) |
131 | return ret; | 130 | return ret; |
132 | 131 | ||
133 | ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, pll_out); | 132 | ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, pll_out); |
134 | if (ret < 0) | 133 | if (ret < 0) |
135 | return ret; | 134 | return ret; |
136 | 135 | ||
137 | if (clk_pout) | 136 | if (clk_pout) |
138 | ret = snd_soc_dai_set_clkdiv(codec_dai, WM9713_PCMCLK_PLL_DIV, | 137 | ret = snd_soc_dai_set_clkdiv(codec_dai, WM9713_PCMCLK_PLL_DIV, |
139 | WM9713_PCMDIV(wm9713_div)); | 138 | WM9713_PCMDIV(wm9713_div)); |
140 | else | 139 | else |
141 | ret = snd_soc_dai_set_clkdiv(codec_dai, WM9713_PCMCLK_DIV, | 140 | ret = snd_soc_dai_set_clkdiv(codec_dai, WM9713_PCMCLK_DIV, |
142 | WM9713_PCMDIV(wm9713_div)); | 141 | WM9713_PCMDIV(wm9713_div)); |
143 | if (ret < 0) | 142 | if (ret < 0) |
144 | return ret; | 143 | return ret; |
145 | 144 | ||
146 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | | 145 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | |
147 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); | 146 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); |
148 | if (ret < 0) | 147 | if (ret < 0) |
149 | return ret; | 148 | return ret; |
150 | 149 | ||
151 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | | 150 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | |
152 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); | 151 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); |
153 | if (ret < 0) | 152 | if (ret < 0) |
154 | return ret; | 153 | return ret; |
155 | 154 | ||
156 | return 0; | 155 | return 0; |
157 | } | 156 | } |
158 | 157 | ||
159 | static struct snd_soc_ops zylonite_voice_ops = { | 158 | static struct snd_soc_ops zylonite_voice_ops = { |
160 | .hw_params = zylonite_voice_hw_params, | 159 | .hw_params = zylonite_voice_hw_params, |
161 | }; | 160 | }; |
162 | 161 | ||
163 | static struct snd_soc_dai_link zylonite_dai[] = { | 162 | static struct snd_soc_dai_link zylonite_dai[] = { |
164 | { | 163 | { |
165 | .name = "AC97", | 164 | .name = "AC97", |
166 | .stream_name = "AC97 HiFi", | 165 | .stream_name = "AC97 HiFi", |
167 | .codec_name = "wm9713-codec", | 166 | .codec_name = "wm9713-codec", |
168 | .platform_name = "pxa-pcm-audio", | 167 | .platform_name = "pxa-pcm-audio", |
169 | .cpu_dai_name = "pxa2xx-ac97", | 168 | .cpu_dai_name = "pxa2xx-ac97", |
170 | .codec_dai_name = "wm9713-hifi", | 169 | .codec_dai_name = "wm9713-hifi", |
171 | .init = zylonite_wm9713_init, | 170 | .init = zylonite_wm9713_init, |
172 | }, | 171 | }, |
173 | { | 172 | { |
174 | .name = "AC97 Aux", | 173 | .name = "AC97 Aux", |
175 | .stream_name = "AC97 Aux", | 174 | .stream_name = "AC97 Aux", |
176 | .codec_name = "wm9713-codec", | 175 | .codec_name = "wm9713-codec", |
177 | .platform_name = "pxa-pcm-audio", | 176 | .platform_name = "pxa-pcm-audio", |
178 | .cpu_dai_name = "pxa2xx-ac97-aux", | 177 | .cpu_dai_name = "pxa2xx-ac97-aux", |
179 | .codec_dai_name = "wm9713-aux", | 178 | .codec_dai_name = "wm9713-aux", |
180 | }, | 179 | }, |
181 | { | 180 | { |
182 | .name = "WM9713 Voice", | 181 | .name = "WM9713 Voice", |
183 | .stream_name = "WM9713 Voice", | 182 | .stream_name = "WM9713 Voice", |
184 | .codec_name = "wm9713-codec", | 183 | .codec_name = "wm9713-codec", |
185 | .platform_name = "pxa-pcm-audio", | 184 | .platform_name = "pxa-pcm-audio", |
186 | .cpu_dai_name = "pxa-ssp-dai.2", | 185 | .cpu_dai_name = "pxa-ssp-dai.2", |
187 | .codec_dai_name = "wm9713-voice", | 186 | .codec_dai_name = "wm9713-voice", |
188 | .ops = &zylonite_voice_ops, | 187 | .ops = &zylonite_voice_ops, |
189 | }, | 188 | }, |
190 | }; | 189 | }; |
191 | 190 | ||
192 | static int zylonite_probe(struct snd_soc_card *card) | 191 | static int zylonite_probe(struct snd_soc_card *card) |
193 | { | 192 | { |
194 | int ret; | 193 | int ret; |
195 | 194 | ||
196 | if (clk_pout) { | 195 | if (clk_pout) { |
197 | pout = clk_get(NULL, "CLK_POUT"); | 196 | pout = clk_get(NULL, "CLK_POUT"); |
198 | if (IS_ERR(pout)) { | 197 | if (IS_ERR(pout)) { |
199 | dev_err(card->dev, "Unable to obtain CLK_POUT: %ld\n", | 198 | dev_err(card->dev, "Unable to obtain CLK_POUT: %ld\n", |
200 | PTR_ERR(pout)); | 199 | PTR_ERR(pout)); |
201 | return PTR_ERR(pout); | 200 | return PTR_ERR(pout); |
202 | } | 201 | } |
203 | 202 | ||
204 | ret = clk_enable(pout); | 203 | ret = clk_enable(pout); |
205 | if (ret != 0) { | 204 | if (ret != 0) { |
206 | dev_err(card->dev, "Unable to enable CLK_POUT: %d\n", | 205 | dev_err(card->dev, "Unable to enable CLK_POUT: %d\n", |
207 | ret); | 206 | ret); |
208 | clk_put(pout); | 207 | clk_put(pout); |
209 | return ret; | 208 | return ret; |
210 | } | 209 | } |
211 | 210 | ||
212 | dev_dbg(card->dev, "MCLK enabled at %luHz\n", | 211 | dev_dbg(card->dev, "MCLK enabled at %luHz\n", |
213 | clk_get_rate(pout)); | 212 | clk_get_rate(pout)); |
214 | } | 213 | } |
215 | 214 | ||
216 | return 0; | 215 | return 0; |
217 | } | 216 | } |
218 | 217 | ||
219 | static int zylonite_remove(struct snd_soc_card *card) | 218 | static int zylonite_remove(struct snd_soc_card *card) |
220 | { | 219 | { |
221 | if (clk_pout) { | 220 | if (clk_pout) { |
222 | clk_disable(pout); | 221 | clk_disable(pout); |
223 | clk_put(pout); | 222 | clk_put(pout); |
224 | } | 223 | } |
225 | 224 | ||
226 | return 0; | 225 | return 0; |
227 | } | 226 | } |
228 | 227 | ||
229 | static int zylonite_suspend_post(struct snd_soc_card *card) | 228 | static int zylonite_suspend_post(struct snd_soc_card *card) |
230 | { | 229 | { |
231 | if (clk_pout) | 230 | if (clk_pout) |
232 | clk_disable(pout); | 231 | clk_disable(pout); |
233 | 232 | ||
234 | return 0; | 233 | return 0; |
235 | } | 234 | } |
236 | 235 | ||
237 | static int zylonite_resume_pre(struct snd_soc_card *card) | 236 | static int zylonite_resume_pre(struct snd_soc_card *card) |
238 | { | 237 | { |
239 | int ret = 0; | 238 | int ret = 0; |
240 | 239 | ||
241 | if (clk_pout) { | 240 | if (clk_pout) { |
242 | ret = clk_enable(pout); | 241 | ret = clk_enable(pout); |
243 | if (ret != 0) | 242 | if (ret != 0) |
244 | dev_err(card->dev, "Unable to enable CLK_POUT: %d\n", | 243 | dev_err(card->dev, "Unable to enable CLK_POUT: %d\n", |
245 | ret); | 244 | ret); |
246 | } | 245 | } |
247 | 246 | ||
248 | return ret; | 247 | return ret; |
249 | } | 248 | } |
250 | 249 | ||
251 | static struct snd_soc_card zylonite = { | 250 | static struct snd_soc_card zylonite = { |
252 | .name = "Zylonite", | 251 | .name = "Zylonite", |
253 | .probe = &zylonite_probe, | 252 | .probe = &zylonite_probe, |
254 | .remove = &zylonite_remove, | 253 | .remove = &zylonite_remove, |
255 | .suspend_post = &zylonite_suspend_post, | 254 | .suspend_post = &zylonite_suspend_post, |
256 | .resume_pre = &zylonite_resume_pre, | 255 | .resume_pre = &zylonite_resume_pre, |
257 | .dai_link = zylonite_dai, | 256 | .dai_link = zylonite_dai, |
258 | .num_links = ARRAY_SIZE(zylonite_dai), | 257 | .num_links = ARRAY_SIZE(zylonite_dai), |
259 | .owner = THIS_MODULE, | 258 | .owner = THIS_MODULE, |
260 | }; | 259 | }; |
261 | 260 | ||
262 | static struct platform_device *zylonite_snd_ac97_device; | 261 | static struct platform_device *zylonite_snd_ac97_device; |
263 | 262 | ||
264 | static int __init zylonite_init(void) | 263 | static int __init zylonite_init(void) |
265 | { | 264 | { |
266 | int ret; | 265 | int ret; |
267 | 266 | ||
268 | zylonite_snd_ac97_device = platform_device_alloc("soc-audio", -1); | 267 | zylonite_snd_ac97_device = platform_device_alloc("soc-audio", -1); |
269 | if (!zylonite_snd_ac97_device) | 268 | if (!zylonite_snd_ac97_device) |
270 | return -ENOMEM; | 269 | return -ENOMEM; |
271 | 270 | ||
272 | platform_set_drvdata(zylonite_snd_ac97_device, &zylonite); | 271 | platform_set_drvdata(zylonite_snd_ac97_device, &zylonite); |
273 | 272 | ||
274 | ret = platform_device_add(zylonite_snd_ac97_device); | 273 | ret = platform_device_add(zylonite_snd_ac97_device); |
275 | if (ret != 0) | 274 | if (ret != 0) |
276 | platform_device_put(zylonite_snd_ac97_device); | 275 | platform_device_put(zylonite_snd_ac97_device); |
277 | 276 | ||
278 | return ret; | 277 | return ret; |
279 | } | 278 | } |
280 | 279 | ||
281 | static void __exit zylonite_exit(void) | 280 | static void __exit zylonite_exit(void) |
282 | { | 281 | { |
283 | platform_device_unregister(zylonite_snd_ac97_device); | 282 | platform_device_unregister(zylonite_snd_ac97_device); |
284 | } | 283 | } |
285 | 284 | ||
286 | module_init(zylonite_init); | 285 | module_init(zylonite_init); |
287 | module_exit(zylonite_exit); | 286 | module_exit(zylonite_exit); |
288 | 287 | ||
289 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); | 288 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); |
290 | MODULE_DESCRIPTION("ALSA SoC WM9713 Zylonite"); | 289 | MODULE_DESCRIPTION("ALSA SoC WM9713 Zylonite"); |
291 | MODULE_LICENSE("GPL"); | 290 | MODULE_LICENSE("GPL"); |
292 | 291 |
sound/soc/samsung/goni_wm8994.c
1 | /* | 1 | /* |
2 | * goni_wm8994.c | 2 | * goni_wm8994.c |
3 | * | 3 | * |
4 | * Copyright (C) 2010 Samsung Electronics Co.Ltd | 4 | * Copyright (C) 2010 Samsung Electronics Co.Ltd |
5 | * Author: Chanwoo Choi <cw00.choi@samsung.com> | 5 | * Author: Chanwoo Choi <cw00.choi@samsung.com> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify it | 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 | 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 | 9 | * Free Software Foundation; either version 2 of the License, or (at your |
10 | * option) any later version. | 10 | * option) any later version. |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <sound/soc.h> | 14 | #include <sound/soc.h> |
15 | #include <sound/jack.h> | 15 | #include <sound/jack.h> |
16 | 16 | ||
17 | #include <asm/mach-types.h> | 17 | #include <asm/mach-types.h> |
18 | #include <mach/gpio.h> | 18 | #include <mach/gpio.h> |
19 | 19 | ||
20 | #include "../codecs/wm8994.h" | 20 | #include "../codecs/wm8994.h" |
21 | 21 | ||
22 | #define MACHINE_NAME 0 | 22 | #define MACHINE_NAME 0 |
23 | #define CPU_VOICE_DAI 1 | 23 | #define CPU_VOICE_DAI 1 |
24 | 24 | ||
25 | static const char *aquila_str[] = { | 25 | static const char *aquila_str[] = { |
26 | [MACHINE_NAME] = "aquila", | 26 | [MACHINE_NAME] = "aquila", |
27 | [CPU_VOICE_DAI] = "aquila-voice-dai", | 27 | [CPU_VOICE_DAI] = "aquila-voice-dai", |
28 | }; | 28 | }; |
29 | 29 | ||
30 | static struct snd_soc_card goni; | 30 | static struct snd_soc_card goni; |
31 | static struct platform_device *goni_snd_device; | 31 | static struct platform_device *goni_snd_device; |
32 | 32 | ||
33 | /* 3.5 pie jack */ | 33 | /* 3.5 pie jack */ |
34 | static struct snd_soc_jack jack; | 34 | static struct snd_soc_jack jack; |
35 | 35 | ||
36 | /* 3.5 pie jack detection DAPM pins */ | 36 | /* 3.5 pie jack detection DAPM pins */ |
37 | static struct snd_soc_jack_pin jack_pins[] = { | 37 | static struct snd_soc_jack_pin jack_pins[] = { |
38 | { | 38 | { |
39 | .pin = "Headset Mic", | 39 | .pin = "Headset Mic", |
40 | .mask = SND_JACK_MICROPHONE, | 40 | .mask = SND_JACK_MICROPHONE, |
41 | }, { | 41 | }, { |
42 | .pin = "Headset Stereophone", | 42 | .pin = "Headset Stereophone", |
43 | .mask = SND_JACK_HEADPHONE | SND_JACK_MECHANICAL | | 43 | .mask = SND_JACK_HEADPHONE | SND_JACK_MECHANICAL | |
44 | SND_JACK_AVOUT, | 44 | SND_JACK_AVOUT, |
45 | }, | 45 | }, |
46 | }; | 46 | }; |
47 | 47 | ||
48 | /* 3.5 pie jack detection gpios */ | 48 | /* 3.5 pie jack detection gpios */ |
49 | static struct snd_soc_jack_gpio jack_gpios[] = { | 49 | static struct snd_soc_jack_gpio jack_gpios[] = { |
50 | { | 50 | { |
51 | .gpio = S5PV210_GPH0(6), | 51 | .gpio = S5PV210_GPH0(6), |
52 | .name = "DET_3.5", | 52 | .name = "DET_3.5", |
53 | .report = SND_JACK_HEADSET | SND_JACK_MECHANICAL | | 53 | .report = SND_JACK_HEADSET | SND_JACK_MECHANICAL | |
54 | SND_JACK_AVOUT, | 54 | SND_JACK_AVOUT, |
55 | .debounce_time = 200, | 55 | .debounce_time = 200, |
56 | }, | 56 | }, |
57 | }; | 57 | }; |
58 | 58 | ||
59 | static const struct snd_soc_dapm_widget goni_dapm_widgets[] = { | 59 | static const struct snd_soc_dapm_widget goni_dapm_widgets[] = { |
60 | SND_SOC_DAPM_SPK("Ext Left Spk", NULL), | 60 | SND_SOC_DAPM_SPK("Ext Left Spk", NULL), |
61 | SND_SOC_DAPM_SPK("Ext Right Spk", NULL), | 61 | SND_SOC_DAPM_SPK("Ext Right Spk", NULL), |
62 | SND_SOC_DAPM_SPK("Ext Rcv", NULL), | 62 | SND_SOC_DAPM_SPK("Ext Rcv", NULL), |
63 | SND_SOC_DAPM_HP("Headset Stereophone", NULL), | 63 | SND_SOC_DAPM_HP("Headset Stereophone", NULL), |
64 | SND_SOC_DAPM_MIC("Headset Mic", NULL), | 64 | SND_SOC_DAPM_MIC("Headset Mic", NULL), |
65 | SND_SOC_DAPM_MIC("Main Mic", NULL), | 65 | SND_SOC_DAPM_MIC("Main Mic", NULL), |
66 | SND_SOC_DAPM_MIC("2nd Mic", NULL), | 66 | SND_SOC_DAPM_MIC("2nd Mic", NULL), |
67 | SND_SOC_DAPM_LINE("Radio In", NULL), | 67 | SND_SOC_DAPM_LINE("Radio In", NULL), |
68 | }; | 68 | }; |
69 | 69 | ||
70 | static const struct snd_soc_dapm_route goni_dapm_routes[] = { | 70 | static const struct snd_soc_dapm_route goni_dapm_routes[] = { |
71 | {"Ext Left Spk", NULL, "SPKOUTLP"}, | 71 | {"Ext Left Spk", NULL, "SPKOUTLP"}, |
72 | {"Ext Left Spk", NULL, "SPKOUTLN"}, | 72 | {"Ext Left Spk", NULL, "SPKOUTLN"}, |
73 | 73 | ||
74 | {"Ext Right Spk", NULL, "SPKOUTRP"}, | 74 | {"Ext Right Spk", NULL, "SPKOUTRP"}, |
75 | {"Ext Right Spk", NULL, "SPKOUTRN"}, | 75 | {"Ext Right Spk", NULL, "SPKOUTRN"}, |
76 | 76 | ||
77 | {"Ext Rcv", NULL, "HPOUT2N"}, | 77 | {"Ext Rcv", NULL, "HPOUT2N"}, |
78 | {"Ext Rcv", NULL, "HPOUT2P"}, | 78 | {"Ext Rcv", NULL, "HPOUT2P"}, |
79 | 79 | ||
80 | {"Headset Stereophone", NULL, "HPOUT1L"}, | 80 | {"Headset Stereophone", NULL, "HPOUT1L"}, |
81 | {"Headset Stereophone", NULL, "HPOUT1R"}, | 81 | {"Headset Stereophone", NULL, "HPOUT1R"}, |
82 | 82 | ||
83 | {"IN1RN", NULL, "Headset Mic"}, | 83 | {"IN1RN", NULL, "Headset Mic"}, |
84 | {"IN1RP", NULL, "Headset Mic"}, | 84 | {"IN1RP", NULL, "Headset Mic"}, |
85 | 85 | ||
86 | {"IN1RN", NULL, "2nd Mic"}, | 86 | {"IN1RN", NULL, "2nd Mic"}, |
87 | {"IN1RP", NULL, "2nd Mic"}, | 87 | {"IN1RP", NULL, "2nd Mic"}, |
88 | 88 | ||
89 | {"IN1LN", NULL, "Main Mic"}, | 89 | {"IN1LN", NULL, "Main Mic"}, |
90 | {"IN1LP", NULL, "Main Mic"}, | 90 | {"IN1LP", NULL, "Main Mic"}, |
91 | 91 | ||
92 | {"IN2LN", NULL, "Radio In"}, | 92 | {"IN2LN", NULL, "Radio In"}, |
93 | {"IN2RN", NULL, "Radio In"}, | 93 | {"IN2RN", NULL, "Radio In"}, |
94 | }; | 94 | }; |
95 | 95 | ||
96 | static int goni_wm8994_init(struct snd_soc_pcm_runtime *rtd) | 96 | static int goni_wm8994_init(struct snd_soc_pcm_runtime *rtd) |
97 | { | 97 | { |
98 | struct snd_soc_codec *codec = rtd->codec; | 98 | struct snd_soc_codec *codec = rtd->codec; |
99 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 99 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
100 | int ret; | 100 | int ret; |
101 | 101 | ||
102 | /* add goni specific widgets */ | 102 | /* add goni specific widgets */ |
103 | snd_soc_dapm_new_controls(dapm, goni_dapm_widgets, | 103 | snd_soc_dapm_new_controls(dapm, goni_dapm_widgets, |
104 | ARRAY_SIZE(goni_dapm_widgets)); | 104 | ARRAY_SIZE(goni_dapm_widgets)); |
105 | 105 | ||
106 | /* set up goni specific audio routes */ | 106 | /* set up goni specific audio routes */ |
107 | snd_soc_dapm_add_routes(dapm, goni_dapm_routes, | 107 | snd_soc_dapm_add_routes(dapm, goni_dapm_routes, |
108 | ARRAY_SIZE(goni_dapm_routes)); | 108 | ARRAY_SIZE(goni_dapm_routes)); |
109 | 109 | ||
110 | /* set endpoints to not connected */ | 110 | /* set endpoints to not connected */ |
111 | snd_soc_dapm_nc_pin(dapm, "IN2LP:VXRN"); | 111 | snd_soc_dapm_nc_pin(dapm, "IN2LP:VXRN"); |
112 | snd_soc_dapm_nc_pin(dapm, "IN2RP:VXRP"); | 112 | snd_soc_dapm_nc_pin(dapm, "IN2RP:VXRP"); |
113 | snd_soc_dapm_nc_pin(dapm, "LINEOUT1N"); | 113 | snd_soc_dapm_nc_pin(dapm, "LINEOUT1N"); |
114 | snd_soc_dapm_nc_pin(dapm, "LINEOUT1P"); | 114 | snd_soc_dapm_nc_pin(dapm, "LINEOUT1P"); |
115 | snd_soc_dapm_nc_pin(dapm, "LINEOUT2N"); | 115 | snd_soc_dapm_nc_pin(dapm, "LINEOUT2N"); |
116 | snd_soc_dapm_nc_pin(dapm, "LINEOUT2P"); | 116 | snd_soc_dapm_nc_pin(dapm, "LINEOUT2P"); |
117 | 117 | ||
118 | if (machine_is_aquila()) { | 118 | if (machine_is_aquila()) { |
119 | snd_soc_dapm_nc_pin(dapm, "SPKOUTRN"); | 119 | snd_soc_dapm_nc_pin(dapm, "SPKOUTRN"); |
120 | snd_soc_dapm_nc_pin(dapm, "SPKOUTRP"); | 120 | snd_soc_dapm_nc_pin(dapm, "SPKOUTRP"); |
121 | } | 121 | } |
122 | 122 | ||
123 | snd_soc_dapm_sync(dapm); | ||
124 | |||
125 | /* Headset jack detection */ | 123 | /* Headset jack detection */ |
126 | ret = snd_soc_jack_new(codec, "Headset Jack", | 124 | ret = snd_soc_jack_new(codec, "Headset Jack", |
127 | SND_JACK_HEADSET | SND_JACK_MECHANICAL | SND_JACK_AVOUT, | 125 | SND_JACK_HEADSET | SND_JACK_MECHANICAL | SND_JACK_AVOUT, |
128 | &jack); | 126 | &jack); |
129 | if (ret) | 127 | if (ret) |
130 | return ret; | 128 | return ret; |
131 | 129 | ||
132 | ret = snd_soc_jack_add_pins(&jack, ARRAY_SIZE(jack_pins), jack_pins); | 130 | ret = snd_soc_jack_add_pins(&jack, ARRAY_SIZE(jack_pins), jack_pins); |
133 | if (ret) | 131 | if (ret) |
134 | return ret; | 132 | return ret; |
135 | 133 | ||
136 | ret = snd_soc_jack_add_gpios(&jack, ARRAY_SIZE(jack_gpios), jack_gpios); | 134 | ret = snd_soc_jack_add_gpios(&jack, ARRAY_SIZE(jack_gpios), jack_gpios); |
137 | if (ret) | 135 | if (ret) |
138 | return ret; | 136 | return ret; |
139 | 137 | ||
140 | return 0; | 138 | return 0; |
141 | } | 139 | } |
142 | 140 | ||
143 | static int goni_hifi_hw_params(struct snd_pcm_substream *substream, | 141 | static int goni_hifi_hw_params(struct snd_pcm_substream *substream, |
144 | struct snd_pcm_hw_params *params) | 142 | struct snd_pcm_hw_params *params) |
145 | { | 143 | { |
146 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 144 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
147 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 145 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
148 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 146 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
149 | unsigned int pll_out = 24000000; | 147 | unsigned int pll_out = 24000000; |
150 | int ret = 0; | 148 | int ret = 0; |
151 | 149 | ||
152 | /* set the cpu DAI configuration */ | 150 | /* set the cpu DAI configuration */ |
153 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | | 151 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | |
154 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); | 152 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); |
155 | if (ret < 0) | 153 | if (ret < 0) |
156 | return ret; | 154 | return ret; |
157 | 155 | ||
158 | /* set codec DAI configuration */ | 156 | /* set codec DAI configuration */ |
159 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | | 157 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | |
160 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); | 158 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); |
161 | if (ret < 0) | 159 | if (ret < 0) |
162 | return ret; | 160 | return ret; |
163 | 161 | ||
164 | /* set the codec FLL */ | 162 | /* set the codec FLL */ |
165 | ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1, 0, pll_out, | 163 | ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1, 0, pll_out, |
166 | params_rate(params) * 256); | 164 | params_rate(params) * 256); |
167 | if (ret < 0) | 165 | if (ret < 0) |
168 | return ret; | 166 | return ret; |
169 | 167 | ||
170 | /* set the codec system clock */ | 168 | /* set the codec system clock */ |
171 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL1, | 169 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL1, |
172 | params_rate(params) * 256, SND_SOC_CLOCK_IN); | 170 | params_rate(params) * 256, SND_SOC_CLOCK_IN); |
173 | if (ret < 0) | 171 | if (ret < 0) |
174 | return ret; | 172 | return ret; |
175 | 173 | ||
176 | return 0; | 174 | return 0; |
177 | } | 175 | } |
178 | 176 | ||
179 | static struct snd_soc_ops goni_hifi_ops = { | 177 | static struct snd_soc_ops goni_hifi_ops = { |
180 | .hw_params = goni_hifi_hw_params, | 178 | .hw_params = goni_hifi_hw_params, |
181 | }; | 179 | }; |
182 | 180 | ||
183 | static int goni_voice_hw_params(struct snd_pcm_substream *substream, | 181 | static int goni_voice_hw_params(struct snd_pcm_substream *substream, |
184 | struct snd_pcm_hw_params *params) | 182 | struct snd_pcm_hw_params *params) |
185 | { | 183 | { |
186 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 184 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
187 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 185 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
188 | unsigned int pll_out = 24000000; | 186 | unsigned int pll_out = 24000000; |
189 | int ret = 0; | 187 | int ret = 0; |
190 | 188 | ||
191 | if (params_rate(params) != 8000) | 189 | if (params_rate(params) != 8000) |
192 | return -EINVAL; | 190 | return -EINVAL; |
193 | 191 | ||
194 | /* set codec DAI configuration */ | 192 | /* set codec DAI configuration */ |
195 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_LEFT_J | | 193 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_LEFT_J | |
196 | SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM); | 194 | SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM); |
197 | if (ret < 0) | 195 | if (ret < 0) |
198 | return ret; | 196 | return ret; |
199 | 197 | ||
200 | /* set the codec FLL */ | 198 | /* set the codec FLL */ |
201 | ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL2, 0, pll_out, | 199 | ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL2, 0, pll_out, |
202 | params_rate(params) * 256); | 200 | params_rate(params) * 256); |
203 | if (ret < 0) | 201 | if (ret < 0) |
204 | return ret; | 202 | return ret; |
205 | 203 | ||
206 | /* set the codec system clock */ | 204 | /* set the codec system clock */ |
207 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL2, | 205 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL2, |
208 | params_rate(params) * 256, SND_SOC_CLOCK_IN); | 206 | params_rate(params) * 256, SND_SOC_CLOCK_IN); |
209 | if (ret < 0) | 207 | if (ret < 0) |
210 | return ret; | 208 | return ret; |
211 | 209 | ||
212 | return 0; | 210 | return 0; |
213 | } | 211 | } |
214 | 212 | ||
215 | static struct snd_soc_dai_driver voice_dai = { | 213 | static struct snd_soc_dai_driver voice_dai = { |
216 | .name = "goni-voice-dai", | 214 | .name = "goni-voice-dai", |
217 | .id = 0, | 215 | .id = 0, |
218 | .playback = { | 216 | .playback = { |
219 | .channels_min = 1, | 217 | .channels_min = 1, |
220 | .channels_max = 2, | 218 | .channels_max = 2, |
221 | .rates = SNDRV_PCM_RATE_8000, | 219 | .rates = SNDRV_PCM_RATE_8000, |
222 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | 220 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, |
223 | .capture = { | 221 | .capture = { |
224 | .channels_min = 1, | 222 | .channels_min = 1, |
225 | .channels_max = 2, | 223 | .channels_max = 2, |
226 | .rates = SNDRV_PCM_RATE_8000, | 224 | .rates = SNDRV_PCM_RATE_8000, |
227 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | 225 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, |
228 | }; | 226 | }; |
229 | 227 | ||
230 | static struct snd_soc_ops goni_voice_ops = { | 228 | static struct snd_soc_ops goni_voice_ops = { |
231 | .hw_params = goni_voice_hw_params, | 229 | .hw_params = goni_voice_hw_params, |
232 | }; | 230 | }; |
233 | 231 | ||
234 | static struct snd_soc_dai_link goni_dai[] = { | 232 | static struct snd_soc_dai_link goni_dai[] = { |
235 | { | 233 | { |
236 | .name = "WM8994", | 234 | .name = "WM8994", |
237 | .stream_name = "WM8994 HiFi", | 235 | .stream_name = "WM8994 HiFi", |
238 | .cpu_dai_name = "samsung-i2s.0", | 236 | .cpu_dai_name = "samsung-i2s.0", |
239 | .codec_dai_name = "wm8994-aif1", | 237 | .codec_dai_name = "wm8994-aif1", |
240 | .platform_name = "samsung-audio", | 238 | .platform_name = "samsung-audio", |
241 | .codec_name = "wm8994-codec.0-001a", | 239 | .codec_name = "wm8994-codec.0-001a", |
242 | .init = goni_wm8994_init, | 240 | .init = goni_wm8994_init, |
243 | .ops = &goni_hifi_ops, | 241 | .ops = &goni_hifi_ops, |
244 | }, { | 242 | }, { |
245 | .name = "WM8994 Voice", | 243 | .name = "WM8994 Voice", |
246 | .stream_name = "Voice", | 244 | .stream_name = "Voice", |
247 | .cpu_dai_name = "goni-voice-dai", | 245 | .cpu_dai_name = "goni-voice-dai", |
248 | .codec_dai_name = "wm8994-aif2", | 246 | .codec_dai_name = "wm8994-aif2", |
249 | .codec_name = "wm8994-codec.0-001a", | 247 | .codec_name = "wm8994-codec.0-001a", |
250 | .ops = &goni_voice_ops, | 248 | .ops = &goni_voice_ops, |
251 | }, | 249 | }, |
252 | }; | 250 | }; |
253 | 251 | ||
254 | static struct snd_soc_card goni = { | 252 | static struct snd_soc_card goni = { |
255 | .name = "goni", | 253 | .name = "goni", |
256 | .dai_link = goni_dai, | 254 | .dai_link = goni_dai, |
257 | .num_links = ARRAY_SIZE(goni_dai), | 255 | .num_links = ARRAY_SIZE(goni_dai), |
258 | }; | 256 | }; |
259 | 257 | ||
260 | static int __init goni_init(void) | 258 | static int __init goni_init(void) |
261 | { | 259 | { |
262 | int ret; | 260 | int ret; |
263 | 261 | ||
264 | if (machine_is_aquila()) { | 262 | if (machine_is_aquila()) { |
265 | voice_dai.name = aquila_str[CPU_VOICE_DAI]; | 263 | voice_dai.name = aquila_str[CPU_VOICE_DAI]; |
266 | goni_dai[1].cpu_dai_name = aquila_str[CPU_VOICE_DAI]; | 264 | goni_dai[1].cpu_dai_name = aquila_str[CPU_VOICE_DAI]; |
267 | goni.name = aquila_str[MACHINE_NAME]; | 265 | goni.name = aquila_str[MACHINE_NAME]; |
268 | } else if (!machine_is_goni()) | 266 | } else if (!machine_is_goni()) |
269 | return -ENODEV; | 267 | return -ENODEV; |
270 | 268 | ||
271 | goni_snd_device = platform_device_alloc("soc-audio", -1); | 269 | goni_snd_device = platform_device_alloc("soc-audio", -1); |
272 | if (!goni_snd_device) | 270 | if (!goni_snd_device) |
273 | return -ENOMEM; | 271 | return -ENOMEM; |
274 | 272 | ||
275 | /* register voice DAI here */ | 273 | /* register voice DAI here */ |
276 | ret = snd_soc_register_dai(&goni_snd_device->dev, &voice_dai); | 274 | ret = snd_soc_register_dai(&goni_snd_device->dev, &voice_dai); |
277 | if (ret) { | 275 | if (ret) { |
278 | platform_device_put(goni_snd_device); | 276 | platform_device_put(goni_snd_device); |
279 | return ret; | 277 | return ret; |
280 | } | 278 | } |
281 | 279 | ||
282 | platform_set_drvdata(goni_snd_device, &goni); | 280 | platform_set_drvdata(goni_snd_device, &goni); |
283 | ret = platform_device_add(goni_snd_device); | 281 | ret = platform_device_add(goni_snd_device); |
284 | 282 | ||
285 | if (ret) { | 283 | if (ret) { |
286 | snd_soc_unregister_dai(&goni_snd_device->dev); | 284 | snd_soc_unregister_dai(&goni_snd_device->dev); |
287 | platform_device_put(goni_snd_device); | 285 | platform_device_put(goni_snd_device); |
288 | } | 286 | } |
289 | 287 | ||
290 | return ret; | 288 | return ret; |
291 | } | 289 | } |
292 | 290 | ||
293 | static void __exit goni_exit(void) | 291 | static void __exit goni_exit(void) |
294 | { | 292 | { |
295 | snd_soc_unregister_dai(&goni_snd_device->dev); | 293 | snd_soc_unregister_dai(&goni_snd_device->dev); |
296 | platform_device_unregister(goni_snd_device); | 294 | platform_device_unregister(goni_snd_device); |
297 | } | 295 | } |
298 | 296 | ||
299 | module_init(goni_init); | 297 | module_init(goni_init); |
300 | module_exit(goni_exit); | 298 | module_exit(goni_exit); |
301 | 299 | ||
302 | /* Module information */ | 300 | /* Module information */ |
303 | MODULE_DESCRIPTION("ALSA SoC WM8994 GONI(S5PV210)"); | 301 | MODULE_DESCRIPTION("ALSA SoC WM8994 GONI(S5PV210)"); |
304 | MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>"); | 302 | MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>"); |
305 | MODULE_LICENSE("GPL"); | 303 | MODULE_LICENSE("GPL"); |
306 | 304 |
sound/soc/samsung/h1940_uda1380.c
1 | /* | 1 | /* |
2 | * h1940-uda1380.c -- ALSA Soc Audio Layer | 2 | * h1940-uda1380.c -- ALSA Soc Audio Layer |
3 | * | 3 | * |
4 | * Copyright (c) 2010 Arnaud Patard <arnaud.patard@rtp-net.org> | 4 | * Copyright (c) 2010 Arnaud Patard <arnaud.patard@rtp-net.org> |
5 | * Copyright (c) 2010 Vasily Khoruzhick <anarsoul@gmail.com> | 5 | * Copyright (c) 2010 Vasily Khoruzhick <anarsoul@gmail.com> |
6 | * | 6 | * |
7 | * Based on version from Arnaud Patard <arnaud.patard@rtp-net.org> | 7 | * Based on version from Arnaud Patard <arnaud.patard@rtp-net.org> |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or modify it | 9 | * This program is free software; you can redistribute it and/or modify it |
10 | * under the terms of the GNU General Public License as published by the | 10 | * under the terms of the GNU General Public License as published by the |
11 | * Free Software Foundation; either version 2 of the License, or (at your | 11 | * Free Software Foundation; either version 2 of the License, or (at your |
12 | * option) any later version. | 12 | * option) any later version. |
13 | * | 13 | * |
14 | */ | 14 | */ |
15 | 15 | ||
16 | #include <linux/types.h> | 16 | #include <linux/types.h> |
17 | #include <linux/gpio.h> | 17 | #include <linux/gpio.h> |
18 | 18 | ||
19 | #include <sound/soc.h> | 19 | #include <sound/soc.h> |
20 | #include <sound/jack.h> | 20 | #include <sound/jack.h> |
21 | 21 | ||
22 | #include <plat/regs-iis.h> | 22 | #include <plat/regs-iis.h> |
23 | #include <mach/h1940-latch.h> | 23 | #include <mach/h1940-latch.h> |
24 | #include <asm/mach-types.h> | 24 | #include <asm/mach-types.h> |
25 | 25 | ||
26 | #include "s3c24xx-i2s.h" | 26 | #include "s3c24xx-i2s.h" |
27 | 27 | ||
28 | static unsigned int rates[] = { | 28 | static unsigned int rates[] = { |
29 | 11025, | 29 | 11025, |
30 | 22050, | 30 | 22050, |
31 | 44100, | 31 | 44100, |
32 | }; | 32 | }; |
33 | 33 | ||
34 | static struct snd_pcm_hw_constraint_list hw_rates = { | 34 | static struct snd_pcm_hw_constraint_list hw_rates = { |
35 | .count = ARRAY_SIZE(rates), | 35 | .count = ARRAY_SIZE(rates), |
36 | .list = rates, | 36 | .list = rates, |
37 | .mask = 0, | 37 | .mask = 0, |
38 | }; | 38 | }; |
39 | 39 | ||
40 | static struct snd_soc_jack hp_jack; | 40 | static struct snd_soc_jack hp_jack; |
41 | 41 | ||
42 | static struct snd_soc_jack_pin hp_jack_pins[] = { | 42 | static struct snd_soc_jack_pin hp_jack_pins[] = { |
43 | { | 43 | { |
44 | .pin = "Headphone Jack", | 44 | .pin = "Headphone Jack", |
45 | .mask = SND_JACK_HEADPHONE, | 45 | .mask = SND_JACK_HEADPHONE, |
46 | }, | 46 | }, |
47 | { | 47 | { |
48 | .pin = "Speaker", | 48 | .pin = "Speaker", |
49 | .mask = SND_JACK_HEADPHONE, | 49 | .mask = SND_JACK_HEADPHONE, |
50 | .invert = 1, | 50 | .invert = 1, |
51 | }, | 51 | }, |
52 | }; | 52 | }; |
53 | 53 | ||
54 | static struct snd_soc_jack_gpio hp_jack_gpios[] = { | 54 | static struct snd_soc_jack_gpio hp_jack_gpios[] = { |
55 | { | 55 | { |
56 | .gpio = S3C2410_GPG(4), | 56 | .gpio = S3C2410_GPG(4), |
57 | .name = "hp-gpio", | 57 | .name = "hp-gpio", |
58 | .report = SND_JACK_HEADPHONE, | 58 | .report = SND_JACK_HEADPHONE, |
59 | .invert = 1, | 59 | .invert = 1, |
60 | .debounce_time = 200, | 60 | .debounce_time = 200, |
61 | }, | 61 | }, |
62 | }; | 62 | }; |
63 | 63 | ||
64 | static int h1940_startup(struct snd_pcm_substream *substream) | 64 | static int h1940_startup(struct snd_pcm_substream *substream) |
65 | { | 65 | { |
66 | struct snd_pcm_runtime *runtime = substream->runtime; | 66 | struct snd_pcm_runtime *runtime = substream->runtime; |
67 | 67 | ||
68 | runtime->hw.rate_min = hw_rates.list[0]; | 68 | runtime->hw.rate_min = hw_rates.list[0]; |
69 | runtime->hw.rate_max = hw_rates.list[hw_rates.count - 1]; | 69 | runtime->hw.rate_max = hw_rates.list[hw_rates.count - 1]; |
70 | runtime->hw.rates = SNDRV_PCM_RATE_KNOT; | 70 | runtime->hw.rates = SNDRV_PCM_RATE_KNOT; |
71 | 71 | ||
72 | return snd_pcm_hw_constraint_list(runtime, 0, | 72 | return snd_pcm_hw_constraint_list(runtime, 0, |
73 | SNDRV_PCM_HW_PARAM_RATE, | 73 | SNDRV_PCM_HW_PARAM_RATE, |
74 | &hw_rates); | 74 | &hw_rates); |
75 | } | 75 | } |
76 | 76 | ||
77 | static int h1940_hw_params(struct snd_pcm_substream *substream, | 77 | static int h1940_hw_params(struct snd_pcm_substream *substream, |
78 | struct snd_pcm_hw_params *params) | 78 | struct snd_pcm_hw_params *params) |
79 | { | 79 | { |
80 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 80 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
81 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 81 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
82 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 82 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
83 | int div; | 83 | int div; |
84 | int ret; | 84 | int ret; |
85 | unsigned int rate = params_rate(params); | 85 | unsigned int rate = params_rate(params); |
86 | 86 | ||
87 | switch (rate) { | 87 | switch (rate) { |
88 | case 11025: | 88 | case 11025: |
89 | case 22050: | 89 | case 22050: |
90 | case 44100: | 90 | case 44100: |
91 | div = s3c24xx_i2s_get_clockrate() / (384 * rate); | 91 | div = s3c24xx_i2s_get_clockrate() / (384 * rate); |
92 | if (s3c24xx_i2s_get_clockrate() % (384 * rate) > (192 * rate)) | 92 | if (s3c24xx_i2s_get_clockrate() % (384 * rate) > (192 * rate)) |
93 | div++; | 93 | div++; |
94 | break; | 94 | break; |
95 | default: | 95 | default: |
96 | dev_err(&rtd->dev, "%s: rate %d is not supported\n", | 96 | dev_err(&rtd->dev, "%s: rate %d is not supported\n", |
97 | __func__, rate); | 97 | __func__, rate); |
98 | return -EINVAL; | 98 | return -EINVAL; |
99 | } | 99 | } |
100 | 100 | ||
101 | /* set codec DAI configuration */ | 101 | /* set codec DAI configuration */ |
102 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | | 102 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | |
103 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); | 103 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); |
104 | if (ret < 0) | 104 | if (ret < 0) |
105 | return ret; | 105 | return ret; |
106 | 106 | ||
107 | /* set cpu DAI configuration */ | 107 | /* set cpu DAI configuration */ |
108 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | | 108 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | |
109 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); | 109 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); |
110 | if (ret < 0) | 110 | if (ret < 0) |
111 | return ret; | 111 | return ret; |
112 | 112 | ||
113 | /* select clock source */ | 113 | /* select clock source */ |
114 | ret = snd_soc_dai_set_sysclk(cpu_dai, S3C24XX_CLKSRC_PCLK, rate, | 114 | ret = snd_soc_dai_set_sysclk(cpu_dai, S3C24XX_CLKSRC_PCLK, rate, |
115 | SND_SOC_CLOCK_OUT); | 115 | SND_SOC_CLOCK_OUT); |
116 | if (ret < 0) | 116 | if (ret < 0) |
117 | return ret; | 117 | return ret; |
118 | 118 | ||
119 | /* set MCLK division for sample rate */ | 119 | /* set MCLK division for sample rate */ |
120 | ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK, | 120 | ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK, |
121 | S3C2410_IISMOD_384FS); | 121 | S3C2410_IISMOD_384FS); |
122 | if (ret < 0) | 122 | if (ret < 0) |
123 | return ret; | 123 | return ret; |
124 | 124 | ||
125 | /* set BCLK division for sample rate */ | 125 | /* set BCLK division for sample rate */ |
126 | ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_BCLK, | 126 | ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_BCLK, |
127 | S3C2410_IISMOD_32FS); | 127 | S3C2410_IISMOD_32FS); |
128 | if (ret < 0) | 128 | if (ret < 0) |
129 | return ret; | 129 | return ret; |
130 | 130 | ||
131 | /* set prescaler division for sample rate */ | 131 | /* set prescaler division for sample rate */ |
132 | ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER, | 132 | ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER, |
133 | S3C24XX_PRESCALE(div, div)); | 133 | S3C24XX_PRESCALE(div, div)); |
134 | if (ret < 0) | 134 | if (ret < 0) |
135 | return ret; | 135 | return ret; |
136 | 136 | ||
137 | return 0; | 137 | return 0; |
138 | } | 138 | } |
139 | 139 | ||
140 | static struct snd_soc_ops h1940_ops = { | 140 | static struct snd_soc_ops h1940_ops = { |
141 | .startup = h1940_startup, | 141 | .startup = h1940_startup, |
142 | .hw_params = h1940_hw_params, | 142 | .hw_params = h1940_hw_params, |
143 | }; | 143 | }; |
144 | 144 | ||
145 | static int h1940_spk_power(struct snd_soc_dapm_widget *w, | 145 | static int h1940_spk_power(struct snd_soc_dapm_widget *w, |
146 | struct snd_kcontrol *kcontrol, int event) | 146 | struct snd_kcontrol *kcontrol, int event) |
147 | { | 147 | { |
148 | if (SND_SOC_DAPM_EVENT_ON(event)) | 148 | if (SND_SOC_DAPM_EVENT_ON(event)) |
149 | gpio_set_value(H1940_LATCH_AUDIO_POWER, 1); | 149 | gpio_set_value(H1940_LATCH_AUDIO_POWER, 1); |
150 | else | 150 | else |
151 | gpio_set_value(H1940_LATCH_AUDIO_POWER, 0); | 151 | gpio_set_value(H1940_LATCH_AUDIO_POWER, 0); |
152 | 152 | ||
153 | return 0; | 153 | return 0; |
154 | } | 154 | } |
155 | 155 | ||
156 | /* h1940 machine dapm widgets */ | 156 | /* h1940 machine dapm widgets */ |
157 | static const struct snd_soc_dapm_widget uda1380_dapm_widgets[] = { | 157 | static const struct snd_soc_dapm_widget uda1380_dapm_widgets[] = { |
158 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | 158 | SND_SOC_DAPM_HP("Headphone Jack", NULL), |
159 | SND_SOC_DAPM_MIC("Mic Jack", NULL), | 159 | SND_SOC_DAPM_MIC("Mic Jack", NULL), |
160 | SND_SOC_DAPM_SPK("Speaker", h1940_spk_power), | 160 | SND_SOC_DAPM_SPK("Speaker", h1940_spk_power), |
161 | }; | 161 | }; |
162 | 162 | ||
163 | /* h1940 machine audio_map */ | 163 | /* h1940 machine audio_map */ |
164 | static const struct snd_soc_dapm_route audio_map[] = { | 164 | static const struct snd_soc_dapm_route audio_map[] = { |
165 | /* headphone connected to VOUTLHP, VOUTRHP */ | 165 | /* headphone connected to VOUTLHP, VOUTRHP */ |
166 | {"Headphone Jack", NULL, "VOUTLHP"}, | 166 | {"Headphone Jack", NULL, "VOUTLHP"}, |
167 | {"Headphone Jack", NULL, "VOUTRHP"}, | 167 | {"Headphone Jack", NULL, "VOUTRHP"}, |
168 | 168 | ||
169 | /* ext speaker connected to VOUTL, VOUTR */ | 169 | /* ext speaker connected to VOUTL, VOUTR */ |
170 | {"Speaker", NULL, "VOUTL"}, | 170 | {"Speaker", NULL, "VOUTL"}, |
171 | {"Speaker", NULL, "VOUTR"}, | 171 | {"Speaker", NULL, "VOUTR"}, |
172 | 172 | ||
173 | /* mic is connected to VINM */ | 173 | /* mic is connected to VINM */ |
174 | {"VINM", NULL, "Mic Jack"}, | 174 | {"VINM", NULL, "Mic Jack"}, |
175 | }; | 175 | }; |
176 | 176 | ||
177 | static struct platform_device *s3c24xx_snd_device; | 177 | static struct platform_device *s3c24xx_snd_device; |
178 | 178 | ||
179 | static int h1940_uda1380_init(struct snd_soc_pcm_runtime *rtd) | 179 | static int h1940_uda1380_init(struct snd_soc_pcm_runtime *rtd) |
180 | { | 180 | { |
181 | struct snd_soc_codec *codec = rtd->codec; | 181 | struct snd_soc_codec *codec = rtd->codec; |
182 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 182 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
183 | int err; | 183 | int err; |
184 | 184 | ||
185 | /* Add h1940 specific widgets */ | 185 | /* Add h1940 specific widgets */ |
186 | err = snd_soc_dapm_new_controls(dapm, uda1380_dapm_widgets, | 186 | err = snd_soc_dapm_new_controls(dapm, uda1380_dapm_widgets, |
187 | ARRAY_SIZE(uda1380_dapm_widgets)); | 187 | ARRAY_SIZE(uda1380_dapm_widgets)); |
188 | if (err) | 188 | if (err) |
189 | return err; | 189 | return err; |
190 | 190 | ||
191 | /* Set up h1940 specific audio path audio_mapnects */ | 191 | /* Set up h1940 specific audio path audio_mapnects */ |
192 | err = snd_soc_dapm_add_routes(dapm, audio_map, | 192 | err = snd_soc_dapm_add_routes(dapm, audio_map, |
193 | ARRAY_SIZE(audio_map)); | 193 | ARRAY_SIZE(audio_map)); |
194 | if (err) | 194 | if (err) |
195 | return err; | 195 | return err; |
196 | 196 | ||
197 | snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); | 197 | snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); |
198 | snd_soc_dapm_enable_pin(dapm, "Speaker"); | 198 | snd_soc_dapm_enable_pin(dapm, "Speaker"); |
199 | snd_soc_dapm_enable_pin(dapm, "Mic Jack"); | 199 | snd_soc_dapm_enable_pin(dapm, "Mic Jack"); |
200 | 200 | ||
201 | snd_soc_dapm_sync(dapm); | ||
202 | |||
203 | snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE, | 201 | snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE, |
204 | &hp_jack); | 202 | &hp_jack); |
205 | 203 | ||
206 | snd_soc_jack_add_pins(&hp_jack, ARRAY_SIZE(hp_jack_pins), | 204 | snd_soc_jack_add_pins(&hp_jack, ARRAY_SIZE(hp_jack_pins), |
207 | hp_jack_pins); | 205 | hp_jack_pins); |
208 | 206 | ||
209 | snd_soc_jack_add_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios), | 207 | snd_soc_jack_add_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios), |
210 | hp_jack_gpios); | 208 | hp_jack_gpios); |
211 | 209 | ||
212 | return 0; | 210 | return 0; |
213 | } | 211 | } |
214 | 212 | ||
215 | /* s3c24xx digital audio interface glue - connects codec <--> CPU */ | 213 | /* s3c24xx digital audio interface glue - connects codec <--> CPU */ |
216 | static struct snd_soc_dai_link h1940_uda1380_dai[] = { | 214 | static struct snd_soc_dai_link h1940_uda1380_dai[] = { |
217 | { | 215 | { |
218 | .name = "uda1380", | 216 | .name = "uda1380", |
219 | .stream_name = "UDA1380 Duplex", | 217 | .stream_name = "UDA1380 Duplex", |
220 | .cpu_dai_name = "s3c24xx-iis", | 218 | .cpu_dai_name = "s3c24xx-iis", |
221 | .codec_dai_name = "uda1380-hifi", | 219 | .codec_dai_name = "uda1380-hifi", |
222 | .init = h1940_uda1380_init, | 220 | .init = h1940_uda1380_init, |
223 | .platform_name = "samsung-audio", | 221 | .platform_name = "samsung-audio", |
224 | .codec_name = "uda1380-codec.0-001a", | 222 | .codec_name = "uda1380-codec.0-001a", |
225 | .ops = &h1940_ops, | 223 | .ops = &h1940_ops, |
226 | }, | 224 | }, |
227 | }; | 225 | }; |
228 | 226 | ||
229 | static struct snd_soc_card h1940_asoc = { | 227 | static struct snd_soc_card h1940_asoc = { |
230 | .name = "h1940", | 228 | .name = "h1940", |
231 | .dai_link = h1940_uda1380_dai, | 229 | .dai_link = h1940_uda1380_dai, |
232 | .num_links = ARRAY_SIZE(h1940_uda1380_dai), | 230 | .num_links = ARRAY_SIZE(h1940_uda1380_dai), |
233 | }; | 231 | }; |
234 | 232 | ||
235 | static int __init h1940_init(void) | 233 | static int __init h1940_init(void) |
236 | { | 234 | { |
237 | int ret; | 235 | int ret; |
238 | 236 | ||
239 | if (!machine_is_h1940()) | 237 | if (!machine_is_h1940()) |
240 | return -ENODEV; | 238 | return -ENODEV; |
241 | 239 | ||
242 | /* configure some gpios */ | 240 | /* configure some gpios */ |
243 | ret = gpio_request(H1940_LATCH_AUDIO_POWER, "speaker-power"); | 241 | ret = gpio_request(H1940_LATCH_AUDIO_POWER, "speaker-power"); |
244 | if (ret) | 242 | if (ret) |
245 | goto err_out; | 243 | goto err_out; |
246 | 244 | ||
247 | ret = gpio_direction_output(H1940_LATCH_AUDIO_POWER, 0); | 245 | ret = gpio_direction_output(H1940_LATCH_AUDIO_POWER, 0); |
248 | if (ret) | 246 | if (ret) |
249 | goto err_gpio; | 247 | goto err_gpio; |
250 | 248 | ||
251 | s3c24xx_snd_device = platform_device_alloc("soc-audio", -1); | 249 | s3c24xx_snd_device = platform_device_alloc("soc-audio", -1); |
252 | if (!s3c24xx_snd_device) { | 250 | if (!s3c24xx_snd_device) { |
253 | ret = -ENOMEM; | 251 | ret = -ENOMEM; |
254 | goto err_gpio; | 252 | goto err_gpio; |
255 | } | 253 | } |
256 | 254 | ||
257 | platform_set_drvdata(s3c24xx_snd_device, &h1940_asoc); | 255 | platform_set_drvdata(s3c24xx_snd_device, &h1940_asoc); |
258 | ret = platform_device_add(s3c24xx_snd_device); | 256 | ret = platform_device_add(s3c24xx_snd_device); |
259 | 257 | ||
260 | if (ret) | 258 | if (ret) |
261 | goto err_plat; | 259 | goto err_plat; |
262 | 260 | ||
263 | return 0; | 261 | return 0; |
264 | 262 | ||
265 | err_plat: | 263 | err_plat: |
266 | platform_device_put(s3c24xx_snd_device); | 264 | platform_device_put(s3c24xx_snd_device); |
267 | err_gpio: | 265 | err_gpio: |
268 | gpio_free(H1940_LATCH_AUDIO_POWER); | 266 | gpio_free(H1940_LATCH_AUDIO_POWER); |
269 | 267 | ||
270 | err_out: | 268 | err_out: |
271 | return ret; | 269 | return ret; |
272 | } | 270 | } |
273 | 271 | ||
274 | static void __exit h1940_exit(void) | 272 | static void __exit h1940_exit(void) |
275 | { | 273 | { |
276 | platform_device_unregister(s3c24xx_snd_device); | 274 | platform_device_unregister(s3c24xx_snd_device); |
277 | snd_soc_jack_free_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios), | 275 | snd_soc_jack_free_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios), |
278 | hp_jack_gpios); | 276 | hp_jack_gpios); |
279 | gpio_free(H1940_LATCH_AUDIO_POWER); | 277 | gpio_free(H1940_LATCH_AUDIO_POWER); |
280 | } | 278 | } |
281 | 279 | ||
282 | module_init(h1940_init); | 280 | module_init(h1940_init); |
283 | module_exit(h1940_exit); | 281 | module_exit(h1940_exit); |
284 | 282 | ||
285 | /* Module information */ | 283 | /* Module information */ |
286 | MODULE_AUTHOR("Arnaud Patard, Vasily Khoruzhick"); | 284 | MODULE_AUTHOR("Arnaud Patard, Vasily Khoruzhick"); |
287 | MODULE_DESCRIPTION("ALSA SoC H1940"); | 285 | MODULE_DESCRIPTION("ALSA SoC H1940"); |
288 | MODULE_LICENSE("GPL"); | 286 | MODULE_LICENSE("GPL"); |
289 | 287 |
sound/soc/samsung/jive_wm8750.c
1 | /* sound/soc/samsung/jive_wm8750.c | 1 | /* sound/soc/samsung/jive_wm8750.c |
2 | * | 2 | * |
3 | * Copyright 2007,2008 Simtec Electronics | 3 | * Copyright 2007,2008 Simtec Electronics |
4 | * | 4 | * |
5 | * Based on sound/soc/pxa/spitz.c | 5 | * Based on sound/soc/pxa/spitz.c |
6 | * Copyright 2005 Wolfson Microelectronics PLC. | 6 | * Copyright 2005 Wolfson Microelectronics PLC. |
7 | * Copyright 2005 Openedhand Ltd. | 7 | * Copyright 2005 Openedhand Ltd. |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or modify | 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 | 10 | * it under the terms of the GNU General Public License version 2 as |
11 | * published by the Free Software Foundation. | 11 | * published by the Free Software Foundation. |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <sound/soc.h> | 14 | #include <sound/soc.h> |
15 | 15 | ||
16 | #include <asm/mach-types.h> | 16 | #include <asm/mach-types.h> |
17 | 17 | ||
18 | #include "s3c2412-i2s.h" | 18 | #include "s3c2412-i2s.h" |
19 | #include "../codecs/wm8750.h" | 19 | #include "../codecs/wm8750.h" |
20 | 20 | ||
21 | static const struct snd_soc_dapm_route audio_map[] = { | 21 | static const struct snd_soc_dapm_route audio_map[] = { |
22 | { "Headphone Jack", NULL, "LOUT1" }, | 22 | { "Headphone Jack", NULL, "LOUT1" }, |
23 | { "Headphone Jack", NULL, "ROUT1" }, | 23 | { "Headphone Jack", NULL, "ROUT1" }, |
24 | { "Internal Speaker", NULL, "LOUT2" }, | 24 | { "Internal Speaker", NULL, "LOUT2" }, |
25 | { "Internal Speaker", NULL, "ROUT2" }, | 25 | { "Internal Speaker", NULL, "ROUT2" }, |
26 | { "LINPUT1", NULL, "Line Input" }, | 26 | { "LINPUT1", NULL, "Line Input" }, |
27 | { "RINPUT1", NULL, "Line Input" }, | 27 | { "RINPUT1", NULL, "Line Input" }, |
28 | }; | 28 | }; |
29 | 29 | ||
30 | static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = { | 30 | static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = { |
31 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | 31 | SND_SOC_DAPM_HP("Headphone Jack", NULL), |
32 | SND_SOC_DAPM_SPK("Internal Speaker", NULL), | 32 | SND_SOC_DAPM_SPK("Internal Speaker", NULL), |
33 | SND_SOC_DAPM_LINE("Line In", NULL), | 33 | SND_SOC_DAPM_LINE("Line In", NULL), |
34 | }; | 34 | }; |
35 | 35 | ||
36 | static int jive_hw_params(struct snd_pcm_substream *substream, | 36 | static int jive_hw_params(struct snd_pcm_substream *substream, |
37 | struct snd_pcm_hw_params *params) | 37 | struct snd_pcm_hw_params *params) |
38 | { | 38 | { |
39 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 39 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
40 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 40 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
41 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 41 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
42 | struct s3c_i2sv2_rate_calc div; | 42 | struct s3c_i2sv2_rate_calc div; |
43 | unsigned int clk = 0; | 43 | unsigned int clk = 0; |
44 | int ret = 0; | 44 | int ret = 0; |
45 | 45 | ||
46 | switch (params_rate(params)) { | 46 | switch (params_rate(params)) { |
47 | case 8000: | 47 | case 8000: |
48 | case 16000: | 48 | case 16000: |
49 | case 48000: | 49 | case 48000: |
50 | case 96000: | 50 | case 96000: |
51 | clk = 12288000; | 51 | clk = 12288000; |
52 | break; | 52 | break; |
53 | case 11025: | 53 | case 11025: |
54 | case 22050: | 54 | case 22050: |
55 | case 44100: | 55 | case 44100: |
56 | clk = 11289600; | 56 | clk = 11289600; |
57 | break; | 57 | break; |
58 | } | 58 | } |
59 | 59 | ||
60 | s3c_i2sv2_iis_calc_rate(&div, NULL, params_rate(params), | 60 | s3c_i2sv2_iis_calc_rate(&div, NULL, params_rate(params), |
61 | s3c_i2sv2_get_clock(cpu_dai)); | 61 | s3c_i2sv2_get_clock(cpu_dai)); |
62 | 62 | ||
63 | /* set codec DAI configuration */ | 63 | /* set codec DAI configuration */ |
64 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | | 64 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | |
65 | SND_SOC_DAIFMT_NB_NF | | 65 | SND_SOC_DAIFMT_NB_NF | |
66 | SND_SOC_DAIFMT_CBS_CFS); | 66 | SND_SOC_DAIFMT_CBS_CFS); |
67 | if (ret < 0) | 67 | if (ret < 0) |
68 | return ret; | 68 | return ret; |
69 | 69 | ||
70 | /* set cpu DAI configuration */ | 70 | /* set cpu DAI configuration */ |
71 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | | 71 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | |
72 | SND_SOC_DAIFMT_NB_NF | | 72 | SND_SOC_DAIFMT_NB_NF | |
73 | SND_SOC_DAIFMT_CBS_CFS); | 73 | SND_SOC_DAIFMT_CBS_CFS); |
74 | if (ret < 0) | 74 | if (ret < 0) |
75 | return ret; | 75 | return ret; |
76 | 76 | ||
77 | /* set the codec system clock for DAC and ADC */ | 77 | /* set the codec system clock for DAC and ADC */ |
78 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk, | 78 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk, |
79 | SND_SOC_CLOCK_IN); | 79 | SND_SOC_CLOCK_IN); |
80 | if (ret < 0) | 80 | if (ret < 0) |
81 | return ret; | 81 | return ret; |
82 | 82 | ||
83 | ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C2412_DIV_RCLK, div.fs_div); | 83 | ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C2412_DIV_RCLK, div.fs_div); |
84 | if (ret < 0) | 84 | if (ret < 0) |
85 | return ret; | 85 | return ret; |
86 | 86 | ||
87 | ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C2412_DIV_PRESCALER, | 87 | ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C2412_DIV_PRESCALER, |
88 | div.clk_div - 1); | 88 | div.clk_div - 1); |
89 | if (ret < 0) | 89 | if (ret < 0) |
90 | return ret; | 90 | return ret; |
91 | 91 | ||
92 | return 0; | 92 | return 0; |
93 | } | 93 | } |
94 | 94 | ||
95 | static struct snd_soc_ops jive_ops = { | 95 | static struct snd_soc_ops jive_ops = { |
96 | .hw_params = jive_hw_params, | 96 | .hw_params = jive_hw_params, |
97 | }; | 97 | }; |
98 | 98 | ||
99 | static int jive_wm8750_init(struct snd_soc_pcm_runtime *rtd) | 99 | static int jive_wm8750_init(struct snd_soc_pcm_runtime *rtd) |
100 | { | 100 | { |
101 | struct snd_soc_codec *codec = rtd->codec; | 101 | struct snd_soc_codec *codec = rtd->codec; |
102 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 102 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
103 | int err; | 103 | int err; |
104 | 104 | ||
105 | /* These endpoints are not being used. */ | 105 | /* These endpoints are not being used. */ |
106 | snd_soc_dapm_nc_pin(dapm, "LINPUT2"); | 106 | snd_soc_dapm_nc_pin(dapm, "LINPUT2"); |
107 | snd_soc_dapm_nc_pin(dapm, "RINPUT2"); | 107 | snd_soc_dapm_nc_pin(dapm, "RINPUT2"); |
108 | snd_soc_dapm_nc_pin(dapm, "LINPUT3"); | 108 | snd_soc_dapm_nc_pin(dapm, "LINPUT3"); |
109 | snd_soc_dapm_nc_pin(dapm, "RINPUT3"); | 109 | snd_soc_dapm_nc_pin(dapm, "RINPUT3"); |
110 | snd_soc_dapm_nc_pin(dapm, "OUT3"); | 110 | snd_soc_dapm_nc_pin(dapm, "OUT3"); |
111 | snd_soc_dapm_nc_pin(dapm, "MONO"); | 111 | snd_soc_dapm_nc_pin(dapm, "MONO"); |
112 | 112 | ||
113 | /* Add jive specific widgets */ | 113 | /* Add jive specific widgets */ |
114 | err = snd_soc_dapm_new_controls(dapm, wm8750_dapm_widgets, | 114 | err = snd_soc_dapm_new_controls(dapm, wm8750_dapm_widgets, |
115 | ARRAY_SIZE(wm8750_dapm_widgets)); | 115 | ARRAY_SIZE(wm8750_dapm_widgets)); |
116 | if (err) { | 116 | if (err) { |
117 | printk(KERN_ERR "%s: failed to add widgets (%d)\n", | 117 | printk(KERN_ERR "%s: failed to add widgets (%d)\n", |
118 | __func__, err); | 118 | __func__, err); |
119 | return err; | 119 | return err; |
120 | } | 120 | } |
121 | 121 | ||
122 | snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); | 122 | snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); |
123 | snd_soc_dapm_sync(dapm); | ||
124 | 123 | ||
125 | return 0; | 124 | return 0; |
126 | } | 125 | } |
127 | 126 | ||
128 | static struct snd_soc_dai_link jive_dai = { | 127 | static struct snd_soc_dai_link jive_dai = { |
129 | .name = "wm8750", | 128 | .name = "wm8750", |
130 | .stream_name = "WM8750", | 129 | .stream_name = "WM8750", |
131 | .cpu_dai_name = "s3c2412-i2s", | 130 | .cpu_dai_name = "s3c2412-i2s", |
132 | .codec_dai_name = "wm8750-hifi", | 131 | .codec_dai_name = "wm8750-hifi", |
133 | .platform_name = "samsung-audio", | 132 | .platform_name = "samsung-audio", |
134 | .codec_name = "wm8750.0-001a", | 133 | .codec_name = "wm8750.0-001a", |
135 | .init = jive_wm8750_init, | 134 | .init = jive_wm8750_init, |
136 | .ops = &jive_ops, | 135 | .ops = &jive_ops, |
137 | }; | 136 | }; |
138 | 137 | ||
139 | /* jive audio machine driver */ | 138 | /* jive audio machine driver */ |
140 | static struct snd_soc_card snd_soc_machine_jive = { | 139 | static struct snd_soc_card snd_soc_machine_jive = { |
141 | .name = "Jive", | 140 | .name = "Jive", |
142 | .dai_link = &jive_dai, | 141 | .dai_link = &jive_dai, |
143 | .num_links = 1, | 142 | .num_links = 1, |
144 | }; | 143 | }; |
145 | 144 | ||
146 | static struct platform_device *jive_snd_device; | 145 | static struct platform_device *jive_snd_device; |
147 | 146 | ||
148 | static int __init jive_init(void) | 147 | static int __init jive_init(void) |
149 | { | 148 | { |
150 | int ret; | 149 | int ret; |
151 | 150 | ||
152 | if (!machine_is_jive()) | 151 | if (!machine_is_jive()) |
153 | return 0; | 152 | return 0; |
154 | 153 | ||
155 | printk("JIVE WM8750 Audio support\n"); | 154 | printk("JIVE WM8750 Audio support\n"); |
156 | 155 | ||
157 | jive_snd_device = platform_device_alloc("soc-audio", -1); | 156 | jive_snd_device = platform_device_alloc("soc-audio", -1); |
158 | if (!jive_snd_device) | 157 | if (!jive_snd_device) |
159 | return -ENOMEM; | 158 | return -ENOMEM; |
160 | 159 | ||
161 | platform_set_drvdata(jive_snd_device, &snd_soc_machine_jive); | 160 | platform_set_drvdata(jive_snd_device, &snd_soc_machine_jive); |
162 | ret = platform_device_add(jive_snd_device); | 161 | ret = platform_device_add(jive_snd_device); |
163 | 162 | ||
164 | if (ret) | 163 | if (ret) |
165 | platform_device_put(jive_snd_device); | 164 | platform_device_put(jive_snd_device); |
166 | 165 | ||
167 | return ret; | 166 | return ret; |
168 | } | 167 | } |
169 | 168 | ||
170 | static void __exit jive_exit(void) | 169 | static void __exit jive_exit(void) |
171 | { | 170 | { |
172 | platform_device_unregister(jive_snd_device); | 171 | platform_device_unregister(jive_snd_device); |
173 | } | 172 | } |
174 | 173 | ||
175 | module_init(jive_init); | 174 | module_init(jive_init); |
176 | module_exit(jive_exit); | 175 | module_exit(jive_exit); |
177 | 176 | ||
178 | MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); | 177 | MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); |
179 | MODULE_DESCRIPTION("ALSA SoC Jive Audio support"); | 178 | MODULE_DESCRIPTION("ALSA SoC Jive Audio support"); |
180 | MODULE_LICENSE("GPL"); | 179 | MODULE_LICENSE("GPL"); |
181 | 180 |
sound/soc/samsung/neo1973_wm8753.c
1 | /* | 1 | /* |
2 | * neo1973_wm8753.c -- SoC audio for Openmoko Neo1973 and Freerunner devices | 2 | * neo1973_wm8753.c -- SoC audio for Openmoko Neo1973 and Freerunner devices |
3 | * | 3 | * |
4 | * Copyright 2007 Openmoko Inc | 4 | * Copyright 2007 Openmoko Inc |
5 | * Author: Graeme Gregory <graeme@openmoko.org> | 5 | * Author: Graeme Gregory <graeme@openmoko.org> |
6 | * Copyright 2007 Wolfson Microelectronics PLC. | 6 | * Copyright 2007 Wolfson Microelectronics PLC. |
7 | * Author: Graeme Gregory | 7 | * Author: Graeme Gregory |
8 | * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com | 8 | * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com |
9 | * Copyright 2009 Wolfson Microelectronics | 9 | * Copyright 2009 Wolfson Microelectronics |
10 | * | 10 | * |
11 | * This program is free software; you can redistribute it and/or modify it | 11 | * This program is free software; you can redistribute it and/or modify it |
12 | * under the terms of the GNU General Public License as published by the | 12 | * under the terms of the GNU General Public License as published by the |
13 | * Free Software Foundation; either version 2 of the License, or (at your | 13 | * Free Software Foundation; either version 2 of the License, or (at your |
14 | * option) any later version. | 14 | * option) any later version. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
18 | #include <linux/platform_device.h> | 18 | #include <linux/platform_device.h> |
19 | #include <linux/gpio.h> | 19 | #include <linux/gpio.h> |
20 | 20 | ||
21 | #include <sound/soc.h> | 21 | #include <sound/soc.h> |
22 | 22 | ||
23 | #include <asm/mach-types.h> | 23 | #include <asm/mach-types.h> |
24 | #include <plat/regs-iis.h> | 24 | #include <plat/regs-iis.h> |
25 | #include <mach/gta02.h> | 25 | #include <mach/gta02.h> |
26 | 26 | ||
27 | #include "../codecs/wm8753.h" | 27 | #include "../codecs/wm8753.h" |
28 | #include "s3c24xx-i2s.h" | 28 | #include "s3c24xx-i2s.h" |
29 | 29 | ||
30 | static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream, | 30 | static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream, |
31 | struct snd_pcm_hw_params *params) | 31 | struct snd_pcm_hw_params *params) |
32 | { | 32 | { |
33 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 33 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
34 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 34 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
35 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 35 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
36 | unsigned int pll_out = 0, bclk = 0; | 36 | unsigned int pll_out = 0, bclk = 0; |
37 | int ret = 0; | 37 | int ret = 0; |
38 | unsigned long iis_clkrate; | 38 | unsigned long iis_clkrate; |
39 | 39 | ||
40 | iis_clkrate = s3c24xx_i2s_get_clockrate(); | 40 | iis_clkrate = s3c24xx_i2s_get_clockrate(); |
41 | 41 | ||
42 | switch (params_rate(params)) { | 42 | switch (params_rate(params)) { |
43 | case 8000: | 43 | case 8000: |
44 | case 16000: | 44 | case 16000: |
45 | pll_out = 12288000; | 45 | pll_out = 12288000; |
46 | break; | 46 | break; |
47 | case 48000: | 47 | case 48000: |
48 | bclk = WM8753_BCLK_DIV_4; | 48 | bclk = WM8753_BCLK_DIV_4; |
49 | pll_out = 12288000; | 49 | pll_out = 12288000; |
50 | break; | 50 | break; |
51 | case 96000: | 51 | case 96000: |
52 | bclk = WM8753_BCLK_DIV_2; | 52 | bclk = WM8753_BCLK_DIV_2; |
53 | pll_out = 12288000; | 53 | pll_out = 12288000; |
54 | break; | 54 | break; |
55 | case 11025: | 55 | case 11025: |
56 | bclk = WM8753_BCLK_DIV_16; | 56 | bclk = WM8753_BCLK_DIV_16; |
57 | pll_out = 11289600; | 57 | pll_out = 11289600; |
58 | break; | 58 | break; |
59 | case 22050: | 59 | case 22050: |
60 | bclk = WM8753_BCLK_DIV_8; | 60 | bclk = WM8753_BCLK_DIV_8; |
61 | pll_out = 11289600; | 61 | pll_out = 11289600; |
62 | break; | 62 | break; |
63 | case 44100: | 63 | case 44100: |
64 | bclk = WM8753_BCLK_DIV_4; | 64 | bclk = WM8753_BCLK_DIV_4; |
65 | pll_out = 11289600; | 65 | pll_out = 11289600; |
66 | break; | 66 | break; |
67 | case 88200: | 67 | case 88200: |
68 | bclk = WM8753_BCLK_DIV_2; | 68 | bclk = WM8753_BCLK_DIV_2; |
69 | pll_out = 11289600; | 69 | pll_out = 11289600; |
70 | break; | 70 | break; |
71 | } | 71 | } |
72 | 72 | ||
73 | /* set codec DAI configuration */ | 73 | /* set codec DAI configuration */ |
74 | ret = snd_soc_dai_set_fmt(codec_dai, | 74 | ret = snd_soc_dai_set_fmt(codec_dai, |
75 | SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | | 75 | SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | |
76 | SND_SOC_DAIFMT_CBM_CFM); | 76 | SND_SOC_DAIFMT_CBM_CFM); |
77 | if (ret < 0) | 77 | if (ret < 0) |
78 | return ret; | 78 | return ret; |
79 | 79 | ||
80 | /* set cpu DAI configuration */ | 80 | /* set cpu DAI configuration */ |
81 | ret = snd_soc_dai_set_fmt(cpu_dai, | 81 | ret = snd_soc_dai_set_fmt(cpu_dai, |
82 | SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | | 82 | SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | |
83 | SND_SOC_DAIFMT_CBM_CFM); | 83 | SND_SOC_DAIFMT_CBM_CFM); |
84 | if (ret < 0) | 84 | if (ret < 0) |
85 | return ret; | 85 | return ret; |
86 | 86 | ||
87 | /* set the codec system clock for DAC and ADC */ | 87 | /* set the codec system clock for DAC and ADC */ |
88 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, pll_out, | 88 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, pll_out, |
89 | SND_SOC_CLOCK_IN); | 89 | SND_SOC_CLOCK_IN); |
90 | if (ret < 0) | 90 | if (ret < 0) |
91 | return ret; | 91 | return ret; |
92 | 92 | ||
93 | /* set MCLK division for sample rate */ | 93 | /* set MCLK division for sample rate */ |
94 | ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK, | 94 | ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK, |
95 | S3C2410_IISMOD_32FS); | 95 | S3C2410_IISMOD_32FS); |
96 | if (ret < 0) | 96 | if (ret < 0) |
97 | return ret; | 97 | return ret; |
98 | 98 | ||
99 | /* set codec BCLK division for sample rate */ | 99 | /* set codec BCLK division for sample rate */ |
100 | ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_BCLKDIV, bclk); | 100 | ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_BCLKDIV, bclk); |
101 | if (ret < 0) | 101 | if (ret < 0) |
102 | return ret; | 102 | return ret; |
103 | 103 | ||
104 | /* set prescaler division for sample rate */ | 104 | /* set prescaler division for sample rate */ |
105 | ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER, | 105 | ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER, |
106 | S3C24XX_PRESCALE(4, 4)); | 106 | S3C24XX_PRESCALE(4, 4)); |
107 | if (ret < 0) | 107 | if (ret < 0) |
108 | return ret; | 108 | return ret; |
109 | 109 | ||
110 | /* codec PLL input is PCLK/4 */ | 110 | /* codec PLL input is PCLK/4 */ |
111 | ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, | 111 | ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, |
112 | iis_clkrate / 4, pll_out); | 112 | iis_clkrate / 4, pll_out); |
113 | if (ret < 0) | 113 | if (ret < 0) |
114 | return ret; | 114 | return ret; |
115 | 115 | ||
116 | return 0; | 116 | return 0; |
117 | } | 117 | } |
118 | 118 | ||
119 | static int neo1973_hifi_hw_free(struct snd_pcm_substream *substream) | 119 | static int neo1973_hifi_hw_free(struct snd_pcm_substream *substream) |
120 | { | 120 | { |
121 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 121 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
122 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 122 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
123 | 123 | ||
124 | /* disable the PLL */ | 124 | /* disable the PLL */ |
125 | return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0, 0); | 125 | return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0, 0); |
126 | } | 126 | } |
127 | 127 | ||
128 | /* | 128 | /* |
129 | * Neo1973 WM8753 HiFi DAI opserations. | 129 | * Neo1973 WM8753 HiFi DAI opserations. |
130 | */ | 130 | */ |
131 | static struct snd_soc_ops neo1973_hifi_ops = { | 131 | static struct snd_soc_ops neo1973_hifi_ops = { |
132 | .hw_params = neo1973_hifi_hw_params, | 132 | .hw_params = neo1973_hifi_hw_params, |
133 | .hw_free = neo1973_hifi_hw_free, | 133 | .hw_free = neo1973_hifi_hw_free, |
134 | }; | 134 | }; |
135 | 135 | ||
136 | static int neo1973_voice_hw_params(struct snd_pcm_substream *substream, | 136 | static int neo1973_voice_hw_params(struct snd_pcm_substream *substream, |
137 | struct snd_pcm_hw_params *params) | 137 | struct snd_pcm_hw_params *params) |
138 | { | 138 | { |
139 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 139 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
140 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 140 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
141 | unsigned int pcmdiv = 0; | 141 | unsigned int pcmdiv = 0; |
142 | int ret = 0; | 142 | int ret = 0; |
143 | unsigned long iis_clkrate; | 143 | unsigned long iis_clkrate; |
144 | 144 | ||
145 | iis_clkrate = s3c24xx_i2s_get_clockrate(); | 145 | iis_clkrate = s3c24xx_i2s_get_clockrate(); |
146 | 146 | ||
147 | if (params_rate(params) != 8000) | 147 | if (params_rate(params) != 8000) |
148 | return -EINVAL; | 148 | return -EINVAL; |
149 | if (params_channels(params) != 1) | 149 | if (params_channels(params) != 1) |
150 | return -EINVAL; | 150 | return -EINVAL; |
151 | 151 | ||
152 | pcmdiv = WM8753_PCM_DIV_6; /* 2.048 MHz */ | 152 | pcmdiv = WM8753_PCM_DIV_6; /* 2.048 MHz */ |
153 | 153 | ||
154 | /* todo: gg check mode (DSP_B) against CSR datasheet */ | 154 | /* todo: gg check mode (DSP_B) against CSR datasheet */ |
155 | /* set codec DAI configuration */ | 155 | /* set codec DAI configuration */ |
156 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B | | 156 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B | |
157 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); | 157 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); |
158 | if (ret < 0) | 158 | if (ret < 0) |
159 | return ret; | 159 | return ret; |
160 | 160 | ||
161 | /* set the codec system clock for DAC and ADC */ | 161 | /* set the codec system clock for DAC and ADC */ |
162 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_PCMCLK, 12288000, | 162 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_PCMCLK, 12288000, |
163 | SND_SOC_CLOCK_IN); | 163 | SND_SOC_CLOCK_IN); |
164 | if (ret < 0) | 164 | if (ret < 0) |
165 | return ret; | 165 | return ret; |
166 | 166 | ||
167 | /* set codec PCM division for sample rate */ | 167 | /* set codec PCM division for sample rate */ |
168 | ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_PCMDIV, pcmdiv); | 168 | ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_PCMDIV, pcmdiv); |
169 | if (ret < 0) | 169 | if (ret < 0) |
170 | return ret; | 170 | return ret; |
171 | 171 | ||
172 | /* configure and enable PLL for 12.288MHz output */ | 172 | /* configure and enable PLL for 12.288MHz output */ |
173 | ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, | 173 | ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, |
174 | iis_clkrate / 4, 12288000); | 174 | iis_clkrate / 4, 12288000); |
175 | if (ret < 0) | 175 | if (ret < 0) |
176 | return ret; | 176 | return ret; |
177 | 177 | ||
178 | return 0; | 178 | return 0; |
179 | } | 179 | } |
180 | 180 | ||
181 | static int neo1973_voice_hw_free(struct snd_pcm_substream *substream) | 181 | static int neo1973_voice_hw_free(struct snd_pcm_substream *substream) |
182 | { | 182 | { |
183 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 183 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
184 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 184 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
185 | 185 | ||
186 | /* disable the PLL */ | 186 | /* disable the PLL */ |
187 | return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0, 0); | 187 | return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0, 0); |
188 | } | 188 | } |
189 | 189 | ||
190 | static struct snd_soc_ops neo1973_voice_ops = { | 190 | static struct snd_soc_ops neo1973_voice_ops = { |
191 | .hw_params = neo1973_voice_hw_params, | 191 | .hw_params = neo1973_voice_hw_params, |
192 | .hw_free = neo1973_voice_hw_free, | 192 | .hw_free = neo1973_voice_hw_free, |
193 | }; | 193 | }; |
194 | 194 | ||
195 | /* Shared routes and controls */ | 195 | /* Shared routes and controls */ |
196 | 196 | ||
197 | static const struct snd_soc_dapm_widget neo1973_wm8753_dapm_widgets[] = { | 197 | static const struct snd_soc_dapm_widget neo1973_wm8753_dapm_widgets[] = { |
198 | SND_SOC_DAPM_LINE("GSM Line Out", NULL), | 198 | SND_SOC_DAPM_LINE("GSM Line Out", NULL), |
199 | SND_SOC_DAPM_LINE("GSM Line In", NULL), | 199 | SND_SOC_DAPM_LINE("GSM Line In", NULL), |
200 | SND_SOC_DAPM_MIC("Headset Mic", NULL), | 200 | SND_SOC_DAPM_MIC("Headset Mic", NULL), |
201 | SND_SOC_DAPM_MIC("Handset Mic", NULL), | 201 | SND_SOC_DAPM_MIC("Handset Mic", NULL), |
202 | }; | 202 | }; |
203 | 203 | ||
204 | static const struct snd_soc_dapm_route neo1973_wm8753_routes[] = { | 204 | static const struct snd_soc_dapm_route neo1973_wm8753_routes[] = { |
205 | /* Connections to the GSM Module */ | 205 | /* Connections to the GSM Module */ |
206 | {"GSM Line Out", NULL, "MONO1"}, | 206 | {"GSM Line Out", NULL, "MONO1"}, |
207 | {"GSM Line Out", NULL, "MONO2"}, | 207 | {"GSM Line Out", NULL, "MONO2"}, |
208 | {"RXP", NULL, "GSM Line In"}, | 208 | {"RXP", NULL, "GSM Line In"}, |
209 | {"RXN", NULL, "GSM Line In"}, | 209 | {"RXN", NULL, "GSM Line In"}, |
210 | 210 | ||
211 | /* Connections to Headset */ | 211 | /* Connections to Headset */ |
212 | {"MIC1", NULL, "Mic Bias"}, | 212 | {"MIC1", NULL, "Mic Bias"}, |
213 | {"Mic Bias", NULL, "Headset Mic"}, | 213 | {"Mic Bias", NULL, "Headset Mic"}, |
214 | 214 | ||
215 | /* Call Mic */ | 215 | /* Call Mic */ |
216 | {"MIC2", NULL, "Mic Bias"}, | 216 | {"MIC2", NULL, "Mic Bias"}, |
217 | {"MIC2N", NULL, "Mic Bias"}, | 217 | {"MIC2N", NULL, "Mic Bias"}, |
218 | {"Mic Bias", NULL, "Handset Mic"}, | 218 | {"Mic Bias", NULL, "Handset Mic"}, |
219 | 219 | ||
220 | /* Connect the ALC pins */ | 220 | /* Connect the ALC pins */ |
221 | {"ACIN", NULL, "ACOP"}, | 221 | {"ACIN", NULL, "ACOP"}, |
222 | }; | 222 | }; |
223 | 223 | ||
224 | static const struct snd_kcontrol_new neo1973_wm8753_controls[] = { | 224 | static const struct snd_kcontrol_new neo1973_wm8753_controls[] = { |
225 | SOC_DAPM_PIN_SWITCH("GSM Line Out"), | 225 | SOC_DAPM_PIN_SWITCH("GSM Line Out"), |
226 | SOC_DAPM_PIN_SWITCH("GSM Line In"), | 226 | SOC_DAPM_PIN_SWITCH("GSM Line In"), |
227 | SOC_DAPM_PIN_SWITCH("Headset Mic"), | 227 | SOC_DAPM_PIN_SWITCH("Headset Mic"), |
228 | SOC_DAPM_PIN_SWITCH("Handset Mic"), | 228 | SOC_DAPM_PIN_SWITCH("Handset Mic"), |
229 | }; | 229 | }; |
230 | 230 | ||
231 | /* GTA02 specific routes and controls */ | 231 | /* GTA02 specific routes and controls */ |
232 | 232 | ||
233 | #ifdef CONFIG_MACH_NEO1973_GTA02 | 233 | #ifdef CONFIG_MACH_NEO1973_GTA02 |
234 | 234 | ||
235 | static int gta02_speaker_enabled; | 235 | static int gta02_speaker_enabled; |
236 | 236 | ||
237 | static int lm4853_set_spk(struct snd_kcontrol *kcontrol, | 237 | static int lm4853_set_spk(struct snd_kcontrol *kcontrol, |
238 | struct snd_ctl_elem_value *ucontrol) | 238 | struct snd_ctl_elem_value *ucontrol) |
239 | { | 239 | { |
240 | gta02_speaker_enabled = ucontrol->value.integer.value[0]; | 240 | gta02_speaker_enabled = ucontrol->value.integer.value[0]; |
241 | 241 | ||
242 | gpio_set_value(GTA02_GPIO_HP_IN, !gta02_speaker_enabled); | 242 | gpio_set_value(GTA02_GPIO_HP_IN, !gta02_speaker_enabled); |
243 | 243 | ||
244 | return 0; | 244 | return 0; |
245 | } | 245 | } |
246 | 246 | ||
247 | static int lm4853_get_spk(struct snd_kcontrol *kcontrol, | 247 | static int lm4853_get_spk(struct snd_kcontrol *kcontrol, |
248 | struct snd_ctl_elem_value *ucontrol) | 248 | struct snd_ctl_elem_value *ucontrol) |
249 | { | 249 | { |
250 | ucontrol->value.integer.value[0] = gta02_speaker_enabled; | 250 | ucontrol->value.integer.value[0] = gta02_speaker_enabled; |
251 | return 0; | 251 | return 0; |
252 | } | 252 | } |
253 | 253 | ||
254 | static int lm4853_event(struct snd_soc_dapm_widget *w, | 254 | static int lm4853_event(struct snd_soc_dapm_widget *w, |
255 | struct snd_kcontrol *k, int event) | 255 | struct snd_kcontrol *k, int event) |
256 | { | 256 | { |
257 | gpio_set_value(GTA02_GPIO_AMP_SHUT, SND_SOC_DAPM_EVENT_OFF(event)); | 257 | gpio_set_value(GTA02_GPIO_AMP_SHUT, SND_SOC_DAPM_EVENT_OFF(event)); |
258 | 258 | ||
259 | return 0; | 259 | return 0; |
260 | } | 260 | } |
261 | 261 | ||
262 | static const struct snd_soc_dapm_route neo1973_gta02_routes[] = { | 262 | static const struct snd_soc_dapm_route neo1973_gta02_routes[] = { |
263 | /* Connections to the amp */ | 263 | /* Connections to the amp */ |
264 | {"Stereo Out", NULL, "LOUT1"}, | 264 | {"Stereo Out", NULL, "LOUT1"}, |
265 | {"Stereo Out", NULL, "ROUT1"}, | 265 | {"Stereo Out", NULL, "ROUT1"}, |
266 | 266 | ||
267 | /* Call Speaker */ | 267 | /* Call Speaker */ |
268 | {"Handset Spk", NULL, "LOUT2"}, | 268 | {"Handset Spk", NULL, "LOUT2"}, |
269 | {"Handset Spk", NULL, "ROUT2"}, | 269 | {"Handset Spk", NULL, "ROUT2"}, |
270 | }; | 270 | }; |
271 | 271 | ||
272 | static const struct snd_kcontrol_new neo1973_gta02_wm8753_controls[] = { | 272 | static const struct snd_kcontrol_new neo1973_gta02_wm8753_controls[] = { |
273 | SOC_DAPM_PIN_SWITCH("Handset Spk"), | 273 | SOC_DAPM_PIN_SWITCH("Handset Spk"), |
274 | SOC_DAPM_PIN_SWITCH("Stereo Out"), | 274 | SOC_DAPM_PIN_SWITCH("Stereo Out"), |
275 | 275 | ||
276 | SOC_SINGLE_BOOL_EXT("Amp Spk Switch", 0, | 276 | SOC_SINGLE_BOOL_EXT("Amp Spk Switch", 0, |
277 | lm4853_get_spk, | 277 | lm4853_get_spk, |
278 | lm4853_set_spk), | 278 | lm4853_set_spk), |
279 | }; | 279 | }; |
280 | 280 | ||
281 | static const struct snd_soc_dapm_widget neo1973_gta02_wm8753_dapm_widgets[] = { | 281 | static const struct snd_soc_dapm_widget neo1973_gta02_wm8753_dapm_widgets[] = { |
282 | SND_SOC_DAPM_SPK("Handset Spk", NULL), | 282 | SND_SOC_DAPM_SPK("Handset Spk", NULL), |
283 | SND_SOC_DAPM_SPK("Stereo Out", lm4853_event), | 283 | SND_SOC_DAPM_SPK("Stereo Out", lm4853_event), |
284 | }; | 284 | }; |
285 | 285 | ||
286 | static int neo1973_gta02_wm8753_init(struct snd_soc_codec *codec) | 286 | static int neo1973_gta02_wm8753_init(struct snd_soc_codec *codec) |
287 | { | 287 | { |
288 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 288 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
289 | int ret; | 289 | int ret; |
290 | 290 | ||
291 | ret = snd_soc_dapm_new_controls(dapm, neo1973_gta02_wm8753_dapm_widgets, | 291 | ret = snd_soc_dapm_new_controls(dapm, neo1973_gta02_wm8753_dapm_widgets, |
292 | ARRAY_SIZE(neo1973_gta02_wm8753_dapm_widgets)); | 292 | ARRAY_SIZE(neo1973_gta02_wm8753_dapm_widgets)); |
293 | if (ret) | 293 | if (ret) |
294 | return ret; | 294 | return ret; |
295 | 295 | ||
296 | ret = snd_soc_dapm_add_routes(dapm, neo1973_gta02_routes, | 296 | ret = snd_soc_dapm_add_routes(dapm, neo1973_gta02_routes, |
297 | ARRAY_SIZE(neo1973_gta02_routes)); | 297 | ARRAY_SIZE(neo1973_gta02_routes)); |
298 | if (ret) | 298 | if (ret) |
299 | return ret; | 299 | return ret; |
300 | 300 | ||
301 | ret = snd_soc_add_controls(codec, neo1973_gta02_wm8753_controls, | 301 | ret = snd_soc_add_controls(codec, neo1973_gta02_wm8753_controls, |
302 | ARRAY_SIZE(neo1973_gta02_wm8753_controls)); | 302 | ARRAY_SIZE(neo1973_gta02_wm8753_controls)); |
303 | if (ret) | 303 | if (ret) |
304 | return ret; | 304 | return ret; |
305 | 305 | ||
306 | snd_soc_dapm_disable_pin(dapm, "Stereo Out"); | 306 | snd_soc_dapm_disable_pin(dapm, "Stereo Out"); |
307 | snd_soc_dapm_disable_pin(dapm, "Handset Spk"); | 307 | snd_soc_dapm_disable_pin(dapm, "Handset Spk"); |
308 | snd_soc_dapm_ignore_suspend(dapm, "Stereo Out"); | 308 | snd_soc_dapm_ignore_suspend(dapm, "Stereo Out"); |
309 | snd_soc_dapm_ignore_suspend(dapm, "Handset Spk"); | 309 | snd_soc_dapm_ignore_suspend(dapm, "Handset Spk"); |
310 | 310 | ||
311 | return 0; | 311 | return 0; |
312 | } | 312 | } |
313 | 313 | ||
314 | #else | 314 | #else |
315 | static int neo1973_gta02_wm8753_init(struct snd_soc_code *codec) { return 0; } | 315 | static int neo1973_gta02_wm8753_init(struct snd_soc_code *codec) { return 0; } |
316 | #endif | 316 | #endif |
317 | 317 | ||
318 | static int neo1973_wm8753_init(struct snd_soc_pcm_runtime *rtd) | 318 | static int neo1973_wm8753_init(struct snd_soc_pcm_runtime *rtd) |
319 | { | 319 | { |
320 | struct snd_soc_codec *codec = rtd->codec; | 320 | struct snd_soc_codec *codec = rtd->codec; |
321 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 321 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
322 | int ret; | 322 | int ret; |
323 | 323 | ||
324 | /* set up NC codec pins */ | 324 | /* set up NC codec pins */ |
325 | if (machine_is_neo1973_gta01()) { | 325 | if (machine_is_neo1973_gta01()) { |
326 | snd_soc_dapm_nc_pin(dapm, "LOUT2"); | 326 | snd_soc_dapm_nc_pin(dapm, "LOUT2"); |
327 | snd_soc_dapm_nc_pin(dapm, "ROUT2"); | 327 | snd_soc_dapm_nc_pin(dapm, "ROUT2"); |
328 | } | 328 | } |
329 | snd_soc_dapm_nc_pin(dapm, "OUT3"); | 329 | snd_soc_dapm_nc_pin(dapm, "OUT3"); |
330 | snd_soc_dapm_nc_pin(dapm, "OUT4"); | 330 | snd_soc_dapm_nc_pin(dapm, "OUT4"); |
331 | snd_soc_dapm_nc_pin(dapm, "LINE1"); | 331 | snd_soc_dapm_nc_pin(dapm, "LINE1"); |
332 | snd_soc_dapm_nc_pin(dapm, "LINE2"); | 332 | snd_soc_dapm_nc_pin(dapm, "LINE2"); |
333 | 333 | ||
334 | /* Add neo1973 specific widgets */ | 334 | /* Add neo1973 specific widgets */ |
335 | ret = snd_soc_dapm_new_controls(dapm, neo1973_wm8753_dapm_widgets, | 335 | ret = snd_soc_dapm_new_controls(dapm, neo1973_wm8753_dapm_widgets, |
336 | ARRAY_SIZE(neo1973_wm8753_dapm_widgets)); | 336 | ARRAY_SIZE(neo1973_wm8753_dapm_widgets)); |
337 | if (ret) | 337 | if (ret) |
338 | return ret; | 338 | return ret; |
339 | 339 | ||
340 | /* add neo1973 specific controls */ | 340 | /* add neo1973 specific controls */ |
341 | ret = snd_soc_add_controls(codec, neo1973_wm8753_controls, | 341 | ret = snd_soc_add_controls(codec, neo1973_wm8753_controls, |
342 | ARRAY_SIZE(neo1973_wm8753_controls)); | 342 | ARRAY_SIZE(neo1973_wm8753_controls)); |
343 | if (ret) | 343 | if (ret) |
344 | return ret; | 344 | return ret; |
345 | 345 | ||
346 | /* set up neo1973 specific audio routes */ | 346 | /* set up neo1973 specific audio routes */ |
347 | ret = snd_soc_dapm_add_routes(dapm, neo1973_wm8753_routes, | 347 | ret = snd_soc_dapm_add_routes(dapm, neo1973_wm8753_routes, |
348 | ARRAY_SIZE(neo1973_wm8753_routes)); | 348 | ARRAY_SIZE(neo1973_wm8753_routes)); |
349 | if (ret) | 349 | if (ret) |
350 | return ret; | 350 | return ret; |
351 | 351 | ||
352 | /* set endpoints to default off mode */ | 352 | /* set endpoints to default off mode */ |
353 | snd_soc_dapm_disable_pin(dapm, "GSM Line Out"); | 353 | snd_soc_dapm_disable_pin(dapm, "GSM Line Out"); |
354 | snd_soc_dapm_disable_pin(dapm, "GSM Line In"); | 354 | snd_soc_dapm_disable_pin(dapm, "GSM Line In"); |
355 | snd_soc_dapm_disable_pin(dapm, "Headset Mic"); | 355 | snd_soc_dapm_disable_pin(dapm, "Headset Mic"); |
356 | snd_soc_dapm_disable_pin(dapm, "Handset Mic"); | 356 | snd_soc_dapm_disable_pin(dapm, "Handset Mic"); |
357 | 357 | ||
358 | /* allow audio paths from the GSM modem to run during suspend */ | 358 | /* allow audio paths from the GSM modem to run during suspend */ |
359 | snd_soc_dapm_ignore_suspend(dapm, "GSM Line Out"); | 359 | snd_soc_dapm_ignore_suspend(dapm, "GSM Line Out"); |
360 | snd_soc_dapm_ignore_suspend(dapm, "GSM Line In"); | 360 | snd_soc_dapm_ignore_suspend(dapm, "GSM Line In"); |
361 | snd_soc_dapm_ignore_suspend(dapm, "Headset Mic"); | 361 | snd_soc_dapm_ignore_suspend(dapm, "Headset Mic"); |
362 | snd_soc_dapm_ignore_suspend(dapm, "Handset Mic"); | 362 | snd_soc_dapm_ignore_suspend(dapm, "Handset Mic"); |
363 | 363 | ||
364 | if (machine_is_neo1973_gta02()) { | 364 | if (machine_is_neo1973_gta02()) { |
365 | ret = neo1973_gta02_wm8753_init(codec); | 365 | ret = neo1973_gta02_wm8753_init(codec); |
366 | if (ret) | 366 | if (ret) |
367 | return ret; | 367 | return ret; |
368 | } | 368 | } |
369 | 369 | ||
370 | snd_soc_dapm_sync(dapm); | ||
371 | |||
372 | return 0; | 370 | return 0; |
373 | } | 371 | } |
374 | 372 | ||
375 | /* GTA01 specific controls */ | 373 | /* GTA01 specific controls */ |
376 | 374 | ||
377 | #ifdef CONFIG_MACH_NEO1973_GTA01 | 375 | #ifdef CONFIG_MACH_NEO1973_GTA01 |
378 | 376 | ||
379 | static const struct snd_soc_dapm_route neo1973_lm4857_routes[] = { | 377 | static const struct snd_soc_dapm_route neo1973_lm4857_routes[] = { |
380 | {"Amp IN", NULL, "ROUT1"}, | 378 | {"Amp IN", NULL, "ROUT1"}, |
381 | {"Amp IN", NULL, "LOUT1"}, | 379 | {"Amp IN", NULL, "LOUT1"}, |
382 | 380 | ||
383 | {"Handset Spk", NULL, "Amp EP"}, | 381 | {"Handset Spk", NULL, "Amp EP"}, |
384 | {"Stereo Out", NULL, "Amp LS"}, | 382 | {"Stereo Out", NULL, "Amp LS"}, |
385 | {"Headphone", NULL, "Amp HP"}, | 383 | {"Headphone", NULL, "Amp HP"}, |
386 | }; | 384 | }; |
387 | 385 | ||
388 | static const struct snd_soc_dapm_widget neo1973_lm4857_dapm_widgets[] = { | 386 | static const struct snd_soc_dapm_widget neo1973_lm4857_dapm_widgets[] = { |
389 | SND_SOC_DAPM_SPK("Handset Spk", NULL), | 387 | SND_SOC_DAPM_SPK("Handset Spk", NULL), |
390 | SND_SOC_DAPM_SPK("Stereo Out", NULL), | 388 | SND_SOC_DAPM_SPK("Stereo Out", NULL), |
391 | SND_SOC_DAPM_HP("Headphone", NULL), | 389 | SND_SOC_DAPM_HP("Headphone", NULL), |
392 | }; | 390 | }; |
393 | 391 | ||
394 | static int neo1973_lm4857_init(struct snd_soc_dapm_context *dapm) | 392 | static int neo1973_lm4857_init(struct snd_soc_dapm_context *dapm) |
395 | { | 393 | { |
396 | int ret; | 394 | int ret; |
397 | 395 | ||
398 | ret = snd_soc_dapm_new_controls(dapm, neo1973_lm4857_dapm_widgets, | 396 | ret = snd_soc_dapm_new_controls(dapm, neo1973_lm4857_dapm_widgets, |
399 | ARRAY_SIZE(neo1973_lm4857_dapm_widgets)); | 397 | ARRAY_SIZE(neo1973_lm4857_dapm_widgets)); |
400 | if (ret) | 398 | if (ret) |
401 | return ret; | 399 | return ret; |
402 | 400 | ||
403 | ret = snd_soc_dapm_add_routes(dapm, neo1973_lm4857_routes, | 401 | ret = snd_soc_dapm_add_routes(dapm, neo1973_lm4857_routes, |
404 | ARRAY_SIZE(neo1973_lm4857_routes)); | 402 | ARRAY_SIZE(neo1973_lm4857_routes)); |
405 | if (ret) | 403 | if (ret) |
406 | return ret; | 404 | return ret; |
407 | 405 | ||
408 | snd_soc_dapm_ignore_suspend(dapm, "Stereo Out"); | 406 | snd_soc_dapm_ignore_suspend(dapm, "Stereo Out"); |
409 | snd_soc_dapm_ignore_suspend(dapm, "Handset Spk"); | 407 | snd_soc_dapm_ignore_suspend(dapm, "Handset Spk"); |
410 | snd_soc_dapm_ignore_suspend(dapm, "Headphone"); | 408 | snd_soc_dapm_ignore_suspend(dapm, "Headphone"); |
411 | |||
412 | snd_soc_dapm_sync(dapm); | ||
413 | 409 | ||
414 | return 0; | 410 | return 0; |
415 | } | 411 | } |
416 | 412 | ||
417 | #else | 413 | #else |
418 | static int neo1973_lm4857_init(struct snd_soc_dapm_context *dapm) { return 0; }; | 414 | static int neo1973_lm4857_init(struct snd_soc_dapm_context *dapm) { return 0; }; |
419 | #endif | 415 | #endif |
420 | 416 | ||
421 | static struct snd_soc_dai_link neo1973_dai[] = { | 417 | static struct snd_soc_dai_link neo1973_dai[] = { |
422 | { /* Hifi Playback - for similatious use with voice below */ | 418 | { /* Hifi Playback - for similatious use with voice below */ |
423 | .name = "WM8753", | 419 | .name = "WM8753", |
424 | .stream_name = "WM8753 HiFi", | 420 | .stream_name = "WM8753 HiFi", |
425 | .platform_name = "samsung-audio", | 421 | .platform_name = "samsung-audio", |
426 | .cpu_dai_name = "s3c24xx-iis", | 422 | .cpu_dai_name = "s3c24xx-iis", |
427 | .codec_dai_name = "wm8753-hifi", | 423 | .codec_dai_name = "wm8753-hifi", |
428 | .codec_name = "wm8753-codec.0-001a", | 424 | .codec_name = "wm8753-codec.0-001a", |
429 | .init = neo1973_wm8753_init, | 425 | .init = neo1973_wm8753_init, |
430 | .ops = &neo1973_hifi_ops, | 426 | .ops = &neo1973_hifi_ops, |
431 | }, | 427 | }, |
432 | { /* Voice via BT */ | 428 | { /* Voice via BT */ |
433 | .name = "Bluetooth", | 429 | .name = "Bluetooth", |
434 | .stream_name = "Voice", | 430 | .stream_name = "Voice", |
435 | .cpu_dai_name = "dfbmcs320-pcm", | 431 | .cpu_dai_name = "dfbmcs320-pcm", |
436 | .codec_dai_name = "wm8753-voice", | 432 | .codec_dai_name = "wm8753-voice", |
437 | .codec_name = "wm8753-codec.0-001a", | 433 | .codec_name = "wm8753-codec.0-001a", |
438 | .ops = &neo1973_voice_ops, | 434 | .ops = &neo1973_voice_ops, |
439 | }, | 435 | }, |
440 | }; | 436 | }; |
441 | 437 | ||
442 | static struct snd_soc_aux_dev neo1973_aux_devs[] = { | 438 | static struct snd_soc_aux_dev neo1973_aux_devs[] = { |
443 | { | 439 | { |
444 | .name = "dfbmcs320", | 440 | .name = "dfbmcs320", |
445 | .codec_name = "dfbmcs320.0", | 441 | .codec_name = "dfbmcs320.0", |
446 | }, | 442 | }, |
447 | { | 443 | { |
448 | .name = "lm4857", | 444 | .name = "lm4857", |
449 | .codec_name = "lm4857.0-007c", | 445 | .codec_name = "lm4857.0-007c", |
450 | .init = neo1973_lm4857_init, | 446 | .init = neo1973_lm4857_init, |
451 | }, | 447 | }, |
452 | }; | 448 | }; |
453 | 449 | ||
454 | static struct snd_soc_codec_conf neo1973_codec_conf[] = { | 450 | static struct snd_soc_codec_conf neo1973_codec_conf[] = { |
455 | { | 451 | { |
456 | .dev_name = "lm4857.0-007c", | 452 | .dev_name = "lm4857.0-007c", |
457 | .name_prefix = "Amp", | 453 | .name_prefix = "Amp", |
458 | }, | 454 | }, |
459 | }; | 455 | }; |
460 | 456 | ||
461 | #ifdef CONFIG_MACH_NEO1973_GTA02 | 457 | #ifdef CONFIG_MACH_NEO1973_GTA02 |
462 | static const struct gpio neo1973_gta02_gpios[] = { | 458 | static const struct gpio neo1973_gta02_gpios[] = { |
463 | { GTA02_GPIO_HP_IN, GPIOF_OUT_INIT_HIGH, "GTA02_HP_IN" }, | 459 | { GTA02_GPIO_HP_IN, GPIOF_OUT_INIT_HIGH, "GTA02_HP_IN" }, |
464 | { GTA02_GPIO_AMP_SHUT, GPIOF_OUT_INIT_HIGH, "GTA02_AMP_SHUT" }, | 460 | { GTA02_GPIO_AMP_SHUT, GPIOF_OUT_INIT_HIGH, "GTA02_AMP_SHUT" }, |
465 | }; | 461 | }; |
466 | #else | 462 | #else |
467 | static const struct gpio neo1973_gta02_gpios[] = {}; | 463 | static const struct gpio neo1973_gta02_gpios[] = {}; |
468 | #endif | 464 | #endif |
469 | 465 | ||
470 | static struct snd_soc_card neo1973 = { | 466 | static struct snd_soc_card neo1973 = { |
471 | .name = "neo1973", | 467 | .name = "neo1973", |
472 | .dai_link = neo1973_dai, | 468 | .dai_link = neo1973_dai, |
473 | .num_links = ARRAY_SIZE(neo1973_dai), | 469 | .num_links = ARRAY_SIZE(neo1973_dai), |
474 | .aux_dev = neo1973_aux_devs, | 470 | .aux_dev = neo1973_aux_devs, |
475 | .num_aux_devs = ARRAY_SIZE(neo1973_aux_devs), | 471 | .num_aux_devs = ARRAY_SIZE(neo1973_aux_devs), |
476 | .codec_conf = neo1973_codec_conf, | 472 | .codec_conf = neo1973_codec_conf, |
477 | .num_configs = ARRAY_SIZE(neo1973_codec_conf), | 473 | .num_configs = ARRAY_SIZE(neo1973_codec_conf), |
478 | }; | 474 | }; |
479 | 475 | ||
480 | static struct platform_device *neo1973_snd_device; | 476 | static struct platform_device *neo1973_snd_device; |
481 | 477 | ||
482 | static int __init neo1973_init(void) | 478 | static int __init neo1973_init(void) |
483 | { | 479 | { |
484 | int ret; | 480 | int ret; |
485 | 481 | ||
486 | if (!machine_is_neo1973_gta01() && !machine_is_neo1973_gta02()) | 482 | if (!machine_is_neo1973_gta01() && !machine_is_neo1973_gta02()) |
487 | return -ENODEV; | 483 | return -ENODEV; |
488 | 484 | ||
489 | if (machine_is_neo1973_gta02()) { | 485 | if (machine_is_neo1973_gta02()) { |
490 | neo1973.name = "neo1973gta02"; | 486 | neo1973.name = "neo1973gta02"; |
491 | neo1973.num_aux_devs = 1; | 487 | neo1973.num_aux_devs = 1; |
492 | 488 | ||
493 | ret = gpio_request_array(neo1973_gta02_gpios, | 489 | ret = gpio_request_array(neo1973_gta02_gpios, |
494 | ARRAY_SIZE(neo1973_gta02_gpios)); | 490 | ARRAY_SIZE(neo1973_gta02_gpios)); |
495 | if (ret) | 491 | if (ret) |
496 | return ret; | 492 | return ret; |
497 | } | 493 | } |
498 | 494 | ||
499 | neo1973_snd_device = platform_device_alloc("soc-audio", -1); | 495 | neo1973_snd_device = platform_device_alloc("soc-audio", -1); |
500 | if (!neo1973_snd_device) { | 496 | if (!neo1973_snd_device) { |
501 | ret = -ENOMEM; | 497 | ret = -ENOMEM; |
502 | goto err_gpio_free; | 498 | goto err_gpio_free; |
503 | } | 499 | } |
504 | 500 | ||
505 | platform_set_drvdata(neo1973_snd_device, &neo1973); | 501 | platform_set_drvdata(neo1973_snd_device, &neo1973); |
506 | ret = platform_device_add(neo1973_snd_device); | 502 | ret = platform_device_add(neo1973_snd_device); |
507 | 503 | ||
508 | if (ret) | 504 | if (ret) |
509 | goto err_put_device; | 505 | goto err_put_device; |
510 | 506 | ||
511 | return 0; | 507 | return 0; |
512 | 508 | ||
513 | err_put_device: | 509 | err_put_device: |
514 | platform_device_put(neo1973_snd_device); | 510 | platform_device_put(neo1973_snd_device); |
515 | err_gpio_free: | 511 | err_gpio_free: |
516 | if (machine_is_neo1973_gta02()) { | 512 | if (machine_is_neo1973_gta02()) { |
517 | gpio_free_array(neo1973_gta02_gpios, | 513 | gpio_free_array(neo1973_gta02_gpios, |
518 | ARRAY_SIZE(neo1973_gta02_gpios)); | 514 | ARRAY_SIZE(neo1973_gta02_gpios)); |
519 | } | 515 | } |
520 | return ret; | 516 | return ret; |
521 | } | 517 | } |
522 | module_init(neo1973_init); | 518 | module_init(neo1973_init); |
523 | 519 | ||
524 | static void __exit neo1973_exit(void) | 520 | static void __exit neo1973_exit(void) |
525 | { | 521 | { |
526 | platform_device_unregister(neo1973_snd_device); | 522 | platform_device_unregister(neo1973_snd_device); |
527 | 523 | ||
528 | if (machine_is_neo1973_gta02()) { | 524 | if (machine_is_neo1973_gta02()) { |
529 | gpio_free_array(neo1973_gta02_gpios, | 525 | gpio_free_array(neo1973_gta02_gpios, |
530 | ARRAY_SIZE(neo1973_gta02_gpios)); | 526 | ARRAY_SIZE(neo1973_gta02_gpios)); |
531 | } | 527 | } |
532 | } | 528 | } |
533 | module_exit(neo1973_exit); | 529 | module_exit(neo1973_exit); |
534 | 530 | ||
535 | /* Module information */ | 531 | /* Module information */ |
536 | MODULE_AUTHOR("Graeme Gregory, graeme@openmoko.org, www.openmoko.org"); | 532 | MODULE_AUTHOR("Graeme Gregory, graeme@openmoko.org, www.openmoko.org"); |
537 | MODULE_DESCRIPTION("ALSA SoC WM8753 Neo1973 and Frerunner"); | 533 | MODULE_DESCRIPTION("ALSA SoC WM8753 Neo1973 and Frerunner"); |
538 | MODULE_LICENSE("GPL"); | 534 | MODULE_LICENSE("GPL"); |
539 | 535 |
sound/soc/samsung/rx1950_uda1380.c
1 | /* | 1 | /* |
2 | * rx1950.c -- ALSA Soc Audio Layer | 2 | * rx1950.c -- ALSA Soc Audio Layer |
3 | * | 3 | * |
4 | * Copyright (c) 2010 Vasily Khoruzhick <anarsoul@gmail.com> | 4 | * Copyright (c) 2010 Vasily Khoruzhick <anarsoul@gmail.com> |
5 | * | 5 | * |
6 | * Based on smdk2440.c and magician.c | 6 | * Based on smdk2440.c and magician.c |
7 | * | 7 | * |
8 | * Authors: Graeme Gregory graeme.gregory@wolfsonmicro.com | 8 | * Authors: Graeme Gregory graeme.gregory@wolfsonmicro.com |
9 | * Philipp Zabel <philipp.zabel@gmail.com> | 9 | * Philipp Zabel <philipp.zabel@gmail.com> |
10 | * Denis Grigoriev <dgreenday@gmail.com> | 10 | * Denis Grigoriev <dgreenday@gmail.com> |
11 | * Vasily Khoruzhick <anarsoul@gmail.com> | 11 | * Vasily Khoruzhick <anarsoul@gmail.com> |
12 | * | 12 | * |
13 | * This program is free software; you can redistribute it and/or modify it | 13 | * This program is free software; you can redistribute it and/or modify it |
14 | * under the terms of the GNU General Public License as published by the | 14 | * under the terms of the GNU General Public License as published by the |
15 | * Free Software Foundation; either version 2 of the License, or (at your | 15 | * Free Software Foundation; either version 2 of the License, or (at your |
16 | * option) any later version. | 16 | * option) any later version. |
17 | * | 17 | * |
18 | */ | 18 | */ |
19 | 19 | ||
20 | #include <linux/types.h> | 20 | #include <linux/types.h> |
21 | #include <linux/gpio.h> | 21 | #include <linux/gpio.h> |
22 | 22 | ||
23 | #include <sound/soc.h> | 23 | #include <sound/soc.h> |
24 | #include <sound/jack.h> | 24 | #include <sound/jack.h> |
25 | 25 | ||
26 | #include <plat/regs-iis.h> | 26 | #include <plat/regs-iis.h> |
27 | #include <asm/mach-types.h> | 27 | #include <asm/mach-types.h> |
28 | 28 | ||
29 | #include "s3c24xx-i2s.h" | 29 | #include "s3c24xx-i2s.h" |
30 | 30 | ||
31 | static int rx1950_uda1380_init(struct snd_soc_pcm_runtime *rtd); | 31 | static int rx1950_uda1380_init(struct snd_soc_pcm_runtime *rtd); |
32 | static int rx1950_startup(struct snd_pcm_substream *substream); | 32 | static int rx1950_startup(struct snd_pcm_substream *substream); |
33 | static int rx1950_hw_params(struct snd_pcm_substream *substream, | 33 | static int rx1950_hw_params(struct snd_pcm_substream *substream, |
34 | struct snd_pcm_hw_params *params); | 34 | struct snd_pcm_hw_params *params); |
35 | static int rx1950_spk_power(struct snd_soc_dapm_widget *w, | 35 | static int rx1950_spk_power(struct snd_soc_dapm_widget *w, |
36 | struct snd_kcontrol *kcontrol, int event); | 36 | struct snd_kcontrol *kcontrol, int event); |
37 | 37 | ||
38 | static unsigned int rates[] = { | 38 | static unsigned int rates[] = { |
39 | 16000, | 39 | 16000, |
40 | 44100, | 40 | 44100, |
41 | 48000, | 41 | 48000, |
42 | }; | 42 | }; |
43 | 43 | ||
44 | static struct snd_pcm_hw_constraint_list hw_rates = { | 44 | static struct snd_pcm_hw_constraint_list hw_rates = { |
45 | .count = ARRAY_SIZE(rates), | 45 | .count = ARRAY_SIZE(rates), |
46 | .list = rates, | 46 | .list = rates, |
47 | .mask = 0, | 47 | .mask = 0, |
48 | }; | 48 | }; |
49 | 49 | ||
50 | static struct snd_soc_jack hp_jack; | 50 | static struct snd_soc_jack hp_jack; |
51 | 51 | ||
52 | static struct snd_soc_jack_pin hp_jack_pins[] = { | 52 | static struct snd_soc_jack_pin hp_jack_pins[] = { |
53 | { | 53 | { |
54 | .pin = "Headphone Jack", | 54 | .pin = "Headphone Jack", |
55 | .mask = SND_JACK_HEADPHONE, | 55 | .mask = SND_JACK_HEADPHONE, |
56 | }, | 56 | }, |
57 | { | 57 | { |
58 | .pin = "Speaker", | 58 | .pin = "Speaker", |
59 | .mask = SND_JACK_HEADPHONE, | 59 | .mask = SND_JACK_HEADPHONE, |
60 | .invert = 1, | 60 | .invert = 1, |
61 | }, | 61 | }, |
62 | }; | 62 | }; |
63 | 63 | ||
64 | static struct snd_soc_jack_gpio hp_jack_gpios[] = { | 64 | static struct snd_soc_jack_gpio hp_jack_gpios[] = { |
65 | [0] = { | 65 | [0] = { |
66 | .gpio = S3C2410_GPG(12), | 66 | .gpio = S3C2410_GPG(12), |
67 | .name = "hp-gpio", | 67 | .name = "hp-gpio", |
68 | .report = SND_JACK_HEADPHONE, | 68 | .report = SND_JACK_HEADPHONE, |
69 | .invert = 1, | 69 | .invert = 1, |
70 | .debounce_time = 200, | 70 | .debounce_time = 200, |
71 | }, | 71 | }, |
72 | }; | 72 | }; |
73 | 73 | ||
74 | static struct snd_soc_ops rx1950_ops = { | 74 | static struct snd_soc_ops rx1950_ops = { |
75 | .startup = rx1950_startup, | 75 | .startup = rx1950_startup, |
76 | .hw_params = rx1950_hw_params, | 76 | .hw_params = rx1950_hw_params, |
77 | }; | 77 | }; |
78 | 78 | ||
79 | /* s3c24xx digital audio interface glue - connects codec <--> CPU */ | 79 | /* s3c24xx digital audio interface glue - connects codec <--> CPU */ |
80 | static struct snd_soc_dai_link rx1950_uda1380_dai[] = { | 80 | static struct snd_soc_dai_link rx1950_uda1380_dai[] = { |
81 | { | 81 | { |
82 | .name = "uda1380", | 82 | .name = "uda1380", |
83 | .stream_name = "UDA1380 Duplex", | 83 | .stream_name = "UDA1380 Duplex", |
84 | .cpu_dai_name = "s3c24xx-iis", | 84 | .cpu_dai_name = "s3c24xx-iis", |
85 | .codec_dai_name = "uda1380-hifi", | 85 | .codec_dai_name = "uda1380-hifi", |
86 | .init = rx1950_uda1380_init, | 86 | .init = rx1950_uda1380_init, |
87 | .platform_name = "samsung-audio", | 87 | .platform_name = "samsung-audio", |
88 | .codec_name = "uda1380-codec.0-001a", | 88 | .codec_name = "uda1380-codec.0-001a", |
89 | .ops = &rx1950_ops, | 89 | .ops = &rx1950_ops, |
90 | }, | 90 | }, |
91 | }; | 91 | }; |
92 | 92 | ||
93 | static struct snd_soc_card rx1950_asoc = { | 93 | static struct snd_soc_card rx1950_asoc = { |
94 | .name = "rx1950", | 94 | .name = "rx1950", |
95 | .dai_link = rx1950_uda1380_dai, | 95 | .dai_link = rx1950_uda1380_dai, |
96 | .num_links = ARRAY_SIZE(rx1950_uda1380_dai), | 96 | .num_links = ARRAY_SIZE(rx1950_uda1380_dai), |
97 | }; | 97 | }; |
98 | 98 | ||
99 | /* rx1950 machine dapm widgets */ | 99 | /* rx1950 machine dapm widgets */ |
100 | static const struct snd_soc_dapm_widget uda1380_dapm_widgets[] = { | 100 | static const struct snd_soc_dapm_widget uda1380_dapm_widgets[] = { |
101 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | 101 | SND_SOC_DAPM_HP("Headphone Jack", NULL), |
102 | SND_SOC_DAPM_MIC("Mic Jack", NULL), | 102 | SND_SOC_DAPM_MIC("Mic Jack", NULL), |
103 | SND_SOC_DAPM_SPK("Speaker", rx1950_spk_power), | 103 | SND_SOC_DAPM_SPK("Speaker", rx1950_spk_power), |
104 | }; | 104 | }; |
105 | 105 | ||
106 | /* rx1950 machine audio_map */ | 106 | /* rx1950 machine audio_map */ |
107 | static const struct snd_soc_dapm_route audio_map[] = { | 107 | static const struct snd_soc_dapm_route audio_map[] = { |
108 | /* headphone connected to VOUTLHP, VOUTRHP */ | 108 | /* headphone connected to VOUTLHP, VOUTRHP */ |
109 | {"Headphone Jack", NULL, "VOUTLHP"}, | 109 | {"Headphone Jack", NULL, "VOUTLHP"}, |
110 | {"Headphone Jack", NULL, "VOUTRHP"}, | 110 | {"Headphone Jack", NULL, "VOUTRHP"}, |
111 | 111 | ||
112 | /* ext speaker connected to VOUTL, VOUTR */ | 112 | /* ext speaker connected to VOUTL, VOUTR */ |
113 | {"Speaker", NULL, "VOUTL"}, | 113 | {"Speaker", NULL, "VOUTL"}, |
114 | {"Speaker", NULL, "VOUTR"}, | 114 | {"Speaker", NULL, "VOUTR"}, |
115 | 115 | ||
116 | /* mic is connected to VINM */ | 116 | /* mic is connected to VINM */ |
117 | {"VINM", NULL, "Mic Jack"}, | 117 | {"VINM", NULL, "Mic Jack"}, |
118 | }; | 118 | }; |
119 | 119 | ||
120 | static struct platform_device *s3c24xx_snd_device; | 120 | static struct platform_device *s3c24xx_snd_device; |
121 | 121 | ||
122 | static int rx1950_startup(struct snd_pcm_substream *substream) | 122 | static int rx1950_startup(struct snd_pcm_substream *substream) |
123 | { | 123 | { |
124 | struct snd_pcm_runtime *runtime = substream->runtime; | 124 | struct snd_pcm_runtime *runtime = substream->runtime; |
125 | 125 | ||
126 | runtime->hw.rate_min = hw_rates.list[0]; | 126 | runtime->hw.rate_min = hw_rates.list[0]; |
127 | runtime->hw.rate_max = hw_rates.list[hw_rates.count - 1]; | 127 | runtime->hw.rate_max = hw_rates.list[hw_rates.count - 1]; |
128 | runtime->hw.rates = SNDRV_PCM_RATE_KNOT; | 128 | runtime->hw.rates = SNDRV_PCM_RATE_KNOT; |
129 | 129 | ||
130 | return snd_pcm_hw_constraint_list(runtime, 0, | 130 | return snd_pcm_hw_constraint_list(runtime, 0, |
131 | SNDRV_PCM_HW_PARAM_RATE, | 131 | SNDRV_PCM_HW_PARAM_RATE, |
132 | &hw_rates); | 132 | &hw_rates); |
133 | } | 133 | } |
134 | 134 | ||
135 | static int rx1950_spk_power(struct snd_soc_dapm_widget *w, | 135 | static int rx1950_spk_power(struct snd_soc_dapm_widget *w, |
136 | struct snd_kcontrol *kcontrol, int event) | 136 | struct snd_kcontrol *kcontrol, int event) |
137 | { | 137 | { |
138 | if (SND_SOC_DAPM_EVENT_ON(event)) | 138 | if (SND_SOC_DAPM_EVENT_ON(event)) |
139 | gpio_set_value(S3C2410_GPA(1), 1); | 139 | gpio_set_value(S3C2410_GPA(1), 1); |
140 | else | 140 | else |
141 | gpio_set_value(S3C2410_GPA(1), 0); | 141 | gpio_set_value(S3C2410_GPA(1), 0); |
142 | 142 | ||
143 | return 0; | 143 | return 0; |
144 | } | 144 | } |
145 | 145 | ||
146 | static int rx1950_hw_params(struct snd_pcm_substream *substream, | 146 | static int rx1950_hw_params(struct snd_pcm_substream *substream, |
147 | struct snd_pcm_hw_params *params) | 147 | struct snd_pcm_hw_params *params) |
148 | { | 148 | { |
149 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 149 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
150 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 150 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
151 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 151 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
152 | int div; | 152 | int div; |
153 | int ret; | 153 | int ret; |
154 | unsigned int rate = params_rate(params); | 154 | unsigned int rate = params_rate(params); |
155 | int clk_source, fs_mode; | 155 | int clk_source, fs_mode; |
156 | 156 | ||
157 | switch (rate) { | 157 | switch (rate) { |
158 | case 16000: | 158 | case 16000: |
159 | case 48000: | 159 | case 48000: |
160 | clk_source = S3C24XX_CLKSRC_PCLK; | 160 | clk_source = S3C24XX_CLKSRC_PCLK; |
161 | fs_mode = S3C2410_IISMOD_256FS; | 161 | fs_mode = S3C2410_IISMOD_256FS; |
162 | div = s3c24xx_i2s_get_clockrate() / (256 * rate); | 162 | div = s3c24xx_i2s_get_clockrate() / (256 * rate); |
163 | if (s3c24xx_i2s_get_clockrate() % (256 * rate) > (128 * rate)) | 163 | if (s3c24xx_i2s_get_clockrate() % (256 * rate) > (128 * rate)) |
164 | div++; | 164 | div++; |
165 | break; | 165 | break; |
166 | case 44100: | 166 | case 44100: |
167 | case 88200: | 167 | case 88200: |
168 | clk_source = S3C24XX_CLKSRC_MPLL; | 168 | clk_source = S3C24XX_CLKSRC_MPLL; |
169 | fs_mode = S3C2410_IISMOD_384FS; | 169 | fs_mode = S3C2410_IISMOD_384FS; |
170 | div = 1; | 170 | div = 1; |
171 | break; | 171 | break; |
172 | default: | 172 | default: |
173 | printk(KERN_ERR "%s: rate %d is not supported\n", | 173 | printk(KERN_ERR "%s: rate %d is not supported\n", |
174 | __func__, rate); | 174 | __func__, rate); |
175 | return -EINVAL; | 175 | return -EINVAL; |
176 | } | 176 | } |
177 | 177 | ||
178 | /* set codec DAI configuration */ | 178 | /* set codec DAI configuration */ |
179 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | | 179 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | |
180 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); | 180 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); |
181 | if (ret < 0) | 181 | if (ret < 0) |
182 | return ret; | 182 | return ret; |
183 | 183 | ||
184 | /* set cpu DAI configuration */ | 184 | /* set cpu DAI configuration */ |
185 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | | 185 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | |
186 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); | 186 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); |
187 | if (ret < 0) | 187 | if (ret < 0) |
188 | return ret; | 188 | return ret; |
189 | 189 | ||
190 | /* select clock source */ | 190 | /* select clock source */ |
191 | ret = snd_soc_dai_set_sysclk(cpu_dai, clk_source, rate, | 191 | ret = snd_soc_dai_set_sysclk(cpu_dai, clk_source, rate, |
192 | SND_SOC_CLOCK_OUT); | 192 | SND_SOC_CLOCK_OUT); |
193 | if (ret < 0) | 193 | if (ret < 0) |
194 | return ret; | 194 | return ret; |
195 | 195 | ||
196 | /* set MCLK division for sample rate */ | 196 | /* set MCLK division for sample rate */ |
197 | ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK, | 197 | ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK, |
198 | fs_mode); | 198 | fs_mode); |
199 | if (ret < 0) | 199 | if (ret < 0) |
200 | return ret; | 200 | return ret; |
201 | 201 | ||
202 | /* set BCLK division for sample rate */ | 202 | /* set BCLK division for sample rate */ |
203 | ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_BCLK, | 203 | ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_BCLK, |
204 | S3C2410_IISMOD_32FS); | 204 | S3C2410_IISMOD_32FS); |
205 | if (ret < 0) | 205 | if (ret < 0) |
206 | return ret; | 206 | return ret; |
207 | 207 | ||
208 | /* set prescaler division for sample rate */ | 208 | /* set prescaler division for sample rate */ |
209 | ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER, | 209 | ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER, |
210 | S3C24XX_PRESCALE(div, div)); | 210 | S3C24XX_PRESCALE(div, div)); |
211 | if (ret < 0) | 211 | if (ret < 0) |
212 | return ret; | 212 | return ret; |
213 | 213 | ||
214 | return 0; | 214 | return 0; |
215 | } | 215 | } |
216 | 216 | ||
217 | static int rx1950_uda1380_init(struct snd_soc_pcm_runtime *rtd) | 217 | static int rx1950_uda1380_init(struct snd_soc_pcm_runtime *rtd) |
218 | { | 218 | { |
219 | struct snd_soc_codec *codec = rtd->codec; | 219 | struct snd_soc_codec *codec = rtd->codec; |
220 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 220 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
221 | int err; | 221 | int err; |
222 | 222 | ||
223 | /* Add rx1950 specific widgets */ | 223 | /* Add rx1950 specific widgets */ |
224 | err = snd_soc_dapm_new_controls(dapm, uda1380_dapm_widgets, | 224 | err = snd_soc_dapm_new_controls(dapm, uda1380_dapm_widgets, |
225 | ARRAY_SIZE(uda1380_dapm_widgets)); | 225 | ARRAY_SIZE(uda1380_dapm_widgets)); |
226 | 226 | ||
227 | if (err) | 227 | if (err) |
228 | return err; | 228 | return err; |
229 | 229 | ||
230 | /* Set up rx1950 specific audio path audio_mapnects */ | 230 | /* Set up rx1950 specific audio path audio_mapnects */ |
231 | err = snd_soc_dapm_add_routes(dapm, audio_map, | 231 | err = snd_soc_dapm_add_routes(dapm, audio_map, |
232 | ARRAY_SIZE(audio_map)); | 232 | ARRAY_SIZE(audio_map)); |
233 | 233 | ||
234 | if (err) | 234 | if (err) |
235 | return err; | 235 | return err; |
236 | 236 | ||
237 | snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); | 237 | snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); |
238 | snd_soc_dapm_enable_pin(dapm, "Speaker"); | 238 | snd_soc_dapm_enable_pin(dapm, "Speaker"); |
239 | snd_soc_dapm_enable_pin(dapm, "Mic Jack"); | 239 | snd_soc_dapm_enable_pin(dapm, "Mic Jack"); |
240 | 240 | ||
241 | snd_soc_dapm_sync(dapm); | ||
242 | |||
243 | snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE, | 241 | snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE, |
244 | &hp_jack); | 242 | &hp_jack); |
245 | 243 | ||
246 | snd_soc_jack_add_pins(&hp_jack, ARRAY_SIZE(hp_jack_pins), | 244 | snd_soc_jack_add_pins(&hp_jack, ARRAY_SIZE(hp_jack_pins), |
247 | hp_jack_pins); | 245 | hp_jack_pins); |
248 | 246 | ||
249 | snd_soc_jack_add_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios), | 247 | snd_soc_jack_add_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios), |
250 | hp_jack_gpios); | 248 | hp_jack_gpios); |
251 | 249 | ||
252 | return 0; | 250 | return 0; |
253 | } | 251 | } |
254 | 252 | ||
255 | static int __init rx1950_init(void) | 253 | static int __init rx1950_init(void) |
256 | { | 254 | { |
257 | int ret; | 255 | int ret; |
258 | 256 | ||
259 | if (!machine_is_rx1950()) | 257 | if (!machine_is_rx1950()) |
260 | return -ENODEV; | 258 | return -ENODEV; |
261 | 259 | ||
262 | /* configure some gpios */ | 260 | /* configure some gpios */ |
263 | ret = gpio_request(S3C2410_GPA(1), "speaker-power"); | 261 | ret = gpio_request(S3C2410_GPA(1), "speaker-power"); |
264 | if (ret) | 262 | if (ret) |
265 | goto err_gpio; | 263 | goto err_gpio; |
266 | 264 | ||
267 | ret = gpio_direction_output(S3C2410_GPA(1), 0); | 265 | ret = gpio_direction_output(S3C2410_GPA(1), 0); |
268 | if (ret) | 266 | if (ret) |
269 | goto err_gpio_conf; | 267 | goto err_gpio_conf; |
270 | 268 | ||
271 | s3c24xx_snd_device = platform_device_alloc("soc-audio", -1); | 269 | s3c24xx_snd_device = platform_device_alloc("soc-audio", -1); |
272 | if (!s3c24xx_snd_device) { | 270 | if (!s3c24xx_snd_device) { |
273 | ret = -ENOMEM; | 271 | ret = -ENOMEM; |
274 | goto err_plat_alloc; | 272 | goto err_plat_alloc; |
275 | } | 273 | } |
276 | 274 | ||
277 | platform_set_drvdata(s3c24xx_snd_device, &rx1950_asoc); | 275 | platform_set_drvdata(s3c24xx_snd_device, &rx1950_asoc); |
278 | ret = platform_device_add(s3c24xx_snd_device); | 276 | ret = platform_device_add(s3c24xx_snd_device); |
279 | 277 | ||
280 | if (ret) { | 278 | if (ret) { |
281 | platform_device_put(s3c24xx_snd_device); | 279 | platform_device_put(s3c24xx_snd_device); |
282 | goto err_plat_add; | 280 | goto err_plat_add; |
283 | } | 281 | } |
284 | 282 | ||
285 | return 0; | 283 | return 0; |
286 | 284 | ||
287 | err_plat_add: | 285 | err_plat_add: |
288 | err_plat_alloc: | 286 | err_plat_alloc: |
289 | err_gpio_conf: | 287 | err_gpio_conf: |
290 | gpio_free(S3C2410_GPA(1)); | 288 | gpio_free(S3C2410_GPA(1)); |
291 | 289 | ||
292 | err_gpio: | 290 | err_gpio: |
293 | return ret; | 291 | return ret; |
294 | } | 292 | } |
295 | 293 | ||
296 | static void __exit rx1950_exit(void) | 294 | static void __exit rx1950_exit(void) |
297 | { | 295 | { |
298 | platform_device_unregister(s3c24xx_snd_device); | 296 | platform_device_unregister(s3c24xx_snd_device); |
299 | snd_soc_jack_free_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios), | 297 | snd_soc_jack_free_gpios(&hp_jack, ARRAY_SIZE(hp_jack_gpios), |
300 | hp_jack_gpios); | 298 | hp_jack_gpios); |
301 | gpio_free(S3C2410_GPA(1)); | 299 | gpio_free(S3C2410_GPA(1)); |
302 | } | 300 | } |
303 | 301 | ||
304 | module_init(rx1950_init); | 302 | module_init(rx1950_init); |
305 | module_exit(rx1950_exit); | 303 | module_exit(rx1950_exit); |
306 | 304 | ||
307 | /* Module information */ | 305 | /* Module information */ |
308 | MODULE_AUTHOR("Vasily Khoruzhick"); | 306 | MODULE_AUTHOR("Vasily Khoruzhick"); |
309 | MODULE_DESCRIPTION("ALSA SoC RX1950"); | 307 | MODULE_DESCRIPTION("ALSA SoC RX1950"); |
310 | MODULE_LICENSE("GPL"); | 308 | MODULE_LICENSE("GPL"); |
311 | 309 |
sound/soc/samsung/s3c24xx_simtec_hermes.c
1 | /* sound/soc/samsung/s3c24xx_simtec_hermes.c | 1 | /* sound/soc/samsung/s3c24xx_simtec_hermes.c |
2 | * | 2 | * |
3 | * Copyright 2009 Simtec Electronics | 3 | * Copyright 2009 Simtec Electronics |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify | 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 | 6 | * it under the terms of the GNU General Public License version 2 as |
7 | * published by the Free Software Foundation. | 7 | * published by the Free Software Foundation. |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include <sound/soc.h> | 10 | #include <sound/soc.h> |
11 | 11 | ||
12 | #include "s3c24xx_simtec.h" | 12 | #include "s3c24xx_simtec.h" |
13 | 13 | ||
14 | static const struct snd_soc_dapm_widget dapm_widgets[] = { | 14 | static const struct snd_soc_dapm_widget dapm_widgets[] = { |
15 | SND_SOC_DAPM_LINE("GSM Out", NULL), | 15 | SND_SOC_DAPM_LINE("GSM Out", NULL), |
16 | SND_SOC_DAPM_LINE("GSM In", NULL), | 16 | SND_SOC_DAPM_LINE("GSM In", NULL), |
17 | SND_SOC_DAPM_LINE("Line In", NULL), | 17 | SND_SOC_DAPM_LINE("Line In", NULL), |
18 | SND_SOC_DAPM_LINE("Line Out", NULL), | 18 | SND_SOC_DAPM_LINE("Line Out", NULL), |
19 | SND_SOC_DAPM_LINE("ZV", NULL), | 19 | SND_SOC_DAPM_LINE("ZV", NULL), |
20 | SND_SOC_DAPM_MIC("Mic Jack", NULL), | 20 | SND_SOC_DAPM_MIC("Mic Jack", NULL), |
21 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | 21 | SND_SOC_DAPM_HP("Headphone Jack", NULL), |
22 | }; | 22 | }; |
23 | 23 | ||
24 | static const struct snd_soc_dapm_route base_map[] = { | 24 | static const struct snd_soc_dapm_route base_map[] = { |
25 | /* Headphone connected to HP{L,R}OUT and HP{L,R}COM */ | 25 | /* Headphone connected to HP{L,R}OUT and HP{L,R}COM */ |
26 | 26 | ||
27 | { "Headphone Jack", NULL, "HPLOUT" }, | 27 | { "Headphone Jack", NULL, "HPLOUT" }, |
28 | { "Headphone Jack", NULL, "HPLCOM" }, | 28 | { "Headphone Jack", NULL, "HPLCOM" }, |
29 | { "Headphone Jack", NULL, "HPROUT" }, | 29 | { "Headphone Jack", NULL, "HPROUT" }, |
30 | { "Headphone Jack", NULL, "HPRCOM" }, | 30 | { "Headphone Jack", NULL, "HPRCOM" }, |
31 | 31 | ||
32 | /* ZV connected to Line1 */ | 32 | /* ZV connected to Line1 */ |
33 | 33 | ||
34 | { "LINE1L", NULL, "ZV" }, | 34 | { "LINE1L", NULL, "ZV" }, |
35 | { "LINE1R", NULL, "ZV" }, | 35 | { "LINE1R", NULL, "ZV" }, |
36 | 36 | ||
37 | /* Line In connected to Line2 */ | 37 | /* Line In connected to Line2 */ |
38 | 38 | ||
39 | { "LINE2L", NULL, "Line In" }, | 39 | { "LINE2L", NULL, "Line In" }, |
40 | { "LINE2R", NULL, "Line In" }, | 40 | { "LINE2R", NULL, "Line In" }, |
41 | 41 | ||
42 | /* Microphone connected to MIC3R and MIC_BIAS */ | 42 | /* Microphone connected to MIC3R and MIC_BIAS */ |
43 | 43 | ||
44 | { "MIC3L", NULL, "Mic Jack" }, | 44 | { "MIC3L", NULL, "Mic Jack" }, |
45 | 45 | ||
46 | /* GSM connected to MONO_LOUT and MIC3L (in) */ | 46 | /* GSM connected to MONO_LOUT and MIC3L (in) */ |
47 | 47 | ||
48 | { "GSM Out", NULL, "MONO_LOUT" }, | 48 | { "GSM Out", NULL, "MONO_LOUT" }, |
49 | { "MIC3L", NULL, "GSM In" }, | 49 | { "MIC3L", NULL, "GSM In" }, |
50 | 50 | ||
51 | /* Speaker is connected to LINEOUT{LN,LP,RN,RP}, however we are | 51 | /* Speaker is connected to LINEOUT{LN,LP,RN,RP}, however we are |
52 | * not using the DAPM to power it up and down as there it makes | 52 | * not using the DAPM to power it up and down as there it makes |
53 | * a click when powering up. */ | 53 | * a click when powering up. */ |
54 | }; | 54 | }; |
55 | 55 | ||
56 | /** | 56 | /** |
57 | * simtec_hermes_init - initialise and add controls | 57 | * simtec_hermes_init - initialise and add controls |
58 | * @codec; The codec instance to attach to. | 58 | * @codec; The codec instance to attach to. |
59 | * | 59 | * |
60 | * Attach our controls and configure the necessary codec | 60 | * Attach our controls and configure the necessary codec |
61 | * mappings for our sound card instance. | 61 | * mappings for our sound card instance. |
62 | */ | 62 | */ |
63 | static int simtec_hermes_init(struct snd_soc_pcm_runtime *rtd) | 63 | static int simtec_hermes_init(struct snd_soc_pcm_runtime *rtd) |
64 | { | 64 | { |
65 | struct snd_soc_codec *codec = rtd->codec; | 65 | struct snd_soc_codec *codec = rtd->codec; |
66 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 66 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
67 | 67 | ||
68 | snd_soc_dapm_new_controls(dapm, dapm_widgets, | 68 | snd_soc_dapm_new_controls(dapm, dapm_widgets, |
69 | ARRAY_SIZE(dapm_widgets)); | 69 | ARRAY_SIZE(dapm_widgets)); |
70 | 70 | ||
71 | snd_soc_dapm_add_routes(dapm, base_map, ARRAY_SIZE(base_map)); | 71 | snd_soc_dapm_add_routes(dapm, base_map, ARRAY_SIZE(base_map)); |
72 | 72 | ||
73 | snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); | 73 | snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); |
74 | snd_soc_dapm_enable_pin(dapm, "Line In"); | 74 | snd_soc_dapm_enable_pin(dapm, "Line In"); |
75 | snd_soc_dapm_enable_pin(dapm, "Line Out"); | 75 | snd_soc_dapm_enable_pin(dapm, "Line Out"); |
76 | snd_soc_dapm_enable_pin(dapm, "Mic Jack"); | 76 | snd_soc_dapm_enable_pin(dapm, "Mic Jack"); |
77 | 77 | ||
78 | simtec_audio_init(rtd); | 78 | simtec_audio_init(rtd); |
79 | snd_soc_dapm_sync(dapm); | ||
80 | 79 | ||
81 | return 0; | 80 | return 0; |
82 | } | 81 | } |
83 | 82 | ||
84 | static struct snd_soc_dai_link simtec_dai_aic33 = { | 83 | static struct snd_soc_dai_link simtec_dai_aic33 = { |
85 | .name = "tlv320aic33", | 84 | .name = "tlv320aic33", |
86 | .stream_name = "TLV320AIC33", | 85 | .stream_name = "TLV320AIC33", |
87 | .codec_name = "tlv320aic3x-codec.0-001a", | 86 | .codec_name = "tlv320aic3x-codec.0-001a", |
88 | .cpu_dai_name = "s3c24xx-iis", | 87 | .cpu_dai_name = "s3c24xx-iis", |
89 | .codec_dai_name = "tlv320aic3x-hifi", | 88 | .codec_dai_name = "tlv320aic3x-hifi", |
90 | .platform_name = "samsung-audio", | 89 | .platform_name = "samsung-audio", |
91 | .init = simtec_hermes_init, | 90 | .init = simtec_hermes_init, |
92 | }; | 91 | }; |
93 | 92 | ||
94 | /* simtec audio machine driver */ | 93 | /* simtec audio machine driver */ |
95 | static struct snd_soc_card snd_soc_machine_simtec_aic33 = { | 94 | static struct snd_soc_card snd_soc_machine_simtec_aic33 = { |
96 | .name = "Simtec-Hermes", | 95 | .name = "Simtec-Hermes", |
97 | .dai_link = &simtec_dai_aic33, | 96 | .dai_link = &simtec_dai_aic33, |
98 | .num_links = 1, | 97 | .num_links = 1, |
99 | }; | 98 | }; |
100 | 99 | ||
101 | static int __devinit simtec_audio_hermes_probe(struct platform_device *pd) | 100 | static int __devinit simtec_audio_hermes_probe(struct platform_device *pd) |
102 | { | 101 | { |
103 | dev_info(&pd->dev, "probing....\n"); | 102 | dev_info(&pd->dev, "probing....\n"); |
104 | return simtec_audio_core_probe(pd, &snd_soc_machine_simtec_aic33); | 103 | return simtec_audio_core_probe(pd, &snd_soc_machine_simtec_aic33); |
105 | } | 104 | } |
106 | 105 | ||
107 | static struct platform_driver simtec_audio_hermes_platdrv = { | 106 | static struct platform_driver simtec_audio_hermes_platdrv = { |
108 | .driver = { | 107 | .driver = { |
109 | .owner = THIS_MODULE, | 108 | .owner = THIS_MODULE, |
110 | .name = "s3c24xx-simtec-hermes-snd", | 109 | .name = "s3c24xx-simtec-hermes-snd", |
111 | .pm = simtec_audio_pm, | 110 | .pm = simtec_audio_pm, |
112 | }, | 111 | }, |
113 | .probe = simtec_audio_hermes_probe, | 112 | .probe = simtec_audio_hermes_probe, |
114 | .remove = __devexit_p(simtec_audio_remove), | 113 | .remove = __devexit_p(simtec_audio_remove), |
115 | }; | 114 | }; |
116 | 115 | ||
117 | MODULE_ALIAS("platform:s3c24xx-simtec-hermes-snd"); | 116 | MODULE_ALIAS("platform:s3c24xx-simtec-hermes-snd"); |
118 | 117 | ||
119 | static int __init simtec_hermes_modinit(void) | 118 | static int __init simtec_hermes_modinit(void) |
120 | { | 119 | { |
121 | return platform_driver_register(&simtec_audio_hermes_platdrv); | 120 | return platform_driver_register(&simtec_audio_hermes_platdrv); |
122 | } | 121 | } |
123 | 122 | ||
124 | static void __exit simtec_hermes_modexit(void) | 123 | static void __exit simtec_hermes_modexit(void) |
125 | { | 124 | { |
126 | platform_driver_unregister(&simtec_audio_hermes_platdrv); | 125 | platform_driver_unregister(&simtec_audio_hermes_platdrv); |
127 | } | 126 | } |
128 | 127 | ||
129 | module_init(simtec_hermes_modinit); | 128 | module_init(simtec_hermes_modinit); |
130 | module_exit(simtec_hermes_modexit); | 129 | module_exit(simtec_hermes_modexit); |
131 | 130 | ||
132 | MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); | 131 | MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); |
133 | MODULE_DESCRIPTION("ALSA SoC Simtec Audio support"); | 132 | MODULE_DESCRIPTION("ALSA SoC Simtec Audio support"); |
134 | MODULE_LICENSE("GPL"); | 133 | MODULE_LICENSE("GPL"); |
135 | 134 |
sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c
1 | /* sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c | 1 | /* sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c |
2 | * | 2 | * |
3 | * Copyright 2009 Simtec Electronics | 3 | * Copyright 2009 Simtec Electronics |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify | 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 | 6 | * it under the terms of the GNU General Public License version 2 as |
7 | * published by the Free Software Foundation. | 7 | * published by the Free Software Foundation. |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include <sound/soc.h> | 10 | #include <sound/soc.h> |
11 | 11 | ||
12 | #include "s3c24xx_simtec.h" | 12 | #include "s3c24xx_simtec.h" |
13 | 13 | ||
14 | /* supported machines: | 14 | /* supported machines: |
15 | * | 15 | * |
16 | * Machine Connections AMP | 16 | * Machine Connections AMP |
17 | * ------- ----------- --- | 17 | * ------- ----------- --- |
18 | * BAST MIC, HPOUT, LOUT, LIN TPA2001D1 (HPOUTL,R) (gain hardwired) | 18 | * BAST MIC, HPOUT, LOUT, LIN TPA2001D1 (HPOUTL,R) (gain hardwired) |
19 | * VR1000 HPOUT, LIN None | 19 | * VR1000 HPOUT, LIN None |
20 | * VR2000 LIN, LOUT, MIC, HP LM4871 (HPOUTL,R) | 20 | * VR2000 LIN, LOUT, MIC, HP LM4871 (HPOUTL,R) |
21 | * DePicture LIN, LOUT, MIC, HP LM4871 (HPOUTL,R) | 21 | * DePicture LIN, LOUT, MIC, HP LM4871 (HPOUTL,R) |
22 | * Anubis LIN, LOUT, MIC, HP TPA2001D1 (HPOUTL,R) | 22 | * Anubis LIN, LOUT, MIC, HP TPA2001D1 (HPOUTL,R) |
23 | */ | 23 | */ |
24 | 24 | ||
25 | static const struct snd_soc_dapm_widget dapm_widgets[] = { | 25 | static const struct snd_soc_dapm_widget dapm_widgets[] = { |
26 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | 26 | SND_SOC_DAPM_HP("Headphone Jack", NULL), |
27 | SND_SOC_DAPM_LINE("Line In", NULL), | 27 | SND_SOC_DAPM_LINE("Line In", NULL), |
28 | SND_SOC_DAPM_LINE("Line Out", NULL), | 28 | SND_SOC_DAPM_LINE("Line Out", NULL), |
29 | SND_SOC_DAPM_MIC("Mic Jack", NULL), | 29 | SND_SOC_DAPM_MIC("Mic Jack", NULL), |
30 | }; | 30 | }; |
31 | 31 | ||
32 | static const struct snd_soc_dapm_route base_map[] = { | 32 | static const struct snd_soc_dapm_route base_map[] = { |
33 | { "Headphone Jack", NULL, "LHPOUT"}, | 33 | { "Headphone Jack", NULL, "LHPOUT"}, |
34 | { "Headphone Jack", NULL, "RHPOUT"}, | 34 | { "Headphone Jack", NULL, "RHPOUT"}, |
35 | 35 | ||
36 | { "Line Out", NULL, "LOUT" }, | 36 | { "Line Out", NULL, "LOUT" }, |
37 | { "Line Out", NULL, "ROUT" }, | 37 | { "Line Out", NULL, "ROUT" }, |
38 | 38 | ||
39 | { "LLINEIN", NULL, "Line In"}, | 39 | { "LLINEIN", NULL, "Line In"}, |
40 | { "RLINEIN", NULL, "Line In"}, | 40 | { "RLINEIN", NULL, "Line In"}, |
41 | 41 | ||
42 | { "MICIN", NULL, "Mic Jack"}, | 42 | { "MICIN", NULL, "Mic Jack"}, |
43 | }; | 43 | }; |
44 | 44 | ||
45 | /** | 45 | /** |
46 | * simtec_tlv320aic23_init - initialise and add controls | 46 | * simtec_tlv320aic23_init - initialise and add controls |
47 | * @codec; The codec instance to attach to. | 47 | * @codec; The codec instance to attach to. |
48 | * | 48 | * |
49 | * Attach our controls and configure the necessary codec | 49 | * Attach our controls and configure the necessary codec |
50 | * mappings for our sound card instance. | 50 | * mappings for our sound card instance. |
51 | */ | 51 | */ |
52 | static int simtec_tlv320aic23_init(struct snd_soc_pcm_runtime *rtd) | 52 | static int simtec_tlv320aic23_init(struct snd_soc_pcm_runtime *rtd) |
53 | { | 53 | { |
54 | struct snd_soc_codec *codec = rtd->codec; | 54 | struct snd_soc_codec *codec = rtd->codec; |
55 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 55 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
56 | 56 | ||
57 | snd_soc_dapm_new_controls(dapm, dapm_widgets, | 57 | snd_soc_dapm_new_controls(dapm, dapm_widgets, |
58 | ARRAY_SIZE(dapm_widgets)); | 58 | ARRAY_SIZE(dapm_widgets)); |
59 | 59 | ||
60 | snd_soc_dapm_add_routes(dapm, base_map, ARRAY_SIZE(base_map)); | 60 | snd_soc_dapm_add_routes(dapm, base_map, ARRAY_SIZE(base_map)); |
61 | 61 | ||
62 | snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); | 62 | snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); |
63 | snd_soc_dapm_enable_pin(dapm, "Line In"); | 63 | snd_soc_dapm_enable_pin(dapm, "Line In"); |
64 | snd_soc_dapm_enable_pin(dapm, "Line Out"); | 64 | snd_soc_dapm_enable_pin(dapm, "Line Out"); |
65 | snd_soc_dapm_enable_pin(dapm, "Mic Jack"); | 65 | snd_soc_dapm_enable_pin(dapm, "Mic Jack"); |
66 | 66 | ||
67 | simtec_audio_init(rtd); | 67 | simtec_audio_init(rtd); |
68 | snd_soc_dapm_sync(dapm); | ||
69 | 68 | ||
70 | return 0; | 69 | return 0; |
71 | } | 70 | } |
72 | 71 | ||
73 | static struct snd_soc_dai_link simtec_dai_aic23 = { | 72 | static struct snd_soc_dai_link simtec_dai_aic23 = { |
74 | .name = "tlv320aic23", | 73 | .name = "tlv320aic23", |
75 | .stream_name = "TLV320AIC23", | 74 | .stream_name = "TLV320AIC23", |
76 | .codec_name = "tlv320aic3x-codec.0-001a", | 75 | .codec_name = "tlv320aic3x-codec.0-001a", |
77 | .cpu_dai_name = "s3c24xx-iis", | 76 | .cpu_dai_name = "s3c24xx-iis", |
78 | .codec_dai_name = "tlv320aic3x-hifi", | 77 | .codec_dai_name = "tlv320aic3x-hifi", |
79 | .platform_name = "samsung-audio", | 78 | .platform_name = "samsung-audio", |
80 | .init = simtec_tlv320aic23_init, | 79 | .init = simtec_tlv320aic23_init, |
81 | }; | 80 | }; |
82 | 81 | ||
83 | /* simtec audio machine driver */ | 82 | /* simtec audio machine driver */ |
84 | static struct snd_soc_card snd_soc_machine_simtec_aic23 = { | 83 | static struct snd_soc_card snd_soc_machine_simtec_aic23 = { |
85 | .name = "Simtec", | 84 | .name = "Simtec", |
86 | .dai_link = &simtec_dai_aic23, | 85 | .dai_link = &simtec_dai_aic23, |
87 | .num_links = 1, | 86 | .num_links = 1, |
88 | }; | 87 | }; |
89 | 88 | ||
90 | static int __devinit simtec_audio_tlv320aic23_probe(struct platform_device *pd) | 89 | static int __devinit simtec_audio_tlv320aic23_probe(struct platform_device *pd) |
91 | { | 90 | { |
92 | return simtec_audio_core_probe(pd, &snd_soc_machine_simtec_aic23); | 91 | return simtec_audio_core_probe(pd, &snd_soc_machine_simtec_aic23); |
93 | } | 92 | } |
94 | 93 | ||
95 | static struct platform_driver simtec_audio_tlv320aic23_platdrv = { | 94 | static struct platform_driver simtec_audio_tlv320aic23_platdrv = { |
96 | .driver = { | 95 | .driver = { |
97 | .owner = THIS_MODULE, | 96 | .owner = THIS_MODULE, |
98 | .name = "s3c24xx-simtec-tlv320aic23", | 97 | .name = "s3c24xx-simtec-tlv320aic23", |
99 | .pm = simtec_audio_pm, | 98 | .pm = simtec_audio_pm, |
100 | }, | 99 | }, |
101 | .probe = simtec_audio_tlv320aic23_probe, | 100 | .probe = simtec_audio_tlv320aic23_probe, |
102 | .remove = __devexit_p(simtec_audio_remove), | 101 | .remove = __devexit_p(simtec_audio_remove), |
103 | }; | 102 | }; |
104 | 103 | ||
105 | MODULE_ALIAS("platform:s3c24xx-simtec-tlv320aic23"); | 104 | MODULE_ALIAS("platform:s3c24xx-simtec-tlv320aic23"); |
106 | 105 | ||
107 | static int __init simtec_tlv320aic23_modinit(void) | 106 | static int __init simtec_tlv320aic23_modinit(void) |
108 | { | 107 | { |
109 | return platform_driver_register(&simtec_audio_tlv320aic23_platdrv); | 108 | return platform_driver_register(&simtec_audio_tlv320aic23_platdrv); |
110 | } | 109 | } |
111 | 110 | ||
112 | static void __exit simtec_tlv320aic23_modexit(void) | 111 | static void __exit simtec_tlv320aic23_modexit(void) |
113 | { | 112 | { |
114 | platform_driver_unregister(&simtec_audio_tlv320aic23_platdrv); | 113 | platform_driver_unregister(&simtec_audio_tlv320aic23_platdrv); |
115 | } | 114 | } |
116 | 115 | ||
117 | module_init(simtec_tlv320aic23_modinit); | 116 | module_init(simtec_tlv320aic23_modinit); |
118 | module_exit(simtec_tlv320aic23_modexit); | 117 | module_exit(simtec_tlv320aic23_modexit); |
119 | 118 | ||
120 | MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); | 119 | MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); |
121 | MODULE_DESCRIPTION("ALSA SoC Simtec Audio support"); | 120 | MODULE_DESCRIPTION("ALSA SoC Simtec Audio support"); |
122 | MODULE_LICENSE("GPL"); | 121 | MODULE_LICENSE("GPL"); |
123 | 122 |
sound/soc/samsung/smartq_wm8987.c
1 | /* sound/soc/samsung/smartq_wm8987.c | 1 | /* sound/soc/samsung/smartq_wm8987.c |
2 | * | 2 | * |
3 | * Copyright 2010 Maurus Cuelenaere <mcuelenaere@gmail.com> | 3 | * Copyright 2010 Maurus Cuelenaere <mcuelenaere@gmail.com> |
4 | * | 4 | * |
5 | * Based on smdk6410_wm8987.c | 5 | * Based on smdk6410_wm8987.c |
6 | * Copyright 2007 Wolfson Microelectronics PLC. - linux@wolfsonmicro.com | 6 | * Copyright 2007 Wolfson Microelectronics PLC. - linux@wolfsonmicro.com |
7 | * Graeme Gregory - graeme.gregory@wolfsonmicro.com | 7 | * Graeme Gregory - graeme.gregory@wolfsonmicro.com |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or modify it | 9 | * This program is free software; you can redistribute it and/or modify it |
10 | * under the terms of the GNU General Public License as published by the | 10 | * under the terms of the GNU General Public License as published by the |
11 | * Free Software Foundation; either version 2 of the License, or (at your | 11 | * Free Software Foundation; either version 2 of the License, or (at your |
12 | * option) any later version. | 12 | * option) any later version. |
13 | * | 13 | * |
14 | */ | 14 | */ |
15 | 15 | ||
16 | #include <linux/gpio.h> | 16 | #include <linux/gpio.h> |
17 | 17 | ||
18 | #include <sound/soc.h> | 18 | #include <sound/soc.h> |
19 | #include <sound/jack.h> | 19 | #include <sound/jack.h> |
20 | 20 | ||
21 | #include <asm/mach-types.h> | 21 | #include <asm/mach-types.h> |
22 | 22 | ||
23 | #include "i2s.h" | 23 | #include "i2s.h" |
24 | #include "../codecs/wm8750.h" | 24 | #include "../codecs/wm8750.h" |
25 | 25 | ||
26 | /* | 26 | /* |
27 | * WM8987 is register compatible with WM8750, so using that as base driver. | 27 | * WM8987 is register compatible with WM8750, so using that as base driver. |
28 | */ | 28 | */ |
29 | 29 | ||
30 | static struct snd_soc_card snd_soc_smartq; | 30 | static struct snd_soc_card snd_soc_smartq; |
31 | 31 | ||
32 | static int smartq_hifi_hw_params(struct snd_pcm_substream *substream, | 32 | static int smartq_hifi_hw_params(struct snd_pcm_substream *substream, |
33 | struct snd_pcm_hw_params *params) | 33 | struct snd_pcm_hw_params *params) |
34 | { | 34 | { |
35 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 35 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
36 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 36 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
37 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 37 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
38 | unsigned int clk = 0; | 38 | unsigned int clk = 0; |
39 | int ret; | 39 | int ret; |
40 | 40 | ||
41 | switch (params_rate(params)) { | 41 | switch (params_rate(params)) { |
42 | case 8000: | 42 | case 8000: |
43 | case 16000: | 43 | case 16000: |
44 | case 32000: | 44 | case 32000: |
45 | case 48000: | 45 | case 48000: |
46 | case 96000: | 46 | case 96000: |
47 | clk = 12288000; | 47 | clk = 12288000; |
48 | break; | 48 | break; |
49 | case 11025: | 49 | case 11025: |
50 | case 22050: | 50 | case 22050: |
51 | case 44100: | 51 | case 44100: |
52 | case 88200: | 52 | case 88200: |
53 | clk = 11289600; | 53 | clk = 11289600; |
54 | break; | 54 | break; |
55 | } | 55 | } |
56 | 56 | ||
57 | /* set codec DAI configuration */ | 57 | /* set codec DAI configuration */ |
58 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | | 58 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | |
59 | SND_SOC_DAIFMT_NB_NF | | 59 | SND_SOC_DAIFMT_NB_NF | |
60 | SND_SOC_DAIFMT_CBS_CFS); | 60 | SND_SOC_DAIFMT_CBS_CFS); |
61 | if (ret < 0) | 61 | if (ret < 0) |
62 | return ret; | 62 | return ret; |
63 | 63 | ||
64 | /* set cpu DAI configuration */ | 64 | /* set cpu DAI configuration */ |
65 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | | 65 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | |
66 | SND_SOC_DAIFMT_NB_NF | | 66 | SND_SOC_DAIFMT_NB_NF | |
67 | SND_SOC_DAIFMT_CBS_CFS); | 67 | SND_SOC_DAIFMT_CBS_CFS); |
68 | if (ret < 0) | 68 | if (ret < 0) |
69 | return ret; | 69 | return ret; |
70 | 70 | ||
71 | /* Use PCLK for I2S signal generation */ | 71 | /* Use PCLK for I2S signal generation */ |
72 | ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_RCLKSRC_0, | 72 | ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_RCLKSRC_0, |
73 | 0, SND_SOC_CLOCK_IN); | 73 | 0, SND_SOC_CLOCK_IN); |
74 | if (ret < 0) | 74 | if (ret < 0) |
75 | return ret; | 75 | return ret; |
76 | 76 | ||
77 | /* Gate the RCLK output on PAD */ | 77 | /* Gate the RCLK output on PAD */ |
78 | ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_CDCLK, | 78 | ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_CDCLK, |
79 | 0, SND_SOC_CLOCK_IN); | 79 | 0, SND_SOC_CLOCK_IN); |
80 | if (ret < 0) | 80 | if (ret < 0) |
81 | return ret; | 81 | return ret; |
82 | 82 | ||
83 | /* set the codec system clock for DAC and ADC */ | 83 | /* set the codec system clock for DAC and ADC */ |
84 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk, | 84 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk, |
85 | SND_SOC_CLOCK_IN); | 85 | SND_SOC_CLOCK_IN); |
86 | if (ret < 0) | 86 | if (ret < 0) |
87 | return ret; | 87 | return ret; |
88 | 88 | ||
89 | return 0; | 89 | return 0; |
90 | } | 90 | } |
91 | 91 | ||
92 | /* | 92 | /* |
93 | * SmartQ WM8987 HiFi DAI operations. | 93 | * SmartQ WM8987 HiFi DAI operations. |
94 | */ | 94 | */ |
95 | static struct snd_soc_ops smartq_hifi_ops = { | 95 | static struct snd_soc_ops smartq_hifi_ops = { |
96 | .hw_params = smartq_hifi_hw_params, | 96 | .hw_params = smartq_hifi_hw_params, |
97 | }; | 97 | }; |
98 | 98 | ||
99 | static struct snd_soc_jack smartq_jack; | 99 | static struct snd_soc_jack smartq_jack; |
100 | 100 | ||
101 | static struct snd_soc_jack_pin smartq_jack_pins[] = { | 101 | static struct snd_soc_jack_pin smartq_jack_pins[] = { |
102 | /* Disable speaker when headphone is plugged in */ | 102 | /* Disable speaker when headphone is plugged in */ |
103 | { | 103 | { |
104 | .pin = "Internal Speaker", | 104 | .pin = "Internal Speaker", |
105 | .mask = SND_JACK_HEADPHONE, | 105 | .mask = SND_JACK_HEADPHONE, |
106 | }, | 106 | }, |
107 | }; | 107 | }; |
108 | 108 | ||
109 | static struct snd_soc_jack_gpio smartq_jack_gpios[] = { | 109 | static struct snd_soc_jack_gpio smartq_jack_gpios[] = { |
110 | { | 110 | { |
111 | .gpio = S3C64XX_GPL(12), | 111 | .gpio = S3C64XX_GPL(12), |
112 | .name = "headphone detect", | 112 | .name = "headphone detect", |
113 | .report = SND_JACK_HEADPHONE, | 113 | .report = SND_JACK_HEADPHONE, |
114 | .debounce_time = 200, | 114 | .debounce_time = 200, |
115 | }, | 115 | }, |
116 | }; | 116 | }; |
117 | 117 | ||
118 | static const struct snd_kcontrol_new wm8987_smartq_controls[] = { | 118 | static const struct snd_kcontrol_new wm8987_smartq_controls[] = { |
119 | SOC_DAPM_PIN_SWITCH("Internal Speaker"), | 119 | SOC_DAPM_PIN_SWITCH("Internal Speaker"), |
120 | SOC_DAPM_PIN_SWITCH("Headphone Jack"), | 120 | SOC_DAPM_PIN_SWITCH("Headphone Jack"), |
121 | SOC_DAPM_PIN_SWITCH("Internal Mic"), | 121 | SOC_DAPM_PIN_SWITCH("Internal Mic"), |
122 | }; | 122 | }; |
123 | 123 | ||
124 | static int smartq_speaker_event(struct snd_soc_dapm_widget *w, | 124 | static int smartq_speaker_event(struct snd_soc_dapm_widget *w, |
125 | struct snd_kcontrol *k, | 125 | struct snd_kcontrol *k, |
126 | int event) | 126 | int event) |
127 | { | 127 | { |
128 | gpio_set_value(S3C64XX_GPK(12), SND_SOC_DAPM_EVENT_OFF(event)); | 128 | gpio_set_value(S3C64XX_GPK(12), SND_SOC_DAPM_EVENT_OFF(event)); |
129 | 129 | ||
130 | return 0; | 130 | return 0; |
131 | } | 131 | } |
132 | 132 | ||
133 | static const struct snd_soc_dapm_widget wm8987_dapm_widgets[] = { | 133 | static const struct snd_soc_dapm_widget wm8987_dapm_widgets[] = { |
134 | SND_SOC_DAPM_SPK("Internal Speaker", smartq_speaker_event), | 134 | SND_SOC_DAPM_SPK("Internal Speaker", smartq_speaker_event), |
135 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | 135 | SND_SOC_DAPM_HP("Headphone Jack", NULL), |
136 | SND_SOC_DAPM_MIC("Internal Mic", NULL), | 136 | SND_SOC_DAPM_MIC("Internal Mic", NULL), |
137 | }; | 137 | }; |
138 | 138 | ||
139 | static const struct snd_soc_dapm_route audio_map[] = { | 139 | static const struct snd_soc_dapm_route audio_map[] = { |
140 | {"Headphone Jack", NULL, "LOUT2"}, | 140 | {"Headphone Jack", NULL, "LOUT2"}, |
141 | {"Headphone Jack", NULL, "ROUT2"}, | 141 | {"Headphone Jack", NULL, "ROUT2"}, |
142 | 142 | ||
143 | {"Internal Speaker", NULL, "LOUT2"}, | 143 | {"Internal Speaker", NULL, "LOUT2"}, |
144 | {"Internal Speaker", NULL, "ROUT2"}, | 144 | {"Internal Speaker", NULL, "ROUT2"}, |
145 | 145 | ||
146 | {"Mic Bias", NULL, "Internal Mic"}, | 146 | {"Mic Bias", NULL, "Internal Mic"}, |
147 | {"LINPUT2", NULL, "Mic Bias"}, | 147 | {"LINPUT2", NULL, "Mic Bias"}, |
148 | }; | 148 | }; |
149 | 149 | ||
150 | static int smartq_wm8987_init(struct snd_soc_pcm_runtime *rtd) | 150 | static int smartq_wm8987_init(struct snd_soc_pcm_runtime *rtd) |
151 | { | 151 | { |
152 | struct snd_soc_codec *codec = rtd->codec; | 152 | struct snd_soc_codec *codec = rtd->codec; |
153 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 153 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
154 | int err = 0; | 154 | int err = 0; |
155 | 155 | ||
156 | /* Add SmartQ specific widgets */ | 156 | /* Add SmartQ specific widgets */ |
157 | snd_soc_dapm_new_controls(dapm, wm8987_dapm_widgets, | 157 | snd_soc_dapm_new_controls(dapm, wm8987_dapm_widgets, |
158 | ARRAY_SIZE(wm8987_dapm_widgets)); | 158 | ARRAY_SIZE(wm8987_dapm_widgets)); |
159 | 159 | ||
160 | /* add SmartQ specific controls */ | 160 | /* add SmartQ specific controls */ |
161 | err = snd_soc_add_controls(codec, wm8987_smartq_controls, | 161 | err = snd_soc_add_controls(codec, wm8987_smartq_controls, |
162 | ARRAY_SIZE(wm8987_smartq_controls)); | 162 | ARRAY_SIZE(wm8987_smartq_controls)); |
163 | 163 | ||
164 | if (err < 0) | 164 | if (err < 0) |
165 | return err; | 165 | return err; |
166 | 166 | ||
167 | /* setup SmartQ specific audio path */ | 167 | /* setup SmartQ specific audio path */ |
168 | snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); | 168 | snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); |
169 | 169 | ||
170 | /* set endpoints to not connected */ | 170 | /* set endpoints to not connected */ |
171 | snd_soc_dapm_nc_pin(dapm, "LINPUT1"); | 171 | snd_soc_dapm_nc_pin(dapm, "LINPUT1"); |
172 | snd_soc_dapm_nc_pin(dapm, "RINPUT1"); | 172 | snd_soc_dapm_nc_pin(dapm, "RINPUT1"); |
173 | snd_soc_dapm_nc_pin(dapm, "OUT3"); | 173 | snd_soc_dapm_nc_pin(dapm, "OUT3"); |
174 | snd_soc_dapm_nc_pin(dapm, "ROUT1"); | 174 | snd_soc_dapm_nc_pin(dapm, "ROUT1"); |
175 | 175 | ||
176 | /* set endpoints to default off mode */ | 176 | /* set endpoints to default off mode */ |
177 | snd_soc_dapm_enable_pin(dapm, "Internal Speaker"); | 177 | snd_soc_dapm_enable_pin(dapm, "Internal Speaker"); |
178 | snd_soc_dapm_enable_pin(dapm, "Internal Mic"); | 178 | snd_soc_dapm_enable_pin(dapm, "Internal Mic"); |
179 | snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); | 179 | snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); |
180 | 180 | ||
181 | err = snd_soc_dapm_sync(dapm); | ||
182 | if (err) | ||
183 | return err; | ||
184 | |||
185 | /* Headphone jack detection */ | 181 | /* Headphone jack detection */ |
186 | err = snd_soc_jack_new(codec, "Headphone Jack", | 182 | err = snd_soc_jack_new(codec, "Headphone Jack", |
187 | SND_JACK_HEADPHONE, &smartq_jack); | 183 | SND_JACK_HEADPHONE, &smartq_jack); |
188 | if (err) | 184 | if (err) |
189 | return err; | 185 | return err; |
190 | 186 | ||
191 | err = snd_soc_jack_add_pins(&smartq_jack, ARRAY_SIZE(smartq_jack_pins), | 187 | err = snd_soc_jack_add_pins(&smartq_jack, ARRAY_SIZE(smartq_jack_pins), |
192 | smartq_jack_pins); | 188 | smartq_jack_pins); |
193 | if (err) | 189 | if (err) |
194 | return err; | 190 | return err; |
195 | 191 | ||
196 | err = snd_soc_jack_add_gpios(&smartq_jack, | 192 | err = snd_soc_jack_add_gpios(&smartq_jack, |
197 | ARRAY_SIZE(smartq_jack_gpios), | 193 | ARRAY_SIZE(smartq_jack_gpios), |
198 | smartq_jack_gpios); | 194 | smartq_jack_gpios); |
199 | 195 | ||
200 | return err; | 196 | return err; |
201 | } | 197 | } |
202 | 198 | ||
203 | static struct snd_soc_dai_link smartq_dai[] = { | 199 | static struct snd_soc_dai_link smartq_dai[] = { |
204 | { | 200 | { |
205 | .name = "wm8987", | 201 | .name = "wm8987", |
206 | .stream_name = "SmartQ Hi-Fi", | 202 | .stream_name = "SmartQ Hi-Fi", |
207 | .cpu_dai_name = "samsung-i2s.0", | 203 | .cpu_dai_name = "samsung-i2s.0", |
208 | .codec_dai_name = "wm8750-hifi", | 204 | .codec_dai_name = "wm8750-hifi", |
209 | .platform_name = "samsung-audio", | 205 | .platform_name = "samsung-audio", |
210 | .codec_name = "wm8750.0-0x1a", | 206 | .codec_name = "wm8750.0-0x1a", |
211 | .init = smartq_wm8987_init, | 207 | .init = smartq_wm8987_init, |
212 | .ops = &smartq_hifi_ops, | 208 | .ops = &smartq_hifi_ops, |
213 | }, | 209 | }, |
214 | }; | 210 | }; |
215 | 211 | ||
216 | static struct snd_soc_card snd_soc_smartq = { | 212 | static struct snd_soc_card snd_soc_smartq = { |
217 | .name = "SmartQ", | 213 | .name = "SmartQ", |
218 | .dai_link = smartq_dai, | 214 | .dai_link = smartq_dai, |
219 | .num_links = ARRAY_SIZE(smartq_dai), | 215 | .num_links = ARRAY_SIZE(smartq_dai), |
220 | }; | 216 | }; |
221 | 217 | ||
222 | static struct platform_device *smartq_snd_device; | 218 | static struct platform_device *smartq_snd_device; |
223 | 219 | ||
224 | static int __init smartq_init(void) | 220 | static int __init smartq_init(void) |
225 | { | 221 | { |
226 | int ret; | 222 | int ret; |
227 | 223 | ||
228 | if (!machine_is_smartq7() && !machine_is_smartq5()) { | 224 | if (!machine_is_smartq7() && !machine_is_smartq5()) { |
229 | pr_info("Only SmartQ is supported by this ASoC driver\n"); | 225 | pr_info("Only SmartQ is supported by this ASoC driver\n"); |
230 | return -ENODEV; | 226 | return -ENODEV; |
231 | } | 227 | } |
232 | 228 | ||
233 | smartq_snd_device = platform_device_alloc("soc-audio", -1); | 229 | smartq_snd_device = platform_device_alloc("soc-audio", -1); |
234 | if (!smartq_snd_device) | 230 | if (!smartq_snd_device) |
235 | return -ENOMEM; | 231 | return -ENOMEM; |
236 | 232 | ||
237 | platform_set_drvdata(smartq_snd_device, &snd_soc_smartq); | 233 | platform_set_drvdata(smartq_snd_device, &snd_soc_smartq); |
238 | 234 | ||
239 | ret = platform_device_add(smartq_snd_device); | 235 | ret = platform_device_add(smartq_snd_device); |
240 | if (ret) { | 236 | if (ret) { |
241 | platform_device_put(smartq_snd_device); | 237 | platform_device_put(smartq_snd_device); |
242 | return ret; | 238 | return ret; |
243 | } | 239 | } |
244 | 240 | ||
245 | /* Initialise GPIOs used by amplifiers */ | 241 | /* Initialise GPIOs used by amplifiers */ |
246 | ret = gpio_request(S3C64XX_GPK(12), "amplifiers shutdown"); | 242 | ret = gpio_request(S3C64XX_GPK(12), "amplifiers shutdown"); |
247 | if (ret) { | 243 | if (ret) { |
248 | dev_err(&smartq_snd_device->dev, "Failed to register GPK12\n"); | 244 | dev_err(&smartq_snd_device->dev, "Failed to register GPK12\n"); |
249 | goto err_unregister_device; | 245 | goto err_unregister_device; |
250 | } | 246 | } |
251 | 247 | ||
252 | /* Disable amplifiers */ | 248 | /* Disable amplifiers */ |
253 | ret = gpio_direction_output(S3C64XX_GPK(12), 1); | 249 | ret = gpio_direction_output(S3C64XX_GPK(12), 1); |
254 | if (ret) { | 250 | if (ret) { |
255 | dev_err(&smartq_snd_device->dev, "Failed to configure GPK12\n"); | 251 | dev_err(&smartq_snd_device->dev, "Failed to configure GPK12\n"); |
256 | goto err_free_gpio_amp_shut; | 252 | goto err_free_gpio_amp_shut; |
257 | } | 253 | } |
258 | 254 | ||
259 | return 0; | 255 | return 0; |
260 | 256 | ||
261 | err_free_gpio_amp_shut: | 257 | err_free_gpio_amp_shut: |
262 | gpio_free(S3C64XX_GPK(12)); | 258 | gpio_free(S3C64XX_GPK(12)); |
263 | err_unregister_device: | 259 | err_unregister_device: |
264 | platform_device_unregister(smartq_snd_device); | 260 | platform_device_unregister(smartq_snd_device); |
265 | 261 | ||
266 | return ret; | 262 | return ret; |
267 | } | 263 | } |
268 | 264 | ||
269 | static void __exit smartq_exit(void) | 265 | static void __exit smartq_exit(void) |
270 | { | 266 | { |
271 | gpio_free(S3C64XX_GPK(12)); | 267 | gpio_free(S3C64XX_GPK(12)); |
272 | snd_soc_jack_free_gpios(&smartq_jack, ARRAY_SIZE(smartq_jack_gpios), | 268 | snd_soc_jack_free_gpios(&smartq_jack, ARRAY_SIZE(smartq_jack_gpios), |
273 | smartq_jack_gpios); | 269 | smartq_jack_gpios); |
274 | 270 | ||
275 | platform_device_unregister(smartq_snd_device); | 271 | platform_device_unregister(smartq_snd_device); |
276 | } | 272 | } |
277 | 273 | ||
278 | module_init(smartq_init); | 274 | module_init(smartq_init); |
279 | module_exit(smartq_exit); | 275 | module_exit(smartq_exit); |
280 | 276 | ||
281 | /* Module information */ | 277 | /* Module information */ |
282 | MODULE_AUTHOR("Maurus Cuelenaere <mcuelenaere@gmail.com>"); | 278 | MODULE_AUTHOR("Maurus Cuelenaere <mcuelenaere@gmail.com>"); |
283 | MODULE_DESCRIPTION("ALSA SoC SmartQ WM8987"); | 279 | MODULE_DESCRIPTION("ALSA SoC SmartQ WM8987"); |
284 | MODULE_LICENSE("GPL"); | 280 | MODULE_LICENSE("GPL"); |
285 | 281 |
sound/soc/samsung/smdk_wm8580.c
1 | /* | 1 | /* |
2 | * smdk_wm8580.c | 2 | * smdk_wm8580.c |
3 | * | 3 | * |
4 | * Copyright (c) 2009 Samsung Electronics Co. Ltd | 4 | * Copyright (c) 2009 Samsung Electronics Co. Ltd |
5 | * Author: Jaswinder Singh <jassi.brar@samsung.com> | 5 | * Author: Jaswinder Singh <jassi.brar@samsung.com> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify it | 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 | 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 | 9 | * Free Software Foundation; either version 2 of the License, or (at your |
10 | * option) any later version. | 10 | * option) any later version. |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <sound/soc.h> | 13 | #include <sound/soc.h> |
14 | #include <sound/pcm_params.h> | 14 | #include <sound/pcm_params.h> |
15 | 15 | ||
16 | #include <asm/mach-types.h> | 16 | #include <asm/mach-types.h> |
17 | 17 | ||
18 | #include "../codecs/wm8580.h" | 18 | #include "../codecs/wm8580.h" |
19 | #include "i2s.h" | 19 | #include "i2s.h" |
20 | 20 | ||
21 | /* | 21 | /* |
22 | * Default CFG switch settings to use this driver: | 22 | * Default CFG switch settings to use this driver: |
23 | * | 23 | * |
24 | * SMDK6410: Set CFG1 1-3 Off, CFG2 1-4 On | 24 | * SMDK6410: Set CFG1 1-3 Off, CFG2 1-4 On |
25 | */ | 25 | */ |
26 | 26 | ||
27 | /* SMDK has a 12MHZ crystal attached to WM8580 */ | 27 | /* SMDK has a 12MHZ crystal attached to WM8580 */ |
28 | #define SMDK_WM8580_FREQ 12000000 | 28 | #define SMDK_WM8580_FREQ 12000000 |
29 | 29 | ||
30 | static int smdk_hw_params(struct snd_pcm_substream *substream, | 30 | static int smdk_hw_params(struct snd_pcm_substream *substream, |
31 | struct snd_pcm_hw_params *params) | 31 | struct snd_pcm_hw_params *params) |
32 | { | 32 | { |
33 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 33 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
34 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 34 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
35 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 35 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
36 | unsigned int pll_out; | 36 | unsigned int pll_out; |
37 | int bfs, rfs, ret; | 37 | int bfs, rfs, ret; |
38 | 38 | ||
39 | switch (params_format(params)) { | 39 | switch (params_format(params)) { |
40 | case SNDRV_PCM_FORMAT_U8: | 40 | case SNDRV_PCM_FORMAT_U8: |
41 | case SNDRV_PCM_FORMAT_S8: | 41 | case SNDRV_PCM_FORMAT_S8: |
42 | bfs = 16; | 42 | bfs = 16; |
43 | break; | 43 | break; |
44 | case SNDRV_PCM_FORMAT_U16_LE: | 44 | case SNDRV_PCM_FORMAT_U16_LE: |
45 | case SNDRV_PCM_FORMAT_S16_LE: | 45 | case SNDRV_PCM_FORMAT_S16_LE: |
46 | bfs = 32; | 46 | bfs = 32; |
47 | break; | 47 | break; |
48 | default: | 48 | default: |
49 | return -EINVAL; | 49 | return -EINVAL; |
50 | } | 50 | } |
51 | 51 | ||
52 | /* The Fvco for WM8580 PLLs must fall within [90,100]MHz. | 52 | /* The Fvco for WM8580 PLLs must fall within [90,100]MHz. |
53 | * This criterion can't be met if we request PLL output | 53 | * This criterion can't be met if we request PLL output |
54 | * as {8000x256, 64000x256, 11025x256}Hz. | 54 | * as {8000x256, 64000x256, 11025x256}Hz. |
55 | * As a wayout, we rather change rfs to a minimum value that | 55 | * As a wayout, we rather change rfs to a minimum value that |
56 | * results in (params_rate(params) * rfs), and itself, acceptable | 56 | * results in (params_rate(params) * rfs), and itself, acceptable |
57 | * to both - the CODEC and the CPU. | 57 | * to both - the CODEC and the CPU. |
58 | */ | 58 | */ |
59 | switch (params_rate(params)) { | 59 | switch (params_rate(params)) { |
60 | case 16000: | 60 | case 16000: |
61 | case 22050: | 61 | case 22050: |
62 | case 32000: | 62 | case 32000: |
63 | case 44100: | 63 | case 44100: |
64 | case 48000: | 64 | case 48000: |
65 | case 88200: | 65 | case 88200: |
66 | case 96000: | 66 | case 96000: |
67 | rfs = 256; | 67 | rfs = 256; |
68 | break; | 68 | break; |
69 | case 64000: | 69 | case 64000: |
70 | rfs = 384; | 70 | rfs = 384; |
71 | break; | 71 | break; |
72 | case 8000: | 72 | case 8000: |
73 | case 11025: | 73 | case 11025: |
74 | rfs = 512; | 74 | rfs = 512; |
75 | break; | 75 | break; |
76 | default: | 76 | default: |
77 | return -EINVAL; | 77 | return -EINVAL; |
78 | } | 78 | } |
79 | pll_out = params_rate(params) * rfs; | 79 | pll_out = params_rate(params) * rfs; |
80 | 80 | ||
81 | /* Set the Codec DAI configuration */ | 81 | /* Set the Codec DAI configuration */ |
82 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | 82 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
83 | | SND_SOC_DAIFMT_NB_NF | 83 | | SND_SOC_DAIFMT_NB_NF |
84 | | SND_SOC_DAIFMT_CBM_CFM); | 84 | | SND_SOC_DAIFMT_CBM_CFM); |
85 | if (ret < 0) | 85 | if (ret < 0) |
86 | return ret; | 86 | return ret; |
87 | 87 | ||
88 | /* Set the AP DAI configuration */ | 88 | /* Set the AP DAI configuration */ |
89 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | 89 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
90 | | SND_SOC_DAIFMT_NB_NF | 90 | | SND_SOC_DAIFMT_NB_NF |
91 | | SND_SOC_DAIFMT_CBM_CFM); | 91 | | SND_SOC_DAIFMT_CBM_CFM); |
92 | if (ret < 0) | 92 | if (ret < 0) |
93 | return ret; | 93 | return ret; |
94 | 94 | ||
95 | /* Set WM8580 to drive MCLK from its PLLA */ | 95 | /* Set WM8580 to drive MCLK from its PLLA */ |
96 | ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK, | 96 | ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK, |
97 | WM8580_CLKSRC_PLLA); | 97 | WM8580_CLKSRC_PLLA); |
98 | if (ret < 0) | 98 | if (ret < 0) |
99 | return ret; | 99 | return ret; |
100 | 100 | ||
101 | ret = snd_soc_dai_set_pll(codec_dai, WM8580_PLLA, 0, | 101 | ret = snd_soc_dai_set_pll(codec_dai, WM8580_PLLA, 0, |
102 | SMDK_WM8580_FREQ, pll_out); | 102 | SMDK_WM8580_FREQ, pll_out); |
103 | if (ret < 0) | 103 | if (ret < 0) |
104 | return ret; | 104 | return ret; |
105 | 105 | ||
106 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8580_CLKSRC_PLLA, | 106 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8580_CLKSRC_PLLA, |
107 | pll_out, SND_SOC_CLOCK_IN); | 107 | pll_out, SND_SOC_CLOCK_IN); |
108 | if (ret < 0) | 108 | if (ret < 0) |
109 | return ret; | 109 | return ret; |
110 | 110 | ||
111 | return 0; | 111 | return 0; |
112 | } | 112 | } |
113 | 113 | ||
114 | /* | 114 | /* |
115 | * SMDK WM8580 DAI operations. | 115 | * SMDK WM8580 DAI operations. |
116 | */ | 116 | */ |
117 | static struct snd_soc_ops smdk_ops = { | 117 | static struct snd_soc_ops smdk_ops = { |
118 | .hw_params = smdk_hw_params, | 118 | .hw_params = smdk_hw_params, |
119 | }; | 119 | }; |
120 | 120 | ||
121 | /* SMDK Playback widgets */ | 121 | /* SMDK Playback widgets */ |
122 | static const struct snd_soc_dapm_widget wm8580_dapm_widgets_pbk[] = { | 122 | static const struct snd_soc_dapm_widget wm8580_dapm_widgets_pbk[] = { |
123 | SND_SOC_DAPM_HP("Front", NULL), | 123 | SND_SOC_DAPM_HP("Front", NULL), |
124 | SND_SOC_DAPM_HP("Center+Sub", NULL), | 124 | SND_SOC_DAPM_HP("Center+Sub", NULL), |
125 | SND_SOC_DAPM_HP("Rear", NULL), | 125 | SND_SOC_DAPM_HP("Rear", NULL), |
126 | }; | 126 | }; |
127 | 127 | ||
128 | /* SMDK Capture widgets */ | 128 | /* SMDK Capture widgets */ |
129 | static const struct snd_soc_dapm_widget wm8580_dapm_widgets_cpt[] = { | 129 | static const struct snd_soc_dapm_widget wm8580_dapm_widgets_cpt[] = { |
130 | SND_SOC_DAPM_MIC("MicIn", NULL), | 130 | SND_SOC_DAPM_MIC("MicIn", NULL), |
131 | SND_SOC_DAPM_LINE("LineIn", NULL), | 131 | SND_SOC_DAPM_LINE("LineIn", NULL), |
132 | }; | 132 | }; |
133 | 133 | ||
134 | /* SMDK-PAIFTX connections */ | 134 | /* SMDK-PAIFTX connections */ |
135 | static const struct snd_soc_dapm_route audio_map_tx[] = { | 135 | static const struct snd_soc_dapm_route audio_map_tx[] = { |
136 | /* MicIn feeds AINL */ | 136 | /* MicIn feeds AINL */ |
137 | {"AINL", NULL, "MicIn"}, | 137 | {"AINL", NULL, "MicIn"}, |
138 | 138 | ||
139 | /* LineIn feeds AINL/R */ | 139 | /* LineIn feeds AINL/R */ |
140 | {"AINL", NULL, "LineIn"}, | 140 | {"AINL", NULL, "LineIn"}, |
141 | {"AINR", NULL, "LineIn"}, | 141 | {"AINR", NULL, "LineIn"}, |
142 | }; | 142 | }; |
143 | 143 | ||
144 | /* SMDK-PAIFRX connections */ | 144 | /* SMDK-PAIFRX connections */ |
145 | static const struct snd_soc_dapm_route audio_map_rx[] = { | 145 | static const struct snd_soc_dapm_route audio_map_rx[] = { |
146 | /* Front Left/Right are fed VOUT1L/R */ | 146 | /* Front Left/Right are fed VOUT1L/R */ |
147 | {"Front", NULL, "VOUT1L"}, | 147 | {"Front", NULL, "VOUT1L"}, |
148 | {"Front", NULL, "VOUT1R"}, | 148 | {"Front", NULL, "VOUT1R"}, |
149 | 149 | ||
150 | /* Center/Sub are fed VOUT2L/R */ | 150 | /* Center/Sub are fed VOUT2L/R */ |
151 | {"Center+Sub", NULL, "VOUT2L"}, | 151 | {"Center+Sub", NULL, "VOUT2L"}, |
152 | {"Center+Sub", NULL, "VOUT2R"}, | 152 | {"Center+Sub", NULL, "VOUT2R"}, |
153 | 153 | ||
154 | /* Rear Left/Right are fed VOUT3L/R */ | 154 | /* Rear Left/Right are fed VOUT3L/R */ |
155 | {"Rear", NULL, "VOUT3L"}, | 155 | {"Rear", NULL, "VOUT3L"}, |
156 | {"Rear", NULL, "VOUT3R"}, | 156 | {"Rear", NULL, "VOUT3R"}, |
157 | }; | 157 | }; |
158 | 158 | ||
159 | static int smdk_wm8580_init_paiftx(struct snd_soc_pcm_runtime *rtd) | 159 | static int smdk_wm8580_init_paiftx(struct snd_soc_pcm_runtime *rtd) |
160 | { | 160 | { |
161 | struct snd_soc_codec *codec = rtd->codec; | 161 | struct snd_soc_codec *codec = rtd->codec; |
162 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 162 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
163 | 163 | ||
164 | /* Add smdk specific Capture widgets */ | 164 | /* Add smdk specific Capture widgets */ |
165 | snd_soc_dapm_new_controls(dapm, wm8580_dapm_widgets_cpt, | 165 | snd_soc_dapm_new_controls(dapm, wm8580_dapm_widgets_cpt, |
166 | ARRAY_SIZE(wm8580_dapm_widgets_cpt)); | 166 | ARRAY_SIZE(wm8580_dapm_widgets_cpt)); |
167 | 167 | ||
168 | /* Set up PAIFTX audio path */ | 168 | /* Set up PAIFTX audio path */ |
169 | snd_soc_dapm_add_routes(dapm, audio_map_tx, ARRAY_SIZE(audio_map_tx)); | 169 | snd_soc_dapm_add_routes(dapm, audio_map_tx, ARRAY_SIZE(audio_map_tx)); |
170 | 170 | ||
171 | /* Enabling the microphone requires the fitting of a 0R | 171 | /* Enabling the microphone requires the fitting of a 0R |
172 | * resistor to connect the line from the microphone jack. | 172 | * resistor to connect the line from the microphone jack. |
173 | */ | 173 | */ |
174 | snd_soc_dapm_disable_pin(dapm, "MicIn"); | 174 | snd_soc_dapm_disable_pin(dapm, "MicIn"); |
175 | 175 | ||
176 | /* signal a DAPM event */ | ||
177 | snd_soc_dapm_sync(dapm); | ||
178 | |||
179 | return 0; | 176 | return 0; |
180 | } | 177 | } |
181 | 178 | ||
182 | static int smdk_wm8580_init_paifrx(struct snd_soc_pcm_runtime *rtd) | 179 | static int smdk_wm8580_init_paifrx(struct snd_soc_pcm_runtime *rtd) |
183 | { | 180 | { |
184 | struct snd_soc_codec *codec = rtd->codec; | 181 | struct snd_soc_codec *codec = rtd->codec; |
185 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 182 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
186 | 183 | ||
187 | /* Add smdk specific Playback widgets */ | 184 | /* Add smdk specific Playback widgets */ |
188 | snd_soc_dapm_new_controls(dapm, wm8580_dapm_widgets_pbk, | 185 | snd_soc_dapm_new_controls(dapm, wm8580_dapm_widgets_pbk, |
189 | ARRAY_SIZE(wm8580_dapm_widgets_pbk)); | 186 | ARRAY_SIZE(wm8580_dapm_widgets_pbk)); |
190 | 187 | ||
191 | /* Set up PAIFRX audio path */ | 188 | /* Set up PAIFRX audio path */ |
192 | snd_soc_dapm_add_routes(dapm, audio_map_rx, ARRAY_SIZE(audio_map_rx)); | 189 | snd_soc_dapm_add_routes(dapm, audio_map_rx, ARRAY_SIZE(audio_map_rx)); |
193 | |||
194 | /* signal a DAPM event */ | ||
195 | snd_soc_dapm_sync(dapm); | ||
196 | 190 | ||
197 | return 0; | 191 | return 0; |
198 | } | 192 | } |
199 | 193 | ||
200 | enum { | 194 | enum { |
201 | PRI_PLAYBACK = 0, | 195 | PRI_PLAYBACK = 0, |
202 | PRI_CAPTURE, | 196 | PRI_CAPTURE, |
203 | SEC_PLAYBACK, | 197 | SEC_PLAYBACK, |
204 | }; | 198 | }; |
205 | 199 | ||
206 | static struct snd_soc_dai_link smdk_dai[] = { | 200 | static struct snd_soc_dai_link smdk_dai[] = { |
207 | [PRI_PLAYBACK] = { /* Primary Playback i/f */ | 201 | [PRI_PLAYBACK] = { /* Primary Playback i/f */ |
208 | .name = "WM8580 PAIF RX", | 202 | .name = "WM8580 PAIF RX", |
209 | .stream_name = "Playback", | 203 | .stream_name = "Playback", |
210 | .cpu_dai_name = "samsung-i2s.0", | 204 | .cpu_dai_name = "samsung-i2s.0", |
211 | .codec_dai_name = "wm8580-hifi-playback", | 205 | .codec_dai_name = "wm8580-hifi-playback", |
212 | .platform_name = "samsung-audio", | 206 | .platform_name = "samsung-audio", |
213 | .codec_name = "wm8580.0-001b", | 207 | .codec_name = "wm8580.0-001b", |
214 | .init = smdk_wm8580_init_paifrx, | 208 | .init = smdk_wm8580_init_paifrx, |
215 | .ops = &smdk_ops, | 209 | .ops = &smdk_ops, |
216 | }, | 210 | }, |
217 | [PRI_CAPTURE] = { /* Primary Capture i/f */ | 211 | [PRI_CAPTURE] = { /* Primary Capture i/f */ |
218 | .name = "WM8580 PAIF TX", | 212 | .name = "WM8580 PAIF TX", |
219 | .stream_name = "Capture", | 213 | .stream_name = "Capture", |
220 | .cpu_dai_name = "samsung-i2s.0", | 214 | .cpu_dai_name = "samsung-i2s.0", |
221 | .codec_dai_name = "wm8580-hifi-capture", | 215 | .codec_dai_name = "wm8580-hifi-capture", |
222 | .platform_name = "samsung-audio", | 216 | .platform_name = "samsung-audio", |
223 | .codec_name = "wm8580.0-001b", | 217 | .codec_name = "wm8580.0-001b", |
224 | .init = smdk_wm8580_init_paiftx, | 218 | .init = smdk_wm8580_init_paiftx, |
225 | .ops = &smdk_ops, | 219 | .ops = &smdk_ops, |
226 | }, | 220 | }, |
227 | [SEC_PLAYBACK] = { /* Sec_Fifo Playback i/f */ | 221 | [SEC_PLAYBACK] = { /* Sec_Fifo Playback i/f */ |
228 | .name = "Sec_FIFO TX", | 222 | .name = "Sec_FIFO TX", |
229 | .stream_name = "Playback", | 223 | .stream_name = "Playback", |
230 | .cpu_dai_name = "samsung-i2s.x", | 224 | .cpu_dai_name = "samsung-i2s.x", |
231 | .codec_dai_name = "wm8580-hifi-playback", | 225 | .codec_dai_name = "wm8580-hifi-playback", |
232 | .platform_name = "samsung-audio", | 226 | .platform_name = "samsung-audio", |
233 | .codec_name = "wm8580.0-001b", | 227 | .codec_name = "wm8580.0-001b", |
234 | .init = smdk_wm8580_init_paifrx, | 228 | .init = smdk_wm8580_init_paifrx, |
235 | .ops = &smdk_ops, | 229 | .ops = &smdk_ops, |
236 | }, | 230 | }, |
237 | }; | 231 | }; |
238 | 232 | ||
239 | static struct snd_soc_card smdk = { | 233 | static struct snd_soc_card smdk = { |
240 | .name = "SMDK-I2S", | 234 | .name = "SMDK-I2S", |
241 | .dai_link = smdk_dai, | 235 | .dai_link = smdk_dai, |
242 | .num_links = 2, | 236 | .num_links = 2, |
243 | }; | 237 | }; |
244 | 238 | ||
245 | static struct platform_device *smdk_snd_device; | 239 | static struct platform_device *smdk_snd_device; |
246 | 240 | ||
247 | static int __init smdk_audio_init(void) | 241 | static int __init smdk_audio_init(void) |
248 | { | 242 | { |
249 | int ret; | 243 | int ret; |
250 | char *str; | 244 | char *str; |
251 | 245 | ||
252 | if (machine_is_smdkc100() | 246 | if (machine_is_smdkc100() |
253 | || machine_is_smdkv210() || machine_is_smdkc110()) { | 247 | || machine_is_smdkv210() || machine_is_smdkc110()) { |
254 | smdk.num_links = 3; | 248 | smdk.num_links = 3; |
255 | /* Secondary is at offset SAMSUNG_I2S_SECOFF from Primary */ | 249 | /* Secondary is at offset SAMSUNG_I2S_SECOFF from Primary */ |
256 | str = (char *)smdk_dai[SEC_PLAYBACK].cpu_dai_name; | 250 | str = (char *)smdk_dai[SEC_PLAYBACK].cpu_dai_name; |
257 | str[strlen(str) - 1] = '0' + SAMSUNG_I2S_SECOFF; | 251 | str[strlen(str) - 1] = '0' + SAMSUNG_I2S_SECOFF; |
258 | } else if (machine_is_smdk6410()) { | 252 | } else if (machine_is_smdk6410()) { |
259 | str = (char *)smdk_dai[PRI_PLAYBACK].cpu_dai_name; | 253 | str = (char *)smdk_dai[PRI_PLAYBACK].cpu_dai_name; |
260 | str[strlen(str) - 1] = '2'; | 254 | str[strlen(str) - 1] = '2'; |
261 | str = (char *)smdk_dai[PRI_CAPTURE].cpu_dai_name; | 255 | str = (char *)smdk_dai[PRI_CAPTURE].cpu_dai_name; |
262 | str[strlen(str) - 1] = '2'; | 256 | str[strlen(str) - 1] = '2'; |
263 | } | 257 | } |
264 | 258 | ||
265 | smdk_snd_device = platform_device_alloc("soc-audio", -1); | 259 | smdk_snd_device = platform_device_alloc("soc-audio", -1); |
266 | if (!smdk_snd_device) | 260 | if (!smdk_snd_device) |
267 | return -ENOMEM; | 261 | return -ENOMEM; |
268 | 262 | ||
269 | platform_set_drvdata(smdk_snd_device, &smdk); | 263 | platform_set_drvdata(smdk_snd_device, &smdk); |
270 | ret = platform_device_add(smdk_snd_device); | 264 | ret = platform_device_add(smdk_snd_device); |
271 | 265 | ||
272 | if (ret) | 266 | if (ret) |
273 | platform_device_put(smdk_snd_device); | 267 | platform_device_put(smdk_snd_device); |
274 | 268 | ||
275 | return ret; | 269 | return ret; |
276 | } | 270 | } |
277 | module_init(smdk_audio_init); | 271 | module_init(smdk_audio_init); |
278 | 272 | ||
279 | static void __exit smdk_audio_exit(void) | 273 | static void __exit smdk_audio_exit(void) |
280 | { | 274 | { |
281 | platform_device_unregister(smdk_snd_device); | 275 | platform_device_unregister(smdk_snd_device); |
282 | } | 276 | } |
283 | module_exit(smdk_audio_exit); | 277 | module_exit(smdk_audio_exit); |
284 | 278 | ||
285 | MODULE_AUTHOR("Jaswinder Singh, jassi.brar@samsung.com"); | 279 | MODULE_AUTHOR("Jaswinder Singh, jassi.brar@samsung.com"); |
286 | MODULE_DESCRIPTION("ALSA SoC SMDK WM8580"); | 280 | MODULE_DESCRIPTION("ALSA SoC SMDK WM8580"); |
287 | MODULE_LICENSE("GPL"); | 281 | MODULE_LICENSE("GPL"); |
288 | 282 |
sound/soc/samsung/smdk_wm8994.c
1 | /* | 1 | /* |
2 | * smdk_wm8994.c | 2 | * smdk_wm8994.c |
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 |
6 | * Free Software Foundation; either version 2 of the License, or (at your | 6 | * Free Software Foundation; either version 2 of the License, or (at your |
7 | * option) any later version. | 7 | * option) any later version. |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include "../codecs/wm8994.h" | 10 | #include "../codecs/wm8994.h" |
11 | #include <sound/pcm_params.h> | 11 | #include <sound/pcm_params.h> |
12 | 12 | ||
13 | /* | 13 | /* |
14 | * Default CFG switch settings to use this driver: | 14 | * Default CFG switch settings to use this driver: |
15 | * SMDKV310: CFG5-1000, CFG7-111111 | 15 | * SMDKV310: CFG5-1000, CFG7-111111 |
16 | */ | 16 | */ |
17 | 17 | ||
18 | /* | 18 | /* |
19 | * Configure audio route as :- | 19 | * Configure audio route as :- |
20 | * $ amixer sset 'DAC1' on,on | 20 | * $ amixer sset 'DAC1' on,on |
21 | * $ amixer sset 'Right Headphone Mux' 'DAC' | 21 | * $ amixer sset 'Right Headphone Mux' 'DAC' |
22 | * $ amixer sset 'Left Headphone Mux' 'DAC' | 22 | * $ amixer sset 'Left Headphone Mux' 'DAC' |
23 | * $ amixer sset 'DAC1R Mixer AIF1.1' on | 23 | * $ amixer sset 'DAC1R Mixer AIF1.1' on |
24 | * $ amixer sset 'DAC1L Mixer AIF1.1' on | 24 | * $ amixer sset 'DAC1L Mixer AIF1.1' on |
25 | * $ amixer sset 'IN2L' on | 25 | * $ amixer sset 'IN2L' on |
26 | * $ amixer sset 'IN2L PGA IN2LN' on | 26 | * $ amixer sset 'IN2L PGA IN2LN' on |
27 | * $ amixer sset 'MIXINL IN2L' on | 27 | * $ amixer sset 'MIXINL IN2L' on |
28 | * $ amixer sset 'AIF1ADC1L Mixer ADC/DMIC' on | 28 | * $ amixer sset 'AIF1ADC1L Mixer ADC/DMIC' on |
29 | * $ amixer sset 'IN2R' on | 29 | * $ amixer sset 'IN2R' on |
30 | * $ amixer sset 'IN2R PGA IN2RN' on | 30 | * $ amixer sset 'IN2R PGA IN2RN' on |
31 | * $ amixer sset 'MIXINR IN2R' on | 31 | * $ amixer sset 'MIXINR IN2R' on |
32 | * $ amixer sset 'AIF1ADC1R Mixer ADC/DMIC' on | 32 | * $ amixer sset 'AIF1ADC1R Mixer ADC/DMIC' on |
33 | */ | 33 | */ |
34 | 34 | ||
35 | /* SMDK has a 16.934MHZ crystal attached to WM8994 */ | 35 | /* SMDK has a 16.934MHZ crystal attached to WM8994 */ |
36 | #define SMDK_WM8994_FREQ 16934000 | 36 | #define SMDK_WM8994_FREQ 16934000 |
37 | 37 | ||
38 | static int smdk_hw_params(struct snd_pcm_substream *substream, | 38 | static int smdk_hw_params(struct snd_pcm_substream *substream, |
39 | struct snd_pcm_hw_params *params) | 39 | struct snd_pcm_hw_params *params) |
40 | { | 40 | { |
41 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 41 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
42 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 42 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
43 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 43 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
44 | unsigned int pll_out; | 44 | unsigned int pll_out; |
45 | int ret; | 45 | int ret; |
46 | 46 | ||
47 | /* AIF1CLK should be >=3MHz for optimal performance */ | 47 | /* AIF1CLK should be >=3MHz for optimal performance */ |
48 | if (params_format(params) == SNDRV_PCM_FORMAT_S24_LE) | 48 | if (params_format(params) == SNDRV_PCM_FORMAT_S24_LE) |
49 | pll_out = params_rate(params) * 384; | 49 | pll_out = params_rate(params) * 384; |
50 | else if (params_rate(params) == 8000 || params_rate(params) == 11025) | 50 | else if (params_rate(params) == 8000 || params_rate(params) == 11025) |
51 | pll_out = params_rate(params) * 512; | 51 | pll_out = params_rate(params) * 512; |
52 | else | 52 | else |
53 | pll_out = params_rate(params) * 256; | 53 | pll_out = params_rate(params) * 256; |
54 | 54 | ||
55 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | 55 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
56 | | SND_SOC_DAIFMT_NB_NF | 56 | | SND_SOC_DAIFMT_NB_NF |
57 | | SND_SOC_DAIFMT_CBM_CFM); | 57 | | SND_SOC_DAIFMT_CBM_CFM); |
58 | if (ret < 0) | 58 | if (ret < 0) |
59 | return ret; | 59 | return ret; |
60 | 60 | ||
61 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | 61 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
62 | | SND_SOC_DAIFMT_NB_NF | 62 | | SND_SOC_DAIFMT_NB_NF |
63 | | SND_SOC_DAIFMT_CBM_CFM); | 63 | | SND_SOC_DAIFMT_CBM_CFM); |
64 | if (ret < 0) | 64 | if (ret < 0) |
65 | return ret; | 65 | return ret; |
66 | 66 | ||
67 | ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1, WM8994_FLL_SRC_MCLK1, | 67 | ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1, WM8994_FLL_SRC_MCLK1, |
68 | SMDK_WM8994_FREQ, pll_out); | 68 | SMDK_WM8994_FREQ, pll_out); |
69 | if (ret < 0) | 69 | if (ret < 0) |
70 | return ret; | 70 | return ret; |
71 | 71 | ||
72 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL1, | 72 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL1, |
73 | pll_out, SND_SOC_CLOCK_IN); | 73 | pll_out, SND_SOC_CLOCK_IN); |
74 | if (ret < 0) | 74 | if (ret < 0) |
75 | return ret; | 75 | return ret; |
76 | 76 | ||
77 | return 0; | 77 | return 0; |
78 | } | 78 | } |
79 | 79 | ||
80 | /* | 80 | /* |
81 | * SMDK WM8994 DAI operations. | 81 | * SMDK WM8994 DAI operations. |
82 | */ | 82 | */ |
83 | static struct snd_soc_ops smdk_ops = { | 83 | static struct snd_soc_ops smdk_ops = { |
84 | .hw_params = smdk_hw_params, | 84 | .hw_params = smdk_hw_params, |
85 | }; | 85 | }; |
86 | 86 | ||
87 | static int smdk_wm8994_init_paiftx(struct snd_soc_pcm_runtime *rtd) | 87 | static int smdk_wm8994_init_paiftx(struct snd_soc_pcm_runtime *rtd) |
88 | { | 88 | { |
89 | struct snd_soc_codec *codec = rtd->codec; | 89 | struct snd_soc_codec *codec = rtd->codec; |
90 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 90 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
91 | 91 | ||
92 | /* HeadPhone */ | 92 | /* HeadPhone */ |
93 | snd_soc_dapm_enable_pin(dapm, "HPOUT1R"); | 93 | snd_soc_dapm_enable_pin(dapm, "HPOUT1R"); |
94 | snd_soc_dapm_enable_pin(dapm, "HPOUT1L"); | 94 | snd_soc_dapm_enable_pin(dapm, "HPOUT1L"); |
95 | 95 | ||
96 | /* MicIn */ | 96 | /* MicIn */ |
97 | snd_soc_dapm_enable_pin(dapm, "IN1LN"); | 97 | snd_soc_dapm_enable_pin(dapm, "IN1LN"); |
98 | snd_soc_dapm_enable_pin(dapm, "IN1RN"); | 98 | snd_soc_dapm_enable_pin(dapm, "IN1RN"); |
99 | 99 | ||
100 | /* LineIn */ | 100 | /* LineIn */ |
101 | snd_soc_dapm_enable_pin(dapm, "IN2LN"); | 101 | snd_soc_dapm_enable_pin(dapm, "IN2LN"); |
102 | snd_soc_dapm_enable_pin(dapm, "IN2RN"); | 102 | snd_soc_dapm_enable_pin(dapm, "IN2RN"); |
103 | 103 | ||
104 | /* Other pins NC */ | 104 | /* Other pins NC */ |
105 | snd_soc_dapm_nc_pin(dapm, "HPOUT2P"); | 105 | snd_soc_dapm_nc_pin(dapm, "HPOUT2P"); |
106 | snd_soc_dapm_nc_pin(dapm, "HPOUT2N"); | 106 | snd_soc_dapm_nc_pin(dapm, "HPOUT2N"); |
107 | snd_soc_dapm_nc_pin(dapm, "SPKOUTLN"); | 107 | snd_soc_dapm_nc_pin(dapm, "SPKOUTLN"); |
108 | snd_soc_dapm_nc_pin(dapm, "SPKOUTLP"); | 108 | snd_soc_dapm_nc_pin(dapm, "SPKOUTLP"); |
109 | snd_soc_dapm_nc_pin(dapm, "SPKOUTRP"); | 109 | snd_soc_dapm_nc_pin(dapm, "SPKOUTRP"); |
110 | snd_soc_dapm_nc_pin(dapm, "SPKOUTRN"); | 110 | snd_soc_dapm_nc_pin(dapm, "SPKOUTRN"); |
111 | snd_soc_dapm_nc_pin(dapm, "LINEOUT1N"); | 111 | snd_soc_dapm_nc_pin(dapm, "LINEOUT1N"); |
112 | snd_soc_dapm_nc_pin(dapm, "LINEOUT1P"); | 112 | snd_soc_dapm_nc_pin(dapm, "LINEOUT1P"); |
113 | snd_soc_dapm_nc_pin(dapm, "LINEOUT2N"); | 113 | snd_soc_dapm_nc_pin(dapm, "LINEOUT2N"); |
114 | snd_soc_dapm_nc_pin(dapm, "LINEOUT2P"); | 114 | snd_soc_dapm_nc_pin(dapm, "LINEOUT2P"); |
115 | snd_soc_dapm_nc_pin(dapm, "IN1LP"); | 115 | snd_soc_dapm_nc_pin(dapm, "IN1LP"); |
116 | snd_soc_dapm_nc_pin(dapm, "IN2LP:VXRN"); | 116 | snd_soc_dapm_nc_pin(dapm, "IN2LP:VXRN"); |
117 | snd_soc_dapm_nc_pin(dapm, "IN1RP"); | 117 | snd_soc_dapm_nc_pin(dapm, "IN1RP"); |
118 | snd_soc_dapm_nc_pin(dapm, "IN2RP:VXRP"); | 118 | snd_soc_dapm_nc_pin(dapm, "IN2RP:VXRP"); |
119 | 119 | ||
120 | snd_soc_dapm_sync(dapm); | ||
121 | |||
122 | return 0; | 120 | return 0; |
123 | } | 121 | } |
124 | 122 | ||
125 | static struct snd_soc_dai_link smdk_dai[] = { | 123 | static struct snd_soc_dai_link smdk_dai[] = { |
126 | { /* Primary DAI i/f */ | 124 | { /* Primary DAI i/f */ |
127 | .name = "WM8994 AIF1", | 125 | .name = "WM8994 AIF1", |
128 | .stream_name = "Pri_Dai", | 126 | .stream_name = "Pri_Dai", |
129 | .cpu_dai_name = "samsung-i2s.0", | 127 | .cpu_dai_name = "samsung-i2s.0", |
130 | .codec_dai_name = "wm8994-aif1", | 128 | .codec_dai_name = "wm8994-aif1", |
131 | .platform_name = "samsung-audio", | 129 | .platform_name = "samsung-audio", |
132 | .codec_name = "wm8994-codec", | 130 | .codec_name = "wm8994-codec", |
133 | .init = smdk_wm8994_init_paiftx, | 131 | .init = smdk_wm8994_init_paiftx, |
134 | .ops = &smdk_ops, | 132 | .ops = &smdk_ops, |
135 | }, { /* Sec_Fifo Playback i/f */ | 133 | }, { /* Sec_Fifo Playback i/f */ |
136 | .name = "Sec_FIFO TX", | 134 | .name = "Sec_FIFO TX", |
137 | .stream_name = "Sec_Dai", | 135 | .stream_name = "Sec_Dai", |
138 | .cpu_dai_name = "samsung-i2s.4", | 136 | .cpu_dai_name = "samsung-i2s.4", |
139 | .codec_dai_name = "wm8994-aif1", | 137 | .codec_dai_name = "wm8994-aif1", |
140 | .platform_name = "samsung-audio", | 138 | .platform_name = "samsung-audio", |
141 | .codec_name = "wm8994-codec", | 139 | .codec_name = "wm8994-codec", |
142 | .ops = &smdk_ops, | 140 | .ops = &smdk_ops, |
143 | }, | 141 | }, |
144 | }; | 142 | }; |
145 | 143 | ||
146 | static struct snd_soc_card smdk = { | 144 | static struct snd_soc_card smdk = { |
147 | .name = "SMDK-I2S", | 145 | .name = "SMDK-I2S", |
148 | .dai_link = smdk_dai, | 146 | .dai_link = smdk_dai, |
149 | .num_links = ARRAY_SIZE(smdk_dai), | 147 | .num_links = ARRAY_SIZE(smdk_dai), |
150 | }; | 148 | }; |
151 | 149 | ||
152 | static struct platform_device *smdk_snd_device; | 150 | static struct platform_device *smdk_snd_device; |
153 | 151 | ||
154 | static int __init smdk_audio_init(void) | 152 | static int __init smdk_audio_init(void) |
155 | { | 153 | { |
156 | int ret; | 154 | int ret; |
157 | 155 | ||
158 | smdk_snd_device = platform_device_alloc("soc-audio", -1); | 156 | smdk_snd_device = platform_device_alloc("soc-audio", -1); |
159 | if (!smdk_snd_device) | 157 | if (!smdk_snd_device) |
160 | return -ENOMEM; | 158 | return -ENOMEM; |
161 | 159 | ||
162 | platform_set_drvdata(smdk_snd_device, &smdk); | 160 | platform_set_drvdata(smdk_snd_device, &smdk); |
163 | 161 | ||
164 | ret = platform_device_add(smdk_snd_device); | 162 | ret = platform_device_add(smdk_snd_device); |
165 | if (ret) | 163 | if (ret) |
166 | platform_device_put(smdk_snd_device); | 164 | platform_device_put(smdk_snd_device); |
167 | 165 | ||
168 | return ret; | 166 | return ret; |
169 | } | 167 | } |
170 | module_init(smdk_audio_init); | 168 | module_init(smdk_audio_init); |
171 | 169 | ||
172 | static void __exit smdk_audio_exit(void) | 170 | static void __exit smdk_audio_exit(void) |
173 | { | 171 | { |
174 | platform_device_unregister(smdk_snd_device); | 172 | platform_device_unregister(smdk_snd_device); |
175 | } | 173 | } |
176 | module_exit(smdk_audio_exit); | 174 | module_exit(smdk_audio_exit); |
177 | 175 | ||
178 | MODULE_DESCRIPTION("ALSA SoC SMDK WM8994"); | 176 | MODULE_DESCRIPTION("ALSA SoC SMDK WM8994"); |
179 | MODULE_LICENSE("GPL"); | 177 | MODULE_LICENSE("GPL"); |
180 | 178 |
sound/soc/sh/sh7760-ac97.c
1 | /* | 1 | /* |
2 | * Generic AC97 sound support for SH7760 | 2 | * Generic AC97 sound support for SH7760 |
3 | * | 3 | * |
4 | * (c) 2007 Manuel Lauss | 4 | * (c) 2007 Manuel Lauss |
5 | * | 5 | * |
6 | * Licensed under the GPLv2. | 6 | * Licensed under the GPLv2. |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/module.h> | 9 | #include <linux/module.h> |
10 | #include <linux/moduleparam.h> | 10 | #include <linux/moduleparam.h> |
11 | #include <linux/platform_device.h> | 11 | #include <linux/platform_device.h> |
12 | #include <sound/core.h> | 12 | #include <sound/core.h> |
13 | #include <sound/pcm.h> | 13 | #include <sound/pcm.h> |
14 | #include <sound/soc.h> | 14 | #include <sound/soc.h> |
15 | #include <asm/io.h> | 15 | #include <asm/io.h> |
16 | 16 | ||
17 | #define IPSEL 0xFE400034 | 17 | #define IPSEL 0xFE400034 |
18 | 18 | ||
19 | /* platform specific structs can be declared here */ | 19 | /* platform specific structs can be declared here */ |
20 | extern struct snd_soc_dai_driver sh4_hac_dai[2]; | 20 | extern struct snd_soc_dai_driver sh4_hac_dai[2]; |
21 | extern struct snd_soc_platform_driver sh7760_soc_platform; | 21 | extern struct snd_soc_platform_driver sh7760_soc_platform; |
22 | 22 | ||
23 | static int machine_init(struct snd_soc_pcm_runtime *rtd) | ||
24 | { | ||
25 | snd_soc_dapm_sync(&rtd->codec->dapm); | ||
26 | return 0; | ||
27 | } | ||
28 | |||
29 | static struct snd_soc_dai_link sh7760_ac97_dai = { | 23 | static struct snd_soc_dai_link sh7760_ac97_dai = { |
30 | .name = "AC97", | 24 | .name = "AC97", |
31 | .stream_name = "AC97 HiFi", | 25 | .stream_name = "AC97 HiFi", |
32 | .cpu_dai_name = "hac-dai.0", /* HAC0 */ | 26 | .cpu_dai_name = "hac-dai.0", /* HAC0 */ |
33 | .codec_dai_name = "ac97-hifi", | 27 | .codec_dai_name = "ac97-hifi", |
34 | .platform_name = "sh7760-pcm-audio", | 28 | .platform_name = "sh7760-pcm-audio", |
35 | .codec_name = "ac97-codec", | 29 | .codec_name = "ac97-codec", |
36 | .init = machine_init, | ||
37 | .ops = NULL, | 30 | .ops = NULL, |
38 | }; | 31 | }; |
39 | 32 | ||
40 | static struct snd_soc_card sh7760_ac97_soc_machine = { | 33 | static struct snd_soc_card sh7760_ac97_soc_machine = { |
41 | .name = "SH7760 AC97", | 34 | .name = "SH7760 AC97", |
42 | .dai_link = &sh7760_ac97_dai, | 35 | .dai_link = &sh7760_ac97_dai, |
43 | .num_links = 1, | 36 | .num_links = 1, |
44 | }; | 37 | }; |
45 | 38 | ||
46 | static struct platform_device *sh7760_ac97_snd_device; | 39 | static struct platform_device *sh7760_ac97_snd_device; |
47 | 40 | ||
48 | static int __init sh7760_ac97_init(void) | 41 | static int __init sh7760_ac97_init(void) |
49 | { | 42 | { |
50 | int ret; | 43 | int ret; |
51 | unsigned short ipsel; | 44 | unsigned short ipsel; |
52 | 45 | ||
53 | /* enable both AC97 controllers in pinmux reg */ | 46 | /* enable both AC97 controllers in pinmux reg */ |
54 | ipsel = __raw_readw(IPSEL); | 47 | ipsel = __raw_readw(IPSEL); |
55 | __raw_writew(ipsel | (3 << 10), IPSEL); | 48 | __raw_writew(ipsel | (3 << 10), IPSEL); |
56 | 49 | ||
57 | ret = -ENOMEM; | 50 | ret = -ENOMEM; |
58 | sh7760_ac97_snd_device = platform_device_alloc("soc-audio", -1); | 51 | sh7760_ac97_snd_device = platform_device_alloc("soc-audio", -1); |
59 | if (!sh7760_ac97_snd_device) | 52 | if (!sh7760_ac97_snd_device) |
60 | goto out; | 53 | goto out; |
61 | 54 | ||
62 | platform_set_drvdata(sh7760_ac97_snd_device, | 55 | platform_set_drvdata(sh7760_ac97_snd_device, |
63 | &sh7760_ac97_soc_machine); | 56 | &sh7760_ac97_soc_machine); |
64 | ret = platform_device_add(sh7760_ac97_snd_device); | 57 | ret = platform_device_add(sh7760_ac97_snd_device); |
65 | 58 | ||
66 | if (ret) | 59 | if (ret) |
67 | platform_device_put(sh7760_ac97_snd_device); | 60 | platform_device_put(sh7760_ac97_snd_device); |
68 | 61 | ||
69 | out: | 62 | out: |
70 | return ret; | 63 | return ret; |
71 | } | 64 | } |
72 | 65 | ||
73 | static void __exit sh7760_ac97_exit(void) | 66 | static void __exit sh7760_ac97_exit(void) |
74 | { | 67 | { |
75 | platform_device_unregister(sh7760_ac97_snd_device); | 68 | platform_device_unregister(sh7760_ac97_snd_device); |
76 | } | 69 | } |
77 | 70 | ||
78 | module_init(sh7760_ac97_init); | 71 | module_init(sh7760_ac97_init); |
79 | module_exit(sh7760_ac97_exit); | 72 | module_exit(sh7760_ac97_exit); |
80 | 73 | ||
81 | MODULE_LICENSE("GPL"); | 74 | MODULE_LICENSE("GPL"); |
82 | MODULE_DESCRIPTION("Generic SH7760 AC97 sound machine"); | 75 | MODULE_DESCRIPTION("Generic SH7760 AC97 sound machine"); |
83 | MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>"); | 76 | MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>"); |
84 | 77 |
sound/soc/tegra/tegra_wm8903.c
1 | /* | 1 | /* |
2 | * tegra_wm8903.c - Tegra machine ASoC driver for boards using WM8903 codec. | 2 | * tegra_wm8903.c - Tegra machine ASoC driver for boards using WM8903 codec. |
3 | * | 3 | * |
4 | * Author: Stephen Warren <swarren@nvidia.com> | 4 | * Author: Stephen Warren <swarren@nvidia.com> |
5 | * Copyright (C) 2010-2011 - NVIDIA, Inc. | 5 | * Copyright (C) 2010-2011 - NVIDIA, Inc. |
6 | * | 6 | * |
7 | * Based on code copyright/by: | 7 | * Based on code copyright/by: |
8 | * | 8 | * |
9 | * (c) 2009, 2010 Nvidia Graphics Pvt. Ltd. | 9 | * (c) 2009, 2010 Nvidia Graphics Pvt. Ltd. |
10 | * | 10 | * |
11 | * Copyright 2007 Wolfson Microelectronics PLC. | 11 | * Copyright 2007 Wolfson Microelectronics PLC. |
12 | * Author: Graeme Gregory | 12 | * Author: Graeme Gregory |
13 | * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com | 13 | * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com |
14 | * | 14 | * |
15 | * This program is free software; you can redistribute it and/or | 15 | * This program is free software; you can redistribute it and/or |
16 | * modify it under the terms of the GNU General Public License | 16 | * modify it under the terms of the GNU General Public License |
17 | * version 2 as published by the Free Software Foundation. | 17 | * version 2 as published by the Free Software Foundation. |
18 | * | 18 | * |
19 | * This program is distributed in the hope that it will be useful, but | 19 | * This program is distributed in the hope that it will be useful, but |
20 | * WITHOUT ANY WARRANTY; without even the implied warranty of | 20 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
22 | * General Public License for more details. | 22 | * General Public License for more details. |
23 | * | 23 | * |
24 | * You should have received a copy of the GNU General Public License | 24 | * You should have received a copy of the GNU General Public License |
25 | * along with this program; if not, write to the Free Software | 25 | * along with this program; if not, write to the Free Software |
26 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | 26 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA |
27 | * 02110-1301 USA | 27 | * 02110-1301 USA |
28 | * | 28 | * |
29 | */ | 29 | */ |
30 | 30 | ||
31 | #include <asm/mach-types.h> | 31 | #include <asm/mach-types.h> |
32 | 32 | ||
33 | #include <linux/module.h> | 33 | #include <linux/module.h> |
34 | #include <linux/platform_device.h> | 34 | #include <linux/platform_device.h> |
35 | #include <linux/slab.h> | 35 | #include <linux/slab.h> |
36 | #include <linux/gpio.h> | 36 | #include <linux/gpio.h> |
37 | 37 | ||
38 | #include <mach/tegra_wm8903_pdata.h> | 38 | #include <mach/tegra_wm8903_pdata.h> |
39 | 39 | ||
40 | #include <sound/core.h> | 40 | #include <sound/core.h> |
41 | #include <sound/jack.h> | 41 | #include <sound/jack.h> |
42 | #include <sound/pcm.h> | 42 | #include <sound/pcm.h> |
43 | #include <sound/pcm_params.h> | 43 | #include <sound/pcm_params.h> |
44 | #include <sound/soc.h> | 44 | #include <sound/soc.h> |
45 | 45 | ||
46 | #include "../codecs/wm8903.h" | 46 | #include "../codecs/wm8903.h" |
47 | 47 | ||
48 | #include "tegra_das.h" | 48 | #include "tegra_das.h" |
49 | #include "tegra_i2s.h" | 49 | #include "tegra_i2s.h" |
50 | #include "tegra_pcm.h" | 50 | #include "tegra_pcm.h" |
51 | #include "tegra_asoc_utils.h" | 51 | #include "tegra_asoc_utils.h" |
52 | 52 | ||
53 | #define DRV_NAME "tegra-snd-wm8903" | 53 | #define DRV_NAME "tegra-snd-wm8903" |
54 | 54 | ||
55 | #define GPIO_SPKR_EN BIT(0) | 55 | #define GPIO_SPKR_EN BIT(0) |
56 | #define GPIO_HP_MUTE BIT(1) | 56 | #define GPIO_HP_MUTE BIT(1) |
57 | #define GPIO_INT_MIC_EN BIT(2) | 57 | #define GPIO_INT_MIC_EN BIT(2) |
58 | #define GPIO_EXT_MIC_EN BIT(3) | 58 | #define GPIO_EXT_MIC_EN BIT(3) |
59 | #define GPIO_HP_DET BIT(4) | 59 | #define GPIO_HP_DET BIT(4) |
60 | 60 | ||
61 | struct tegra_wm8903 { | 61 | struct tegra_wm8903 { |
62 | struct tegra_asoc_utils_data util_data; | 62 | struct tegra_asoc_utils_data util_data; |
63 | struct tegra_wm8903_platform_data *pdata; | 63 | struct tegra_wm8903_platform_data *pdata; |
64 | int gpio_requested; | 64 | int gpio_requested; |
65 | }; | 65 | }; |
66 | 66 | ||
67 | static int tegra_wm8903_hw_params(struct snd_pcm_substream *substream, | 67 | static int tegra_wm8903_hw_params(struct snd_pcm_substream *substream, |
68 | struct snd_pcm_hw_params *params) | 68 | struct snd_pcm_hw_params *params) |
69 | { | 69 | { |
70 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 70 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
71 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 71 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
72 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 72 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
73 | struct snd_soc_codec *codec = rtd->codec; | 73 | struct snd_soc_codec *codec = rtd->codec; |
74 | struct snd_soc_card *card = codec->card; | 74 | struct snd_soc_card *card = codec->card; |
75 | struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); | 75 | struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); |
76 | int srate, mclk; | 76 | int srate, mclk; |
77 | int err; | 77 | int err; |
78 | 78 | ||
79 | srate = params_rate(params); | 79 | srate = params_rate(params); |
80 | switch (srate) { | 80 | switch (srate) { |
81 | case 64000: | 81 | case 64000: |
82 | case 88200: | 82 | case 88200: |
83 | case 96000: | 83 | case 96000: |
84 | mclk = 128 * srate; | 84 | mclk = 128 * srate; |
85 | break; | 85 | break; |
86 | default: | 86 | default: |
87 | mclk = 256 * srate; | 87 | mclk = 256 * srate; |
88 | break; | 88 | break; |
89 | } | 89 | } |
90 | /* FIXME: Codec only requires >= 3MHz if OSR==0 */ | 90 | /* FIXME: Codec only requires >= 3MHz if OSR==0 */ |
91 | while (mclk < 6000000) | 91 | while (mclk < 6000000) |
92 | mclk *= 2; | 92 | mclk *= 2; |
93 | 93 | ||
94 | err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); | 94 | err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); |
95 | if (err < 0) { | 95 | if (err < 0) { |
96 | dev_err(card->dev, "Can't configure clocks\n"); | 96 | dev_err(card->dev, "Can't configure clocks\n"); |
97 | return err; | 97 | return err; |
98 | } | 98 | } |
99 | 99 | ||
100 | err = snd_soc_dai_set_fmt(codec_dai, | 100 | err = snd_soc_dai_set_fmt(codec_dai, |
101 | SND_SOC_DAIFMT_I2S | | 101 | SND_SOC_DAIFMT_I2S | |
102 | SND_SOC_DAIFMT_NB_NF | | 102 | SND_SOC_DAIFMT_NB_NF | |
103 | SND_SOC_DAIFMT_CBS_CFS); | 103 | SND_SOC_DAIFMT_CBS_CFS); |
104 | if (err < 0) { | 104 | if (err < 0) { |
105 | dev_err(card->dev, "codec_dai fmt not set\n"); | 105 | dev_err(card->dev, "codec_dai fmt not set\n"); |
106 | return err; | 106 | return err; |
107 | } | 107 | } |
108 | 108 | ||
109 | err = snd_soc_dai_set_fmt(cpu_dai, | 109 | err = snd_soc_dai_set_fmt(cpu_dai, |
110 | SND_SOC_DAIFMT_I2S | | 110 | SND_SOC_DAIFMT_I2S | |
111 | SND_SOC_DAIFMT_NB_NF | | 111 | SND_SOC_DAIFMT_NB_NF | |
112 | SND_SOC_DAIFMT_CBS_CFS); | 112 | SND_SOC_DAIFMT_CBS_CFS); |
113 | if (err < 0) { | 113 | if (err < 0) { |
114 | dev_err(card->dev, "cpu_dai fmt not set\n"); | 114 | dev_err(card->dev, "cpu_dai fmt not set\n"); |
115 | return err; | 115 | return err; |
116 | } | 116 | } |
117 | 117 | ||
118 | err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, | 118 | err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, |
119 | SND_SOC_CLOCK_IN); | 119 | SND_SOC_CLOCK_IN); |
120 | if (err < 0) { | 120 | if (err < 0) { |
121 | dev_err(card->dev, "codec_dai clock not set\n"); | 121 | dev_err(card->dev, "codec_dai clock not set\n"); |
122 | return err; | 122 | return err; |
123 | } | 123 | } |
124 | 124 | ||
125 | return 0; | 125 | return 0; |
126 | } | 126 | } |
127 | 127 | ||
128 | static struct snd_soc_ops tegra_wm8903_ops = { | 128 | static struct snd_soc_ops tegra_wm8903_ops = { |
129 | .hw_params = tegra_wm8903_hw_params, | 129 | .hw_params = tegra_wm8903_hw_params, |
130 | }; | 130 | }; |
131 | 131 | ||
132 | static struct snd_soc_jack tegra_wm8903_hp_jack; | 132 | static struct snd_soc_jack tegra_wm8903_hp_jack; |
133 | 133 | ||
134 | static struct snd_soc_jack_pin tegra_wm8903_hp_jack_pins[] = { | 134 | static struct snd_soc_jack_pin tegra_wm8903_hp_jack_pins[] = { |
135 | { | 135 | { |
136 | .pin = "Headphone Jack", | 136 | .pin = "Headphone Jack", |
137 | .mask = SND_JACK_HEADPHONE, | 137 | .mask = SND_JACK_HEADPHONE, |
138 | }, | 138 | }, |
139 | }; | 139 | }; |
140 | 140 | ||
141 | static struct snd_soc_jack_gpio tegra_wm8903_hp_jack_gpio = { | 141 | static struct snd_soc_jack_gpio tegra_wm8903_hp_jack_gpio = { |
142 | .name = "headphone detect", | 142 | .name = "headphone detect", |
143 | .report = SND_JACK_HEADPHONE, | 143 | .report = SND_JACK_HEADPHONE, |
144 | .debounce_time = 150, | 144 | .debounce_time = 150, |
145 | .invert = 1, | 145 | .invert = 1, |
146 | }; | 146 | }; |
147 | 147 | ||
148 | static struct snd_soc_jack tegra_wm8903_mic_jack; | 148 | static struct snd_soc_jack tegra_wm8903_mic_jack; |
149 | 149 | ||
150 | static struct snd_soc_jack_pin tegra_wm8903_mic_jack_pins[] = { | 150 | static struct snd_soc_jack_pin tegra_wm8903_mic_jack_pins[] = { |
151 | { | 151 | { |
152 | .pin = "Mic Jack", | 152 | .pin = "Mic Jack", |
153 | .mask = SND_JACK_MICROPHONE, | 153 | .mask = SND_JACK_MICROPHONE, |
154 | }, | 154 | }, |
155 | }; | 155 | }; |
156 | 156 | ||
157 | static int tegra_wm8903_event_int_spk(struct snd_soc_dapm_widget *w, | 157 | static int tegra_wm8903_event_int_spk(struct snd_soc_dapm_widget *w, |
158 | struct snd_kcontrol *k, int event) | 158 | struct snd_kcontrol *k, int event) |
159 | { | 159 | { |
160 | struct snd_soc_dapm_context *dapm = w->dapm; | 160 | struct snd_soc_dapm_context *dapm = w->dapm; |
161 | struct snd_soc_card *card = dapm->card; | 161 | struct snd_soc_card *card = dapm->card; |
162 | struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); | 162 | struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); |
163 | struct tegra_wm8903_platform_data *pdata = machine->pdata; | 163 | struct tegra_wm8903_platform_data *pdata = machine->pdata; |
164 | 164 | ||
165 | if (!(machine->gpio_requested & GPIO_SPKR_EN)) | 165 | if (!(machine->gpio_requested & GPIO_SPKR_EN)) |
166 | return 0; | 166 | return 0; |
167 | 167 | ||
168 | gpio_set_value_cansleep(pdata->gpio_spkr_en, | 168 | gpio_set_value_cansleep(pdata->gpio_spkr_en, |
169 | SND_SOC_DAPM_EVENT_ON(event)); | 169 | SND_SOC_DAPM_EVENT_ON(event)); |
170 | 170 | ||
171 | return 0; | 171 | return 0; |
172 | } | 172 | } |
173 | 173 | ||
174 | static int tegra_wm8903_event_hp(struct snd_soc_dapm_widget *w, | 174 | static int tegra_wm8903_event_hp(struct snd_soc_dapm_widget *w, |
175 | struct snd_kcontrol *k, int event) | 175 | struct snd_kcontrol *k, int event) |
176 | { | 176 | { |
177 | struct snd_soc_dapm_context *dapm = w->dapm; | 177 | struct snd_soc_dapm_context *dapm = w->dapm; |
178 | struct snd_soc_card *card = dapm->card; | 178 | struct snd_soc_card *card = dapm->card; |
179 | struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); | 179 | struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); |
180 | struct tegra_wm8903_platform_data *pdata = machine->pdata; | 180 | struct tegra_wm8903_platform_data *pdata = machine->pdata; |
181 | 181 | ||
182 | if (!(machine->gpio_requested & GPIO_HP_MUTE)) | 182 | if (!(machine->gpio_requested & GPIO_HP_MUTE)) |
183 | return 0; | 183 | return 0; |
184 | 184 | ||
185 | gpio_set_value_cansleep(pdata->gpio_hp_mute, | 185 | gpio_set_value_cansleep(pdata->gpio_hp_mute, |
186 | !SND_SOC_DAPM_EVENT_ON(event)); | 186 | !SND_SOC_DAPM_EVENT_ON(event)); |
187 | 187 | ||
188 | return 0; | 188 | return 0; |
189 | } | 189 | } |
190 | 190 | ||
191 | static const struct snd_soc_dapm_widget tegra_wm8903_dapm_widgets[] = { | 191 | static const struct snd_soc_dapm_widget tegra_wm8903_dapm_widgets[] = { |
192 | SND_SOC_DAPM_SPK("Int Spk", tegra_wm8903_event_int_spk), | 192 | SND_SOC_DAPM_SPK("Int Spk", tegra_wm8903_event_int_spk), |
193 | SND_SOC_DAPM_HP("Headphone Jack", tegra_wm8903_event_hp), | 193 | SND_SOC_DAPM_HP("Headphone Jack", tegra_wm8903_event_hp), |
194 | SND_SOC_DAPM_MIC("Mic Jack", NULL), | 194 | SND_SOC_DAPM_MIC("Mic Jack", NULL), |
195 | }; | 195 | }; |
196 | 196 | ||
197 | static const struct snd_soc_dapm_route harmony_audio_map[] = { | 197 | static const struct snd_soc_dapm_route harmony_audio_map[] = { |
198 | {"Headphone Jack", NULL, "HPOUTR"}, | 198 | {"Headphone Jack", NULL, "HPOUTR"}, |
199 | {"Headphone Jack", NULL, "HPOUTL"}, | 199 | {"Headphone Jack", NULL, "HPOUTL"}, |
200 | {"Int Spk", NULL, "ROP"}, | 200 | {"Int Spk", NULL, "ROP"}, |
201 | {"Int Spk", NULL, "RON"}, | 201 | {"Int Spk", NULL, "RON"}, |
202 | {"Int Spk", NULL, "LOP"}, | 202 | {"Int Spk", NULL, "LOP"}, |
203 | {"Int Spk", NULL, "LON"}, | 203 | {"Int Spk", NULL, "LON"}, |
204 | {"Mic Bias", NULL, "Mic Jack"}, | 204 | {"Mic Bias", NULL, "Mic Jack"}, |
205 | {"IN1L", NULL, "Mic Bias"}, | 205 | {"IN1L", NULL, "Mic Bias"}, |
206 | }; | 206 | }; |
207 | 207 | ||
208 | static const struct snd_soc_dapm_route seaboard_audio_map[] = { | 208 | static const struct snd_soc_dapm_route seaboard_audio_map[] = { |
209 | {"Headphone Jack", NULL, "HPOUTR"}, | 209 | {"Headphone Jack", NULL, "HPOUTR"}, |
210 | {"Headphone Jack", NULL, "HPOUTL"}, | 210 | {"Headphone Jack", NULL, "HPOUTL"}, |
211 | {"Int Spk", NULL, "ROP"}, | 211 | {"Int Spk", NULL, "ROP"}, |
212 | {"Int Spk", NULL, "RON"}, | 212 | {"Int Spk", NULL, "RON"}, |
213 | {"Int Spk", NULL, "LOP"}, | 213 | {"Int Spk", NULL, "LOP"}, |
214 | {"Int Spk", NULL, "LON"}, | 214 | {"Int Spk", NULL, "LON"}, |
215 | {"Mic Bias", NULL, "Mic Jack"}, | 215 | {"Mic Bias", NULL, "Mic Jack"}, |
216 | {"IN1R", NULL, "Mic Bias"}, | 216 | {"IN1R", NULL, "Mic Bias"}, |
217 | }; | 217 | }; |
218 | 218 | ||
219 | static const struct snd_soc_dapm_route kaen_audio_map[] = { | 219 | static const struct snd_soc_dapm_route kaen_audio_map[] = { |
220 | {"Headphone Jack", NULL, "HPOUTR"}, | 220 | {"Headphone Jack", NULL, "HPOUTR"}, |
221 | {"Headphone Jack", NULL, "HPOUTL"}, | 221 | {"Headphone Jack", NULL, "HPOUTL"}, |
222 | {"Int Spk", NULL, "ROP"}, | 222 | {"Int Spk", NULL, "ROP"}, |
223 | {"Int Spk", NULL, "RON"}, | 223 | {"Int Spk", NULL, "RON"}, |
224 | {"Int Spk", NULL, "LOP"}, | 224 | {"Int Spk", NULL, "LOP"}, |
225 | {"Int Spk", NULL, "LON"}, | 225 | {"Int Spk", NULL, "LON"}, |
226 | {"Mic Bias", NULL, "Mic Jack"}, | 226 | {"Mic Bias", NULL, "Mic Jack"}, |
227 | {"IN2R", NULL, "Mic Bias"}, | 227 | {"IN2R", NULL, "Mic Bias"}, |
228 | }; | 228 | }; |
229 | 229 | ||
230 | static const struct snd_soc_dapm_route aebl_audio_map[] = { | 230 | static const struct snd_soc_dapm_route aebl_audio_map[] = { |
231 | {"Headphone Jack", NULL, "HPOUTR"}, | 231 | {"Headphone Jack", NULL, "HPOUTR"}, |
232 | {"Headphone Jack", NULL, "HPOUTL"}, | 232 | {"Headphone Jack", NULL, "HPOUTL"}, |
233 | {"Int Spk", NULL, "LINEOUTR"}, | 233 | {"Int Spk", NULL, "LINEOUTR"}, |
234 | {"Int Spk", NULL, "LINEOUTL"}, | 234 | {"Int Spk", NULL, "LINEOUTL"}, |
235 | {"Mic Bias", NULL, "Mic Jack"}, | 235 | {"Mic Bias", NULL, "Mic Jack"}, |
236 | {"IN1R", NULL, "Mic Bias"}, | 236 | {"IN1R", NULL, "Mic Bias"}, |
237 | }; | 237 | }; |
238 | 238 | ||
239 | static const struct snd_kcontrol_new tegra_wm8903_controls[] = { | 239 | static const struct snd_kcontrol_new tegra_wm8903_controls[] = { |
240 | SOC_DAPM_PIN_SWITCH("Int Spk"), | 240 | SOC_DAPM_PIN_SWITCH("Int Spk"), |
241 | }; | 241 | }; |
242 | 242 | ||
243 | static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd) | 243 | static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd) |
244 | { | 244 | { |
245 | struct snd_soc_codec *codec = rtd->codec; | 245 | struct snd_soc_codec *codec = rtd->codec; |
246 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 246 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
247 | struct snd_soc_card *card = codec->card; | 247 | struct snd_soc_card *card = codec->card; |
248 | struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); | 248 | struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); |
249 | struct tegra_wm8903_platform_data *pdata = machine->pdata; | 249 | struct tegra_wm8903_platform_data *pdata = machine->pdata; |
250 | int ret; | 250 | int ret; |
251 | 251 | ||
252 | if (gpio_is_valid(pdata->gpio_spkr_en)) { | 252 | if (gpio_is_valid(pdata->gpio_spkr_en)) { |
253 | ret = gpio_request(pdata->gpio_spkr_en, "spkr_en"); | 253 | ret = gpio_request(pdata->gpio_spkr_en, "spkr_en"); |
254 | if (ret) { | 254 | if (ret) { |
255 | dev_err(card->dev, "cannot get spkr_en gpio\n"); | 255 | dev_err(card->dev, "cannot get spkr_en gpio\n"); |
256 | return ret; | 256 | return ret; |
257 | } | 257 | } |
258 | machine->gpio_requested |= GPIO_SPKR_EN; | 258 | machine->gpio_requested |= GPIO_SPKR_EN; |
259 | 259 | ||
260 | gpio_direction_output(pdata->gpio_spkr_en, 0); | 260 | gpio_direction_output(pdata->gpio_spkr_en, 0); |
261 | } | 261 | } |
262 | 262 | ||
263 | if (gpio_is_valid(pdata->gpio_hp_mute)) { | 263 | if (gpio_is_valid(pdata->gpio_hp_mute)) { |
264 | ret = gpio_request(pdata->gpio_hp_mute, "hp_mute"); | 264 | ret = gpio_request(pdata->gpio_hp_mute, "hp_mute"); |
265 | if (ret) { | 265 | if (ret) { |
266 | dev_err(card->dev, "cannot get hp_mute gpio\n"); | 266 | dev_err(card->dev, "cannot get hp_mute gpio\n"); |
267 | return ret; | 267 | return ret; |
268 | } | 268 | } |
269 | machine->gpio_requested |= GPIO_HP_MUTE; | 269 | machine->gpio_requested |= GPIO_HP_MUTE; |
270 | 270 | ||
271 | gpio_direction_output(pdata->gpio_hp_mute, 1); | 271 | gpio_direction_output(pdata->gpio_hp_mute, 1); |
272 | } | 272 | } |
273 | 273 | ||
274 | if (gpio_is_valid(pdata->gpio_int_mic_en)) { | 274 | if (gpio_is_valid(pdata->gpio_int_mic_en)) { |
275 | ret = gpio_request(pdata->gpio_int_mic_en, "int_mic_en"); | 275 | ret = gpio_request(pdata->gpio_int_mic_en, "int_mic_en"); |
276 | if (ret) { | 276 | if (ret) { |
277 | dev_err(card->dev, "cannot get int_mic_en gpio\n"); | 277 | dev_err(card->dev, "cannot get int_mic_en gpio\n"); |
278 | return ret; | 278 | return ret; |
279 | } | 279 | } |
280 | machine->gpio_requested |= GPIO_INT_MIC_EN; | 280 | machine->gpio_requested |= GPIO_INT_MIC_EN; |
281 | 281 | ||
282 | /* Disable int mic; enable signal is active-high */ | 282 | /* Disable int mic; enable signal is active-high */ |
283 | gpio_direction_output(pdata->gpio_int_mic_en, 0); | 283 | gpio_direction_output(pdata->gpio_int_mic_en, 0); |
284 | } | 284 | } |
285 | 285 | ||
286 | if (gpio_is_valid(pdata->gpio_ext_mic_en)) { | 286 | if (gpio_is_valid(pdata->gpio_ext_mic_en)) { |
287 | ret = gpio_request(pdata->gpio_ext_mic_en, "ext_mic_en"); | 287 | ret = gpio_request(pdata->gpio_ext_mic_en, "ext_mic_en"); |
288 | if (ret) { | 288 | if (ret) { |
289 | dev_err(card->dev, "cannot get ext_mic_en gpio\n"); | 289 | dev_err(card->dev, "cannot get ext_mic_en gpio\n"); |
290 | return ret; | 290 | return ret; |
291 | } | 291 | } |
292 | machine->gpio_requested |= GPIO_EXT_MIC_EN; | 292 | machine->gpio_requested |= GPIO_EXT_MIC_EN; |
293 | 293 | ||
294 | /* Enable ext mic; enable signal is active-low */ | 294 | /* Enable ext mic; enable signal is active-low */ |
295 | gpio_direction_output(pdata->gpio_ext_mic_en, 0); | 295 | gpio_direction_output(pdata->gpio_ext_mic_en, 0); |
296 | } | 296 | } |
297 | 297 | ||
298 | if (gpio_is_valid(pdata->gpio_hp_det)) { | 298 | if (gpio_is_valid(pdata->gpio_hp_det)) { |
299 | tegra_wm8903_hp_jack_gpio.gpio = pdata->gpio_hp_det; | 299 | tegra_wm8903_hp_jack_gpio.gpio = pdata->gpio_hp_det; |
300 | snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE, | 300 | snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE, |
301 | &tegra_wm8903_hp_jack); | 301 | &tegra_wm8903_hp_jack); |
302 | snd_soc_jack_add_pins(&tegra_wm8903_hp_jack, | 302 | snd_soc_jack_add_pins(&tegra_wm8903_hp_jack, |
303 | ARRAY_SIZE(tegra_wm8903_hp_jack_pins), | 303 | ARRAY_SIZE(tegra_wm8903_hp_jack_pins), |
304 | tegra_wm8903_hp_jack_pins); | 304 | tegra_wm8903_hp_jack_pins); |
305 | snd_soc_jack_add_gpios(&tegra_wm8903_hp_jack, | 305 | snd_soc_jack_add_gpios(&tegra_wm8903_hp_jack, |
306 | 1, | 306 | 1, |
307 | &tegra_wm8903_hp_jack_gpio); | 307 | &tegra_wm8903_hp_jack_gpio); |
308 | machine->gpio_requested |= GPIO_HP_DET; | 308 | machine->gpio_requested |= GPIO_HP_DET; |
309 | } | 309 | } |
310 | 310 | ||
311 | snd_soc_jack_new(codec, "Mic Jack", SND_JACK_MICROPHONE, | 311 | snd_soc_jack_new(codec, "Mic Jack", SND_JACK_MICROPHONE, |
312 | &tegra_wm8903_mic_jack); | 312 | &tegra_wm8903_mic_jack); |
313 | snd_soc_jack_add_pins(&tegra_wm8903_mic_jack, | 313 | snd_soc_jack_add_pins(&tegra_wm8903_mic_jack, |
314 | ARRAY_SIZE(tegra_wm8903_mic_jack_pins), | 314 | ARRAY_SIZE(tegra_wm8903_mic_jack_pins), |
315 | tegra_wm8903_mic_jack_pins); | 315 | tegra_wm8903_mic_jack_pins); |
316 | wm8903_mic_detect(codec, &tegra_wm8903_mic_jack, SND_JACK_MICROPHONE, | 316 | wm8903_mic_detect(codec, &tegra_wm8903_mic_jack, SND_JACK_MICROPHONE, |
317 | 0); | 317 | 0); |
318 | 318 | ||
319 | snd_soc_dapm_force_enable_pin(dapm, "Mic Bias"); | 319 | snd_soc_dapm_force_enable_pin(dapm, "Mic Bias"); |
320 | 320 | ||
321 | /* FIXME: Calculate automatically based on DAPM routes? */ | 321 | /* FIXME: Calculate automatically based on DAPM routes? */ |
322 | if (!machine_is_harmony()) | 322 | if (!machine_is_harmony()) |
323 | snd_soc_dapm_nc_pin(dapm, "IN1L"); | 323 | snd_soc_dapm_nc_pin(dapm, "IN1L"); |
324 | if (!machine_is_seaboard() && !machine_is_aebl()) | 324 | if (!machine_is_seaboard() && !machine_is_aebl()) |
325 | snd_soc_dapm_nc_pin(dapm, "IN1R"); | 325 | snd_soc_dapm_nc_pin(dapm, "IN1R"); |
326 | snd_soc_dapm_nc_pin(dapm, "IN2L"); | 326 | snd_soc_dapm_nc_pin(dapm, "IN2L"); |
327 | if (!machine_is_kaen()) | 327 | if (!machine_is_kaen()) |
328 | snd_soc_dapm_nc_pin(dapm, "IN2R"); | 328 | snd_soc_dapm_nc_pin(dapm, "IN2R"); |
329 | snd_soc_dapm_nc_pin(dapm, "IN3L"); | 329 | snd_soc_dapm_nc_pin(dapm, "IN3L"); |
330 | snd_soc_dapm_nc_pin(dapm, "IN3R"); | 330 | snd_soc_dapm_nc_pin(dapm, "IN3R"); |
331 | 331 | ||
332 | if (machine_is_aebl()) { | 332 | if (machine_is_aebl()) { |
333 | snd_soc_dapm_nc_pin(dapm, "LON"); | 333 | snd_soc_dapm_nc_pin(dapm, "LON"); |
334 | snd_soc_dapm_nc_pin(dapm, "RON"); | 334 | snd_soc_dapm_nc_pin(dapm, "RON"); |
335 | snd_soc_dapm_nc_pin(dapm, "ROP"); | 335 | snd_soc_dapm_nc_pin(dapm, "ROP"); |
336 | snd_soc_dapm_nc_pin(dapm, "LOP"); | 336 | snd_soc_dapm_nc_pin(dapm, "LOP"); |
337 | } else { | 337 | } else { |
338 | snd_soc_dapm_nc_pin(dapm, "LINEOUTR"); | 338 | snd_soc_dapm_nc_pin(dapm, "LINEOUTR"); |
339 | snd_soc_dapm_nc_pin(dapm, "LINEOUTL"); | 339 | snd_soc_dapm_nc_pin(dapm, "LINEOUTL"); |
340 | } | 340 | } |
341 | 341 | ||
342 | snd_soc_dapm_sync(dapm); | ||
343 | |||
344 | return 0; | 342 | return 0; |
345 | } | 343 | } |
346 | 344 | ||
347 | static struct snd_soc_dai_link tegra_wm8903_dai = { | 345 | static struct snd_soc_dai_link tegra_wm8903_dai = { |
348 | .name = "WM8903", | 346 | .name = "WM8903", |
349 | .stream_name = "WM8903 PCM", | 347 | .stream_name = "WM8903 PCM", |
350 | .codec_name = "wm8903.0-001a", | 348 | .codec_name = "wm8903.0-001a", |
351 | .platform_name = "tegra-pcm-audio", | 349 | .platform_name = "tegra-pcm-audio", |
352 | .cpu_dai_name = "tegra-i2s.0", | 350 | .cpu_dai_name = "tegra-i2s.0", |
353 | .codec_dai_name = "wm8903-hifi", | 351 | .codec_dai_name = "wm8903-hifi", |
354 | .init = tegra_wm8903_init, | 352 | .init = tegra_wm8903_init, |
355 | .ops = &tegra_wm8903_ops, | 353 | .ops = &tegra_wm8903_ops, |
356 | }; | 354 | }; |
357 | 355 | ||
358 | static struct snd_soc_card snd_soc_tegra_wm8903 = { | 356 | static struct snd_soc_card snd_soc_tegra_wm8903 = { |
359 | .name = "tegra-wm8903", | 357 | .name = "tegra-wm8903", |
360 | .dai_link = &tegra_wm8903_dai, | 358 | .dai_link = &tegra_wm8903_dai, |
361 | .num_links = 1, | 359 | .num_links = 1, |
362 | 360 | ||
363 | .controls = tegra_wm8903_controls, | 361 | .controls = tegra_wm8903_controls, |
364 | .num_controls = ARRAY_SIZE(tegra_wm8903_controls), | 362 | .num_controls = ARRAY_SIZE(tegra_wm8903_controls), |
365 | .dapm_widgets = tegra_wm8903_dapm_widgets, | 363 | .dapm_widgets = tegra_wm8903_dapm_widgets, |
366 | .num_dapm_widgets = ARRAY_SIZE(tegra_wm8903_dapm_widgets), | 364 | .num_dapm_widgets = ARRAY_SIZE(tegra_wm8903_dapm_widgets), |
367 | }; | 365 | }; |
368 | 366 | ||
369 | static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev) | 367 | static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev) |
370 | { | 368 | { |
371 | struct snd_soc_card *card = &snd_soc_tegra_wm8903; | 369 | struct snd_soc_card *card = &snd_soc_tegra_wm8903; |
372 | struct tegra_wm8903 *machine; | 370 | struct tegra_wm8903 *machine; |
373 | struct tegra_wm8903_platform_data *pdata; | 371 | struct tegra_wm8903_platform_data *pdata; |
374 | int ret; | 372 | int ret; |
375 | 373 | ||
376 | pdata = pdev->dev.platform_data; | 374 | pdata = pdev->dev.platform_data; |
377 | if (!pdata) { | 375 | if (!pdata) { |
378 | dev_err(&pdev->dev, "No platform data supplied\n"); | 376 | dev_err(&pdev->dev, "No platform data supplied\n"); |
379 | return -EINVAL; | 377 | return -EINVAL; |
380 | } | 378 | } |
381 | 379 | ||
382 | machine = kzalloc(sizeof(struct tegra_wm8903), GFP_KERNEL); | 380 | machine = kzalloc(sizeof(struct tegra_wm8903), GFP_KERNEL); |
383 | if (!machine) { | 381 | if (!machine) { |
384 | dev_err(&pdev->dev, "Can't allocate tegra_wm8903 struct\n"); | 382 | dev_err(&pdev->dev, "Can't allocate tegra_wm8903 struct\n"); |
385 | return -ENOMEM; | 383 | return -ENOMEM; |
386 | } | 384 | } |
387 | 385 | ||
388 | machine->pdata = pdata; | 386 | machine->pdata = pdata; |
389 | 387 | ||
390 | ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev); | 388 | ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev); |
391 | if (ret) | 389 | if (ret) |
392 | goto err_free_machine; | 390 | goto err_free_machine; |
393 | 391 | ||
394 | card->dev = &pdev->dev; | 392 | card->dev = &pdev->dev; |
395 | platform_set_drvdata(pdev, card); | 393 | platform_set_drvdata(pdev, card); |
396 | snd_soc_card_set_drvdata(card, machine); | 394 | snd_soc_card_set_drvdata(card, machine); |
397 | 395 | ||
398 | if (machine_is_harmony()) { | 396 | if (machine_is_harmony()) { |
399 | card->dapm_routes = harmony_audio_map; | 397 | card->dapm_routes = harmony_audio_map; |
400 | card->num_dapm_routes = ARRAY_SIZE(harmony_audio_map); | 398 | card->num_dapm_routes = ARRAY_SIZE(harmony_audio_map); |
401 | } else if (machine_is_seaboard()) { | 399 | } else if (machine_is_seaboard()) { |
402 | card->dapm_routes = seaboard_audio_map; | 400 | card->dapm_routes = seaboard_audio_map; |
403 | card->num_dapm_routes = ARRAY_SIZE(seaboard_audio_map); | 401 | card->num_dapm_routes = ARRAY_SIZE(seaboard_audio_map); |
404 | } else if (machine_is_kaen()) { | 402 | } else if (machine_is_kaen()) { |
405 | card->dapm_routes = kaen_audio_map; | 403 | card->dapm_routes = kaen_audio_map; |
406 | card->num_dapm_routes = ARRAY_SIZE(kaen_audio_map); | 404 | card->num_dapm_routes = ARRAY_SIZE(kaen_audio_map); |
407 | } else { | 405 | } else { |
408 | card->dapm_routes = aebl_audio_map; | 406 | card->dapm_routes = aebl_audio_map; |
409 | card->num_dapm_routes = ARRAY_SIZE(aebl_audio_map); | 407 | card->num_dapm_routes = ARRAY_SIZE(aebl_audio_map); |
410 | } | 408 | } |
411 | 409 | ||
412 | ret = snd_soc_register_card(card); | 410 | ret = snd_soc_register_card(card); |
413 | if (ret) { | 411 | if (ret) { |
414 | dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", | 412 | dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", |
415 | ret); | 413 | ret); |
416 | goto err_fini_utils; | 414 | goto err_fini_utils; |
417 | } | 415 | } |
418 | 416 | ||
419 | return 0; | 417 | return 0; |
420 | 418 | ||
421 | err_fini_utils: | 419 | err_fini_utils: |
422 | tegra_asoc_utils_fini(&machine->util_data); | 420 | tegra_asoc_utils_fini(&machine->util_data); |
423 | err_free_machine: | 421 | err_free_machine: |
424 | kfree(machine); | 422 | kfree(machine); |
425 | return ret; | 423 | return ret; |
426 | } | 424 | } |
427 | 425 | ||
428 | static int __devexit tegra_wm8903_driver_remove(struct platform_device *pdev) | 426 | static int __devexit tegra_wm8903_driver_remove(struct platform_device *pdev) |
429 | { | 427 | { |
430 | struct snd_soc_card *card = platform_get_drvdata(pdev); | 428 | struct snd_soc_card *card = platform_get_drvdata(pdev); |
431 | struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); | 429 | struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); |
432 | struct tegra_wm8903_platform_data *pdata = machine->pdata; | 430 | struct tegra_wm8903_platform_data *pdata = machine->pdata; |
433 | 431 | ||
434 | if (machine->gpio_requested & GPIO_HP_DET) | 432 | if (machine->gpio_requested & GPIO_HP_DET) |
435 | snd_soc_jack_free_gpios(&tegra_wm8903_hp_jack, | 433 | snd_soc_jack_free_gpios(&tegra_wm8903_hp_jack, |
436 | 1, | 434 | 1, |
437 | &tegra_wm8903_hp_jack_gpio); | 435 | &tegra_wm8903_hp_jack_gpio); |
438 | if (machine->gpio_requested & GPIO_EXT_MIC_EN) | 436 | if (machine->gpio_requested & GPIO_EXT_MIC_EN) |
439 | gpio_free(pdata->gpio_ext_mic_en); | 437 | gpio_free(pdata->gpio_ext_mic_en); |
440 | if (machine->gpio_requested & GPIO_INT_MIC_EN) | 438 | if (machine->gpio_requested & GPIO_INT_MIC_EN) |
441 | gpio_free(pdata->gpio_int_mic_en); | 439 | gpio_free(pdata->gpio_int_mic_en); |
442 | if (machine->gpio_requested & GPIO_HP_MUTE) | 440 | if (machine->gpio_requested & GPIO_HP_MUTE) |
443 | gpio_free(pdata->gpio_hp_mute); | 441 | gpio_free(pdata->gpio_hp_mute); |
444 | if (machine->gpio_requested & GPIO_SPKR_EN) | 442 | if (machine->gpio_requested & GPIO_SPKR_EN) |
445 | gpio_free(pdata->gpio_spkr_en); | 443 | gpio_free(pdata->gpio_spkr_en); |
446 | machine->gpio_requested = 0; | 444 | machine->gpio_requested = 0; |
447 | 445 | ||
448 | snd_soc_unregister_card(card); | 446 | snd_soc_unregister_card(card); |
449 | 447 | ||
450 | tegra_asoc_utils_fini(&machine->util_data); | 448 | tegra_asoc_utils_fini(&machine->util_data); |
451 | 449 | ||
452 | kfree(machine); | 450 | kfree(machine); |
453 | 451 | ||
454 | return 0; | 452 | return 0; |
455 | } | 453 | } |
456 | 454 | ||
457 | static struct platform_driver tegra_wm8903_driver = { | 455 | static struct platform_driver tegra_wm8903_driver = { |
458 | .driver = { | 456 | .driver = { |
459 | .name = DRV_NAME, | 457 | .name = DRV_NAME, |
460 | .owner = THIS_MODULE, | 458 | .owner = THIS_MODULE, |
461 | .pm = &snd_soc_pm_ops, | 459 | .pm = &snd_soc_pm_ops, |
462 | }, | 460 | }, |
463 | .probe = tegra_wm8903_driver_probe, | 461 | .probe = tegra_wm8903_driver_probe, |
464 | .remove = __devexit_p(tegra_wm8903_driver_remove), | 462 | .remove = __devexit_p(tegra_wm8903_driver_remove), |
465 | }; | 463 | }; |
466 | 464 | ||
467 | static int __init tegra_wm8903_modinit(void) | 465 | static int __init tegra_wm8903_modinit(void) |
468 | { | 466 | { |
469 | return platform_driver_register(&tegra_wm8903_driver); | 467 | return platform_driver_register(&tegra_wm8903_driver); |
470 | } | 468 | } |
471 | module_init(tegra_wm8903_modinit); | 469 | module_init(tegra_wm8903_modinit); |
472 | 470 | ||
473 | static void __exit tegra_wm8903_modexit(void) | 471 | static void __exit tegra_wm8903_modexit(void) |
474 | { | 472 | { |
475 | platform_driver_unregister(&tegra_wm8903_driver); | 473 | platform_driver_unregister(&tegra_wm8903_driver); |
476 | } | 474 | } |
477 | module_exit(tegra_wm8903_modexit); | 475 | module_exit(tegra_wm8903_modexit); |
478 | 476 | ||
479 | MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>"); | 477 | MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>"); |
480 | MODULE_DESCRIPTION("Tegra+WM8903 machine ASoC driver"); | 478 | MODULE_DESCRIPTION("Tegra+WM8903 machine ASoC driver"); |
481 | MODULE_LICENSE("GPL"); | 479 | MODULE_LICENSE("GPL"); |
482 | MODULE_ALIAS("platform:" DRV_NAME); | 480 | MODULE_ALIAS("platform:" DRV_NAME); |
483 | 481 |
sound/soc/tegra/trimslice.c
1 | /* | 1 | /* |
2 | * trimslice.c - TrimSlice machine ASoC driver | 2 | * trimslice.c - TrimSlice machine ASoC driver |
3 | * | 3 | * |
4 | * Copyright (C) 2011 - CompuLab, Ltd. | 4 | * Copyright (C) 2011 - CompuLab, Ltd. |
5 | * Author: Mike Rapoport <mike@compulab.co.il> | 5 | * Author: Mike Rapoport <mike@compulab.co.il> |
6 | * | 6 | * |
7 | * Based on code copyright/by: | 7 | * Based on code copyright/by: |
8 | * Author: Stephen Warren <swarren@nvidia.com> | 8 | * Author: Stephen Warren <swarren@nvidia.com> |
9 | * Copyright (C) 2010-2011 - NVIDIA, Inc. | 9 | * Copyright (C) 2010-2011 - NVIDIA, Inc. |
10 | * | 10 | * |
11 | * This program is free software; you can redistribute it and/or | 11 | * This program is free software; you can redistribute it and/or |
12 | * modify it under the terms of the GNU General Public License | 12 | * modify it under the terms of the GNU General Public License |
13 | * version 2 as published by the Free Software Foundation. | 13 | * version 2 as published by the Free Software Foundation. |
14 | * | 14 | * |
15 | * This program is distributed in the hope that it will be useful, but | 15 | * This program is distributed in the hope that it will be useful, but |
16 | * WITHOUT ANY WARRANTY; without even the implied warranty of | 16 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
18 | * General Public License for more details. | 18 | * General Public License for more details. |
19 | * | 19 | * |
20 | * You should have received a copy of the GNU General Public License | 20 | * You should have received a copy of the GNU General Public License |
21 | * along with this program; if not, write to the Free Software | 21 | * along with this program; if not, write to the Free Software |
22 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | 22 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA |
23 | * 02110-1301 USA | 23 | * 02110-1301 USA |
24 | * | 24 | * |
25 | */ | 25 | */ |
26 | 26 | ||
27 | #include <asm/mach-types.h> | 27 | #include <asm/mach-types.h> |
28 | 28 | ||
29 | #include <linux/module.h> | 29 | #include <linux/module.h> |
30 | #include <linux/platform_device.h> | 30 | #include <linux/platform_device.h> |
31 | #include <linux/slab.h> | 31 | #include <linux/slab.h> |
32 | 32 | ||
33 | #include <sound/core.h> | 33 | #include <sound/core.h> |
34 | #include <sound/jack.h> | 34 | #include <sound/jack.h> |
35 | #include <sound/pcm.h> | 35 | #include <sound/pcm.h> |
36 | #include <sound/pcm_params.h> | 36 | #include <sound/pcm_params.h> |
37 | #include <sound/soc.h> | 37 | #include <sound/soc.h> |
38 | 38 | ||
39 | #include "../codecs/tlv320aic23.h" | 39 | #include "../codecs/tlv320aic23.h" |
40 | 40 | ||
41 | #include "tegra_das.h" | 41 | #include "tegra_das.h" |
42 | #include "tegra_i2s.h" | 42 | #include "tegra_i2s.h" |
43 | #include "tegra_pcm.h" | 43 | #include "tegra_pcm.h" |
44 | #include "tegra_asoc_utils.h" | 44 | #include "tegra_asoc_utils.h" |
45 | 45 | ||
46 | #define DRV_NAME "tegra-snd-trimslice" | 46 | #define DRV_NAME "tegra-snd-trimslice" |
47 | 47 | ||
48 | struct tegra_trimslice { | 48 | struct tegra_trimslice { |
49 | struct tegra_asoc_utils_data util_data; | 49 | struct tegra_asoc_utils_data util_data; |
50 | }; | 50 | }; |
51 | 51 | ||
52 | static int trimslice_asoc_hw_params(struct snd_pcm_substream *substream, | 52 | static int trimslice_asoc_hw_params(struct snd_pcm_substream *substream, |
53 | struct snd_pcm_hw_params *params) | 53 | struct snd_pcm_hw_params *params) |
54 | { | 54 | { |
55 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 55 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
56 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 56 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
57 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 57 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
58 | struct snd_soc_codec *codec = rtd->codec; | 58 | struct snd_soc_codec *codec = rtd->codec; |
59 | struct snd_soc_card *card = codec->card; | 59 | struct snd_soc_card *card = codec->card; |
60 | struct tegra_trimslice *trimslice = snd_soc_card_get_drvdata(card); | 60 | struct tegra_trimslice *trimslice = snd_soc_card_get_drvdata(card); |
61 | int srate, mclk; | 61 | int srate, mclk; |
62 | int err; | 62 | int err; |
63 | 63 | ||
64 | srate = params_rate(params); | 64 | srate = params_rate(params); |
65 | mclk = 128 * srate; | 65 | mclk = 128 * srate; |
66 | 66 | ||
67 | err = tegra_asoc_utils_set_rate(&trimslice->util_data, srate, mclk); | 67 | err = tegra_asoc_utils_set_rate(&trimslice->util_data, srate, mclk); |
68 | if (err < 0) { | 68 | if (err < 0) { |
69 | dev_err(card->dev, "Can't configure clocks\n"); | 69 | dev_err(card->dev, "Can't configure clocks\n"); |
70 | return err; | 70 | return err; |
71 | } | 71 | } |
72 | 72 | ||
73 | err = snd_soc_dai_set_fmt(codec_dai, | 73 | err = snd_soc_dai_set_fmt(codec_dai, |
74 | SND_SOC_DAIFMT_I2S | | 74 | SND_SOC_DAIFMT_I2S | |
75 | SND_SOC_DAIFMT_NB_NF | | 75 | SND_SOC_DAIFMT_NB_NF | |
76 | SND_SOC_DAIFMT_CBS_CFS); | 76 | SND_SOC_DAIFMT_CBS_CFS); |
77 | if (err < 0) { | 77 | if (err < 0) { |
78 | dev_err(card->dev, "codec_dai fmt not set\n"); | 78 | dev_err(card->dev, "codec_dai fmt not set\n"); |
79 | return err; | 79 | return err; |
80 | } | 80 | } |
81 | 81 | ||
82 | err = snd_soc_dai_set_fmt(cpu_dai, | 82 | err = snd_soc_dai_set_fmt(cpu_dai, |
83 | SND_SOC_DAIFMT_I2S | | 83 | SND_SOC_DAIFMT_I2S | |
84 | SND_SOC_DAIFMT_NB_NF | | 84 | SND_SOC_DAIFMT_NB_NF | |
85 | SND_SOC_DAIFMT_CBS_CFS); | 85 | SND_SOC_DAIFMT_CBS_CFS); |
86 | if (err < 0) { | 86 | if (err < 0) { |
87 | dev_err(card->dev, "cpu_dai fmt not set\n"); | 87 | dev_err(card->dev, "cpu_dai fmt not set\n"); |
88 | return err; | 88 | return err; |
89 | } | 89 | } |
90 | 90 | ||
91 | err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, | 91 | err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, |
92 | SND_SOC_CLOCK_IN); | 92 | SND_SOC_CLOCK_IN); |
93 | if (err < 0) { | 93 | if (err < 0) { |
94 | dev_err(card->dev, "codec_dai clock not set\n"); | 94 | dev_err(card->dev, "codec_dai clock not set\n"); |
95 | return err; | 95 | return err; |
96 | } | 96 | } |
97 | 97 | ||
98 | return 0; | 98 | return 0; |
99 | } | 99 | } |
100 | 100 | ||
101 | static struct snd_soc_ops trimslice_asoc_ops = { | 101 | static struct snd_soc_ops trimslice_asoc_ops = { |
102 | .hw_params = trimslice_asoc_hw_params, | 102 | .hw_params = trimslice_asoc_hw_params, |
103 | }; | 103 | }; |
104 | 104 | ||
105 | static const struct snd_soc_dapm_widget trimslice_dapm_widgets[] = { | 105 | static const struct snd_soc_dapm_widget trimslice_dapm_widgets[] = { |
106 | SND_SOC_DAPM_HP("Line Out", NULL), | 106 | SND_SOC_DAPM_HP("Line Out", NULL), |
107 | SND_SOC_DAPM_LINE("Line In", NULL), | 107 | SND_SOC_DAPM_LINE("Line In", NULL), |
108 | }; | 108 | }; |
109 | 109 | ||
110 | static const struct snd_soc_dapm_route trimslice_audio_map[] = { | 110 | static const struct snd_soc_dapm_route trimslice_audio_map[] = { |
111 | {"Line Out", NULL, "LOUT"}, | 111 | {"Line Out", NULL, "LOUT"}, |
112 | {"Line Out", NULL, "ROUT"}, | 112 | {"Line Out", NULL, "ROUT"}, |
113 | 113 | ||
114 | {"LLINEIN", NULL, "Line In"}, | 114 | {"LLINEIN", NULL, "Line In"}, |
115 | {"RLINEIN", NULL, "Line In"}, | 115 | {"RLINEIN", NULL, "Line In"}, |
116 | }; | 116 | }; |
117 | 117 | ||
118 | static int trimslice_asoc_init(struct snd_soc_pcm_runtime *rtd) | 118 | static int trimslice_asoc_init(struct snd_soc_pcm_runtime *rtd) |
119 | { | 119 | { |
120 | struct snd_soc_codec *codec = rtd->codec; | 120 | struct snd_soc_codec *codec = rtd->codec; |
121 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 121 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
122 | 122 | ||
123 | snd_soc_dapm_nc_pin(dapm, "LHPOUT"); | 123 | snd_soc_dapm_nc_pin(dapm, "LHPOUT"); |
124 | snd_soc_dapm_nc_pin(dapm, "RHPOUT"); | 124 | snd_soc_dapm_nc_pin(dapm, "RHPOUT"); |
125 | snd_soc_dapm_nc_pin(dapm, "MICIN"); | 125 | snd_soc_dapm_nc_pin(dapm, "MICIN"); |
126 | 126 | ||
127 | snd_soc_dapm_sync(dapm); | ||
128 | |||
129 | return 0; | 127 | return 0; |
130 | } | 128 | } |
131 | 129 | ||
132 | static struct snd_soc_dai_link trimslice_tlv320aic23_dai = { | 130 | static struct snd_soc_dai_link trimslice_tlv320aic23_dai = { |
133 | .name = "TLV320AIC23", | 131 | .name = "TLV320AIC23", |
134 | .stream_name = "AIC23", | 132 | .stream_name = "AIC23", |
135 | .codec_name = "tlv320aic23-codec.2-001a", | 133 | .codec_name = "tlv320aic23-codec.2-001a", |
136 | .platform_name = "tegra-pcm-audio", | 134 | .platform_name = "tegra-pcm-audio", |
137 | .cpu_dai_name = "tegra-i2s.0", | 135 | .cpu_dai_name = "tegra-i2s.0", |
138 | .codec_dai_name = "tlv320aic23-hifi", | 136 | .codec_dai_name = "tlv320aic23-hifi", |
139 | .init = trimslice_asoc_init, | 137 | .init = trimslice_asoc_init, |
140 | .ops = &trimslice_asoc_ops, | 138 | .ops = &trimslice_asoc_ops, |
141 | }; | 139 | }; |
142 | 140 | ||
143 | static struct snd_soc_card snd_soc_trimslice = { | 141 | static struct snd_soc_card snd_soc_trimslice = { |
144 | .name = "tegra-trimslice", | 142 | .name = "tegra-trimslice", |
145 | .dai_link = &trimslice_tlv320aic23_dai, | 143 | .dai_link = &trimslice_tlv320aic23_dai, |
146 | .num_links = 1, | 144 | .num_links = 1, |
147 | 145 | ||
148 | .dapm_widgets = trimslice_dapm_widgets, | 146 | .dapm_widgets = trimslice_dapm_widgets, |
149 | .num_dapm_widgets = ARRAY_SIZE(trimslice_dapm_widgets), | 147 | .num_dapm_widgets = ARRAY_SIZE(trimslice_dapm_widgets), |
150 | .dapm_routes = trimslice_audio_map, | 148 | .dapm_routes = trimslice_audio_map, |
151 | .num_dapm_routes = ARRAY_SIZE(trimslice_audio_map), | 149 | .num_dapm_routes = ARRAY_SIZE(trimslice_audio_map), |
152 | }; | 150 | }; |
153 | 151 | ||
154 | static __devinit int tegra_snd_trimslice_probe(struct platform_device *pdev) | 152 | static __devinit int tegra_snd_trimslice_probe(struct platform_device *pdev) |
155 | { | 153 | { |
156 | struct snd_soc_card *card = &snd_soc_trimslice; | 154 | struct snd_soc_card *card = &snd_soc_trimslice; |
157 | struct tegra_trimslice *trimslice; | 155 | struct tegra_trimslice *trimslice; |
158 | int ret; | 156 | int ret; |
159 | 157 | ||
160 | trimslice = kzalloc(sizeof(struct tegra_trimslice), GFP_KERNEL); | 158 | trimslice = kzalloc(sizeof(struct tegra_trimslice), GFP_KERNEL); |
161 | if (!trimslice) { | 159 | if (!trimslice) { |
162 | dev_err(&pdev->dev, "Can't allocate tegra_trimslice\n"); | 160 | dev_err(&pdev->dev, "Can't allocate tegra_trimslice\n"); |
163 | return -ENOMEM; | 161 | return -ENOMEM; |
164 | } | 162 | } |
165 | 163 | ||
166 | ret = tegra_asoc_utils_init(&trimslice->util_data, &pdev->dev); | 164 | ret = tegra_asoc_utils_init(&trimslice->util_data, &pdev->dev); |
167 | if (ret) | 165 | if (ret) |
168 | goto err_free_trimslice; | 166 | goto err_free_trimslice; |
169 | 167 | ||
170 | card->dev = &pdev->dev; | 168 | card->dev = &pdev->dev; |
171 | platform_set_drvdata(pdev, card); | 169 | platform_set_drvdata(pdev, card); |
172 | snd_soc_card_set_drvdata(card, trimslice); | 170 | snd_soc_card_set_drvdata(card, trimslice); |
173 | 171 | ||
174 | ret = snd_soc_register_card(card); | 172 | ret = snd_soc_register_card(card); |
175 | if (ret) { | 173 | if (ret) { |
176 | dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", | 174 | dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", |
177 | ret); | 175 | ret); |
178 | goto err_fini_utils; | 176 | goto err_fini_utils; |
179 | } | 177 | } |
180 | 178 | ||
181 | return 0; | 179 | return 0; |
182 | 180 | ||
183 | err_fini_utils: | 181 | err_fini_utils: |
184 | tegra_asoc_utils_fini(&trimslice->util_data); | 182 | tegra_asoc_utils_fini(&trimslice->util_data); |
185 | err_free_trimslice: | 183 | err_free_trimslice: |
186 | kfree(trimslice); | 184 | kfree(trimslice); |
187 | return ret; | 185 | return ret; |
188 | } | 186 | } |
189 | 187 | ||
190 | static int __devexit tegra_snd_trimslice_remove(struct platform_device *pdev) | 188 | static int __devexit tegra_snd_trimslice_remove(struct platform_device *pdev) |
191 | { | 189 | { |
192 | struct snd_soc_card *card = platform_get_drvdata(pdev); | 190 | struct snd_soc_card *card = platform_get_drvdata(pdev); |
193 | struct tegra_trimslice *trimslice = snd_soc_card_get_drvdata(card); | 191 | struct tegra_trimslice *trimslice = snd_soc_card_get_drvdata(card); |
194 | 192 | ||
195 | snd_soc_unregister_card(card); | 193 | snd_soc_unregister_card(card); |
196 | 194 | ||
197 | tegra_asoc_utils_fini(&trimslice->util_data); | 195 | tegra_asoc_utils_fini(&trimslice->util_data); |
198 | 196 | ||
199 | kfree(trimslice); | 197 | kfree(trimslice); |
200 | 198 | ||
201 | return 0; | 199 | return 0; |
202 | } | 200 | } |
203 | 201 | ||
204 | static struct platform_driver tegra_snd_trimslice_driver = { | 202 | static struct platform_driver tegra_snd_trimslice_driver = { |
205 | .driver = { | 203 | .driver = { |
206 | .name = DRV_NAME, | 204 | .name = DRV_NAME, |
207 | .owner = THIS_MODULE, | 205 | .owner = THIS_MODULE, |
208 | }, | 206 | }, |
209 | .probe = tegra_snd_trimslice_probe, | 207 | .probe = tegra_snd_trimslice_probe, |
210 | .remove = __devexit_p(tegra_snd_trimslice_remove), | 208 | .remove = __devexit_p(tegra_snd_trimslice_remove), |
211 | }; | 209 | }; |
212 | 210 | ||
213 | static int __init snd_tegra_trimslice_init(void) | 211 | static int __init snd_tegra_trimslice_init(void) |
214 | { | 212 | { |
215 | return platform_driver_register(&tegra_snd_trimslice_driver); | 213 | return platform_driver_register(&tegra_snd_trimslice_driver); |
216 | } | 214 | } |
217 | module_init(snd_tegra_trimslice_init); | 215 | module_init(snd_tegra_trimslice_init); |
218 | 216 | ||
219 | static void __exit snd_tegra_trimslice_exit(void) | 217 | static void __exit snd_tegra_trimslice_exit(void) |
220 | { | 218 | { |
221 | platform_driver_unregister(&tegra_snd_trimslice_driver); | 219 | platform_driver_unregister(&tegra_snd_trimslice_driver); |
222 | } | 220 | } |
223 | module_exit(snd_tegra_trimslice_exit); | 221 | module_exit(snd_tegra_trimslice_exit); |
224 | 222 | ||
225 | MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>"); | 223 | MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>"); |
226 | MODULE_DESCRIPTION("Trimslice machine ASoC driver"); | 224 | MODULE_DESCRIPTION("Trimslice machine ASoC driver"); |
227 | MODULE_LICENSE("GPL"); | 225 | MODULE_LICENSE("GPL"); |
228 | MODULE_ALIAS("platform:" DRV_NAME); | 226 | MODULE_ALIAS("platform:" DRV_NAME); |
229 | 227 |