[alsa-devel][PATCH 1/4] ASoC: wm8960: codec mclk should be enabled early to avoid jack detect error

From: Zidan Wang
Date: Thu Jun 11 2015 - 07:14:17 EST


It will playback from speaker in the first 2 seconds, then switch to
headphone. Steps to reproduce this issue:
1. plug out headphone and playback a wav.
2. stop playback and wait for at least 5 seconds, then
plug in headphone and playback a wav.

Signed-off-by: Zidan Wang <zidan.wang@xxxxxxxxxxxxx>
---
sound/soc/codecs/wm8960.c | 73 +++++++++++++++++++++--------------------------
1 file changed, 33 insertions(+), 40 deletions(-)

diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
index 761418f..729205f 100644
--- a/sound/soc/codecs/wm8960.c
+++ b/sound/soc/codecs/wm8960.c
@@ -491,6 +491,34 @@ static int wm8960_add_widgets(struct snd_soc_codec *codec)
return 0;
}

+int wm8960_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *codec_dai)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
+ int ret;
+
+ if (!IS_ERR(wm8960->mclk)) {
+ ret = clk_prepare_enable(wm8960->mclk);
+ if (ret) {
+ dev_err(codec->dev,
+ "Failed to enable MCLK: %d\n", ret);
+ return ret;
+ }
+ }
+ return 0;
+}
+
+void wm8960_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *codec_dai)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
+
+ if (!IS_ERR(wm8960->mclk))
+ clk_disable_unprepare(wm8960->mclk);
+}
+
static int wm8960_set_dai_fmt(struct snd_soc_dai *codec_dai,
unsigned int fmt)
{
@@ -702,38 +730,14 @@ static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
- int ret;

switch (level) {
case SND_SOC_BIAS_ON:
break;

case SND_SOC_BIAS_PREPARE:
- switch (snd_soc_codec_get_bias_level(codec)) {
- case SND_SOC_BIAS_STANDBY:
- if (!IS_ERR(wm8960->mclk)) {
- ret = clk_prepare_enable(wm8960->mclk);
- if (ret) {
- dev_err(codec->dev,
- "Failed to enable MCLK: %d\n",
- ret);
- return ret;
- }
- }
-
- /* Set VMID to 2x50k */
- snd_soc_update_bits(codec, WM8960_POWER1, 0x180, 0x80);
- break;
-
- case SND_SOC_BIAS_ON:
- if (!IS_ERR(wm8960->mclk))
- clk_disable_unprepare(wm8960->mclk);
- break;
-
- default:
- break;
- }
-
+ /* Set VMID to 2x50k */
+ snd_soc_update_bits(codec, WM8960_POWER1, 0x180, 0x80);
break;

case SND_SOC_BIAS_STANDBY:
@@ -780,7 +784,7 @@ static int wm8960_set_bias_level_capless(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
- int reg, ret;
+ int reg;

switch (level) {
case SND_SOC_BIAS_ON:
@@ -821,22 +825,9 @@ static int wm8960_set_bias_level_capless(struct snd_soc_codec *codec,
WM8960_VREF, WM8960_VREF);

msleep(100);
-
- if (!IS_ERR(wm8960->mclk)) {
- ret = clk_prepare_enable(wm8960->mclk);
- if (ret) {
- dev_err(codec->dev,
- "Failed to enable MCLK: %d\n",
- ret);
- return ret;
- }
- }
break;

case SND_SOC_BIAS_ON:
- if (!IS_ERR(wm8960->mclk))
- clk_disable_unprepare(wm8960->mclk);
-
/* Enable anti-pop mode */
snd_soc_update_bits(codec, WM8960_APOP1,
WM8960_POBCTRL | WM8960_SOFT_ST |
@@ -1059,6 +1050,8 @@ static int wm8960_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)

static const struct snd_soc_dai_ops wm8960_dai_ops = {
+ .startup = wm8960_startup,
+ .shutdown = wm8960_shutdown,
.hw_params = wm8960_hw_params,
.digital_mute = wm8960_mute,
.set_fmt = wm8960_set_dai_fmt,
--
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/