diff options
Diffstat (limited to 'sound/soc/codecs/wm8940.c')
-rw-r--r-- | sound/soc/codecs/wm8940.c | 53 |
1 files changed, 25 insertions, 28 deletions
diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c index 056daa0010f..de9ec9b8b7d 100644 --- a/sound/soc/codecs/wm8940.c +++ b/sound/soc/codecs/wm8940.c | |||
@@ -43,9 +43,19 @@ | |||
43 | struct wm8940_priv { | 43 | struct wm8940_priv { |
44 | unsigned int sysclk; | 44 | unsigned int sysclk; |
45 | enum snd_soc_control_type control_type; | 45 | enum snd_soc_control_type control_type; |
46 | void *control_data; | ||
47 | }; | 46 | }; |
48 | 47 | ||
48 | static int wm8940_volatile_register(struct snd_soc_codec *codec, | ||
49 | unsigned int reg) | ||
50 | { | ||
51 | switch (reg) { | ||
52 | case WM8940_SOFTRESET: | ||
53 | return 1; | ||
54 | default: | ||
55 | return 0; | ||
56 | } | ||
57 | } | ||
58 | |||
49 | static u16 wm8940_reg_defaults[] = { | 59 | static u16 wm8940_reg_defaults[] = { |
50 | 0x8940, /* Soft Reset */ | 60 | 0x8940, /* Soft Reset */ |
51 | 0x0000, /* Power 1 */ | 61 | 0x0000, /* Power 1 */ |
@@ -460,6 +470,14 @@ static int wm8940_set_bias_level(struct snd_soc_codec *codec, | |||
460 | ret = snd_soc_write(codec, WM8940_POWER1, pwr_reg | 0x1); | 470 | ret = snd_soc_write(codec, WM8940_POWER1, pwr_reg | 0x1); |
461 | break; | 471 | break; |
462 | case SND_SOC_BIAS_STANDBY: | 472 | case SND_SOC_BIAS_STANDBY: |
473 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | ||
474 | ret = snd_soc_cache_sync(codec); | ||
475 | if (ret < 0) { | ||
476 | dev_err(codec->dev, "Failed to sync cache: %d\n", ret); | ||
477 | return ret; | ||
478 | } | ||
479 | } | ||
480 | |||
463 | /* ensure bufioen and biasen */ | 481 | /* ensure bufioen and biasen */ |
464 | pwr_reg |= (1 << 2) | (1 << 3); | 482 | pwr_reg |= (1 << 2) | (1 << 3); |
465 | /* set vmid to 300k for standby */ | 483 | /* set vmid to 300k for standby */ |
@@ -470,6 +488,8 @@ static int wm8940_set_bias_level(struct snd_soc_codec *codec, | |||
470 | break; | 488 | break; |
471 | } | 489 | } |
472 | 490 | ||
491 | codec->dapm.bias_level = level; | ||
492 | |||
473 | return ret; | 493 | return ret; |
474 | } | 494 | } |
475 | 495 | ||
@@ -601,7 +621,7 @@ static int wm8940_set_dai_clkdiv(struct snd_soc_dai *codec_dai, | |||
601 | 621 | ||
602 | switch (div_id) { | 622 | switch (div_id) { |
603 | case WM8940_BCLKDIV: | 623 | case WM8940_BCLKDIV: |
604 | reg = snd_soc_read(codec, WM8940_CLOCK) & 0xFFEF3; | 624 | reg = snd_soc_read(codec, WM8940_CLOCK) & 0xFFE3; |
605 | ret = snd_soc_write(codec, WM8940_CLOCK, reg | (div << 2)); | 625 | ret = snd_soc_write(codec, WM8940_CLOCK, reg | (div << 2)); |
606 | break; | 626 | break; |
607 | case WM8940_MCLKDIV: | 627 | case WM8940_MCLKDIV: |
@@ -660,30 +680,8 @@ static int wm8940_suspend(struct snd_soc_codec *codec, pm_message_t state) | |||
660 | 680 | ||
661 | static int wm8940_resume(struct snd_soc_codec *codec) | 681 | static int wm8940_resume(struct snd_soc_codec *codec) |
662 | { | 682 | { |
663 | int i; | 683 | wm8940_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
664 | int ret; | 684 | return 0; |
665 | u8 data[3]; | ||
666 | u16 *cache = codec->reg_cache; | ||
667 | |||
668 | /* Sync reg_cache with the hardware | ||
669 | * Could use auto incremented writes to speed this up | ||
670 | */ | ||
671 | for (i = 0; i < ARRAY_SIZE(wm8940_reg_defaults); i++) { | ||
672 | data[0] = i; | ||
673 | data[1] = (cache[i] & 0xFF00) >> 8; | ||
674 | data[2] = cache[i] & 0x00FF; | ||
675 | ret = codec->hw_write(codec->control_data, data, 3); | ||
676 | if (ret < 0) | ||
677 | goto error_ret; | ||
678 | else if (ret != 3) { | ||
679 | ret = -EIO; | ||
680 | goto error_ret; | ||
681 | } | ||
682 | } | ||
683 | ret = wm8940_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
684 | |||
685 | error_ret: | ||
686 | return ret; | ||
687 | } | 685 | } |
688 | 686 | ||
689 | static int wm8940_probe(struct snd_soc_codec *codec) | 687 | static int wm8940_probe(struct snd_soc_codec *codec) |
@@ -693,7 +691,6 @@ static int wm8940_probe(struct snd_soc_codec *codec) | |||
693 | int ret; | 691 | int ret; |
694 | u16 reg; | 692 | u16 reg; |
695 | 693 | ||
696 | codec->control_data = wm8940->control_data; | ||
697 | ret = snd_soc_codec_set_cache_io(codec, 8, 16, wm8940->control_type); | 694 | ret = snd_soc_codec_set_cache_io(codec, 8, 16, wm8940->control_type); |
698 | if (ret < 0) { | 695 | if (ret < 0) { |
699 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | 696 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); |
@@ -744,6 +741,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8940 = { | |||
744 | .reg_cache_size = ARRAY_SIZE(wm8940_reg_defaults), | 741 | .reg_cache_size = ARRAY_SIZE(wm8940_reg_defaults), |
745 | .reg_word_size = sizeof(u16), | 742 | .reg_word_size = sizeof(u16), |
746 | .reg_cache_default = wm8940_reg_defaults, | 743 | .reg_cache_default = wm8940_reg_defaults, |
744 | .volatile_register = wm8940_volatile_register, | ||
747 | }; | 745 | }; |
748 | 746 | ||
749 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 747 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
@@ -758,7 +756,6 @@ static __devinit int wm8940_i2c_probe(struct i2c_client *i2c, | |||
758 | return -ENOMEM; | 756 | return -ENOMEM; |
759 | 757 | ||
760 | i2c_set_clientdata(i2c, wm8940); | 758 | i2c_set_clientdata(i2c, wm8940); |
761 | wm8940->control_data = i2c; | ||
762 | wm8940->control_type = SND_SOC_I2C; | 759 | wm8940->control_type = SND_SOC_I2C; |
763 | 760 | ||
764 | ret = snd_soc_register_codec(&i2c->dev, | 761 | ret = snd_soc_register_codec(&i2c->dev, |