clear-pkgs-linux-iot-lts2018/0465-ASoC-tdf8532-add-crit-...

210 lines
6.0 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Gustaw Lewandowski <gustaw.lewandowski@intel.com>
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 <gustaw.lewandowski@intel.com>
---
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 <sound/soc.h>
#include <sound/tlv.h>
#include <sound/pcm_params.h>
+#include <linux/mutex.h>
#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