diff options
author | Stephen Warren <swarren@nvidia.com> | 2011-04-12 13:40:39 -0400 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2011-04-18 16:34:16 -0400 |
commit | 773b1d3d31bbf7257c48f6257b4ab06bcf4f5dfa (patch) | |
tree | d13b18f3155a408af36855fa23f2741efd78d36a /sound/soc/tegra/tegra_wm8903.c | |
parent | 3eb25f998d3aede5f0011ba236e7586351e450bf (diff) |
ASoC: Tegra: Support more boards
* Ventana is identical to Harmony.
* Seaboard, Kaen, and Aebl are all pretty similar, mainly with slightly
different sets of GPIOs, and slightly different WM8903 pin connectivity.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Acked-by: Liam Girdwood <lrg@ti.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/tegra/tegra_wm8903.c')
-rw-r--r-- | sound/soc/tegra/tegra_wm8903.c | 180 |
1 files changed, 141 insertions, 39 deletions
diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c index 2b3844322c40..37f6010a9109 100644 --- a/sound/soc/tegra/tegra_wm8903.c +++ b/sound/soc/tegra/tegra_wm8903.c | |||
@@ -53,8 +53,9 @@ | |||
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_INT_MIC_EN BIT(1) | 56 | #define GPIO_HP_MUTE BIT(1) |
57 | #define GPIO_EXT_MIC_EN BIT(2) | 57 | #define GPIO_INT_MIC_EN BIT(2) |
58 | #define GPIO_EXT_MIC_EN BIT(3) | ||
58 | 59 | ||
59 | struct tegra_wm8903 { | 60 | struct tegra_wm8903 { |
60 | struct tegra_asoc_utils_data util_data; | 61 | struct tegra_asoc_utils_data util_data; |
@@ -163,15 +164,35 @@ static int tegra_wm8903_event_int_spk(struct snd_soc_dapm_widget *w, | |||
163 | struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); | 164 | struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); |
164 | struct tegra_wm8903_platform_data *pdata = machine->pdata; | 165 | struct tegra_wm8903_platform_data *pdata = machine->pdata; |
165 | 166 | ||
167 | if (!(machine->gpio_requested & GPIO_SPKR_EN)) | ||
168 | return 0; | ||
169 | |||
166 | gpio_set_value_cansleep(pdata->gpio_spkr_en, | 170 | gpio_set_value_cansleep(pdata->gpio_spkr_en, |
167 | SND_SOC_DAPM_EVENT_ON(event)); | 171 | SND_SOC_DAPM_EVENT_ON(event)); |
168 | 172 | ||
169 | return 0; | 173 | return 0; |
170 | } | 174 | } |
171 | 175 | ||
176 | static int tegra_wm8903_event_hp(struct snd_soc_dapm_widget *w, | ||
177 | struct snd_kcontrol *k, int event) | ||
178 | { | ||
179 | struct snd_soc_codec *codec = w->codec; | ||
180 | struct snd_soc_card *card = codec->card; | ||
181 | struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); | ||
182 | struct tegra_wm8903_platform_data *pdata = machine->pdata; | ||
183 | |||
184 | if (!(machine->gpio_requested & GPIO_HP_MUTE)) | ||
185 | return 0; | ||
186 | |||
187 | gpio_set_value_cansleep(pdata->gpio_hp_mute, | ||
188 | !SND_SOC_DAPM_EVENT_ON(event)); | ||
189 | |||
190 | return 0; | ||
191 | } | ||
192 | |||
172 | static const struct snd_soc_dapm_widget tegra_wm8903_dapm_widgets[] = { | 193 | static const struct snd_soc_dapm_widget tegra_wm8903_dapm_widgets[] = { |
173 | SND_SOC_DAPM_SPK("Int Spk", tegra_wm8903_event_int_spk), | 194 | SND_SOC_DAPM_SPK("Int Spk", tegra_wm8903_event_int_spk), |
174 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | 195 | SND_SOC_DAPM_HP("Headphone Jack", tegra_wm8903_event_hp), |
175 | SND_SOC_DAPM_MIC("Mic Jack", NULL), | 196 | SND_SOC_DAPM_MIC("Mic Jack", NULL), |
176 | }; | 197 | }; |
177 | 198 | ||
@@ -186,6 +207,37 @@ static const struct snd_soc_dapm_route harmony_audio_map[] = { | |||
186 | {"IN1L", NULL, "Mic Bias"}, | 207 | {"IN1L", NULL, "Mic Bias"}, |
187 | }; | 208 | }; |
188 | 209 | ||
210 | static const struct snd_soc_dapm_route seaboard_audio_map[] = { | ||
211 | {"Headphone Jack", NULL, "HPOUTR"}, | ||
212 | {"Headphone Jack", NULL, "HPOUTL"}, | ||
213 | {"Int Spk", NULL, "ROP"}, | ||
214 | {"Int Spk", NULL, "RON"}, | ||
215 | {"Int Spk", NULL, "LOP"}, | ||
216 | {"Int Spk", NULL, "LON"}, | ||
217 | {"Mic Bias", NULL, "Mic Jack"}, | ||
218 | {"IN1R", NULL, "Mic Bias"}, | ||
219 | }; | ||
220 | |||
221 | static const struct snd_soc_dapm_route kaen_audio_map[] = { | ||
222 | {"Headphone Jack", NULL, "HPOUTR"}, | ||
223 | {"Headphone Jack", NULL, "HPOUTL"}, | ||
224 | {"Int Spk", NULL, "ROP"}, | ||
225 | {"Int Spk", NULL, "RON"}, | ||
226 | {"Int Spk", NULL, "LOP"}, | ||
227 | {"Int Spk", NULL, "LON"}, | ||
228 | {"Mic Bias", NULL, "Mic Jack"}, | ||
229 | {"IN2R", NULL, "Mic Bias"}, | ||
230 | }; | ||
231 | |||
232 | static const struct snd_soc_dapm_route aebl_audio_map[] = { | ||
233 | {"Headphone Jack", NULL, "HPOUTR"}, | ||
234 | {"Headphone Jack", NULL, "HPOUTL"}, | ||
235 | {"Int Spk", NULL, "LINEOUTR"}, | ||
236 | {"Int Spk", NULL, "LINEOUTL"}, | ||
237 | {"Mic Bias", NULL, "Mic Jack"}, | ||
238 | {"IN1R", NULL, "Mic Bias"}, | ||
239 | }; | ||
240 | |||
189 | static const struct snd_kcontrol_new tegra_wm8903_controls[] = { | 241 | static const struct snd_kcontrol_new tegra_wm8903_controls[] = { |
190 | SOC_DAPM_PIN_SWITCH("Int Spk"), | 242 | SOC_DAPM_PIN_SWITCH("Int Spk"), |
191 | }; | 243 | }; |
@@ -199,34 +251,51 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd) | |||
199 | struct tegra_wm8903_platform_data *pdata = machine->pdata; | 251 | struct tegra_wm8903_platform_data *pdata = machine->pdata; |
200 | int ret; | 252 | int ret; |
201 | 253 | ||
202 | ret = gpio_request(pdata->gpio_spkr_en, "spkr_en"); | 254 | if (gpio_is_valid(pdata->gpio_spkr_en)) { |
203 | if (ret) { | 255 | ret = gpio_request(pdata->gpio_spkr_en, "spkr_en"); |
204 | dev_err(card->dev, "cannot get spkr_en gpio\n"); | 256 | if (ret) { |
205 | return ret; | 257 | dev_err(card->dev, "cannot get spkr_en gpio\n"); |
258 | return ret; | ||
259 | } | ||
260 | machine->gpio_requested |= GPIO_SPKR_EN; | ||
261 | |||
262 | gpio_direction_output(pdata->gpio_spkr_en, 0); | ||
206 | } | 263 | } |
207 | machine->gpio_requested |= GPIO_SPKR_EN; | ||
208 | 264 | ||
209 | gpio_direction_output(pdata->gpio_spkr_en, 0); | 265 | if (gpio_is_valid(pdata->gpio_hp_mute)) { |
266 | ret = gpio_request(pdata->gpio_hp_mute, "hp_mute"); | ||
267 | if (ret) { | ||
268 | dev_err(card->dev, "cannot get hp_mute gpio\n"); | ||
269 | return ret; | ||
270 | } | ||
271 | machine->gpio_requested |= GPIO_HP_MUTE; | ||
210 | 272 | ||
211 | ret = gpio_request(pdata->gpio_int_mic_en, "int_mic_en"); | 273 | gpio_direction_output(pdata->gpio_hp_mute, 0); |
212 | if (ret) { | ||
213 | dev_err(card->dev, "cannot get int_mic_en gpio\n"); | ||
214 | return ret; | ||
215 | } | 274 | } |
216 | machine->gpio_requested |= GPIO_INT_MIC_EN; | ||
217 | 275 | ||
218 | /* Disable int mic; enable signal is active-high */ | 276 | if (gpio_is_valid(pdata->gpio_int_mic_en)) { |
219 | gpio_direction_output(pdata->gpio_int_mic_en, 0); | 277 | ret = gpio_request(pdata->gpio_int_mic_en, "int_mic_en"); |
278 | if (ret) { | ||
279 | dev_err(card->dev, "cannot get int_mic_en gpio\n"); | ||
280 | return ret; | ||
281 | } | ||
282 | machine->gpio_requested |= GPIO_INT_MIC_EN; | ||
220 | 283 | ||
221 | ret = gpio_request(pdata->gpio_ext_mic_en, "ext_mic_en"); | 284 | /* Disable int mic; enable signal is active-high */ |
222 | if (ret) { | 285 | gpio_direction_output(pdata->gpio_int_mic_en, 0); |
223 | dev_err(card->dev, "cannot get ext_mic_en gpio\n"); | ||
224 | return ret; | ||
225 | } | 286 | } |
226 | machine->gpio_requested |= GPIO_EXT_MIC_EN; | ||
227 | 287 | ||
228 | /* Enable ext mic; enable signal is active-low */ | 288 | if (gpio_is_valid(pdata->gpio_ext_mic_en)) { |
229 | gpio_direction_output(pdata->gpio_ext_mic_en, 0); | 289 | ret = gpio_request(pdata->gpio_ext_mic_en, "ext_mic_en"); |
290 | if (ret) { | ||
291 | dev_err(card->dev, "cannot get ext_mic_en gpio\n"); | ||
292 | return ret; | ||
293 | } | ||
294 | machine->gpio_requested |= GPIO_EXT_MIC_EN; | ||
295 | |||
296 | /* Enable ext mic; enable signal is active-low */ | ||
297 | gpio_direction_output(pdata->gpio_ext_mic_en, 0); | ||
298 | } | ||
230 | 299 | ||
231 | ret = snd_soc_add_controls(codec, tegra_wm8903_controls, | 300 | ret = snd_soc_add_controls(codec, tegra_wm8903_controls, |
232 | ARRAY_SIZE(tegra_wm8903_controls)); | 301 | ARRAY_SIZE(tegra_wm8903_controls)); |
@@ -236,18 +305,31 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd) | |||
236 | snd_soc_dapm_new_controls(dapm, tegra_wm8903_dapm_widgets, | 305 | snd_soc_dapm_new_controls(dapm, tegra_wm8903_dapm_widgets, |
237 | ARRAY_SIZE(tegra_wm8903_dapm_widgets)); | 306 | ARRAY_SIZE(tegra_wm8903_dapm_widgets)); |
238 | 307 | ||
239 | snd_soc_dapm_add_routes(dapm, harmony_audio_map, | 308 | if (machine_is_harmony() || machine_is_ventana()) { |
240 | ARRAY_SIZE(harmony_audio_map)); | 309 | snd_soc_dapm_add_routes(dapm, harmony_audio_map, |
310 | ARRAY_SIZE(harmony_audio_map)); | ||
311 | } else if (machine_is_seaboard()) { | ||
312 | snd_soc_dapm_add_routes(dapm, seaboard_audio_map, | ||
313 | ARRAY_SIZE(seaboard_audio_map)); | ||
314 | } else if (machine_is_kaen()) { | ||
315 | snd_soc_dapm_add_routes(dapm, kaen_audio_map, | ||
316 | ARRAY_SIZE(kaen_audio_map)); | ||
317 | } else { | ||
318 | snd_soc_dapm_add_routes(dapm, aebl_audio_map, | ||
319 | ARRAY_SIZE(aebl_audio_map)); | ||
320 | } | ||
241 | 321 | ||
242 | tegra_wm8903_hp_jack_gpio.gpio = pdata->gpio_hp_det; | 322 | if (gpio_is_valid(pdata->gpio_hp_det)) { |
243 | snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE, | 323 | tegra_wm8903_hp_jack_gpio.gpio = pdata->gpio_hp_det; |
244 | &tegra_wm8903_hp_jack); | 324 | snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE, |
245 | snd_soc_jack_add_pins(&tegra_wm8903_hp_jack, | 325 | &tegra_wm8903_hp_jack); |
246 | ARRAY_SIZE(tegra_wm8903_hp_jack_pins), | 326 | snd_soc_jack_add_pins(&tegra_wm8903_hp_jack, |
247 | tegra_wm8903_hp_jack_pins); | 327 | ARRAY_SIZE(tegra_wm8903_hp_jack_pins), |
248 | snd_soc_jack_add_gpios(&tegra_wm8903_hp_jack, | 328 | tegra_wm8903_hp_jack_pins); |
249 | 1, | 329 | snd_soc_jack_add_gpios(&tegra_wm8903_hp_jack, |
250 | &tegra_wm8903_hp_jack_gpio); | 330 | 1, |
331 | &tegra_wm8903_hp_jack_gpio); | ||
332 | } | ||
251 | 333 | ||
252 | snd_soc_jack_new(codec, "Mic Jack", SND_JACK_MICROPHONE, | 334 | snd_soc_jack_new(codec, "Mic Jack", SND_JACK_MICROPHONE, |
253 | &tegra_wm8903_mic_jack); | 335 | &tegra_wm8903_mic_jack); |
@@ -259,10 +341,26 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd) | |||
259 | 341 | ||
260 | snd_soc_dapm_force_enable_pin(dapm, "Mic Bias"); | 342 | snd_soc_dapm_force_enable_pin(dapm, "Mic Bias"); |
261 | 343 | ||
344 | /* FIXME: Calculate automatically based on DAPM routes? */ | ||
345 | if (!machine_is_harmony() && !machine_is_ventana()) | ||
346 | snd_soc_dapm_nc_pin(dapm, "IN1L"); | ||
347 | if (!machine_is_seaboard() && !machine_is_aebl()) | ||
348 | snd_soc_dapm_nc_pin(dapm, "IN1R"); | ||
349 | snd_soc_dapm_nc_pin(dapm, "IN2L"); | ||
350 | if (!machine_is_kaen()) | ||
351 | snd_soc_dapm_nc_pin(dapm, "IN2R"); | ||
262 | snd_soc_dapm_nc_pin(dapm, "IN3L"); | 352 | snd_soc_dapm_nc_pin(dapm, "IN3L"); |
263 | snd_soc_dapm_nc_pin(dapm, "IN3R"); | 353 | snd_soc_dapm_nc_pin(dapm, "IN3R"); |
264 | snd_soc_dapm_nc_pin(dapm, "LINEOUTL"); | 354 | |
265 | snd_soc_dapm_nc_pin(dapm, "LINEOUTR"); | 355 | if (machine_is_aebl()) { |
356 | snd_soc_dapm_nc_pin(dapm, "LON"); | ||
357 | snd_soc_dapm_nc_pin(dapm, "RON"); | ||
358 | snd_soc_dapm_nc_pin(dapm, "ROP"); | ||
359 | snd_soc_dapm_nc_pin(dapm, "LOP"); | ||
360 | } else { | ||
361 | snd_soc_dapm_nc_pin(dapm, "LINEOUTR"); | ||
362 | snd_soc_dapm_nc_pin(dapm, "LINEOUTL"); | ||
363 | } | ||
266 | 364 | ||
267 | snd_soc_dapm_sync(dapm); | 365 | snd_soc_dapm_sync(dapm); |
268 | 366 | ||
@@ -293,14 +391,16 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev) | |||
293 | struct tegra_wm8903_platform_data *pdata; | 391 | struct tegra_wm8903_platform_data *pdata; |
294 | int ret; | 392 | int ret; |
295 | 393 | ||
296 | if (!machine_is_harmony()) { | 394 | if (!machine_is_harmony() && !machine_is_ventana() && |
297 | dev_err(&pdev->dev, "Not running on Tegra Harmony!\n"); | 395 | !machine_is_seaboard() && !machine_is_kaen() && |
396 | !machine_is_aebl()) { | ||
397 | dev_err(&pdev->dev, "Not running on a supported board!\n"); | ||
298 | return -ENODEV; | 398 | return -ENODEV; |
299 | } | 399 | } |
300 | 400 | ||
301 | pdata = pdev->dev.platform_data; | 401 | pdata = pdev->dev.platform_data; |
302 | if (!pdata) { | 402 | if (!pdata) { |
303 | dev_err(&pdev->dev, "no platform data supplied\n"); | 403 | dev_err(&pdev->dev, "No platform data supplied\n"); |
304 | return -EINVAL; | 404 | return -EINVAL; |
305 | } | 405 | } |
306 | 406 | ||
@@ -357,6 +457,8 @@ static int __devexit tegra_wm8903_driver_remove(struct platform_device *pdev) | |||
357 | gpio_free(pdata->gpio_ext_mic_en); | 457 | gpio_free(pdata->gpio_ext_mic_en); |
358 | if (machine->gpio_requested & GPIO_INT_MIC_EN) | 458 | if (machine->gpio_requested & GPIO_INT_MIC_EN) |
359 | gpio_free(pdata->gpio_int_mic_en); | 459 | gpio_free(pdata->gpio_int_mic_en); |
460 | if (machine->gpio_requested & GPIO_HP_MUTE) | ||
461 | gpio_free(pdata->gpio_hp_mute); | ||
360 | if (machine->gpio_requested & GPIO_SPKR_EN) | 462 | if (machine->gpio_requested & GPIO_SPKR_EN) |
361 | gpio_free(pdata->gpio_spkr_en); | 463 | gpio_free(pdata->gpio_spkr_en); |
362 | 464 | ||