Commit | Line | Data |
---|---|---|
8f0dc655 RJ |
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 | ||
8f0dc655 RJ |
57 | #include "pxa2xx-ac97.h" |
58 | #include "../codecs/wm9713.h" | |
59 | ||
60 | #define ARRAY_AND_SIZE(x) (x), ARRAY_SIZE(x) | |
61 | ||
62 | #define AC97_GPIO_PULL 0x58 | |
63 | ||
64 | /* Use GPIO8 for rear speaker amplifier */ | |
65 | static int rear_amp_power(struct snd_soc_codec *codec, int power) | |
66 | { | |
67 | unsigned short reg; | |
68 | ||
69 | if (power) { | |
70 | reg = snd_soc_read(codec, AC97_GPIO_CFG); | |
71 | snd_soc_write(codec, AC97_GPIO_CFG, reg | 0x0100); | |
72 | reg = snd_soc_read(codec, AC97_GPIO_PULL); | |
73 | snd_soc_write(codec, AC97_GPIO_PULL, reg | (1<<15)); | |
74 | } else { | |
75 | reg = snd_soc_read(codec, AC97_GPIO_CFG); | |
76 | snd_soc_write(codec, AC97_GPIO_CFG, reg & ~0x0100); | |
77 | reg = snd_soc_read(codec, AC97_GPIO_PULL); | |
78 | snd_soc_write(codec, AC97_GPIO_PULL, reg & ~(1<<15)); | |
79 | } | |
80 | ||
81 | return 0; | |
82 | } | |
83 | ||
84 | static int rear_amp_event(struct snd_soc_dapm_widget *widget, | |
85 | struct snd_kcontrol *kctl, int event) | |
86 | { | |
87 | struct snd_soc_codec *codec = widget->codec; | |
88 | ||
89 | return rear_amp_power(codec, SND_SOC_DAPM_EVENT_ON(event)); | |
90 | } | |
91 | ||
92 | /* mioa701 machine dapm widgets */ | |
93 | static const struct snd_soc_dapm_widget mioa701_dapm_widgets[] = { | |
94 | SND_SOC_DAPM_SPK("Front Speaker", NULL), | |
95 | SND_SOC_DAPM_SPK("Rear Speaker", rear_amp_event), | |
96 | SND_SOC_DAPM_MIC("Headset", NULL), | |
97 | SND_SOC_DAPM_LINE("GSM Line Out", NULL), | |
98 | SND_SOC_DAPM_LINE("GSM Line In", NULL), | |
99 | SND_SOC_DAPM_MIC("Headset Mic", NULL), | |
100 | SND_SOC_DAPM_MIC("Front Mic", NULL), | |
101 | }; | |
102 | ||
103 | static const struct snd_soc_dapm_route audio_map[] = { | |
104 | /* Call Mic */ | |
105 | {"Mic Bias", NULL, "Front Mic"}, | |
106 | {"MIC1", NULL, "Mic Bias"}, | |
107 | ||
108 | /* Headset Mic */ | |
109 | {"LINEL", NULL, "Headset Mic"}, | |
110 | {"LINER", NULL, "Headset Mic"}, | |
111 | ||
112 | /* GSM Module */ | |
113 | {"MONOIN", NULL, "GSM Line Out"}, | |
114 | {"PCBEEP", NULL, "GSM Line Out"}, | |
115 | {"GSM Line In", NULL, "MONO"}, | |
116 | ||
117 | /* headphone connected to HPL, HPR */ | |
118 | {"Headset", NULL, "HPL"}, | |
119 | {"Headset", NULL, "HPR"}, | |
120 | ||
121 | /* front speaker connected to HPL, OUT3 */ | |
122 | {"Front Speaker", NULL, "HPL"}, | |
123 | {"Front Speaker", NULL, "OUT3"}, | |
124 | ||
125 | /* rear speaker connected to SPKL, SPKR */ | |
126 | {"Rear Speaker", NULL, "SPKL"}, | |
127 | {"Rear Speaker", NULL, "SPKR"}, | |
128 | }; | |
129 | ||
f0fba2ad | 130 | static int mioa701_wm9713_init(struct snd_soc_pcm_runtime *rtd) |
8f0dc655 | 131 | { |
f0fba2ad | 132 | struct snd_soc_codec *codec = rtd->codec; |
8f0dc655 RJ |
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 */ | |
f0fba2ad LG |
142 | reg = codec->driver->read(codec, AC97_GPIO_CFG); |
143 | codec->driver->write(codec, AC97_GPIO_CFG, reg | 0x0100); | |
8f0dc655 RJ |
144 | |
145 | /* Prepare MIC input */ | |
f0fba2ad LG |
146 | reg = codec->driver->read(codec, AC97_3D_CONTROL); |
147 | codec->driver->write(codec, AC97_3D_CONTROL, reg | 0xc000); | |
8f0dc655 RJ |
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", | |
f0fba2ad LG |
165 | .cpu_dai_name = "pxa-ac97.0", |
166 | .codec_dai_name = "wm9713-hifi", | |
167 | .codec_name = "wm9713-codec", | |
8f0dc655 | 168 | .init = mioa701_wm9713_init, |
f0fba2ad | 169 | .platform_name = "pxa-pcm-audio", |
8f0dc655 RJ |
170 | .ops = &mioa701_ops, |
171 | }, | |
172 | { | |
173 | .name = "AC97 Aux", | |
174 | .stream_name = "AC97 Aux", | |
f0fba2ad LG |
175 | .cpu_dai_name = "pxa-ac97.1", |
176 | .codec_dai_name ="wm9713-aux", | |
177 | .codec_name = "wm9713-codec", | |
178 | .platform_name = "pxa-pcm-audio", | |
8f0dc655 RJ |
179 | .ops = &mioa701_ops, |
180 | }, | |
181 | }; | |
182 | ||
183 | static struct snd_soc_card mioa701 = { | |
184 | .name = "MioA701", | |
8f0dc655 RJ |
185 | .dai_link = mioa701_dai, |
186 | .num_links = ARRAY_SIZE(mioa701_dai), | |
187 | }; | |
188 | ||
8f0dc655 RJ |
189 | static struct platform_device *mioa701_snd_device; |
190 | ||
191 | static int mioa701_wm9713_probe(struct platform_device *pdev) | |
192 | { | |
193 | int ret; | |
194 | ||
195 | if (!machine_is_mioa701()) | |
196 | return -ENODEV; | |
197 | ||
198 | dev_warn(&pdev->dev, "Be warned that incorrect mixers/muxes setup will" | |
199 | "lead to overheating and possible destruction of your device." | |
200 | "Do not use without a good knowledge of mio's board design!\n"); | |
201 | ||
202 | mioa701_snd_device = platform_device_alloc("soc-audio", -1); | |
203 | if (!mioa701_snd_device) | |
204 | return -ENOMEM; | |
205 | ||
f0fba2ad | 206 | platform_set_drvdata(mioa701_snd_device, &mioa701); |
8f0dc655 RJ |
207 | |
208 | ret = platform_device_add(mioa701_snd_device); | |
209 | if (!ret) | |
210 | return 0; | |
211 | ||
212 | platform_device_put(mioa701_snd_device); | |
213 | return ret; | |
214 | } | |
215 | ||
216 | static int __devexit mioa701_wm9713_remove(struct platform_device *pdev) | |
217 | { | |
218 | platform_device_unregister(mioa701_snd_device); | |
219 | return 0; | |
220 | } | |
221 | ||
222 | static struct platform_driver mioa701_wm9713_driver = { | |
223 | .probe = mioa701_wm9713_probe, | |
224 | .remove = __devexit_p(mioa701_wm9713_remove), | |
225 | .driver = { | |
226 | .name = "mioa701-wm9713", | |
227 | .owner = THIS_MODULE, | |
228 | }, | |
229 | }; | |
230 | ||
231 | static int __init mioa701_asoc_init(void) | |
232 | { | |
233 | return platform_driver_register(&mioa701_wm9713_driver); | |
234 | } | |
235 | ||
236 | static void __exit mioa701_asoc_exit(void) | |
237 | { | |
238 | platform_driver_unregister(&mioa701_wm9713_driver); | |
239 | } | |
240 | ||
241 | module_init(mioa701_asoc_init); | |
242 | module_exit(mioa701_asoc_exit); | |
243 | ||
244 | /* Module information */ | |
245 | MODULE_AUTHOR("Robert Jarzmik (rjarzmik@free.fr)"); | |
246 | MODULE_DESCRIPTION("ALSA SoC WM9713 MIO A701"); | |
247 | MODULE_LICENSE("GPL"); |