aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/tegra/tegra_wm8903.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/tegra/tegra_wm8903.c')
-rw-r--r--sound/soc/tegra/tegra_wm8903.c193
1 files changed, 120 insertions, 73 deletions
diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c
index a81cf39257bf..566655e23b7d 100644
--- a/sound/soc/tegra/tegra_wm8903.c
+++ b/sound/soc/tegra/tegra_wm8903.c
@@ -34,6 +34,7 @@
34#include <linux/platform_device.h> 34#include <linux/platform_device.h>
35#include <linux/slab.h> 35#include <linux/slab.h>
36#include <linux/gpio.h> 36#include <linux/gpio.h>
37#include <linux/of_gpio.h>
37 38
38#include <mach/tegra_wm8903_pdata.h> 39#include <mach/tegra_wm8903_pdata.h>
39 40
@@ -59,8 +60,9 @@
59#define GPIO_HP_DET BIT(4) 60#define GPIO_HP_DET BIT(4)
60 61
61struct tegra_wm8903 { 62struct tegra_wm8903 {
63 struct tegra_wm8903_platform_data pdata;
64 struct platform_device *pcm_dev;
62 struct tegra_asoc_utils_data util_data; 65 struct tegra_asoc_utils_data util_data;
63 struct tegra_wm8903_platform_data *pdata;
64 int gpio_requested; 66 int gpio_requested;
65}; 67};
66 68
@@ -160,7 +162,7 @@ static int tegra_wm8903_event_int_spk(struct snd_soc_dapm_widget *w,
160 struct snd_soc_dapm_context *dapm = w->dapm; 162 struct snd_soc_dapm_context *dapm = w->dapm;
161 struct snd_soc_card *card = dapm->card; 163 struct snd_soc_card *card = dapm->card;
162 struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); 164 struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
163 struct tegra_wm8903_platform_data *pdata = machine->pdata; 165 struct tegra_wm8903_platform_data *pdata = &machine->pdata;
164 166
165 if (!(machine->gpio_requested & GPIO_SPKR_EN)) 167 if (!(machine->gpio_requested & GPIO_SPKR_EN))
166 return 0; 168 return 0;
@@ -177,7 +179,7 @@ static int tegra_wm8903_event_hp(struct snd_soc_dapm_widget *w,
177 struct snd_soc_dapm_context *dapm = w->dapm; 179 struct snd_soc_dapm_context *dapm = w->dapm;
178 struct snd_soc_card *card = dapm->card; 180 struct snd_soc_card *card = dapm->card;
179 struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); 181 struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
180 struct tegra_wm8903_platform_data *pdata = machine->pdata; 182 struct tegra_wm8903_platform_data *pdata = &machine->pdata;
181 183
182 if (!(machine->gpio_requested & GPIO_HP_MUTE)) 184 if (!(machine->gpio_requested & GPIO_HP_MUTE))
183 return 0; 185 return 0;
@@ -201,8 +203,8 @@ static const struct snd_soc_dapm_route harmony_audio_map[] = {
201 {"Int Spk", NULL, "RON"}, 203 {"Int Spk", NULL, "RON"},
202 {"Int Spk", NULL, "LOP"}, 204 {"Int Spk", NULL, "LOP"},
203 {"Int Spk", NULL, "LON"}, 205 {"Int Spk", NULL, "LON"},
204 {"Mic Bias", NULL, "Mic Jack"}, 206 {"Mic Jack", NULL, "MICBIAS"},
205 {"IN1L", NULL, "Mic Bias"}, 207 {"IN1L", NULL, "Mic Jack"},
206}; 208};
207 209
208static const struct snd_soc_dapm_route seaboard_audio_map[] = { 210static const struct snd_soc_dapm_route seaboard_audio_map[] = {
@@ -212,8 +214,8 @@ static const struct snd_soc_dapm_route seaboard_audio_map[] = {
212 {"Int Spk", NULL, "RON"}, 214 {"Int Spk", NULL, "RON"},
213 {"Int Spk", NULL, "LOP"}, 215 {"Int Spk", NULL, "LOP"},
214 {"Int Spk", NULL, "LON"}, 216 {"Int Spk", NULL, "LON"},
215 {"Mic Bias", NULL, "Mic Jack"}, 217 {"Mic Jack", NULL, "MICBIAS"},
216 {"IN1R", NULL, "Mic Bias"}, 218 {"IN1R", NULL, "Mic Jack"},
217}; 219};
218 220
219static const struct snd_soc_dapm_route kaen_audio_map[] = { 221static const struct snd_soc_dapm_route kaen_audio_map[] = {
@@ -223,8 +225,8 @@ static const struct snd_soc_dapm_route kaen_audio_map[] = {
223 {"Int Spk", NULL, "RON"}, 225 {"Int Spk", NULL, "RON"},
224 {"Int Spk", NULL, "LOP"}, 226 {"Int Spk", NULL, "LOP"},
225 {"Int Spk", NULL, "LON"}, 227 {"Int Spk", NULL, "LON"},
226 {"Mic Bias", NULL, "Mic Jack"}, 228 {"Mic Jack", NULL, "MICBIAS"},
227 {"IN2R", NULL, "Mic Bias"}, 229 {"IN2R", NULL, "Mic Jack"},
228}; 230};
229 231
230static const struct snd_soc_dapm_route aebl_audio_map[] = { 232static const struct snd_soc_dapm_route aebl_audio_map[] = {
@@ -232,8 +234,8 @@ static const struct snd_soc_dapm_route aebl_audio_map[] = {
232 {"Headphone Jack", NULL, "HPOUTL"}, 234 {"Headphone Jack", NULL, "HPOUTL"},
233 {"Int Spk", NULL, "LINEOUTR"}, 235 {"Int Spk", NULL, "LINEOUTR"},
234 {"Int Spk", NULL, "LINEOUTL"}, 236 {"Int Spk", NULL, "LINEOUTL"},
235 {"Mic Bias", NULL, "Mic Jack"}, 237 {"Mic Jack", NULL, "MICBIAS"},
236 {"IN1R", NULL, "Mic Bias"}, 238 {"IN1R", NULL, "Mic Jack"},
237}; 239};
238 240
239static const struct snd_kcontrol_new tegra_wm8903_controls[] = { 241static const struct snd_kcontrol_new tegra_wm8903_controls[] = {
@@ -246,9 +248,36 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd)
246 struct snd_soc_dapm_context *dapm = &codec->dapm; 248 struct snd_soc_dapm_context *dapm = &codec->dapm;
247 struct snd_soc_card *card = codec->card; 249 struct snd_soc_card *card = codec->card;
248 struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); 250 struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
249 struct tegra_wm8903_platform_data *pdata = machine->pdata; 251 struct tegra_wm8903_platform_data *pdata = &machine->pdata;
252 struct device_node *np = card->dev->of_node;
250 int ret; 253 int ret;
251 254
255 if (card->dev->platform_data) {
256 memcpy(pdata, card->dev->platform_data, sizeof(*pdata));
257 } else if (np) {
258 /*
259 * This part must be in init() rather than probe() in order to
260 * guarantee that the WM8903 has been probed, and hence its
261 * GPIO controller registered, which is a pre-condition for
262 * of_get_named_gpio() to be able to map the phandles in the
263 * properties to the controller node. Given this, all
264 * pdata handling is in init() for consistency.
265 */
266 pdata->gpio_spkr_en = of_get_named_gpio(np,
267 "nvidia,spkr-en-gpios", 0);
268 pdata->gpio_hp_mute = of_get_named_gpio(np,
269 "nvidia,hp-mute-gpios", 0);
270 pdata->gpio_hp_det = of_get_named_gpio(np,
271 "nvidia,hp-det-gpios", 0);
272 pdata->gpio_int_mic_en = of_get_named_gpio(np,
273 "nvidia,int-mic-en-gpios", 0);
274 pdata->gpio_ext_mic_en = of_get_named_gpio(np,
275 "nvidia,ext-mic-en-gpios", 0);
276 } else {
277 dev_err(card->dev, "No platform data supplied\n");
278 return -EINVAL;
279 }
280
252 if (gpio_is_valid(pdata->gpio_spkr_en)) { 281 if (gpio_is_valid(pdata->gpio_spkr_en)) {
253 ret = gpio_request(pdata->gpio_spkr_en, "spkr_en"); 282 ret = gpio_request(pdata->gpio_spkr_en, "spkr_en");
254 if (ret) { 283 if (ret) {
@@ -316,28 +345,7 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd)
316 wm8903_mic_detect(codec, &tegra_wm8903_mic_jack, SND_JACK_MICROPHONE, 345 wm8903_mic_detect(codec, &tegra_wm8903_mic_jack, SND_JACK_MICROPHONE,
317 0); 346 0);
318 347
319 snd_soc_dapm_force_enable_pin(dapm, "Mic Bias"); 348 snd_soc_dapm_force_enable_pin(dapm, "MICBIAS");
320
321 /* FIXME: Calculate automatically based on DAPM routes? */
322 if (!machine_is_harmony())
323 snd_soc_dapm_nc_pin(dapm, "IN1L");
324 if (!machine_is_seaboard() && !machine_is_aebl())
325 snd_soc_dapm_nc_pin(dapm, "IN1R");
326 snd_soc_dapm_nc_pin(dapm, "IN2L");
327 if (!machine_is_kaen())
328 snd_soc_dapm_nc_pin(dapm, "IN2R");
329 snd_soc_dapm_nc_pin(dapm, "IN3L");
330 snd_soc_dapm_nc_pin(dapm, "IN3R");
331
332 if (machine_is_aebl()) {
333 snd_soc_dapm_nc_pin(dapm, "LON");
334 snd_soc_dapm_nc_pin(dapm, "RON");
335 snd_soc_dapm_nc_pin(dapm, "ROP");
336 snd_soc_dapm_nc_pin(dapm, "LOP");
337 } else {
338 snd_soc_dapm_nc_pin(dapm, "LINEOUTR");
339 snd_soc_dapm_nc_pin(dapm, "LINEOUTL");
340 }
341 349
342 return 0; 350 return 0;
343} 351}
@@ -355,6 +363,7 @@ static struct snd_soc_dai_link tegra_wm8903_dai = {
355 363
356static struct snd_soc_card snd_soc_tegra_wm8903 = { 364static struct snd_soc_card snd_soc_tegra_wm8903 = {
357 .name = "tegra-wm8903", 365 .name = "tegra-wm8903",
366 .owner = THIS_MODULE,
358 .dai_link = &tegra_wm8903_dai, 367 .dai_link = &tegra_wm8903_dai,
359 .num_links = 1, 368 .num_links = 1,
360 369
@@ -362,51 +371,91 @@ static struct snd_soc_card snd_soc_tegra_wm8903 = {
362 .num_controls = ARRAY_SIZE(tegra_wm8903_controls), 371 .num_controls = ARRAY_SIZE(tegra_wm8903_controls),
363 .dapm_widgets = tegra_wm8903_dapm_widgets, 372 .dapm_widgets = tegra_wm8903_dapm_widgets,
364 .num_dapm_widgets = ARRAY_SIZE(tegra_wm8903_dapm_widgets), 373 .num_dapm_widgets = ARRAY_SIZE(tegra_wm8903_dapm_widgets),
374 .fully_routed = true,
365}; 375};
366 376
367static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev) 377static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev)
368{ 378{
369 struct snd_soc_card *card = &snd_soc_tegra_wm8903; 379 struct snd_soc_card *card = &snd_soc_tegra_wm8903;
370 struct tegra_wm8903 *machine; 380 struct tegra_wm8903 *machine;
371 struct tegra_wm8903_platform_data *pdata;
372 int ret; 381 int ret;
373 382
374 pdata = pdev->dev.platform_data; 383 if (!pdev->dev.platform_data && !pdev->dev.of_node) {
375 if (!pdata) {
376 dev_err(&pdev->dev, "No platform data supplied\n"); 384 dev_err(&pdev->dev, "No platform data supplied\n");
377 return -EINVAL; 385 return -EINVAL;
378 } 386 }
379 387
380 machine = kzalloc(sizeof(struct tegra_wm8903), GFP_KERNEL); 388 machine = devm_kzalloc(&pdev->dev, sizeof(struct tegra_wm8903),
389 GFP_KERNEL);
381 if (!machine) { 390 if (!machine) {
382 dev_err(&pdev->dev, "Can't allocate tegra_wm8903 struct\n"); 391 dev_err(&pdev->dev, "Can't allocate tegra_wm8903 struct\n");
383 return -ENOMEM; 392 ret = -ENOMEM;
393 goto err;
384 } 394 }
385 395 machine->pcm_dev = ERR_PTR(-EINVAL);
386 machine->pdata = pdata;
387
388 ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev);
389 if (ret)
390 goto err_free_machine;
391 396
392 card->dev = &pdev->dev; 397 card->dev = &pdev->dev;
393 platform_set_drvdata(pdev, card); 398 platform_set_drvdata(pdev, card);
394 snd_soc_card_set_drvdata(card, machine); 399 snd_soc_card_set_drvdata(card, machine);
395 400
396 if (machine_is_harmony()) { 401 if (pdev->dev.of_node) {
397 card->dapm_routes = harmony_audio_map; 402 ret = snd_soc_of_parse_card_name(card, "nvidia,model");
398 card->num_dapm_routes = ARRAY_SIZE(harmony_audio_map); 403 if (ret)
399 } else if (machine_is_seaboard()) { 404 goto err;
400 card->dapm_routes = seaboard_audio_map; 405
401 card->num_dapm_routes = ARRAY_SIZE(seaboard_audio_map); 406 ret = snd_soc_of_parse_audio_routing(card,
402 } else if (machine_is_kaen()) { 407 "nvidia,audio-routing");
403 card->dapm_routes = kaen_audio_map; 408 if (ret)
404 card->num_dapm_routes = ARRAY_SIZE(kaen_audio_map); 409 goto err;
410
411 tegra_wm8903_dai.codec_name = NULL;
412 tegra_wm8903_dai.codec_of_node = of_parse_phandle(
413 pdev->dev.of_node, "nvidia,audio-codec", 0);
414 if (!tegra_wm8903_dai.codec_of_node) {
415 dev_err(&pdev->dev,
416 "Property 'nvidia,audio-codec' missing or invalid\n");
417 ret = -EINVAL;
418 goto err;
419 }
420
421 tegra_wm8903_dai.cpu_dai_name = NULL;
422 tegra_wm8903_dai.cpu_dai_of_node = of_parse_phandle(
423 pdev->dev.of_node, "nvidia,i2s-controller", 0);
424 if (!tegra_wm8903_dai.cpu_dai_of_node) {
425 dev_err(&pdev->dev,
426 "Property 'nvidia,i2s-controller' missing or invalid\n");
427 ret = -EINVAL;
428 goto err;
429 }
430
431 machine->pcm_dev = platform_device_register_simple(
432 "tegra-pcm-audio", -1, NULL, 0);
433 if (IS_ERR(machine->pcm_dev)) {
434 dev_err(&pdev->dev,
435 "Can't instantiate tegra-pcm-audio\n");
436 ret = PTR_ERR(machine->pcm_dev);
437 goto err;
438 }
405 } else { 439 } else {
406 card->dapm_routes = aebl_audio_map; 440 if (machine_is_harmony()) {
407 card->num_dapm_routes = ARRAY_SIZE(aebl_audio_map); 441 card->dapm_routes = harmony_audio_map;
442 card->num_dapm_routes = ARRAY_SIZE(harmony_audio_map);
443 } else if (machine_is_seaboard()) {
444 card->dapm_routes = seaboard_audio_map;
445 card->num_dapm_routes = ARRAY_SIZE(seaboard_audio_map);
446 } else if (machine_is_kaen()) {
447 card->dapm_routes = kaen_audio_map;
448 card->num_dapm_routes = ARRAY_SIZE(kaen_audio_map);
449 } else {
450 card->dapm_routes = aebl_audio_map;
451 card->num_dapm_routes = ARRAY_SIZE(aebl_audio_map);
452 }
408 } 453 }
409 454
455 ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev);
456 if (ret)
457 goto err_unregister;
458
410 ret = snd_soc_register_card(card); 459 ret = snd_soc_register_card(card);
411 if (ret) { 460 if (ret) {
412 dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", 461 dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
@@ -418,8 +467,10 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev)
418 467
419err_fini_utils: 468err_fini_utils:
420 tegra_asoc_utils_fini(&machine->util_data); 469 tegra_asoc_utils_fini(&machine->util_data);
421err_free_machine: 470err_unregister:
422 kfree(machine); 471 if (!IS_ERR(machine->pcm_dev))
472 platform_device_unregister(machine->pcm_dev);
473err:
423 return ret; 474 return ret;
424} 475}
425 476
@@ -427,7 +478,7 @@ static int __devexit tegra_wm8903_driver_remove(struct platform_device *pdev)
427{ 478{
428 struct snd_soc_card *card = platform_get_drvdata(pdev); 479 struct snd_soc_card *card = platform_get_drvdata(pdev);
429 struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); 480 struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
430 struct tegra_wm8903_platform_data *pdata = machine->pdata; 481 struct tegra_wm8903_platform_data *pdata = &machine->pdata;
431 482
432 if (machine->gpio_requested & GPIO_HP_DET) 483 if (machine->gpio_requested & GPIO_HP_DET)
433 snd_soc_jack_free_gpios(&tegra_wm8903_hp_jack, 484 snd_soc_jack_free_gpios(&tegra_wm8903_hp_jack,
@@ -446,35 +497,31 @@ static int __devexit tegra_wm8903_driver_remove(struct platform_device *pdev)
446 snd_soc_unregister_card(card); 497 snd_soc_unregister_card(card);
447 498
448 tegra_asoc_utils_fini(&machine->util_data); 499 tegra_asoc_utils_fini(&machine->util_data);
449 500 if (!IS_ERR(machine->pcm_dev))
450 kfree(machine); 501 platform_device_unregister(machine->pcm_dev);
451 502
452 return 0; 503 return 0;
453} 504}
454 505
506static const struct of_device_id tegra_wm8903_of_match[] __devinitconst = {
507 { .compatible = "nvidia,tegra-audio-wm8903", },
508 {},
509};
510
455static struct platform_driver tegra_wm8903_driver = { 511static struct platform_driver tegra_wm8903_driver = {
456 .driver = { 512 .driver = {
457 .name = DRV_NAME, 513 .name = DRV_NAME,
458 .owner = THIS_MODULE, 514 .owner = THIS_MODULE,
459 .pm = &snd_soc_pm_ops, 515 .pm = &snd_soc_pm_ops,
516 .of_match_table = tegra_wm8903_of_match,
460 }, 517 },
461 .probe = tegra_wm8903_driver_probe, 518 .probe = tegra_wm8903_driver_probe,
462 .remove = __devexit_p(tegra_wm8903_driver_remove), 519 .remove = __devexit_p(tegra_wm8903_driver_remove),
463}; 520};
464 521module_platform_driver(tegra_wm8903_driver);
465static int __init tegra_wm8903_modinit(void)
466{
467 return platform_driver_register(&tegra_wm8903_driver);
468}
469module_init(tegra_wm8903_modinit);
470
471static void __exit tegra_wm8903_modexit(void)
472{
473 platform_driver_unregister(&tegra_wm8903_driver);
474}
475module_exit(tegra_wm8903_modexit);
476 522
477MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>"); 523MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
478MODULE_DESCRIPTION("Tegra+WM8903 machine ASoC driver"); 524MODULE_DESCRIPTION("Tegra+WM8903 machine ASoC driver");
479MODULE_LICENSE("GPL"); 525MODULE_LICENSE("GPL");
480MODULE_ALIAS("platform:" DRV_NAME); 526MODULE_ALIAS("platform:" DRV_NAME);
527MODULE_DEVICE_TABLE(of, tegra_wm8903_of_match);