diff options
Diffstat (limited to 'sound/soc/samsung/neo1973_wm8753.c')
-rw-r--r-- | sound/soc/samsung/neo1973_wm8753.c | 538 |
1 files changed, 538 insertions, 0 deletions
diff --git a/sound/soc/samsung/neo1973_wm8753.c b/sound/soc/samsung/neo1973_wm8753.c new file mode 100644 index 000000000000..16152ed08648 --- /dev/null +++ b/sound/soc/samsung/neo1973_wm8753.c | |||
@@ -0,0 +1,538 @@ | |||
1 | /* | ||
2 | * neo1973_wm8753.c -- SoC audio for Openmoko Neo1973 and Freerunner devices | ||
3 | * | ||
4 | * Copyright 2007 Openmoko Inc | ||
5 | * Author: Graeme Gregory <graeme@openmoko.org> | ||
6 | * Copyright 2007 Wolfson Microelectronics PLC. | ||
7 | * Author: Graeme Gregory | ||
8 | * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com | ||
9 | * Copyright 2009 Wolfson Microelectronics | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify it | ||
12 | * under the terms of the GNU General Public License as published by the | ||
13 | * Free Software Foundation; either version 2 of the License, or (at your | ||
14 | * option) any later version. | ||
15 | */ | ||
16 | |||
17 | #include <linux/module.h> | ||
18 | #include <linux/platform_device.h> | ||
19 | #include <linux/gpio.h> | ||
20 | |||
21 | #include <sound/soc.h> | ||
22 | |||
23 | #include <asm/mach-types.h> | ||
24 | #include <plat/regs-iis.h> | ||
25 | #include <mach/gta02.h> | ||
26 | |||
27 | #include "../codecs/wm8753.h" | ||
28 | #include "s3c24xx-i2s.h" | ||
29 | |||
30 | static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream, | ||
31 | struct snd_pcm_hw_params *params) | ||
32 | { | ||
33 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
34 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
35 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
36 | unsigned int pll_out = 0, bclk = 0; | ||
37 | int ret = 0; | ||
38 | unsigned long iis_clkrate; | ||
39 | |||
40 | iis_clkrate = s3c24xx_i2s_get_clockrate(); | ||
41 | |||
42 | switch (params_rate(params)) { | ||
43 | case 8000: | ||
44 | case 16000: | ||
45 | pll_out = 12288000; | ||
46 | break; | ||
47 | case 48000: | ||
48 | bclk = WM8753_BCLK_DIV_4; | ||
49 | pll_out = 12288000; | ||
50 | break; | ||
51 | case 96000: | ||
52 | bclk = WM8753_BCLK_DIV_2; | ||
53 | pll_out = 12288000; | ||
54 | break; | ||
55 | case 11025: | ||
56 | bclk = WM8753_BCLK_DIV_16; | ||
57 | pll_out = 11289600; | ||
58 | break; | ||
59 | case 22050: | ||
60 | bclk = WM8753_BCLK_DIV_8; | ||
61 | pll_out = 11289600; | ||
62 | break; | ||
63 | case 44100: | ||
64 | bclk = WM8753_BCLK_DIV_4; | ||
65 | pll_out = 11289600; | ||
66 | break; | ||
67 | case 88200: | ||
68 | bclk = WM8753_BCLK_DIV_2; | ||
69 | pll_out = 11289600; | ||
70 | break; | ||
71 | } | ||
72 | |||
73 | /* set codec DAI configuration */ | ||
74 | ret = snd_soc_dai_set_fmt(codec_dai, | ||
75 | SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | | ||
76 | SND_SOC_DAIFMT_CBM_CFM); | ||
77 | if (ret < 0) | ||
78 | return ret; | ||
79 | |||
80 | /* set cpu DAI configuration */ | ||
81 | ret = snd_soc_dai_set_fmt(cpu_dai, | ||
82 | SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | | ||
83 | SND_SOC_DAIFMT_CBM_CFM); | ||
84 | if (ret < 0) | ||
85 | return ret; | ||
86 | |||
87 | /* set the codec system clock for DAC and ADC */ | ||
88 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, pll_out, | ||
89 | SND_SOC_CLOCK_IN); | ||
90 | if (ret < 0) | ||
91 | return ret; | ||
92 | |||
93 | /* set MCLK division for sample rate */ | ||
94 | ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK, | ||
95 | S3C2410_IISMOD_32FS); | ||
96 | if (ret < 0) | ||
97 | return ret; | ||
98 | |||
99 | /* set codec BCLK division for sample rate */ | ||
100 | ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_BCLKDIV, bclk); | ||
101 | if (ret < 0) | ||
102 | return ret; | ||
103 | |||
104 | /* set prescaler division for sample rate */ | ||
105 | ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER, | ||
106 | S3C24XX_PRESCALE(4, 4)); | ||
107 | if (ret < 0) | ||
108 | return ret; | ||
109 | |||
110 | /* codec PLL input is PCLK/4 */ | ||
111 | ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, | ||
112 | iis_clkrate / 4, pll_out); | ||
113 | if (ret < 0) | ||
114 | return ret; | ||
115 | |||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | static int neo1973_hifi_hw_free(struct snd_pcm_substream *substream) | ||
120 | { | ||
121 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
122 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
123 | |||
124 | /* disable the PLL */ | ||
125 | return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0, 0); | ||
126 | } | ||
127 | |||
128 | /* | ||
129 | * Neo1973 WM8753 HiFi DAI opserations. | ||
130 | */ | ||
131 | static struct snd_soc_ops neo1973_hifi_ops = { | ||
132 | .hw_params = neo1973_hifi_hw_params, | ||
133 | .hw_free = neo1973_hifi_hw_free, | ||
134 | }; | ||
135 | |||
136 | static int neo1973_voice_hw_params(struct snd_pcm_substream *substream, | ||
137 | struct snd_pcm_hw_params *params) | ||
138 | { | ||
139 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
140 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
141 | unsigned int pcmdiv = 0; | ||
142 | int ret = 0; | ||
143 | unsigned long iis_clkrate; | ||
144 | |||
145 | iis_clkrate = s3c24xx_i2s_get_clockrate(); | ||
146 | |||
147 | if (params_rate(params) != 8000) | ||
148 | return -EINVAL; | ||
149 | if (params_channels(params) != 1) | ||
150 | return -EINVAL; | ||
151 | |||
152 | pcmdiv = WM8753_PCM_DIV_6; /* 2.048 MHz */ | ||
153 | |||
154 | /* todo: gg check mode (DSP_B) against CSR datasheet */ | ||
155 | /* set codec DAI configuration */ | ||
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); | ||
158 | if (ret < 0) | ||
159 | return ret; | ||
160 | |||
161 | /* set the codec system clock for DAC and ADC */ | ||
162 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_PCMCLK, 12288000, | ||
163 | SND_SOC_CLOCK_IN); | ||
164 | if (ret < 0) | ||
165 | return ret; | ||
166 | |||
167 | /* set codec PCM division for sample rate */ | ||
168 | ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_PCMDIV, pcmdiv); | ||
169 | if (ret < 0) | ||
170 | return ret; | ||
171 | |||
172 | /* configure and enable PLL for 12.288MHz output */ | ||
173 | ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, | ||
174 | iis_clkrate / 4, 12288000); | ||
175 | if (ret < 0) | ||
176 | return ret; | ||
177 | |||
178 | return 0; | ||
179 | } | ||
180 | |||
181 | static int neo1973_voice_hw_free(struct snd_pcm_substream *substream) | ||
182 | { | ||
183 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
184 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
185 | |||
186 | /* disable the PLL */ | ||
187 | return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0, 0); | ||
188 | } | ||
189 | |||
190 | static struct snd_soc_ops neo1973_voice_ops = { | ||
191 | .hw_params = neo1973_voice_hw_params, | ||
192 | .hw_free = neo1973_voice_hw_free, | ||
193 | }; | ||
194 | |||
195 | /* Shared routes and controls */ | ||
196 | |||
197 | static const struct snd_soc_dapm_widget neo1973_wm8753_dapm_widgets[] = { | ||
198 | SND_SOC_DAPM_LINE("GSM Line Out", NULL), | ||
199 | SND_SOC_DAPM_LINE("GSM Line In", NULL), | ||
200 | SND_SOC_DAPM_MIC("Headset Mic", NULL), | ||
201 | SND_SOC_DAPM_MIC("Handset Mic", NULL), | ||
202 | }; | ||
203 | |||
204 | static const struct snd_soc_dapm_route neo1973_wm8753_routes[] = { | ||
205 | /* Connections to the GSM Module */ | ||
206 | {"GSM Line Out", NULL, "MONO1"}, | ||
207 | {"GSM Line Out", NULL, "MONO2"}, | ||
208 | {"RXP", NULL, "GSM Line In"}, | ||
209 | {"RXN", NULL, "GSM Line In"}, | ||
210 | |||
211 | /* Connections to Headset */ | ||
212 | {"MIC1", NULL, "Mic Bias"}, | ||
213 | {"Mic Bias", NULL, "Headset Mic"}, | ||
214 | |||
215 | /* Call Mic */ | ||
216 | {"MIC2", NULL, "Mic Bias"}, | ||
217 | {"MIC2N", NULL, "Mic Bias"}, | ||
218 | {"Mic Bias", NULL, "Handset Mic"}, | ||
219 | |||
220 | /* Connect the ALC pins */ | ||
221 | {"ACIN", NULL, "ACOP"}, | ||
222 | }; | ||
223 | |||
224 | static const struct snd_kcontrol_new neo1973_wm8753_controls[] = { | ||
225 | SOC_DAPM_PIN_SWITCH("GSM Line Out"), | ||
226 | SOC_DAPM_PIN_SWITCH("GSM Line In"), | ||
227 | SOC_DAPM_PIN_SWITCH("Headset Mic"), | ||
228 | SOC_DAPM_PIN_SWITCH("Handset Mic"), | ||
229 | }; | ||
230 | |||
231 | /* GTA02 specific routes and controls */ | ||
232 | |||
233 | #ifdef CONFIG_MACH_NEO1973_GTA02 | ||
234 | |||
235 | static int gta02_speaker_enabled; | ||
236 | |||
237 | static int lm4853_set_spk(struct snd_kcontrol *kcontrol, | ||
238 | struct snd_ctl_elem_value *ucontrol) | ||
239 | { | ||
240 | gta02_speaker_enabled = ucontrol->value.integer.value[0]; | ||
241 | |||
242 | gpio_set_value(GTA02_GPIO_HP_IN, !gta02_speaker_enabled); | ||
243 | |||
244 | return 0; | ||
245 | } | ||
246 | |||
247 | static int lm4853_get_spk(struct snd_kcontrol *kcontrol, | ||
248 | struct snd_ctl_elem_value *ucontrol) | ||
249 | { | ||
250 | ucontrol->value.integer.value[0] = gta02_speaker_enabled; | ||
251 | return 0; | ||
252 | } | ||
253 | |||
254 | static int lm4853_event(struct snd_soc_dapm_widget *w, | ||
255 | struct snd_kcontrol *k, int event) | ||
256 | { | ||
257 | gpio_set_value(GTA02_GPIO_AMP_SHUT, SND_SOC_DAPM_EVENT_OFF(event)); | ||
258 | |||
259 | return 0; | ||
260 | } | ||
261 | |||
262 | static const struct snd_soc_dapm_route neo1973_gta02_routes[] = { | ||
263 | /* Connections to the amp */ | ||
264 | {"Stereo Out", NULL, "LOUT1"}, | ||
265 | {"Stereo Out", NULL, "ROUT1"}, | ||
266 | |||
267 | /* Call Speaker */ | ||
268 | {"Handset Spk", NULL, "LOUT2"}, | ||
269 | {"Handset Spk", NULL, "ROUT2"}, | ||
270 | }; | ||
271 | |||
272 | static const struct snd_kcontrol_new neo1973_gta02_wm8753_controls[] = { | ||
273 | SOC_DAPM_PIN_SWITCH("Handset Spk"), | ||
274 | SOC_DAPM_PIN_SWITCH("Stereo Out"), | ||
275 | |||
276 | SOC_SINGLE_BOOL_EXT("Amp Spk Switch", 0, | ||
277 | lm4853_get_spk, | ||
278 | lm4853_set_spk), | ||
279 | }; | ||
280 | |||
281 | static const struct snd_soc_dapm_widget neo1973_gta02_wm8753_dapm_widgets[] = { | ||
282 | SND_SOC_DAPM_SPK("Handset Spk", NULL), | ||
283 | SND_SOC_DAPM_SPK("Stereo Out", lm4853_event), | ||
284 | }; | ||
285 | |||
286 | static int neo1973_gta02_wm8753_init(struct snd_soc_codec *codec) | ||
287 | { | ||
288 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
289 | int ret; | ||
290 | |||
291 | ret = snd_soc_dapm_new_controls(dapm, neo1973_gta02_wm8753_dapm_widgets, | ||
292 | ARRAY_SIZE(neo1973_gta02_wm8753_dapm_widgets)); | ||
293 | if (ret) | ||
294 | return ret; | ||
295 | |||
296 | ret = snd_soc_dapm_add_routes(dapm, neo1973_gta02_routes, | ||
297 | ARRAY_SIZE(neo1973_gta02_routes)); | ||
298 | if (ret) | ||
299 | return ret; | ||
300 | |||
301 | ret = snd_soc_add_controls(codec, neo1973_gta02_wm8753_controls, | ||
302 | ARRAY_SIZE(neo1973_gta02_wm8753_controls)); | ||
303 | if (ret) | ||
304 | return ret; | ||
305 | |||
306 | snd_soc_dapm_disable_pin(dapm, "Stereo Out"); | ||
307 | snd_soc_dapm_disable_pin(dapm, "Handset Spk"); | ||
308 | snd_soc_dapm_ignore_suspend(dapm, "Stereo Out"); | ||
309 | snd_soc_dapm_ignore_suspend(dapm, "Handset Spk"); | ||
310 | |||
311 | return 0; | ||
312 | } | ||
313 | |||
314 | #else | ||
315 | static int neo1973_gta02_wm8753_init(struct snd_soc_code *codec) { return 0; } | ||
316 | #endif | ||
317 | |||
318 | static int neo1973_wm8753_init(struct snd_soc_pcm_runtime *rtd) | ||
319 | { | ||
320 | struct snd_soc_codec *codec = rtd->codec; | ||
321 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
322 | int ret; | ||
323 | |||
324 | /* set up NC codec pins */ | ||
325 | if (machine_is_neo1973_gta01()) { | ||
326 | snd_soc_dapm_nc_pin(dapm, "LOUT2"); | ||
327 | snd_soc_dapm_nc_pin(dapm, "ROUT2"); | ||
328 | } | ||
329 | snd_soc_dapm_nc_pin(dapm, "OUT3"); | ||
330 | snd_soc_dapm_nc_pin(dapm, "OUT4"); | ||
331 | snd_soc_dapm_nc_pin(dapm, "LINE1"); | ||
332 | snd_soc_dapm_nc_pin(dapm, "LINE2"); | ||
333 | |||
334 | /* Add neo1973 specific widgets */ | ||
335 | ret = snd_soc_dapm_new_controls(dapm, neo1973_wm8753_dapm_widgets, | ||
336 | ARRAY_SIZE(neo1973_wm8753_dapm_widgets)); | ||
337 | if (ret) | ||
338 | return ret; | ||
339 | |||
340 | /* add neo1973 specific controls */ | ||
341 | ret = snd_soc_add_controls(codec, neo1973_wm8753_controls, | ||
342 | ARRAY_SIZE(neo1973_wm8753_controls)); | ||
343 | if (ret) | ||
344 | return ret; | ||
345 | |||
346 | /* set up neo1973 specific audio routes */ | ||
347 | ret = snd_soc_dapm_add_routes(dapm, neo1973_wm8753_routes, | ||
348 | ARRAY_SIZE(neo1973_wm8753_routes)); | ||
349 | if (ret) | ||
350 | return ret; | ||
351 | |||
352 | /* set endpoints to default off mode */ | ||
353 | snd_soc_dapm_disable_pin(dapm, "GSM Line Out"); | ||
354 | snd_soc_dapm_disable_pin(dapm, "GSM Line In"); | ||
355 | snd_soc_dapm_disable_pin(dapm, "Headset Mic"); | ||
356 | snd_soc_dapm_disable_pin(dapm, "Handset Mic"); | ||
357 | |||
358 | /* allow audio paths from the GSM modem to run during suspend */ | ||
359 | snd_soc_dapm_ignore_suspend(dapm, "GSM Line Out"); | ||
360 | snd_soc_dapm_ignore_suspend(dapm, "GSM Line In"); | ||
361 | snd_soc_dapm_ignore_suspend(dapm, "Headset Mic"); | ||
362 | snd_soc_dapm_ignore_suspend(dapm, "Handset Mic"); | ||
363 | |||
364 | if (machine_is_neo1973_gta02()) { | ||
365 | ret = neo1973_gta02_wm8753_init(codec); | ||
366 | if (ret) | ||
367 | return ret; | ||
368 | } | ||
369 | |||
370 | snd_soc_dapm_sync(dapm); | ||
371 | |||
372 | return 0; | ||
373 | } | ||
374 | |||
375 | /* GTA01 specific controls */ | ||
376 | |||
377 | #ifdef CONFIG_MACH_NEO1973_GTA01 | ||
378 | |||
379 | static const struct snd_soc_dapm_route neo1973_lm4857_routes[] = { | ||
380 | {"Amp IN", NULL, "ROUT1"}, | ||
381 | {"Amp IN", NULL, "LOUT1"}, | ||
382 | |||
383 | {"Handset Spk", NULL, "Amp EP"}, | ||
384 | {"Stereo Out", NULL, "Amp LS"}, | ||
385 | {"Headphone", NULL, "Amp HP"}, | ||
386 | }; | ||
387 | |||
388 | static const struct snd_soc_dapm_widget neo1973_lm4857_dapm_widgets[] = { | ||
389 | SND_SOC_DAPM_SPK("Handset Spk", NULL), | ||
390 | SND_SOC_DAPM_SPK("Stereo Out", NULL), | ||
391 | SND_SOC_DAPM_HP("Headphone", NULL), | ||
392 | }; | ||
393 | |||
394 | static int neo1973_lm4857_init(struct snd_soc_dapm_context *dapm) | ||
395 | { | ||
396 | int ret; | ||
397 | |||
398 | ret = snd_soc_dapm_new_controls(dapm, neo1973_lm4857_dapm_widgets, | ||
399 | ARRAY_SIZE(neo1973_lm4857_dapm_widgets)); | ||
400 | if (ret) | ||
401 | return ret; | ||
402 | |||
403 | ret = snd_soc_dapm_add_routes(dapm, neo1973_lm4857_routes, | ||
404 | ARRAY_SIZE(neo1973_lm4857_routes)); | ||
405 | if (ret) | ||
406 | return ret; | ||
407 | |||
408 | snd_soc_dapm_ignore_suspend(dapm, "Stereo Out"); | ||
409 | snd_soc_dapm_ignore_suspend(dapm, "Handset Spk"); | ||
410 | snd_soc_dapm_ignore_suspend(dapm, "Headphone"); | ||
411 | |||
412 | snd_soc_dapm_sync(dapm); | ||
413 | |||
414 | return 0; | ||
415 | } | ||
416 | |||
417 | #else | ||
418 | static int neo1973_lm4857_init(struct snd_soc_dapm_context *dapm) { return 0; }; | ||
419 | #endif | ||
420 | |||
421 | static struct snd_soc_dai_link neo1973_dai[] = { | ||
422 | { /* Hifi Playback - for similatious use with voice below */ | ||
423 | .name = "WM8753", | ||
424 | .stream_name = "WM8753 HiFi", | ||
425 | .platform_name = "samsung-audio", | ||
426 | .cpu_dai_name = "s3c24xx-iis", | ||
427 | .codec_dai_name = "wm8753-hifi", | ||
428 | .codec_name = "wm8753-codec.0-001a", | ||
429 | .init = neo1973_wm8753_init, | ||
430 | .ops = &neo1973_hifi_ops, | ||
431 | }, | ||
432 | { /* Voice via BT */ | ||
433 | .name = "Bluetooth", | ||
434 | .stream_name = "Voice", | ||
435 | .cpu_dai_name = "dfbmcs320-pcm", | ||
436 | .codec_dai_name = "wm8753-voice", | ||
437 | .codec_name = "wm8753-codec.0-001a", | ||
438 | .ops = &neo1973_voice_ops, | ||
439 | }, | ||
440 | }; | ||
441 | |||
442 | static struct snd_soc_aux_dev neo1973_aux_devs[] = { | ||
443 | { | ||
444 | .name = "dfbmcs320", | ||
445 | .codec_name = "dfbmcs320.0", | ||
446 | }, | ||
447 | { | ||
448 | .name = "lm4857", | ||
449 | .codec_name = "lm4857.0-007c", | ||
450 | .init = neo1973_lm4857_init, | ||
451 | }, | ||
452 | }; | ||
453 | |||
454 | static struct snd_soc_codec_conf neo1973_codec_conf[] = { | ||
455 | { | ||
456 | .dev_name = "lm4857.0-007c", | ||
457 | .name_prefix = "Amp", | ||
458 | }, | ||
459 | }; | ||
460 | |||
461 | #ifdef CONFIG_MACH_NEO1973_GTA02 | ||
462 | static const struct gpio neo1973_gta02_gpios[] = { | ||
463 | { GTA02_GPIO_HP_IN, GPIOF_OUT_INIT_HIGH, "GTA02_HP_IN" }, | ||
464 | { GTA02_GPIO_AMP_SHUT, GPIOF_OUT_INIT_HIGH, "GTA02_AMP_SHUT" }, | ||
465 | }; | ||
466 | #else | ||
467 | static const struct gpio neo1973_gta02_gpios[] = {}; | ||
468 | #endif | ||
469 | |||
470 | static struct snd_soc_card neo1973 = { | ||
471 | .name = "neo1973", | ||
472 | .dai_link = neo1973_dai, | ||
473 | .num_links = ARRAY_SIZE(neo1973_dai), | ||
474 | .aux_dev = neo1973_aux_devs, | ||
475 | .num_aux_devs = ARRAY_SIZE(neo1973_aux_devs), | ||
476 | .codec_conf = neo1973_codec_conf, | ||
477 | .num_configs = ARRAY_SIZE(neo1973_codec_conf), | ||
478 | }; | ||
479 | |||
480 | static struct platform_device *neo1973_snd_device; | ||
481 | |||
482 | static int __init neo1973_init(void) | ||
483 | { | ||
484 | int ret; | ||
485 | |||
486 | if (!machine_is_neo1973_gta01() && !machine_is_neo1973_gta02()) | ||
487 | return -ENODEV; | ||
488 | |||
489 | if (machine_is_neo1973_gta02()) { | ||
490 | neo1973.name = "neo1973gta02"; | ||
491 | neo1973.num_aux_devs = 1; | ||
492 | |||
493 | ret = gpio_request_array(neo1973_gta02_gpios, | ||
494 | ARRAY_SIZE(neo1973_gta02_gpios)); | ||
495 | if (ret) | ||
496 | return ret; | ||
497 | } | ||
498 | |||
499 | neo1973_snd_device = platform_device_alloc("soc-audio", -1); | ||
500 | if (!neo1973_snd_device) { | ||
501 | ret = -ENOMEM; | ||
502 | goto err_gpio_free; | ||
503 | } | ||
504 | |||
505 | platform_set_drvdata(neo1973_snd_device, &neo1973); | ||
506 | ret = platform_device_add(neo1973_snd_device); | ||
507 | |||
508 | if (ret) | ||
509 | goto err_put_device; | ||
510 | |||
511 | return 0; | ||
512 | |||
513 | err_put_device: | ||
514 | platform_device_put(neo1973_snd_device); | ||
515 | err_gpio_free: | ||
516 | if (machine_is_neo1973_gta02()) { | ||
517 | gpio_free_array(neo1973_gta02_gpios, | ||
518 | ARRAY_SIZE(neo1973_gta02_gpios)); | ||
519 | } | ||
520 | return ret; | ||
521 | } | ||
522 | module_init(neo1973_init); | ||
523 | |||
524 | static void __exit neo1973_exit(void) | ||
525 | { | ||
526 | platform_device_unregister(neo1973_snd_device); | ||
527 | |||
528 | if (machine_is_neo1973_gta02()) { | ||
529 | gpio_free_array(neo1973_gta02_gpios, | ||
530 | ARRAY_SIZE(neo1973_gta02_gpios)); | ||
531 | } | ||
532 | } | ||
533 | module_exit(neo1973_exit); | ||
534 | |||
535 | /* Module information */ | ||
536 | MODULE_AUTHOR("Graeme Gregory, graeme@openmoko.org, www.openmoko.org"); | ||
537 | MODULE_DESCRIPTION("ALSA SoC WM8753 Neo1973 and Frerunner"); | ||
538 | MODULE_LICENSE("GPL"); | ||