diff options
Diffstat (limited to 'sound/soc/codecs/wm8731.c')
-rw-r--r-- | sound/soc/codecs/wm8731.c | 98 |
1 files changed, 51 insertions, 47 deletions
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index d3fd4f28d96e..e7c6bf163185 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c | |||
@@ -18,7 +18,9 @@ | |||
18 | #include <linux/delay.h> | 18 | #include <linux/delay.h> |
19 | #include <linux/pm.h> | 19 | #include <linux/pm.h> |
20 | #include <linux/i2c.h> | 20 | #include <linux/i2c.h> |
21 | #include <linux/slab.h> | ||
21 | #include <linux/platform_device.h> | 22 | #include <linux/platform_device.h> |
23 | #include <linux/regulator/consumer.h> | ||
22 | #include <linux/spi/spi.h> | 24 | #include <linux/spi/spi.h> |
23 | #include <sound/core.h> | 25 | #include <sound/core.h> |
24 | #include <sound/pcm.h> | 26 | #include <sound/pcm.h> |
@@ -33,9 +35,18 @@ | |||
33 | static struct snd_soc_codec *wm8731_codec; | 35 | static struct snd_soc_codec *wm8731_codec; |
34 | struct snd_soc_codec_device soc_codec_dev_wm8731; | 36 | struct snd_soc_codec_device soc_codec_dev_wm8731; |
35 | 37 | ||
38 | #define WM8731_NUM_SUPPLIES 4 | ||
39 | static const char *wm8731_supply_names[WM8731_NUM_SUPPLIES] = { | ||
40 | "AVDD", | ||
41 | "HPVDD", | ||
42 | "DCVDD", | ||
43 | "DBVDD", | ||
44 | }; | ||
45 | |||
36 | /* codec private data */ | 46 | /* codec private data */ |
37 | struct wm8731_priv { | 47 | struct wm8731_priv { |
38 | struct snd_soc_codec codec; | 48 | struct snd_soc_codec codec; |
49 | struct regulator_bulk_data supplies[WM8731_NUM_SUPPLIES]; | ||
39 | u16 reg_cache[WM8731_CACHEREGNUM]; | 50 | u16 reg_cache[WM8731_CACHEREGNUM]; |
40 | unsigned int sysclk; | 51 | unsigned int sysclk; |
41 | }; | 52 | }; |
@@ -149,7 +160,6 @@ static int wm8731_add_widgets(struct snd_soc_codec *codec) | |||
149 | 160 | ||
150 | snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); | 161 | snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); |
151 | 162 | ||
152 | snd_soc_dapm_new_widgets(codec); | ||
153 | return 0; | 163 | return 0; |
154 | } | 164 | } |
155 | 165 | ||
@@ -422,9 +432,12 @@ static int wm8731_suspend(struct platform_device *pdev, pm_message_t state) | |||
422 | { | 432 | { |
423 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 433 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
424 | struct snd_soc_codec *codec = socdev->card->codec; | 434 | struct snd_soc_codec *codec = socdev->card->codec; |
435 | struct wm8731_priv *wm8731 = codec->private_data; | ||
425 | 436 | ||
426 | snd_soc_write(codec, WM8731_ACTIVE, 0x0); | 437 | snd_soc_write(codec, WM8731_ACTIVE, 0x0); |
427 | wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF); | 438 | wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF); |
439 | regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), | ||
440 | wm8731->supplies); | ||
428 | return 0; | 441 | return 0; |
429 | } | 442 | } |
430 | 443 | ||
@@ -432,18 +445,28 @@ static int wm8731_resume(struct platform_device *pdev) | |||
432 | { | 445 | { |
433 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 446 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
434 | struct snd_soc_codec *codec = socdev->card->codec; | 447 | struct snd_soc_codec *codec = socdev->card->codec; |
435 | int i; | 448 | struct wm8731_priv *wm8731 = codec->private_data; |
449 | int i, ret; | ||
436 | u8 data[2]; | 450 | u8 data[2]; |
437 | u16 *cache = codec->reg_cache; | 451 | u16 *cache = codec->reg_cache; |
438 | 452 | ||
453 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8731->supplies), | ||
454 | wm8731->supplies); | ||
455 | if (ret != 0) | ||
456 | return ret; | ||
457 | |||
439 | /* Sync reg_cache with the hardware */ | 458 | /* Sync reg_cache with the hardware */ |
440 | for (i = 0; i < ARRAY_SIZE(wm8731_reg); i++) { | 459 | for (i = 0; i < ARRAY_SIZE(wm8731_reg); i++) { |
460 | if (cache[i] == wm8731_reg[i]) | ||
461 | continue; | ||
462 | |||
441 | data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); | 463 | data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); |
442 | data[1] = cache[i] & 0x00ff; | 464 | data[1] = cache[i] & 0x00ff; |
443 | codec->hw_write(codec->control_data, data, 2); | 465 | codec->hw_write(codec->control_data, data, 2); |
444 | } | 466 | } |
445 | wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 467 | wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
446 | wm8731_set_bias_level(codec, codec->suspend_bias_level); | 468 | wm8731_set_bias_level(codec, codec->suspend_bias_level); |
469 | |||
447 | return 0; | 470 | return 0; |
448 | } | 471 | } |
449 | #else | 472 | #else |
@@ -475,17 +498,9 @@ static int wm8731_probe(struct platform_device *pdev) | |||
475 | snd_soc_add_controls(codec, wm8731_snd_controls, | 498 | snd_soc_add_controls(codec, wm8731_snd_controls, |
476 | ARRAY_SIZE(wm8731_snd_controls)); | 499 | ARRAY_SIZE(wm8731_snd_controls)); |
477 | wm8731_add_widgets(codec); | 500 | wm8731_add_widgets(codec); |
478 | ret = snd_soc_init_card(socdev); | ||
479 | if (ret < 0) { | ||
480 | dev_err(codec->dev, "failed to register card: %d\n", ret); | ||
481 | goto card_err; | ||
482 | } | ||
483 | 501 | ||
484 | return ret; | 502 | return ret; |
485 | 503 | ||
486 | card_err: | ||
487 | snd_soc_free_pcms(socdev); | ||
488 | snd_soc_dapm_free(socdev); | ||
489 | pcm_err: | 504 | pcm_err: |
490 | return ret; | 505 | return ret; |
491 | } | 506 | } |
@@ -512,7 +527,7 @@ EXPORT_SYMBOL_GPL(soc_codec_dev_wm8731); | |||
512 | static int wm8731_register(struct wm8731_priv *wm8731, | 527 | static int wm8731_register(struct wm8731_priv *wm8731, |
513 | enum snd_soc_control_type control) | 528 | enum snd_soc_control_type control) |
514 | { | 529 | { |
515 | int ret; | 530 | int ret, i; |
516 | struct snd_soc_codec *codec = &wm8731->codec; | 531 | struct snd_soc_codec *codec = &wm8731->codec; |
517 | 532 | ||
518 | if (wm8731_codec) { | 533 | if (wm8731_codec) { |
@@ -543,10 +558,27 @@ static int wm8731_register(struct wm8731_priv *wm8731, | |||
543 | goto err; | 558 | goto err; |
544 | } | 559 | } |
545 | 560 | ||
561 | for (i = 0; i < ARRAY_SIZE(wm8731->supplies); i++) | ||
562 | wm8731->supplies[i].supply = wm8731_supply_names[i]; | ||
563 | |||
564 | ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8731->supplies), | ||
565 | wm8731->supplies); | ||
566 | if (ret != 0) { | ||
567 | dev_err(codec->dev, "Failed to request supplies: %d\n", ret); | ||
568 | goto err; | ||
569 | } | ||
570 | |||
571 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8731->supplies), | ||
572 | wm8731->supplies); | ||
573 | if (ret != 0) { | ||
574 | dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); | ||
575 | goto err_regulator_get; | ||
576 | } | ||
577 | |||
546 | ret = wm8731_reset(codec); | 578 | ret = wm8731_reset(codec); |
547 | if (ret < 0) { | 579 | if (ret < 0) { |
548 | dev_err(codec->dev, "Failed to issue reset: %d\n", ret); | 580 | dev_err(codec->dev, "Failed to issue reset: %d\n", ret); |
549 | goto err; | 581 | goto err_regulator_enable; |
550 | } | 582 | } |
551 | 583 | ||
552 | wm8731_dai.dev = codec->dev; | 584 | wm8731_dai.dev = codec->dev; |
@@ -567,7 +599,7 @@ static int wm8731_register(struct wm8731_priv *wm8731, | |||
567 | ret = snd_soc_register_codec(codec); | 599 | ret = snd_soc_register_codec(codec); |
568 | if (ret != 0) { | 600 | if (ret != 0) { |
569 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | 601 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); |
570 | goto err; | 602 | goto err_regulator_enable; |
571 | } | 603 | } |
572 | 604 | ||
573 | ret = snd_soc_register_dai(&wm8731_dai); | 605 | ret = snd_soc_register_dai(&wm8731_dai); |
@@ -581,6 +613,10 @@ static int wm8731_register(struct wm8731_priv *wm8731, | |||
581 | 613 | ||
582 | err_codec: | 614 | err_codec: |
583 | snd_soc_unregister_codec(codec); | 615 | snd_soc_unregister_codec(codec); |
616 | err_regulator_enable: | ||
617 | regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies); | ||
618 | err_regulator_get: | ||
619 | regulator_bulk_free(ARRAY_SIZE(wm8731->supplies), wm8731->supplies); | ||
584 | err: | 620 | err: |
585 | kfree(wm8731); | 621 | kfree(wm8731); |
586 | return ret; | 622 | return ret; |
@@ -591,6 +627,8 @@ static void wm8731_unregister(struct wm8731_priv *wm8731) | |||
591 | wm8731_set_bias_level(&wm8731->codec, SND_SOC_BIAS_OFF); | 627 | wm8731_set_bias_level(&wm8731->codec, SND_SOC_BIAS_OFF); |
592 | snd_soc_unregister_dai(&wm8731_dai); | 628 | snd_soc_unregister_dai(&wm8731_dai); |
593 | snd_soc_unregister_codec(&wm8731->codec); | 629 | snd_soc_unregister_codec(&wm8731->codec); |
630 | regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies); | ||
631 | regulator_bulk_free(ARRAY_SIZE(wm8731->supplies), wm8731->supplies); | ||
594 | kfree(wm8731); | 632 | kfree(wm8731); |
595 | wm8731_codec = NULL; | 633 | wm8731_codec = NULL; |
596 | } | 634 | } |
@@ -623,21 +661,6 @@ static int __devexit wm8731_spi_remove(struct spi_device *spi) | |||
623 | return 0; | 661 | return 0; |
624 | } | 662 | } |
625 | 663 | ||
626 | #ifdef CONFIG_PM | ||
627 | static int wm8731_spi_suspend(struct spi_device *spi, pm_message_t msg) | ||
628 | { | ||
629 | return snd_soc_suspend_device(&spi->dev); | ||
630 | } | ||
631 | |||
632 | static int wm8731_spi_resume(struct spi_device *spi) | ||
633 | { | ||
634 | return snd_soc_resume_device(&spi->dev); | ||
635 | } | ||
636 | #else | ||
637 | #define wm8731_spi_suspend NULL | ||
638 | #define wm8731_spi_resume NULL | ||
639 | #endif | ||
640 | |||
641 | static struct spi_driver wm8731_spi_driver = { | 664 | static struct spi_driver wm8731_spi_driver = { |
642 | .driver = { | 665 | .driver = { |
643 | .name = "wm8731", | 666 | .name = "wm8731", |
@@ -645,8 +668,6 @@ static struct spi_driver wm8731_spi_driver = { | |||
645 | .owner = THIS_MODULE, | 668 | .owner = THIS_MODULE, |
646 | }, | 669 | }, |
647 | .probe = wm8731_spi_probe, | 670 | .probe = wm8731_spi_probe, |
648 | .suspend = wm8731_spi_suspend, | ||
649 | .resume = wm8731_spi_resume, | ||
650 | .remove = __devexit_p(wm8731_spi_remove), | 671 | .remove = __devexit_p(wm8731_spi_remove), |
651 | }; | 672 | }; |
652 | #endif /* CONFIG_SPI_MASTER */ | 673 | #endif /* CONFIG_SPI_MASTER */ |
@@ -679,21 +700,6 @@ static __devexit int wm8731_i2c_remove(struct i2c_client *client) | |||
679 | return 0; | 700 | return 0; |
680 | } | 701 | } |
681 | 702 | ||
682 | #ifdef CONFIG_PM | ||
683 | static int wm8731_i2c_suspend(struct i2c_client *i2c, pm_message_t msg) | ||
684 | { | ||
685 | return snd_soc_suspend_device(&i2c->dev); | ||
686 | } | ||
687 | |||
688 | static int wm8731_i2c_resume(struct i2c_client *i2c) | ||
689 | { | ||
690 | return snd_soc_resume_device(&i2c->dev); | ||
691 | } | ||
692 | #else | ||
693 | #define wm8731_i2c_suspend NULL | ||
694 | #define wm8731_i2c_resume NULL | ||
695 | #endif | ||
696 | |||
697 | static const struct i2c_device_id wm8731_i2c_id[] = { | 703 | static const struct i2c_device_id wm8731_i2c_id[] = { |
698 | { "wm8731", 0 }, | 704 | { "wm8731", 0 }, |
699 | { } | 705 | { } |
@@ -707,8 +713,6 @@ static struct i2c_driver wm8731_i2c_driver = { | |||
707 | }, | 713 | }, |
708 | .probe = wm8731_i2c_probe, | 714 | .probe = wm8731_i2c_probe, |
709 | .remove = __devexit_p(wm8731_i2c_remove), | 715 | .remove = __devexit_p(wm8731_i2c_remove), |
710 | .suspend = wm8731_i2c_suspend, | ||
711 | .resume = wm8731_i2c_resume, | ||
712 | .id_table = wm8731_i2c_id, | 716 | .id_table = wm8731_i2c_id, |
713 | }; | 717 | }; |
714 | #endif | 718 | #endif |