From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Gustaw Lewandowski Date: Fri, 12 Oct 2018 10:24:41 +0200 Subject: [PATCH] ASoC: tdf8532: add crit sections Stop of playback caused that entire tdf8532 codec has been put into IDLE state despite current capture activity. Change-Id: I3756094e182cd44c225ba8224a840fc8c435625c Signed-off-by: Gustaw Lewandowski --- sound/soc/codecs/tdf8532.c | 93 ++++++++++++++++++++++---------------- sound/soc/codecs/tdf8532.h | 1 + 2 files changed, 55 insertions(+), 39 deletions(-) diff --git a/sound/soc/codecs/tdf8532.c b/sound/soc/codecs/tdf8532.c index 02e63f9..9fc73b6 100644 --- a/sound/soc/codecs/tdf8532.c +++ b/sound/soc/codecs/tdf8532.c @@ -21,8 +21,11 @@ #include #include #include +#include #include "tdf8532.h" +static DEFINE_MUTEX(tdf8532_lock); + static int __tdf8532_build_pkt(struct tdf8532_priv *dev_data, va_list valist, u8 *payload) { @@ -210,11 +213,12 @@ static int tdf8532_wait_state(struct tdf8532_priv *dev_data, u8 req_state, static int tdf8532_start_play(struct tdf8532_priv *tdf8532) { - int ret; + int ret = 0; + mutex_lock(&tdf8532_lock); ret = tdf8532_amp_write(tdf8532, SET_CLK_STATE, CLK_CONNECT); if (ret < 0) - return ret; + goto out; ret = tdf8532_amp_write(tdf8532, SET_CHNL_ENABLE, CHNL_MASK(tdf8532->channels)); @@ -222,22 +226,22 @@ static int tdf8532_start_play(struct tdf8532_priv *tdf8532) if (ret >= 0) ret = tdf8532_wait_state(tdf8532, STATE_PLAY, ACK_TIMEOUT); +out: + if (ret >= 0) + tdf8532->powered = 1; + mutex_unlock(&tdf8532_lock); return ret; } - static int tdf8532_stop_play(struct tdf8532_priv *tdf8532) { - int ret; - + int ret = 0; ret = tdf8532_amp_write(tdf8532, SET_CHNL_DISABLE, CHNL_MASK(tdf8532->channels)); if (ret < 0) goto out; - ret = tdf8532_wait_state(tdf8532, STATE_STBY, ACK_TIMEOUT); - if (ret < 0) - goto out; + tdf8532_wait_state(tdf8532, STATE_STBY, ACK_TIMEOUT); ret = tdf8532_amp_write(tdf8532, SET_CLK_STATE, CLK_DISCONNECT); if (ret < 0) @@ -249,30 +253,17 @@ static int tdf8532_stop_play(struct tdf8532_priv *tdf8532) return ret; } - -static int tdf8532_dai_trigger(struct snd_pcm_substream *substream, int cmd, +static int tdf8532_dai_trigger_pb(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { int ret = 0; struct snd_soc_component *component = dai->component; struct tdf8532_priv *tdf8532 = snd_soc_component_get_drvdata(component); + dev_dbg(component->dev, "%s: cmd:%d substream:%d\n", __func__, cmd, + substream->stream); - dev_dbg(component->dev, "%s: cmd = %d\n", __func__, cmd); - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - case SNDRV_PCM_TRIGGER_RESUME: + if (cmd == SNDRV_PCM_TRIGGER_START && !tdf8532->powered) ret = tdf8532_start_play(tdf8532); - break; - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_STOP: - /* WA on unexpected codec down during S3 - SNDRV_PCM_TRIGGER_STOP fails so skip set ret */ - tdf8532_stop_play(tdf8532); - break; - } return ret; } @@ -281,25 +272,48 @@ static int tdf8532_mute(struct snd_soc_dai *dai, int mute) { struct snd_soc_component *component = dai->component; struct tdf8532_priv *tdf8532 = snd_soc_component_get_drvdata(component); + int ret; - dev_dbg(component->dev, "%s\n", __func__); - - if (mute) - return tdf8532_amp_write(tdf8532, SET_CHNL_MUTE, - CHNL_MASK(CHNL_MAX)); - else - return tdf8532_amp_write(tdf8532, SET_CHNL_UNMUTE, - CHNL_MASK(CHNL_MAX)); + dev_dbg(component->dev, "%s mute:%d\n", __func__, mute); + mutex_lock(&tdf8532_lock); + ret = tdf8532_amp_write(tdf8532, (mute)?SET_CHNL_MUTE:SET_CHNL_UNMUTE, + CHNL_MASK(CHNL_MAX)); + mutex_unlock(&tdf8532_lock); + return ret; } -static const struct snd_soc_dai_ops tdf8532_dai_ops = { - .trigger = tdf8532_dai_trigger, +static const struct snd_soc_dai_ops tdf8532_dai_ops_pb = { + .trigger = tdf8532_dai_trigger_pb, .digital_mute = tdf8532_mute, }; -static struct snd_soc_component_driver soc_component_tdf8532; +static int tdf8532_resume(struct snd_soc_component *component) +{ + int ret; + struct tdf8532_priv *tdf8532 = snd_soc_component_get_drvdata(component); + u8 cur_state = STATE_NONE; + struct get_dev_status_repl *status_repl = NULL; + + dev_dbg(component->dev, "%s\n", __func__); + mutex_lock(&tdf8532_lock); + ret = tdf8532_get_state(tdf8532, &status_repl); + mutex_unlock(&tdf8532_lock); + if (ret < 0) + goto out; + cur_state = status_repl->state; + dev_dbg(component->dev, "%s cur_state:%d\n", __func__, cur_state); + if (cur_state < STATE_PLAY) + tdf8532_start_play(tdf8532); +out: + + return 0; +} + +static const struct snd_soc_component_driver soc_component_tdf8532 = { + .resume = tdf8532_resume, +}; -static struct snd_soc_dai_driver tdf8532_dai[] = { +static struct snd_soc_dai_driver tdf8532_dai_pb[] = { { .name = "tdf8532-hifi", .playback = { @@ -309,7 +323,7 @@ static struct snd_soc_dai_driver tdf8532_dai[] = { .rates = SNDRV_PCM_RATE_48000, .formats = SNDRV_PCM_FMTBIT_S16_LE, }, - .ops = &tdf8532_dai_ops, + .ops = &tdf8532_dai_ops_pb, } }; @@ -332,11 +346,12 @@ static int tdf8532_i2c_probe(struct i2c_client *i2c, dev_data->i2c = i2c; dev_data->pkt_id = 0; dev_data->channels = 4; + dev_data->powered = 0; i2c_set_clientdata(i2c, dev_data); ret = devm_snd_soc_register_component(&i2c->dev, &soc_component_tdf8532, - tdf8532_dai, ARRAY_SIZE(tdf8532_dai)); + tdf8532_dai_pb, ARRAY_SIZE(tdf8532_dai_pb)); if (ret != 0) { dev_err(&i2c->dev, "Failed to register codec: %d\n", ret); goto out; diff --git a/sound/soc/codecs/tdf8532.h b/sound/soc/codecs/tdf8532.h index 39353a0..0f35407 100644 --- a/sound/soc/codecs/tdf8532.h +++ b/sound/soc/codecs/tdf8532.h @@ -96,6 +96,7 @@ struct tdf8532_priv { struct i2c_client *i2c; u8 channels; u8 pkt_id; + u8 powered:1; }; #endif -- https://clearlinux.org