summarylogtreecommitdiffstats
path: root/0001-ALSA-cs35l41-Use-mbox-command-to-enable-speaker-outp.patch
diff options
context:
space:
mode:
Diffstat (limited to '0001-ALSA-cs35l41-Use-mbox-command-to-enable-speaker-outp.patch')
-rw-r--r--0001-ALSA-cs35l41-Use-mbox-command-to-enable-speaker-outp.patch238
1 files changed, 238 insertions, 0 deletions
diff --git a/0001-ALSA-cs35l41-Use-mbox-command-to-enable-speaker-outp.patch b/0001-ALSA-cs35l41-Use-mbox-command-to-enable-speaker-outp.patch
new file mode 100644
index 000000000000..57823933eba4
--- /dev/null
+++ b/0001-ALSA-cs35l41-Use-mbox-command-to-enable-speaker-outp.patch
@@ -0,0 +1,238 @@
+From c21139c6470a5b08c7463e451f2ff404e55f652f Mon Sep 17 00:00:00 2001
+From: Stefan Binding <sbinding@opensource.cirrus.com>
+Date: Fri, 21 Jul 2023 16:18:06 +0100
+Subject: [PATCH 01/11] ALSA: cs35l41: Use mbox command to enable speaker
+ output for external boost
+
+To enable the speaker output in external boost mode, 2 registers must
+be set, one after another. The longer the time between the writes of
+the two registers, the more likely, and more loudly a pop may occur.
+To minimize this, an mbox command can be used to allow the firmware
+to perform this action, minimizing any delay between write, thus
+minimizing any pop or click as a result. The old method will remain
+when running without firmware.
+
+Acked-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Stefan Binding <sbinding@opensource.cirrus.com>
+---
+ include/sound/cs35l41.h | 5 ++-
+ sound/pci/hda/cs35l41_hda.c | 9 ++--
+ sound/soc/codecs/cs35l41-lib.c | 76 +++++++++++++++++++++++++++-------
+ sound/soc/codecs/cs35l41.c | 8 ++--
+ 4 files changed, 74 insertions(+), 24 deletions(-)
+
+diff --git a/include/sound/cs35l41.h b/include/sound/cs35l41.h
+index 7239d943942c..1bf757901d02 100644
+--- a/include/sound/cs35l41.h
++++ b/include/sound/cs35l41.h
+@@ -829,6 +829,7 @@ enum cs35l41_cspl_mbox_cmd {
+ CSPL_MBOX_CMD_STOP_PRE_REINIT = 4,
+ CSPL_MBOX_CMD_HIBERNATE = 5,
+ CSPL_MBOX_CMD_OUT_OF_HIBERNATE = 6,
++ CSPL_MBOX_CMD_SPK_OUT_ENABLE = 7,
+ CSPL_MBOX_CMD_UNKNOWN_CMD = -1,
+ CSPL_MBOX_CMD_INVALID_SEQUENCE = -2,
+ };
+@@ -901,7 +902,7 @@ int cs35l41_exit_hibernate(struct device *dev, struct regmap *regmap);
+ int cs35l41_init_boost(struct device *dev, struct regmap *regmap,
+ struct cs35l41_hw_cfg *hw_cfg);
+ bool cs35l41_safe_reset(struct regmap *regmap, enum cs35l41_boost_type b_type);
+-int cs35l41_global_enable(struct regmap *regmap, enum cs35l41_boost_type b_type, int enable,
+- struct completion *pll_lock);
++int cs35l41_global_enable(struct device *dev, struct regmap *regmap, enum cs35l41_boost_type b_type,
++ int enable, struct completion *pll_lock, bool firmware_running);
+
+ #endif /* __CS35L41_H */
+diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c
+index ce5faa620517..f9c97270db6f 100644
+--- a/sound/pci/hda/cs35l41_hda.c
++++ b/sound/pci/hda/cs35l41_hda.c
+@@ -514,13 +514,15 @@ static void cs35l41_hda_playback_hook(struct device *dev, int action)
+ break;
+ case HDA_GEN_PCM_ACT_PREPARE:
+ mutex_lock(&cs35l41->fw_mutex);
+- ret = cs35l41_global_enable(reg, cs35l41->hw_cfg.bst_type, 1, NULL);
++ ret = cs35l41_global_enable(dev, reg, cs35l41->hw_cfg.bst_type, 1, NULL,
++ cs35l41->firmware_running);
+ mutex_unlock(&cs35l41->fw_mutex);
+ break;
+ case HDA_GEN_PCM_ACT_CLEANUP:
+ mutex_lock(&cs35l41->fw_mutex);
+ regmap_multi_reg_write(reg, cs35l41_hda_mute, ARRAY_SIZE(cs35l41_hda_mute));
+- ret = cs35l41_global_enable(reg, cs35l41->hw_cfg.bst_type, 0, NULL);
++ ret = cs35l41_global_enable(dev, reg, cs35l41->hw_cfg.bst_type, 0, NULL,
++ cs35l41->firmware_running);
+ mutex_unlock(&cs35l41->fw_mutex);
+ break;
+ case HDA_GEN_PCM_ACT_CLOSE:
+@@ -672,7 +674,8 @@ static int cs35l41_runtime_suspend(struct device *dev)
+ if (cs35l41->playback_started) {
+ regmap_multi_reg_write(cs35l41->regmap, cs35l41_hda_mute,
+ ARRAY_SIZE(cs35l41_hda_mute));
+- cs35l41_global_enable(cs35l41->regmap, cs35l41->hw_cfg.bst_type, 0, NULL);
++ cs35l41_global_enable(cs35l41->dev, cs35l41->regmap, cs35l41->hw_cfg.bst_type, 0,
++ NULL, cs35l41->firmware_running);
+ regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL2,
+ CS35L41_AMP_EN_MASK, 0 << CS35L41_AMP_EN_SHIFT);
+ if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST)
+diff --git a/sound/soc/codecs/cs35l41-lib.c b/sound/soc/codecs/cs35l41-lib.c
+index 1e4205295a0d..a7556fa33cdd 100644
+--- a/sound/soc/codecs/cs35l41-lib.c
++++ b/sound/soc/codecs/cs35l41-lib.c
+@@ -1080,28 +1080,32 @@ static const struct reg_sequence cs35l41_safe_to_reset[] = {
+ { 0x00000040, 0x00000033 },
+ };
+
+-static const struct reg_sequence cs35l41_active_to_safe[] = {
++static const struct reg_sequence cs35l41_active_to_safe_start[] = {
+ { 0x00000040, 0x00000055 },
+ { 0x00000040, 0x000000AA },
+ { 0x00007438, 0x00585941 },
+ { CS35L41_PWR_CTRL1, 0x00000000 },
+- { 0x0000742C, 0x00000009, 3000 },
++ { 0x0000742C, 0x00000009 },
++};
++
++static const struct reg_sequence cs35l41_active_to_safe_end[] = {
+ { 0x00007438, 0x00580941 },
+ { 0x00000040, 0x000000CC },
+ { 0x00000040, 0x00000033 },
+ };
+
+-static const struct reg_sequence cs35l41_safe_to_active[] = {
++static const struct reg_sequence cs35l41_safe_to_active_start[] = {
+ { 0x00000040, 0x00000055 },
+ { 0x00000040, 0x000000AA },
+ { 0x0000742C, 0x0000000F },
+ { 0x0000742C, 0x00000079 },
+ { 0x00007438, 0x00585941 },
+- { CS35L41_PWR_CTRL1, 0x00000001, 3000 }, // GLOBAL_EN = 1
++ { CS35L41_PWR_CTRL1, 0x00000001 }, // GLOBAL_EN = 1
++};
++
++static const struct reg_sequence cs35l41_safe_to_active_en_spk[] = {
+ { 0x0000742C, 0x000000F9 },
+ { 0x00007438, 0x00580941 },
+- { 0x00000040, 0x000000CC },
+- { 0x00000040, 0x00000033 },
+ };
+
+ static const struct reg_sequence cs35l41_reset_to_safe[] = {
+@@ -1188,11 +1192,11 @@ bool cs35l41_safe_reset(struct regmap *regmap, enum cs35l41_boost_type b_type)
+ }
+ EXPORT_SYMBOL_GPL(cs35l41_safe_reset);
+
+-int cs35l41_global_enable(struct regmap *regmap, enum cs35l41_boost_type b_type, int enable,
+- struct completion *pll_lock)
++int cs35l41_global_enable(struct device *dev, struct regmap *regmap, enum cs35l41_boost_type b_type,
++ int enable, struct completion *pll_lock, bool firmware_running)
+ {
+ int ret;
+- unsigned int gpio1_func, pad_control, pwr_ctrl1, pwr_ctrl3;
++ unsigned int gpio1_func, pad_control, pwr_ctrl1, pwr_ctrl3, int_status;
+ struct reg_sequence cs35l41_mdsync_down_seq[] = {
+ {CS35L41_PWR_CTRL3, 0},
+ {CS35L41_GPIO_PAD_CONTROL, 0},
+@@ -1204,6 +1208,14 @@ int cs35l41_global_enable(struct regmap *regmap, enum cs35l41_boost_type b_type,
+ {CS35L41_PWR_CTRL1, 0x00000001, 3000},
+ };
+
++ if ((pwr_ctl1_val & CS35L41_GLOBAL_EN_MASK) && enable) {
++ dev_dbg(dev, "Cannot set Global Enable - already set.\n");
++ return 0;
++ } else if (!(pwr_ctl1_val & CS35L41_GLOBAL_EN_MASK) && !enable) {
++ dev_dbg(dev, "Cannot unset Global Enable - not set.\n");
++ return 0;
++ }
++
+ switch (b_type) {
+ case CS35L41_SHD_BOOST_ACTV:
+ case CS35L41_SHD_BOOST_PASS:
+@@ -1244,16 +1256,48 @@ int cs35l41_global_enable(struct regmap *regmap, enum cs35l41_boost_type b_type,
+ case CS35L41_INT_BOOST:
+ ret = regmap_update_bits(regmap, CS35L41_PWR_CTRL1, CS35L41_GLOBAL_EN_MASK,
+ enable << CS35L41_GLOBAL_EN_SHIFT);
++ if (ret) {
++ dev_err(dev, "CS35L41_PWR_CTRL1 set failed: %d\n", ret);
++ return ret;
++ }
+ usleep_range(3000, 3100);
+ break;
+ case CS35L41_EXT_BOOST:
+ case CS35L41_EXT_BOOST_NO_VSPK_SWITCH:
+- if (enable)
+- ret = regmap_multi_reg_write(regmap, cs35l41_safe_to_active,
+- ARRAY_SIZE(cs35l41_safe_to_active));
+- else
+- ret = regmap_multi_reg_write(regmap, cs35l41_active_to_safe,
+- ARRAY_SIZE(cs35l41_active_to_safe));
++ if (enable) {
++ /* Test Key is unlocked here */
++ ret = regmap_multi_reg_write(regmap, cs35l41_safe_to_active_start,
++ ARRAY_SIZE(cs35l41_safe_to_active_start));
++ if (ret)
++ return ret;
++
++ usleep_range(3000, 3100);
++
++ if (firmware_running)
++ ret = cs35l41_set_cspl_mbox_cmd(dev, regmap,
++ CSPL_MBOX_CMD_SPK_OUT_ENABLE);
++ else
++ ret = regmap_multi_reg_write(regmap, cs35l41_safe_to_active_en_spk,
++ ARRAY_SIZE(cs35l41_safe_to_active_en_spk));
++
++ /* Lock the test key, it was unlocked during the multi_reg_write */
++ cs35l41_test_key_lock(dev, regmap);
++ } else {
++ /* Test Key is unlocked here */
++ ret = regmap_multi_reg_write(regmap, cs35l41_active_to_safe_start,
++ ARRAY_SIZE(cs35l41_active_to_safe_start));
++ if (ret) {
++ /* Lock the test key, it was unlocked during the multi_reg_write */
++ cs35l41_test_key_lock(dev, regmap);
++ return ret;
++ }
++
++ usleep_range(3000, 3100);
++
++ /* Test Key is locked here */
++ ret = regmap_multi_reg_write(regmap, cs35l41_active_to_safe_end,
++ ARRAY_SIZE(cs35l41_active_to_safe_end));
++ }
+ break;
+ default:
+ ret = -EINVAL;
+@@ -1344,6 +1388,8 @@ static bool cs35l41_check_cspl_mbox_sts(enum cs35l41_cspl_mbox_cmd cmd,
+ return (sts == CSPL_MBOX_STS_RUNNING);
+ case CSPL_MBOX_CMD_STOP_PRE_REINIT:
+ return (sts == CSPL_MBOX_STS_RDY_FOR_REINIT);
++ case CSPL_MBOX_CMD_SPK_OUT_ENABLE:
++ return (sts == CSPL_MBOX_STS_RUNNING);
+ default:
+ return false;
+ }
+diff --git a/sound/soc/codecs/cs35l41.c b/sound/soc/codecs/cs35l41.c
+index 6ac501f008ec..d4e9c9d9b50a 100644
+--- a/sound/soc/codecs/cs35l41.c
++++ b/sound/soc/codecs/cs35l41.c
+@@ -500,12 +500,12 @@ static int cs35l41_main_amp_event(struct snd_soc_dapm_widget *w,
+ cs35l41_pup_patch,
+ ARRAY_SIZE(cs35l41_pup_patch));
+
+- cs35l41_global_enable(cs35l41->regmap, cs35l41->hw_cfg.bst_type, 1,
+- &cs35l41->pll_lock);
++ ret = cs35l41_global_enable(cs35l41->dev, cs35l41->regmap, cs35l41->hw_cfg.bst_type,
++ 1, &cs35l41->pll_lock, cs35l41->dsp.cs_dsp.running);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+- cs35l41_global_enable(cs35l41->regmap, cs35l41->hw_cfg.bst_type, 0,
+- &cs35l41->pll_lock);
++ ret = cs35l41_global_enable(cs35l41->dev, cs35l41->regmap, cs35l41->hw_cfg.bst_type,
++ 0, &cs35l41->pll_lock, cs35l41->dsp.cs_dsp.running);
+
+ ret = regmap_read_poll_timeout(cs35l41->regmap, CS35L41_IRQ1_STATUS1,
+ val, val & CS35L41_PDN_DONE_MASK,
+--
+2.41.0
+