[alsa-devel] [PATCH] ASoC: ak4613: call dummy write for PW_MGMT1/3 when Playback
Kuninori Morimoto
kuninori.morimoto.gx at renesas.com
Tue Nov 14 07:31:02 CET 2017
From: Kuninori Morimoto <kuninori.morimoto.gx at renesas.com>
Power Down Release Command (PMVR, PMDAC, RSTN, PMDA1-PMDA6)
which are located on PW_MGMT1 / PW_MGMT3 register must be
write again after at least 5 LRCK cycle or later from the first
command. Otherwise, Playback volume will be 0dB.
This patch adds dummy write when Playback Start timing.
Tested-by: Hiroyuki Yokoyama <hiroyuki.yokoyama.vx at renesas.com>
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx at renesas.com>
---
sound/soc/codecs/ak4613.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 59 insertions(+)
diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c
index ee9e822..836c111 100644
--- a/sound/soc/codecs/ak4613.c
+++ b/sound/soc/codecs/ak4613.c
@@ -15,6 +15,7 @@
*/
#include <linux/clk.h>
+#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/of_device.h>
@@ -95,6 +96,9 @@ struct ak4613_priv {
struct mutex lock;
const struct ak4613_interface *iface;
struct snd_pcm_hw_constraint_list constraint;
+ struct delayed_work dummy_write_work;
+ struct snd_soc_component *component;
+ unsigned int rate;
unsigned int sysclk;
unsigned int fmt;
@@ -392,6 +396,7 @@ static int ak4613_dai_hw_params(struct snd_pcm_substream *substream,
default:
return -EINVAL;
}
+ priv->rate = rate;
/*
* FIXME
@@ -467,11 +472,64 @@ static int ak4613_set_bias_level(struct snd_soc_component *component,
return 0;
}
+static void ak4613_dummy_write(struct work_struct *work)
+{
+ struct ak4613_priv *priv = container_of(work,
+ struct ak4613_priv,
+ dummy_write_work.work);
+ struct snd_soc_component *component = priv->component;
+ unsigned int mgmt1;
+ unsigned int mgmt3;
+
+ snd_soc_component_read(component, PW_MGMT1, &mgmt1);
+ snd_soc_component_read(component, PW_MGMT3, &mgmt3);
+
+ snd_soc_component_write(component, PW_MGMT1, mgmt1);
+ snd_soc_component_write(component, PW_MGMT3, mgmt3);
+}
+
+static int ak4613_dai_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct ak4613_priv *priv = snd_soc_codec_get_drvdata(codec);
+ unsigned long delay;
+
+ /*
+ * FIXME
+ *
+ * PW_MGMT1 / PW_MGMT3 needs dummy write at least after 5 LR clocks
+ * from Power Down Release. Otherwise, Playback volume will be 0dB.
+ * To avoid complex multiple delayed_work call from
+ * ak4613_set_bias_level() / SND_SOC_DAPM_DAC_E("DACx", ...),
+ * call it once here. Here Let's call it after 6 LR
+ */
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ break;
+ default:
+ return 0;
+ }
+
+ if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
+ return 0;
+
+ delay = 6000000 / priv->rate;
+ priv->component = &codec->component;
+ schedule_delayed_work(&priv->dummy_write_work,
+ usecs_to_jiffies(delay));
+
+ return 0;
+}
+
static const struct snd_soc_dai_ops ak4613_dai_ops = {
.startup = ak4613_dai_startup,
.shutdown = ak4613_dai_shutdown,
.set_sysclk = ak4613_dai_set_sysclk,
.set_fmt = ak4613_dai_set_fmt,
+ .trigger = ak4613_dai_trigger,
.hw_params = ak4613_dai_hw_params,
};
@@ -591,6 +649,7 @@ static int ak4613_i2c_probe(struct i2c_client *i2c,
priv->iface = NULL;
priv->cnt = 0;
priv->sysclk = 0;
+ INIT_DELAYED_WORK(&priv->dummy_write_work, ak4613_dummy_write);
mutex_init(&priv->lock);
--
1.9.1
More information about the Alsa-devel
mailing list