From 5ec000c5dca45df04b74fb4f7bf402a0b78e07dd Mon Sep 17 00:00:00 2001
From: Li Xu
Date: Fri, 15 Jun 2018 13:32:44 -0500
Subject: [PATCH] ASoC: cs35l41: Implement support for dynamic DMA
Implement support for dynamically allocating DMA buffer
in CSPL firmware for firmware.
SQA-1029
Mot-CRs-fixed: (CR): River: AoU bringup on Marley+Prince
Change-Id: I0ff90e85e96ff5029e276f00e82f0503913fb9f1
Signed-off-by: Li Xu
Reviewed-on: https://gerrit.mot.com/1238847
Tested-by: Jira Key
SLTApproved: Slta Waiver
SME-Granted: SME Approvals Granted
Reviewed-by: Konstantin Makariev
Submit-Approved: Jira Key
---
include/sound/cs35l41.h | 1 +
sound/soc/codecs/cs35l41.c | 239 ++++++++++++++++++++++++-------------
sound/soc/codecs/cs35l41.h | 8 +-
3 files changed, 166 insertions(+), 82 deletions(-)
diff --git a/include/sound/cs35l41.h b/include/sound/cs35l41.h
index e6871dc873ea..b138d4ce778e 100644
--- a/include/sound/cs35l41.h
+++ b/include/sound/cs35l41.h
@@ -61,6 +61,7 @@ struct cs35l41_private {
int extclk_freq;
int extclk_cfg;
int sclk;
+ unsigned int cspl_cmd;
bool tdm_mode;
bool i2s_mode;
bool swire_mode;
diff --git a/sound/soc/codecs/cs35l41.c b/sound/soc/codecs/cs35l41.c
index 8d9b0cc2b567..9bcc629d4dda 100644
--- a/sound/soc/codecs/cs35l41.c
+++ b/sound/soc/codecs/cs35l41.c
@@ -216,6 +216,143 @@ static SOC_ENUM_SINGLE_DECL(pcm_sft_ramp,
CS35L41_AMP_DIG_VOL_CTRL, 0,
cs35l41_pcm_sftramp_text);
+static const char * const cs35l41_cspl_cmd_text[] = {
+ "CSPL_MBOX_CMD_RESUME",
+ "CSPL_MBOX_CMD_REINIT",
+ "CSPL_MBOX_CMD_STOP_PRE_REINIT",
+};
+
+static const unsigned int cs35l41_cspl_cmd_val[] = {
+ (unsigned int)CSPL_MBOX_CMD_RESUME,
+ (unsigned int)CSPL_MBOX_CMD_REINIT,
+ (unsigned int)CSPL_MBOX_CMD_STOP_PRE_REINIT,
+};
+
+static SOC_VALUE_ENUM_SINGLE_DECL(cs35l41_cspl_cmd, SND_SOC_NOPM, 0, 0,
+ cs35l41_cspl_cmd_text, cs35l41_cspl_cmd_val);
+
+static bool cs35l41_is_csplmboxsts_correct(enum cs35l41_cspl_mboxcmd cmd,
+ enum cs35l41_cspl_mboxstate sts)
+{
+ switch (cmd) {
+ case CSPL_MBOX_CMD_NONE:
+ case CSPL_MBOX_CMD_UNKNOWN_CMD:
+ return true;
+ case CSPL_MBOX_CMD_PAUSE:
+ return (sts == CSPL_MBOX_STS_PAUSED);
+ case CSPL_MBOX_CMD_RESUME:
+ return (sts == CSPL_MBOX_STS_RUNNING);
+ case CSPL_MBOX_CMD_REINIT:
+ return (sts == CSPL_MBOX_STS_RUNNING);
+ case CSPL_MBOX_CMD_STOP_PRE_REINIT:
+ return (sts == CSPL_MBOX_STS_RDY_FOR_REINIT);
+ default:
+ return false;
+ }
+}
+
+static int cs35l41_set_csplmboxcmd(struct cs35l41_private *cs35l41,
+ enum cs35l41_cspl_mboxcmd cmd)
+{
+ int ret;
+ unsigned int sts;
+
+ /* Reset DSP sticky bit */
+ regmap_write(cs35l41->regmap, CS35L41_IRQ2_STATUS2,
+ 1 << CS35L41_CSPL_MBOX_CMD_DRV_SHIFT);
+
+ /* Reset AP sticky bit */
+ regmap_write(cs35l41->regmap, CS35L41_IRQ1_STATUS2,
+ 1 << CS35L41_CSPL_MBOX_CMD_FW_SHIFT);
+
+ /*
+ * Set mailbox cmd
+ */
+ reinit_completion(&cs35l41->mbox_cmd);
+ /* Unmask DSP INT */
+ regmap_update_bits(cs35l41->regmap, CS35L41_IRQ2_MASK2,
+ 1 << CS35L41_CSPL_MBOX_CMD_DRV_SHIFT, 0);
+ /* Unmask AP INT */
+ regmap_update_bits(cs35l41->regmap, CS35L41_IRQ1_MASK2,
+ 1 << CS35L41_CSPL_MBOX_CMD_FW_SHIFT, 0);
+ regmap_write(cs35l41->regmap, CS35L41_CSPL_MBOX_CMD_DRV, cmd);
+ ret = wait_for_completion_timeout(&cs35l41->mbox_cmd,
+ usecs_to_jiffies(CS35L41_MBOXWAIT));
+ if (ret == 0) {
+ dev_err(cs35l41->dev,
+ "Timout waiting for DSP to set mbox cmd\n");
+ ret = -ETIMEDOUT;
+ }
+
+ /* Mask AP INT */
+ regmap_update_bits(cs35l41->regmap, CS35L41_IRQ1_MASK2,
+ 1 << CS35L41_CSPL_MBOX_CMD_FW_SHIFT,
+ 1 << CS35L41_CSPL_MBOX_CMD_FW_SHIFT);
+ /* Mask DSP INT */
+ regmap_update_bits(cs35l41->regmap, CS35L41_IRQ2_MASK2,
+ 1 << CS35L41_CSPL_MBOX_CMD_DRV_SHIFT,
+ 1 << CS35L41_CSPL_MBOX_CMD_DRV_SHIFT);
+
+ if (regmap_read(cs35l41->regmap,
+ CS35L41_CSPL_MBOX_STS, &sts) < 0) {
+ dev_err(cs35l41->dev, "Failed to read %u\n",
+ CS35L41_CSPL_MBOX_STS);
+ ret = -EACCES;
+ }
+
+ if (!cs35l41_is_csplmboxsts_correct(cmd,
+ (enum cs35l41_cspl_mboxstate)sts)) {
+ dev_err(cs35l41->dev,
+ "Failed to set mailbox(cmd: %u, sts: %u)\n", cmd, sts);
+ ret = -ENOMSG;
+ }
+
+ return ret;
+}
+
+static int cs35l41_cspl_cmd_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct cs35l41_private *cs35l41 = snd_soc_codec_get_drvdata(codec);
+ struct soc_enum *soc_enum;
+ unsigned int i = ucontrol->value.enumerated.item[0];
+ int ret = 0;
+
+ soc_enum = (struct soc_enum *)kcontrol->private_value;
+ cs35l41->cspl_cmd = soc_enum->values[i];
+
+ return ret;
+}
+
+static int cs35l41_cspl_cmd_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct cs35l41_private *cs35l41 = snd_soc_codec_get_drvdata(codec);
+ struct soc_enum *soc_enum;
+ unsigned int i;
+ int ret = 0;
+
+ soc_enum = (struct soc_enum *)kcontrol->private_value;
+
+ for (i = 0; i < soc_enum->items; i++) {
+ if (cs35l41->cspl_cmd == soc_enum->values[i])
+ break;
+ }
+
+ if (i >= soc_enum->items) {
+ /* Cannot find value */
+ dev_err(cs35l41->dev, "Cannot find cspl cmd\n");
+ i = 0;
+ ret = -EINVAL;
+ }
+
+ ucontrol->value.enumerated.item[0] = i;
+
+ return ret;
+}
+
static const char * const cs35l41_pcm_source_texts[] = {"ASP", "DSP"};
static const unsigned int cs35l41_pcm_source_values[] = {0x08, 0x32};
static SOC_VALUE_ENUM_SINGLE_DECL(cs35l41_pcm_source_enum,
@@ -326,6 +463,8 @@ static const struct snd_kcontrol_new cs35l41_aud_controls[] = {
SOC_SINGLE_RANGE("ASPTX4 Slot Position", CS35L41_SP_FRAME_TX_SLOT, 24,
0, 7, 0),
SOC_ENUM("PCM Soft Ramp", pcm_sft_ramp),
+ SOC_VALUE_ENUM_EXT("CSPL Command", cs35l41_cspl_cmd,
+ cs35l41_cspl_cmd_get, cs35l41_cspl_cmd_put),
SOC_SINGLE_EXT("DSP Booted", SND_SOC_NOPM, 0, 1, 0,
cs35l41_halo_booted_get, cs35l41_halo_booted_put),
WM_ADSP2_PRELOAD_SWITCH("DSP1", 1),
@@ -618,80 +757,6 @@ static const struct reg_sequence cs35l41_pdn_patch[] = {
{0x00000040, 0x00000033},
};
-static bool cs35l41_is_csplmboxsts_correct(enum cspl_mboxcmd cmd,
- enum cspl_mboxstate sts)
-{
- switch (cmd) {
- case CSPL_MBOX_CMD_NONE:
- case CSPL_MBOX_CMD_UNKNOWN_CMD:
- return true;
- case CSPL_MBOX_CMD_PAUSE:
- return (sts == CSPL_MBOX_STS_PAUSED);
- case CSPL_MBOX_CMD_RESUME:
- return (sts == CSPL_MBOX_STS_RUNNING);
- default:
- return false;
- }
-}
-
-static int cs35l41_set_csplmboxcmd(struct cs35l41_private *cs35l41,
- enum cspl_mboxcmd cmd)
-{
- int ret;
- unsigned int sts;
-
- /* Reset DSP sticky bit */
- regmap_write(cs35l41->regmap, CS35L41_IRQ2_STATUS2,
- 1 << CS35L41_CSPL_MBOX_CMD_DRV_SHIFT);
-
- /* Reset AP sticky bit */
- regmap_write(cs35l41->regmap, CS35L41_IRQ1_STATUS2,
- 1 << CS35L41_CSPL_MBOX_CMD_FW_SHIFT);
-
- /*
- * Set mailbox cmd
- */
- reinit_completion(&cs35l41->mbox_cmd);
- /* Unmask DSP INT */
- regmap_update_bits(cs35l41->regmap, CS35L41_IRQ2_MASK2,
- 1 << CS35L41_CSPL_MBOX_CMD_DRV_SHIFT, 0);
- /* Unmask AP INT */
- regmap_update_bits(cs35l41->regmap, CS35L41_IRQ1_MASK2,
- 1 << CS35L41_CSPL_MBOX_CMD_FW_SHIFT, 0);
- regmap_write(cs35l41->regmap, CS35L41_CSPL_MBOX_CMD_DRV, cmd);
- ret = wait_for_completion_timeout(&cs35l41->mbox_cmd,
- usecs_to_jiffies(CS35L41_MBOXWAIT));
- if (ret == 0) {
- dev_err(cs35l41->dev,
- "Timout waiting for DSP to set mbox cmd\n");
- ret = -ETIMEDOUT;
- }
-
- /* Mask AP INT */
- regmap_update_bits(cs35l41->regmap, CS35L41_IRQ1_MASK2,
- 1 << CS35L41_CSPL_MBOX_CMD_FW_SHIFT,
- 1 << CS35L41_CSPL_MBOX_CMD_FW_SHIFT);
- /* Mask DSP INT */
- regmap_update_bits(cs35l41->regmap, CS35L41_IRQ2_MASK2,
- 1 << CS35L41_CSPL_MBOX_CMD_DRV_SHIFT,
- 1 << CS35L41_CSPL_MBOX_CMD_DRV_SHIFT);
-
- if (regmap_read(cs35l41->regmap,
- CS35L41_CSPL_MBOX_STS, &sts) < 0) {
- dev_err(cs35l41->dev, "Failed to read %u\n",
- CS35L41_CSPL_MBOX_STS);
- ret = -EACCES;
- }
-
- if (!cs35l41_is_csplmboxsts_correct(cmd, (enum cspl_mboxstate)sts)) {
- dev_err(cs35l41->dev,
- "Failed to set mailbox(cmd: %u, sts: %u)\n", cmd, sts);
- ret = -ENOMSG;
- }
-
- return ret;
-}
-
static int cs35l41_main_amp_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -711,14 +776,25 @@ static int cs35l41_main_amp_event(struct snd_soc_dapm_widget *w,
usleep_range(1000, 1100);
- if (cs35l41->halo_booted)
- ret = cs35l41_set_csplmboxcmd(cs35l41,
- CSPL_MBOX_CMD_RESUME);
+ if (cs35l41->halo_booted) {
+ if (cs35l41->cspl_cmd == CSPL_MBOX_CMD_STOP_PRE_REINIT)
+ /* Send this command on power down event */
+ ret = cs35l41_set_csplmboxcmd(cs35l41,
+ CSPL_MBOX_CMD_RESUME);
+ else
+ ret = cs35l41_set_csplmboxcmd(cs35l41,
+ cs35l41->cspl_cmd);
+ }
break;
case SND_SOC_DAPM_POST_PMD:
- if (cs35l41->halo_booted)
- ret = cs35l41_set_csplmboxcmd(cs35l41,
- CSPL_MBOX_CMD_PAUSE);
+ if (cs35l41->halo_booted) {
+ if (cs35l41->cspl_cmd == CSPL_MBOX_CMD_STOP_PRE_REINIT)
+ ret = cs35l41_set_csplmboxcmd(cs35l41,
+ cs35l41->cspl_cmd);
+ else
+ ret = cs35l41_set_csplmboxcmd(cs35l41,
+ CSPL_MBOX_CMD_PAUSE);
+ }
regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL1,
CS35L41_GLOBAL_EN_MASK, 0);
@@ -1669,6 +1745,9 @@ int cs35l41_probe(struct cs35l41_private *cs35l41,
int timeout = 100;
int irq_pol = 0;
+ /* Default to RESUME cmd */
+ cs35l41->cspl_cmd = (unsigned int)CSPL_MBOX_CMD_RESUME;
+
for (i = 0; i < ARRAY_SIZE(cs35l41_supplies); i++)
cs35l41->supplies[i].supply = cs35l41_supplies[i];
diff --git a/sound/soc/codecs/cs35l41.h b/sound/soc/codecs/cs35l41.h
index 72c173c5e19c..9cce2801ce2e 100644
--- a/sound/soc/codecs/cs35l41.h
+++ b/sound/soc/codecs/cs35l41.h
@@ -741,16 +741,20 @@ extern const struct cs35l41_otp_map_element_t
#define CS35L41_CSPL_MBOX_CMD_DRV CS35L41_DSP_VIRT1_MBOX_1
#define CS35L41_CSPL_MBOX_CMD_DRV_SHIFT CS35L41_DSP_VIRT1_MBOX_SHIFT
-enum cspl_mboxstate {
+enum cs35l41_cspl_mboxstate {
CSPL_MBOX_STS_RUNNING = 0,
CSPL_MBOX_STS_PAUSED = 1,
+ CSPL_MBOX_STS_RDY_FOR_REINIT = 2,
};
-enum cspl_mboxcmd {
+enum cs35l41_cspl_mboxcmd {
CSPL_MBOX_CMD_NONE = 0,
CSPL_MBOX_CMD_PAUSE = 1,
CSPL_MBOX_CMD_RESUME = 2,
+ CSPL_MBOX_CMD_REINIT = 3,
+ CSPL_MBOX_CMD_STOP_PRE_REINIT = 4,
CSPL_MBOX_CMD_UNKNOWN_CMD = -1,
+ CSPL_MBOX_CMD_INVALID_SEQUENCE = -2,
};
#endif /*__CS35L41_H__*/