diff options
Diffstat (limited to 'sound/soc/pxa/mioa701_wm9713.c')
-rw-r--r-- | sound/soc/pxa/mioa701_wm9713.c | 250 |
1 files changed, 250 insertions, 0 deletions
diff --git a/sound/soc/pxa/mioa701_wm9713.c b/sound/soc/pxa/mioa701_wm9713.c new file mode 100644 index 000000000000..19eda8bbfdaf --- /dev/null +++ b/sound/soc/pxa/mioa701_wm9713.c | |||
@@ -0,0 +1,250 @@ | |||
1 | /* | ||
2 | * Handles the Mitac mioa701 SoC system | ||
3 | * | ||
4 | * Copyright (C) 2008 Robert Jarzmik | ||
5 | * | ||
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 | ||
8 | * the Free Software Foundation in version 2 of the License. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
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 | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | * | ||
19 | * This is a little schema of the sound interconnections : | ||
20 | * | ||
21 | * Sagem X200 Wolfson WM9713 | ||
22 | * +--------+ +-------------------+ Rear Speaker | ||
23 | * | | | | /-+ | ||
24 | * | +--->----->---+MONOIN SPKL+--->----+-+ | | ||
25 | * | GSM | | | | | | | ||
26 | * | +--->----->---+PCBEEP SPKR+--->----+-+ | | ||
27 | * | CHIP | | | \-+ | ||
28 | * | +---<-----<---+MONO | | ||
29 | * | | | | Front Speaker | ||
30 | * +--------+ | | /-+ | ||
31 | * | HPL+--->----+-+ | | ||
32 | * | | | | | | ||
33 | * | OUT3+--->----+-+ | | ||
34 | * | | \-+ | ||
35 | * | | | ||
36 | * | | Front Micro | ||
37 | * | | + | ||
38 | * | MIC1+-----<--+o+ | ||
39 | * | | + | ||
40 | * +-------------------+ --- | ||
41 | */ | ||
42 | |||
43 | #include <linux/module.h> | ||
44 | #include <linux/moduleparam.h> | ||
45 | #include <linux/platform_device.h> | ||
46 | |||
47 | #include <asm/mach-types.h> | ||
48 | #include <mach/audio.h> | ||
49 | |||
50 | #include <sound/core.h> | ||
51 | #include <sound/pcm.h> | ||
52 | #include <sound/soc.h> | ||
53 | #include <sound/soc-dapm.h> | ||
54 | #include <sound/initval.h> | ||
55 | #include <sound/ac97_codec.h> | ||
56 | |||
57 | #include "pxa2xx-pcm.h" | ||
58 | #include "pxa2xx-ac97.h" | ||
59 | #include "../codecs/wm9713.h" | ||
60 | |||
61 | #define ARRAY_AND_SIZE(x) (x), ARRAY_SIZE(x) | ||
62 | |||
63 | #define AC97_GPIO_PULL 0x58 | ||
64 | |||
65 | /* Use GPIO8 for rear speaker amplifier */ | ||
66 | static int rear_amp_power(struct snd_soc_codec *codec, int power) | ||
67 | { | ||
68 | unsigned short reg; | ||
69 | |||
70 | if (power) { | ||
71 | reg = snd_soc_read(codec, AC97_GPIO_CFG); | ||
72 | snd_soc_write(codec, AC97_GPIO_CFG, reg | 0x0100); | ||
73 | reg = snd_soc_read(codec, AC97_GPIO_PULL); | ||
74 | snd_soc_write(codec, AC97_GPIO_PULL, reg | (1<<15)); | ||
75 | } else { | ||
76 | reg = snd_soc_read(codec, AC97_GPIO_CFG); | ||
77 | snd_soc_write(codec, AC97_GPIO_CFG, reg & ~0x0100); | ||
78 | reg = snd_soc_read(codec, AC97_GPIO_PULL); | ||
79 | snd_soc_write(codec, AC97_GPIO_PULL, reg & ~(1<<15)); | ||
80 | } | ||
81 | |||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | static int rear_amp_event(struct snd_soc_dapm_widget *widget, | ||
86 | struct snd_kcontrol *kctl, int event) | ||
87 | { | ||
88 | struct snd_soc_codec *codec = widget->codec; | ||
89 | |||
90 | return rear_amp_power(codec, SND_SOC_DAPM_EVENT_ON(event)); | ||
91 | } | ||
92 | |||
93 | /* mioa701 machine dapm widgets */ | ||
94 | static const struct snd_soc_dapm_widget mioa701_dapm_widgets[] = { | ||
95 | SND_SOC_DAPM_SPK("Front Speaker", NULL), | ||
96 | SND_SOC_DAPM_SPK("Rear Speaker", rear_amp_event), | ||
97 | SND_SOC_DAPM_MIC("Headset", NULL), | ||
98 | SND_SOC_DAPM_LINE("GSM Line Out", NULL), | ||
99 | SND_SOC_DAPM_LINE("GSM Line In", NULL), | ||
100 | SND_SOC_DAPM_MIC("Headset Mic", NULL), | ||
101 | SND_SOC_DAPM_MIC("Front Mic", NULL), | ||
102 | }; | ||
103 | |||
104 | static const struct snd_soc_dapm_route audio_map[] = { | ||
105 | /* Call Mic */ | ||
106 | {"Mic Bias", NULL, "Front Mic"}, | ||
107 | {"MIC1", NULL, "Mic Bias"}, | ||
108 | |||
109 | /* Headset Mic */ | ||
110 | {"LINEL", NULL, "Headset Mic"}, | ||
111 | {"LINER", NULL, "Headset Mic"}, | ||
112 | |||
113 | /* GSM Module */ | ||
114 | {"MONOIN", NULL, "GSM Line Out"}, | ||
115 | {"PCBEEP", NULL, "GSM Line Out"}, | ||
116 | {"GSM Line In", NULL, "MONO"}, | ||
117 | |||
118 | /* headphone connected to HPL, HPR */ | ||
119 | {"Headset", NULL, "HPL"}, | ||
120 | {"Headset", NULL, "HPR"}, | ||
121 | |||
122 | /* front speaker connected to HPL, OUT3 */ | ||
123 | {"Front Speaker", NULL, "HPL"}, | ||
124 | {"Front Speaker", NULL, "OUT3"}, | ||
125 | |||
126 | /* rear speaker connected to SPKL, SPKR */ | ||
127 | {"Rear Speaker", NULL, "SPKL"}, | ||
128 | {"Rear Speaker", NULL, "SPKR"}, | ||
129 | }; | ||
130 | |||
131 | static int mioa701_wm9713_init(struct snd_soc_codec *codec) | ||
132 | { | ||
133 | unsigned short reg; | ||
134 | |||
135 | /* Add mioa701 specific widgets */ | ||
136 | snd_soc_dapm_new_controls(codec, ARRAY_AND_SIZE(mioa701_dapm_widgets)); | ||
137 | |||
138 | /* Set up mioa701 specific audio path audio_mapnects */ | ||
139 | snd_soc_dapm_add_routes(codec, ARRAY_AND_SIZE(audio_map)); | ||
140 | |||
141 | /* Prepare GPIO8 for rear speaker amplifier */ | ||
142 | reg = codec->read(codec, AC97_GPIO_CFG); | ||
143 | codec->write(codec, AC97_GPIO_CFG, reg | 0x0100); | ||
144 | |||
145 | /* Prepare MIC input */ | ||
146 | reg = codec->read(codec, AC97_3D_CONTROL); | ||
147 | codec->write(codec, AC97_3D_CONTROL, reg | 0xc000); | ||
148 | |||
149 | snd_soc_dapm_enable_pin(codec, "Front Speaker"); | ||
150 | snd_soc_dapm_enable_pin(codec, "Rear Speaker"); | ||
151 | snd_soc_dapm_enable_pin(codec, "Front Mic"); | ||
152 | snd_soc_dapm_enable_pin(codec, "GSM Line In"); | ||
153 | snd_soc_dapm_enable_pin(codec, "GSM Line Out"); | ||
154 | snd_soc_dapm_sync(codec); | ||
155 | |||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | static struct snd_soc_ops mioa701_ops; | ||
160 | |||
161 | static struct snd_soc_dai_link mioa701_dai[] = { | ||
162 | { | ||
163 | .name = "AC97", | ||
164 | .stream_name = "AC97 HiFi", | ||
165 | .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI], | ||
166 | .codec_dai = &wm9713_dai[WM9713_DAI_AC97_HIFI], | ||
167 | .init = mioa701_wm9713_init, | ||
168 | .ops = &mioa701_ops, | ||
169 | }, | ||
170 | { | ||
171 | .name = "AC97 Aux", | ||
172 | .stream_name = "AC97 Aux", | ||
173 | .cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX], | ||
174 | .codec_dai = &wm9713_dai[WM9713_DAI_AC97_AUX], | ||
175 | .ops = &mioa701_ops, | ||
176 | }, | ||
177 | }; | ||
178 | |||
179 | static struct snd_soc_card mioa701 = { | ||
180 | .name = "MioA701", | ||
181 | .platform = &pxa2xx_soc_platform, | ||
182 | .dai_link = mioa701_dai, | ||
183 | .num_links = ARRAY_SIZE(mioa701_dai), | ||
184 | }; | ||
185 | |||
186 | static struct snd_soc_device mioa701_snd_devdata = { | ||
187 | .card = &mioa701, | ||
188 | .codec_dev = &soc_codec_dev_wm9713, | ||
189 | }; | ||
190 | |||
191 | static struct platform_device *mioa701_snd_device; | ||
192 | |||
193 | static int mioa701_wm9713_probe(struct platform_device *pdev) | ||
194 | { | ||
195 | int ret; | ||
196 | |||
197 | if (!machine_is_mioa701()) | ||
198 | return -ENODEV; | ||
199 | |||
200 | dev_warn(&pdev->dev, "Be warned that incorrect mixers/muxes setup will" | ||
201 | "lead to overheating and possible destruction of your device." | ||
202 | "Do not use without a good knowledge of mio's board design!\n"); | ||
203 | |||
204 | mioa701_snd_device = platform_device_alloc("soc-audio", -1); | ||
205 | if (!mioa701_snd_device) | ||
206 | return -ENOMEM; | ||
207 | |||
208 | platform_set_drvdata(mioa701_snd_device, &mioa701_snd_devdata); | ||
209 | mioa701_snd_devdata.dev = &mioa701_snd_device->dev; | ||
210 | |||
211 | ret = platform_device_add(mioa701_snd_device); | ||
212 | if (!ret) | ||
213 | return 0; | ||
214 | |||
215 | platform_device_put(mioa701_snd_device); | ||
216 | return ret; | ||
217 | } | ||
218 | |||
219 | static int __devexit mioa701_wm9713_remove(struct platform_device *pdev) | ||
220 | { | ||
221 | platform_device_unregister(mioa701_snd_device); | ||
222 | return 0; | ||
223 | } | ||
224 | |||
225 | static struct platform_driver mioa701_wm9713_driver = { | ||
226 | .probe = mioa701_wm9713_probe, | ||
227 | .remove = __devexit_p(mioa701_wm9713_remove), | ||
228 | .driver = { | ||
229 | .name = "mioa701-wm9713", | ||
230 | .owner = THIS_MODULE, | ||
231 | }, | ||
232 | }; | ||
233 | |||
234 | static int __init mioa701_asoc_init(void) | ||
235 | { | ||
236 | return platform_driver_register(&mioa701_wm9713_driver); | ||
237 | } | ||
238 | |||
239 | static void __exit mioa701_asoc_exit(void) | ||
240 | { | ||
241 | platform_driver_unregister(&mioa701_wm9713_driver); | ||
242 | } | ||
243 | |||
244 | module_init(mioa701_asoc_init); | ||
245 | module_exit(mioa701_asoc_exit); | ||
246 | |||
247 | /* Module information */ | ||
248 | MODULE_AUTHOR("Robert Jarzmik (rjarzmik@free.fr)"); | ||
249 | MODULE_DESCRIPTION("ALSA SoC WM9713 MIO A701"); | ||
250 | MODULE_LICENSE("GPL"); | ||