diff options
| -rw-r--r-- | sound/soc/codecs/wm8731.c | 51 |
1 files changed, 47 insertions, 4 deletions
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 0e59219a59f4..bb95af950971 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | #include <linux/pm.h> | 19 | #include <linux/pm.h> |
| 20 | #include <linux/i2c.h> | 20 | #include <linux/i2c.h> |
| 21 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
| 22 | #include <linux/regulator/consumer.h> | ||
| 22 | #include <linux/spi/spi.h> | 23 | #include <linux/spi/spi.h> |
| 23 | #include <sound/core.h> | 24 | #include <sound/core.h> |
| 24 | #include <sound/pcm.h> | 25 | #include <sound/pcm.h> |
| @@ -33,9 +34,18 @@ | |||
| 33 | static struct snd_soc_codec *wm8731_codec; | 34 | static struct snd_soc_codec *wm8731_codec; |
| 34 | struct snd_soc_codec_device soc_codec_dev_wm8731; | 35 | struct snd_soc_codec_device soc_codec_dev_wm8731; |
| 35 | 36 | ||
| 37 | #define WM8731_NUM_SUPPLIES 4 | ||
| 38 | static const char *wm8731_supply_names[WM8731_NUM_SUPPLIES] = { | ||
| 39 | "AVDD", | ||
| 40 | "HPVDD", | ||
| 41 | "DCVDD", | ||
| 42 | "DBVDD", | ||
| 43 | }; | ||
| 44 | |||
| 36 | /* codec private data */ | 45 | /* codec private data */ |
| 37 | struct wm8731_priv { | 46 | struct wm8731_priv { |
| 38 | struct snd_soc_codec codec; | 47 | struct snd_soc_codec codec; |
| 48 | struct regulator_bulk_data supplies[WM8731_NUM_SUPPLIES]; | ||
| 39 | u16 reg_cache[WM8731_CACHEREGNUM]; | 49 | u16 reg_cache[WM8731_CACHEREGNUM]; |
| 40 | unsigned int sysclk; | 50 | unsigned int sysclk; |
| 41 | }; | 51 | }; |
| @@ -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,10 +445,16 @@ 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++) { |
| 441 | data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); | 460 | data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); |
| @@ -444,6 +463,7 @@ static int wm8731_resume(struct platform_device *pdev) | |||
| 444 | } | 463 | } |
| 445 | wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 464 | wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
| 446 | wm8731_set_bias_level(codec, codec->suspend_bias_level); | 465 | wm8731_set_bias_level(codec, codec->suspend_bias_level); |
| 466 | |||
| 447 | return 0; | 467 | return 0; |
| 448 | } | 468 | } |
| 449 | #else | 469 | #else |
| @@ -512,7 +532,7 @@ EXPORT_SYMBOL_GPL(soc_codec_dev_wm8731); | |||
| 512 | static int wm8731_register(struct wm8731_priv *wm8731, | 532 | static int wm8731_register(struct wm8731_priv *wm8731, |
| 513 | enum snd_soc_control_type control) | 533 | enum snd_soc_control_type control) |
| 514 | { | 534 | { |
| 515 | int ret; | 535 | int ret, i; |
| 516 | struct snd_soc_codec *codec = &wm8731->codec; | 536 | struct snd_soc_codec *codec = &wm8731->codec; |
| 517 | 537 | ||
| 518 | if (wm8731_codec) { | 538 | if (wm8731_codec) { |
| @@ -543,10 +563,27 @@ static int wm8731_register(struct wm8731_priv *wm8731, | |||
| 543 | goto err; | 563 | goto err; |
| 544 | } | 564 | } |
| 545 | 565 | ||
| 566 | for (i = 0; i < ARRAY_SIZE(wm8731->supplies); i++) | ||
| 567 | wm8731->supplies[i].supply = wm8731_supply_names[i]; | ||
| 568 | |||
| 569 | ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8731->supplies), | ||
| 570 | wm8731->supplies); | ||
| 571 | if (ret != 0) { | ||
| 572 | dev_err(codec->dev, "Failed to request supplies: %d\n", ret); | ||
| 573 | goto err; | ||
| 574 | } | ||
| 575 | |||
| 576 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8731->supplies), | ||
| 577 | wm8731->supplies); | ||
| 578 | if (ret != 0) { | ||
| 579 | dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); | ||
| 580 | goto err_regulator_get; | ||
| 581 | } | ||
| 582 | |||
| 546 | ret = wm8731_reset(codec); | 583 | ret = wm8731_reset(codec); |
| 547 | if (ret < 0) { | 584 | if (ret < 0) { |
| 548 | dev_err(codec->dev, "Failed to issue reset: %d\n", ret); | 585 | dev_err(codec->dev, "Failed to issue reset: %d\n", ret); |
| 549 | goto err; | 586 | goto err_regulator_enable; |
| 550 | } | 587 | } |
| 551 | 588 | ||
| 552 | wm8731_dai.dev = codec->dev; | 589 | wm8731_dai.dev = codec->dev; |
| @@ -567,7 +604,7 @@ static int wm8731_register(struct wm8731_priv *wm8731, | |||
| 567 | ret = snd_soc_register_codec(codec); | 604 | ret = snd_soc_register_codec(codec); |
| 568 | if (ret != 0) { | 605 | if (ret != 0) { |
| 569 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | 606 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); |
| 570 | goto err; | 607 | goto err_regulator_enable; |
| 571 | } | 608 | } |
| 572 | 609 | ||
| 573 | ret = snd_soc_register_dai(&wm8731_dai); | 610 | ret = snd_soc_register_dai(&wm8731_dai); |
| @@ -581,6 +618,10 @@ static int wm8731_register(struct wm8731_priv *wm8731, | |||
| 581 | 618 | ||
| 582 | err_codec: | 619 | err_codec: |
| 583 | snd_soc_unregister_codec(codec); | 620 | snd_soc_unregister_codec(codec); |
| 621 | err_regulator_enable: | ||
| 622 | regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies); | ||
| 623 | err_regulator_get: | ||
| 624 | regulator_bulk_free(ARRAY_SIZE(wm8731->supplies), wm8731->supplies); | ||
| 584 | err: | 625 | err: |
| 585 | kfree(wm8731); | 626 | kfree(wm8731); |
| 586 | return ret; | 627 | return ret; |
| @@ -591,6 +632,8 @@ static void wm8731_unregister(struct wm8731_priv *wm8731) | |||
| 591 | wm8731_set_bias_level(&wm8731->codec, SND_SOC_BIAS_OFF); | 632 | wm8731_set_bias_level(&wm8731->codec, SND_SOC_BIAS_OFF); |
| 592 | snd_soc_unregister_dai(&wm8731_dai); | 633 | snd_soc_unregister_dai(&wm8731_dai); |
| 593 | snd_soc_unregister_codec(&wm8731->codec); | 634 | snd_soc_unregister_codec(&wm8731->codec); |
| 635 | regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies); | ||
| 636 | regulator_bulk_free(ARRAY_SIZE(wm8731->supplies), wm8731->supplies); | ||
| 594 | kfree(wm8731); | 637 | kfree(wm8731); |
| 595 | wm8731_codec = NULL; | 638 | wm8731_codec = NULL; |
| 596 | } | 639 | } |
