aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZidan Wang <b50113@freescale.com>2015-01-07 02:31:44 -0500
committerMark Brown <broonie@kernel.org>2015-01-14 14:18:34 -0500
commit75aa88684d73ed00a38bfa14b9edfac18b2acae8 (patch)
tree1129d295d668c29db25ba4b983f0815eebbe585d
parent97bf6af1f928216fd6c5a66e8a57bfa95a659672 (diff)
ASoC: wm8960: Let wm8960 codec driver manage its own MCLK
When we want to use wm8960 codec, we should enable its MCLK in machine driver. It's reasonable for wm8960 codec driver to manage its own MCLK. When current bias_level is SND_SOC_BIAS_ON, it is preparing for a transition away from ON. In this case, disable the codec mclk. When current bias_level is not SND_SOC_BIAS_ON, it preparing for a transition to ON. In this case, enable the codec mclk. Signed-off-by: Zidan Wang <b50113@freescale.com> Signed-off-by: Mark Brown <broonie@kernel.org>
-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 031a1ae71d94..f63cadf45215 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);