diff options
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.patch | 238 |
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 + |