aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/wm8960.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs/wm8960.c')
-rw-r--r--sound/soc/codecs/wm8960.c51
1 files changed, 48 insertions, 3 deletions
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
index a96eb497a379..cf8fecf97f2c 100644
--- a/sound/soc/codecs/wm8960.c
+++ b/sound/soc/codecs/wm8960.c
@@ -15,6 +15,7 @@
15#include <linux/init.h> 15#include <linux/init.h>
16#include <linux/delay.h> 16#include <linux/delay.h>
17#include <linux/pm.h> 17#include <linux/pm.h>
18#include <linux/clk.h>
18#include <linux/i2c.h> 19#include <linux/i2c.h>
19#include <linux/slab.h> 20#include <linux/slab.h>
20#include <sound/core.h> 21#include <sound/core.h>
@@ -117,6 +118,7 @@ static bool wm8960_volatile(struct device *dev, unsigned int reg)
117} 118}
118 119
119struct wm8960_priv { 120struct wm8960_priv {
121 struct clk *mclk;
120 struct regmap *regmap; 122 struct regmap *regmap;
121 int (*set_bias_level)(struct snd_soc_codec *, 123 int (*set_bias_level)(struct snd_soc_codec *,
122 enum snd_soc_bias_level level); 124 enum snd_soc_bias_level level);
@@ -618,14 +620,38 @@ static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec,
618 enum snd_soc_bias_level level) 620 enum snd_soc_bias_level level)
619{ 621{
620 struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); 622 struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
623 int ret;
621 624
622 switch (level) { 625 switch (level) {
623 case SND_SOC_BIAS_ON: 626 case SND_SOC_BIAS_ON:
624 break; 627 break;
625 628
626 case SND_SOC_BIAS_PREPARE: 629 case SND_SOC_BIAS_PREPARE:
627 /* Set VMID to 2x50k */ 630 switch (codec->dapm.bias_level) {
628 snd_soc_update_bits(codec, WM8960_POWER1, 0x180, 0x80); 631 case SND_SOC_BIAS_STANDBY:
632 if (!IS_ERR(wm8960->mclk)) {
633 ret = clk_prepare_enable(wm8960->mclk);
634 if (ret) {
635 dev_err(codec->dev,
636 "Failed to enable MCLK: %d\n",
637 ret);
638 return ret;
639 }
640 }
641
642 /* Set VMID to 2x50k */
643 snd_soc_update_bits(codec, WM8960_POWER1, 0x180, 0x80);
644 break;
645
646 case SND_SOC_BIAS_ON:
647 if (!IS_ERR(wm8960->mclk))
648 clk_disable_unprepare(wm8960->mclk);
649 break;
650
651 default:
652 break;
653 }
654
629 break; 655 break;
630 656
631 case SND_SOC_BIAS_STANDBY: 657 case SND_SOC_BIAS_STANDBY:
@@ -674,7 +700,7 @@ static int wm8960_set_bias_level_capless(struct snd_soc_codec *codec,
674 enum snd_soc_bias_level level) 700 enum snd_soc_bias_level level)
675{ 701{
676 struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); 702 struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
677 int reg; 703 int reg, ret;
678 704
679 switch (level) { 705 switch (level) {
680 case SND_SOC_BIAS_ON: 706 case SND_SOC_BIAS_ON:
@@ -715,9 +741,22 @@ static int wm8960_set_bias_level_capless(struct snd_soc_codec *codec,
715 WM8960_VREF, WM8960_VREF); 741 WM8960_VREF, WM8960_VREF);
716 742
717 msleep(100); 743 msleep(100);
744
745 if (!IS_ERR(wm8960->mclk)) {
746 ret = clk_prepare_enable(wm8960->mclk);
747 if (ret) {
748 dev_err(codec->dev,
749 "Failed to enable MCLK: %d\n",
750 ret);
751 return ret;
752 }
753 }
718 break; 754 break;
719 755
720 case SND_SOC_BIAS_ON: 756 case SND_SOC_BIAS_ON:
757 if (!IS_ERR(wm8960->mclk))
758 clk_disable_unprepare(wm8960->mclk);
759
721 /* Enable anti-pop mode */ 760 /* Enable anti-pop mode */
722 snd_soc_update_bits(codec, WM8960_APOP1, 761 snd_soc_update_bits(codec, WM8960_APOP1,
723 WM8960_POBCTRL | WM8960_SOFT_ST | 762 WM8960_POBCTRL | WM8960_SOFT_ST |
@@ -1002,6 +1041,12 @@ static int wm8960_i2c_probe(struct i2c_client *i2c,
1002 if (wm8960 == NULL) 1041 if (wm8960 == NULL)
1003 return -ENOMEM; 1042 return -ENOMEM;
1004 1043
1044 wm8960->mclk = devm_clk_get(&i2c->dev, "mclk");
1045 if (IS_ERR(wm8960->mclk)) {
1046 if (PTR_ERR(wm8960->mclk) == -EPROBE_DEFER)
1047 return -EPROBE_DEFER;
1048 }
1049
1005 wm8960->regmap = devm_regmap_init_i2c(i2c, &wm8960_regmap); 1050 wm8960->regmap = devm_regmap_init_i2c(i2c, &wm8960_regmap);
1006 if (IS_ERR(wm8960->regmap)) 1051 if (IS_ERR(wm8960->regmap))
1007 return PTR_ERR(wm8960->regmap); 1052 return PTR_ERR(wm8960->regmap);