diff options
author | Ian Molton <ian@mnementh.co.uk> | 2009-01-08 16:16:05 -0500 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2009-01-16 11:40:26 -0500 |
commit | 0465c7aa6fbab89de820442aed449ceb8d9145a6 (patch) | |
tree | a3db814699f9e22e0332ddd01d2b084b873142e1 /sound/soc/pxa | |
parent | a7e2e735dcf98717150d3c8eaa731de8038af05a (diff) |
ASoC: machine driver for Toshiba e800
This patch adds support for the wm9712 ac97 codec as used in the Toshiba e800
PDA. It includes support for powering up / down the external headphone and
speaker amplifiers on this machine.
Signed-off-by: Ian Molton <ian@mnementh.co.uk>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/pxa')
-rw-r--r-- | sound/soc/pxa/e800_wm9712.c | 116 |
1 files changed, 102 insertions, 14 deletions
diff --git a/sound/soc/pxa/e800_wm9712.c b/sound/soc/pxa/e800_wm9712.c index 2e3386dfa0f0..78a1770b986c 100644 --- a/sound/soc/pxa/e800_wm9712.c +++ b/sound/soc/pxa/e800_wm9712.c | |||
@@ -1,8 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * e800-wm9712.c -- SoC audio for e800 | 2 | * e800-wm9712.c -- SoC audio for e800 |
3 | * | 3 | * |
4 | * Based on tosa.c | ||
5 | * | ||
6 | * Copyright 2007 (c) Ian Molton <spyro@f2s.com> | 4 | * Copyright 2007 (c) Ian Molton <spyro@f2s.com> |
7 | * | 5 | * |
8 | * 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 |
@@ -13,31 +11,96 @@ | |||
13 | 11 | ||
14 | #include <linux/module.h> | 12 | #include <linux/module.h> |
15 | #include <linux/moduleparam.h> | 13 | #include <linux/moduleparam.h> |
16 | #include <linux/device.h> | 14 | #include <linux/gpio.h> |
17 | 15 | ||
18 | #include <sound/core.h> | 16 | #include <sound/core.h> |
19 | #include <sound/pcm.h> | 17 | #include <sound/pcm.h> |
20 | #include <sound/soc.h> | 18 | #include <sound/soc.h> |
21 | #include <sound/soc-dapm.h> | 19 | #include <sound/soc-dapm.h> |
22 | 20 | ||
23 | #include <asm/mach-types.h> | ||
24 | #include <mach/pxa-regs.h> | 21 | #include <mach/pxa-regs.h> |
25 | #include <mach/hardware.h> | 22 | #include <mach/hardware.h> |
26 | #include <mach/audio.h> | 23 | #include <mach/audio.h> |
24 | #include <mach/eseries-gpio.h> | ||
25 | |||
26 | #include <asm/mach-types.h> | ||
27 | 27 | ||
28 | #include "../codecs/wm9712.h" | 28 | #include "../codecs/wm9712.h" |
29 | #include "pxa2xx-pcm.h" | 29 | #include "pxa2xx-pcm.h" |
30 | #include "pxa2xx-ac97.h" | 30 | #include "pxa2xx-ac97.h" |
31 | 31 | ||
32 | static struct snd_soc_card e800; | 32 | static int e800_spk_amp_event(struct snd_soc_dapm_widget *w, |
33 | struct snd_kcontrol *kcontrol, int event) | ||
34 | { | ||
35 | if (event & SND_SOC_DAPM_PRE_PMU) | ||
36 | gpio_set_value(GPIO_E800_SPK_AMP_ON, 1); | ||
37 | else if (event & SND_SOC_DAPM_POST_PMD) | ||
38 | gpio_set_value(GPIO_E800_SPK_AMP_ON, 0); | ||
33 | 39 | ||
34 | static struct snd_soc_dai_link e800_dai[] = { | 40 | return 0; |
41 | } | ||
42 | |||
43 | static int e800_hp_amp_event(struct snd_soc_dapm_widget *w, | ||
44 | struct snd_kcontrol *kcontrol, int event) | ||
35 | { | 45 | { |
36 | .name = "AC97 Aux", | 46 | if (event & SND_SOC_DAPM_PRE_PMU) |
37 | .stream_name = "AC97 Aux", | 47 | gpio_set_value(GPIO_E800_HP_AMP_OFF, 0); |
38 | .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX], | 48 | else if (event & SND_SOC_DAPM_POST_PMD) |
39 | .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX], | 49 | gpio_set_value(GPIO_E800_HP_AMP_OFF, 1); |
40 | }, | 50 | |
51 | return 0; | ||
52 | } | ||
53 | |||
54 | static const struct snd_soc_dapm_widget e800_dapm_widgets[] = { | ||
55 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | ||
56 | SND_SOC_DAPM_MIC("Mic (Internal1)", NULL), | ||
57 | SND_SOC_DAPM_MIC("Mic (Internal2)", NULL), | ||
58 | SND_SOC_DAPM_SPK("Speaker", NULL), | ||
59 | SND_SOC_DAPM_PGA_E("Headphone Amp", SND_SOC_NOPM, 0, 0, NULL, 0, | ||
60 | e800_hp_amp_event, SND_SOC_DAPM_PRE_PMU | | ||
61 | SND_SOC_DAPM_POST_PMD), | ||
62 | SND_SOC_DAPM_PGA_E("Speaker Amp", SND_SOC_NOPM, 0, 0, NULL, 0, | ||
63 | e800_spk_amp_event, SND_SOC_DAPM_PRE_PMU | | ||
64 | SND_SOC_DAPM_POST_PMD), | ||
65 | }; | ||
66 | |||
67 | static const struct snd_soc_dapm_route audio_map[] = { | ||
68 | {"Headphone Jack", NULL, "HPOUTL"}, | ||
69 | {"Headphone Jack", NULL, "HPOUTR"}, | ||
70 | {"Headphone Jack", NULL, "Headphone Amp"}, | ||
71 | |||
72 | {"Speaker Amp", NULL, "MONOOUT"}, | ||
73 | {"Speaker", NULL, "Speaker Amp"}, | ||
74 | |||
75 | {"MIC1", NULL, "Mic (Internal1)"}, | ||
76 | {"MIC2", NULL, "Mic (Internal2)"}, | ||
77 | }; | ||
78 | |||
79 | static int e800_ac97_init(struct snd_soc_codec *codec) | ||
80 | { | ||
81 | snd_soc_dapm_new_controls(codec, e800_dapm_widgets, | ||
82 | ARRAY_SIZE(e800_dapm_widgets)); | ||
83 | |||
84 | snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | ||
85 | snd_soc_dapm_sync(codec); | ||
86 | |||
87 | return 0; | ||
88 | } | ||
89 | |||
90 | static struct snd_soc_dai_link e800_dai[] = { | ||
91 | { | ||
92 | .name = "AC97", | ||
93 | .stream_name = "AC97 HiFi", | ||
94 | .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI], | ||
95 | .codec_dai = &wm9712_dai[WM9712_DAI_AC97_HIFI], | ||
96 | .init = e800_ac97_init, | ||
97 | }, | ||
98 | { | ||
99 | .name = "AC97 Aux", | ||
100 | .stream_name = "AC97 Aux", | ||
101 | .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX], | ||
102 | .codec_dai = &wm9712_dai[WM9712_DAI_AC97_AUX], | ||
103 | }, | ||
41 | }; | 104 | }; |
42 | 105 | ||
43 | static struct snd_soc_card e800 = { | 106 | static struct snd_soc_card e800 = { |
@@ -61,6 +124,22 @@ static int __init e800_init(void) | |||
61 | if (!machine_is_e800()) | 124 | if (!machine_is_e800()) |
62 | return -ENODEV; | 125 | return -ENODEV; |
63 | 126 | ||
127 | ret = gpio_request(GPIO_E800_HP_AMP_OFF, "Headphone amp"); | ||
128 | if (ret) | ||
129 | return ret; | ||
130 | |||
131 | ret = gpio_request(GPIO_E800_SPK_AMP_ON, "Speaker amp"); | ||
132 | if (ret) | ||
133 | goto free_hp_amp_gpio; | ||
134 | |||
135 | ret = gpio_direction_output(GPIO_E800_HP_AMP_OFF, 1); | ||
136 | if (ret) | ||
137 | goto free_spk_amp_gpio; | ||
138 | |||
139 | ret = gpio_direction_output(GPIO_E800_SPK_AMP_ON, 1); | ||
140 | if (ret) | ||
141 | goto free_spk_amp_gpio; | ||
142 | |||
64 | e800_snd_device = platform_device_alloc("soc-audio", -1); | 143 | e800_snd_device = platform_device_alloc("soc-audio", -1); |
65 | if (!e800_snd_device) | 144 | if (!e800_snd_device) |
66 | return -ENOMEM; | 145 | return -ENOMEM; |
@@ -69,8 +148,15 @@ static int __init e800_init(void) | |||
69 | e800_snd_devdata.dev = &e800_snd_device->dev; | 148 | e800_snd_devdata.dev = &e800_snd_device->dev; |
70 | ret = platform_device_add(e800_snd_device); | 149 | ret = platform_device_add(e800_snd_device); |
71 | 150 | ||
72 | if (ret) | 151 | if (!ret) |
73 | platform_device_put(e800_snd_device); | 152 | return 0; |
153 | |||
154 | /* Fail gracefully */ | ||
155 | platform_device_put(e800_snd_device); | ||
156 | free_spk_amp_gpio: | ||
157 | gpio_free(GPIO_E800_SPK_AMP_ON); | ||
158 | free_hp_amp_gpio: | ||
159 | gpio_free(GPIO_E800_HP_AMP_OFF); | ||
74 | 160 | ||
75 | return ret; | 161 | return ret; |
76 | } | 162 | } |
@@ -78,6 +164,8 @@ static int __init e800_init(void) | |||
78 | static void __exit e800_exit(void) | 164 | static void __exit e800_exit(void) |
79 | { | 165 | { |
80 | platform_device_unregister(e800_snd_device); | 166 | platform_device_unregister(e800_snd_device); |
167 | gpio_free(GPIO_E800_SPK_AMP_ON); | ||
168 | gpio_free(GPIO_E800_HP_AMP_OFF); | ||
81 | } | 169 | } |
82 | 170 | ||
83 | module_init(e800_init); | 171 | module_init(e800_init); |
@@ -86,4 +174,4 @@ module_exit(e800_exit); | |||
86 | /* Module information */ | 174 | /* Module information */ |
87 | MODULE_AUTHOR("Ian Molton <spyro@f2s.com>"); | 175 | MODULE_AUTHOR("Ian Molton <spyro@f2s.com>"); |
88 | MODULE_DESCRIPTION("ALSA SoC driver for e800"); | 176 | MODULE_DESCRIPTION("ALSA SoC driver for e800"); |
89 | MODULE_LICENSE("GPL"); | 177 | MODULE_LICENSE("GPL v2"); |