On 09.02.2023 10:37, Lucas Tanure wrote: > EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe > > Shared boost allows two amplifiers to share a single boost circuit by > communicating on the MDSYNC bus. > The passive amplifier does not control the boost and receives data from > the active amplifier. > > Shared Boost is not supported in HDA Systems. > Based on David Rhodes shared boost patches. > > Signed-off-by: Lucas Tanure <lucas.tanure@xxxxxxxxxxxxx> > --- > include/sound/cs35l41.h | 13 +++++- > sound/pci/hda/cs35l41_hda.c | 6 +-- > sound/soc/codecs/cs35l41-lib.c | 73 +++++++++++++++++++++++++++++++++- > sound/soc/codecs/cs35l41.c | 27 ++++++++++++- > sound/soc/codecs/cs35l41.h | 1 + > 5 files changed, 113 insertions(+), 7 deletions(-) > > diff --git a/include/sound/cs35l41.h b/include/sound/cs35l41.h > index 9ac5918269a5..7239d943942c 100644 > --- a/include/sound/cs35l41.h > +++ b/include/sound/cs35l41.h > @@ -11,6 +11,7 @@ > #define __CS35L41_H > > #include <linux/regmap.h> > +#include <linux/completion.h> > #include <linux/firmware/cirrus/cs_dsp.h> > > #define CS35L41_FIRSTREG 0x00000000 > @@ -677,6 +678,7 @@ > > #define CS35L36_PUP_DONE_IRQ_UNMASK 0x5F > #define CS35L36_PUP_DONE_IRQ_MASK 0xBF > +#define CS35L41_SYNC_EN_MASK BIT(8) > > #define CS35L41_AMP_SHORT_ERR 0x80000000 > #define CS35L41_BST_SHORT_ERR 0x0100 > @@ -686,6 +688,7 @@ > #define CS35L41_BST_DCM_UVP_ERR 0x80 > #define CS35L41_OTP_BOOT_DONE 0x02 > #define CS35L41_PLL_UNLOCK 0x10 > +#define CS35L41_PLL_LOCK BIT(1) > #define CS35L41_OTP_BOOT_ERR 0x80000000 > > #define CS35L41_AMP_SHORT_ERR_RLS 0x02 > @@ -705,6 +708,8 @@ > #define CS35L41_INT1_MASK_DEFAULT 0x7FFCFE3F > #define CS35L41_INT1_UNMASK_PUP 0xFEFFFFFF > #define CS35L41_INT1_UNMASK_PDN 0xFF7FFFFF > +#define CS35L41_INT3_PLL_LOCK_SHIFT 1 > +#define CS35L41_INT3_PLL_LOCK_MASK BIT(CS35L41_INT3_PLL_LOCK_SHIFT) > > #define CS35L41_GPIO_DIR_MASK 0x80000000 > #define CS35L41_GPIO_DIR_SHIFT 31 > @@ -742,6 +747,11 @@ > enum cs35l41_boost_type { > CS35L41_INT_BOOST, > CS35L41_EXT_BOOST, > + CS35L41_SHD_BOOST_ACTV, > + CS35L41_SHD_BOOST_PASS, > + > + // Not present in Binding Documentation, so no system should use this value. > + // This value is only used in CLSA0100 Laptop > CS35L41_EXT_BOOST_NO_VSPK_SWITCH, > }; > > @@ -891,6 +901,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); > +int cs35l41_global_enable(struct regmap *regmap, enum cs35l41_boost_type b_type, int enable, > + struct completion *pll_lock); > > #endif /* __CS35L41_H */ > diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c > index f7815ee24f83..38c0079ef303 100644 > --- a/sound/pci/hda/cs35l41_hda.c > +++ b/sound/pci/hda/cs35l41_hda.c > @@ -515,13 +515,13 @@ 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); > + ret = cs35l41_global_enable(reg, cs35l41->hw_cfg.bst_type, 1, NULL); > 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); > + ret = cs35l41_global_enable(reg, cs35l41->hw_cfg.bst_type, 0, NULL); > mutex_unlock(&cs35l41->fw_mutex); > break; > case HDA_GEN_PCM_ACT_CLOSE: > @@ -673,7 +673,7 @@ 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); > + cs35l41_global_enable(cs35l41->regmap, cs35l41->hw_cfg.bst_type, 0, NULL); > 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 04be71435491..4d6417ce70bb 100644 > --- a/sound/soc/codecs/cs35l41-lib.c > +++ b/sound/soc/codecs/cs35l41-lib.c > @@ -1114,12 +1114,31 @@ static const struct reg_sequence cs35l41_reset_to_safe[] = { > { 0x00000040, 0x00000033 }, > }; > > +static const struct reg_sequence cs35l41_actv_seq[] = { > + /* SYNC_BST_CTL_RX_EN = 0; SYNC_BST_CTL_TX_EN = 1 */ > + {CS35L41_MDSYNC_EN, 0x00001000}, You have spaces here. Probably you want tabs. Same for next entry in this array and the next array. > + /* BST_CTL_SEL = CLASSH */ > + {CS35L41_BSTCVRT_VCTRL2, 0x00000001}, > +}; > + > +static const struct reg_sequence cs35l41_pass_seq[] = { > + /* SYNC_BST_CTL_RX_EN = 1; SYNC_BST_CTL_TX_EN = 0 */ > + {CS35L41_MDSYNC_EN, 0x00002000}, > + /* BST_EN = 0 */ > + {CS35L41_PWR_CTRL2, 0x00003300}, > + /* BST_CTL_SEL = MDSYNC */ > + {CS35L41_BSTCVRT_VCTRL2, 0x00000002}, > +}; > + > int cs35l41_init_boost(struct device *dev, struct regmap *regmap, > struct cs35l41_hw_cfg *hw_cfg) > { > int ret; > > switch (hw_cfg->bst_type) { > + case CS35L41_SHD_BOOST_ACTV: > + regmap_multi_reg_write(regmap, cs35l41_actv_seq, ARRAY_SIZE(cs35l41_actv_seq)); > + fallthrough; > case CS35L41_INT_BOOST: > ret = cs35l41_boost_config(dev, regmap, hw_cfg->bst_ind, > hw_cfg->bst_cap, hw_cfg->bst_ipk); > @@ -1138,6 +1157,10 @@ int cs35l41_init_boost(struct device *dev, struct regmap *regmap, > ret = regmap_update_bits(regmap, CS35L41_PWR_CTRL2, CS35L41_BST_EN_MASK, > CS35L41_BST_DIS_FET_OFF << CS35L41_BST_EN_SHIFT); > break; > + case CS35L41_SHD_BOOST_PASS: > + ret = regmap_multi_reg_write(regmap, cs35l41_pass_seq, > + ARRAY_SIZE(cs35l41_pass_seq)); > + break; > default: > dev_err(dev, "Boost type %d not supported\n", hw_cfg->bst_type); > ret = -EINVAL; > @@ -1165,11 +1188,59 @@ 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) > +int cs35l41_global_enable(struct regmap *regmap, enum cs35l41_boost_type b_type, int enable, > + struct completion *pll_lock) > { > int ret; > + unsigned int gpio1_func, pad_control, pwr_ctrl1, pwr_ctrl3; > + struct reg_sequence cs35l41_mdsync_down_seq[] = { > + {CS35L41_PWR_CTRL3, 0}, > + {CS35L41_GPIO_PAD_CONTROL, 0}, > + {CS35L41_PWR_CTRL1, 0, 3000}, > + }; > + struct reg_sequence cs35l41_mdsync_up_seq[] = { > + {CS35L41_PWR_CTRL3, 0}, > + {CS35L41_PWR_CTRL1, 0x00000000, 3000}, > + {CS35L41_PWR_CTRL1, 0x00000001, 3000}, > + }; > > switch (b_type) { > + case CS35L41_SHD_BOOST_ACTV: > + case CS35L41_SHD_BOOST_PASS: > + regmap_read(regmap, CS35L41_PWR_CTRL3, &pwr_ctrl3); > + regmap_read(regmap, CS35L41_GPIO_PAD_CONTROL, &pad_control); > + > + pwr_ctrl3 &= ~CS35L41_SYNC_EN_MASK; > + pwr_ctrl1 = enable << CS35L41_GLOBAL_EN_SHIFT; > + > + gpio1_func = enable ? CS35L41_GPIO1_MDSYNC : CS35L41_GPIO1_HIZ; > + gpio1_func <<= CS35L41_GPIO1_CTRL_SHIFT; > + > + pad_control &= ~CS35L41_GPIO1_CTRL_MASK; > + pad_control |= gpio1_func & CS35L41_GPIO1_CTRL_MASK; > + > + cs35l41_mdsync_down_seq[0].def = pwr_ctrl3; > + cs35l41_mdsync_down_seq[1].def = pad_control; > + cs35l41_mdsync_down_seq[2].def = pwr_ctrl1; > + ret = regmap_multi_reg_write(regmap, cs35l41_mdsync_down_seq, > + ARRAY_SIZE(cs35l41_mdsync_down_seq)); > + if (!enable) > + break; > + > + if (!pll_lock) > + return -EINVAL; > + > + ret = wait_for_completion_timeout(pll_lock, msecs_to_jiffies(1000)); > + if (ret == 0) { > + ret = -ETIMEDOUT; > + } else { > + regmap_read(regmap, CS35L41_PWR_CTRL3, &pwr_ctrl3); > + pwr_ctrl3 |= CS35L41_SYNC_EN_MASK; > + cs35l41_mdsync_up_seq[0].def = pwr_ctrl3; > + ret = regmap_multi_reg_write(regmap, cs35l41_mdsync_up_seq, > + ARRAY_SIZE(cs35l41_mdsync_up_seq)); > + } > + break; > case CS35L41_INT_BOOST: > ret = regmap_update_bits(regmap, CS35L41_PWR_CTRL1, CS35L41_GLOBAL_EN_MASK, > enable << CS35L41_GLOBAL_EN_SHIFT); > diff --git a/sound/soc/codecs/cs35l41.c b/sound/soc/codecs/cs35l41.c > index c006364e5335..1624510d09c0 100644 > --- a/sound/soc/codecs/cs35l41.c > +++ b/sound/soc/codecs/cs35l41.c > @@ -360,6 +360,7 @@ static void cs35l41_boost_enable(struct cs35l41_private *cs35l41, unsigned int e > { > switch (cs35l41->hw_cfg.bst_type) { > case CS35L41_INT_BOOST: > + case CS35L41_SHD_BOOST_ACTV: > enable = enable ? CS35L41_BST_EN_DEFAULT : CS35L41_BST_DIS_FET_OFF; > regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL2, CS35L41_BST_EN_MASK, > enable << CS35L41_BST_EN_SHIFT); > @@ -455,6 +456,12 @@ static irqreturn_t cs35l41_irq(int irq, void *data) > ret = IRQ_HANDLED; > } > > + if (status[2] & CS35L41_PLL_LOCK) { > + regmap_write(cs35l41->regmap, CS35L41_IRQ1_STATUS3, CS35L41_PLL_LOCK); > + complete(&cs35l41->pll_lock); > + ret = IRQ_HANDLED; > + } > + > done: > pm_runtime_mark_last_busy(cs35l41->dev); > pm_runtime_put_autosuspend(cs35l41->dev); > @@ -492,10 +499,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_global_enable(cs35l41->regmap, cs35l41->hw_cfg.bst_type, 1, > + &cs35l41->pll_lock); > break; > case SND_SOC_DAPM_POST_PMD: > - cs35l41_global_enable(cs35l41->regmap, cs35l41->hw_cfg.bst_type, 0); > + cs35l41_global_enable(cs35l41->regmap, cs35l41->hw_cfg.bst_type, 0, > + &cs35l41->pll_lock); > > ret = regmap_read_poll_timeout(cs35l41->regmap, CS35L41_IRQ1_STATUS1, > val, val & CS35L41_PDN_DONE_MASK, > @@ -802,6 +811,10 @@ static const struct snd_pcm_hw_constraint_list cs35l41_constraints = { > static int cs35l41_pcm_startup(struct snd_pcm_substream *substream, > struct snd_soc_dai *dai) > { > + struct cs35l41_private *cs35l41 = snd_soc_component_get_drvdata(dai->component); > + > + reinit_completion(&cs35l41->pll_lock); > + > if (substream->runtime) > return snd_pcm_hw_constraint_list(substream->runtime, 0, > SNDRV_PCM_HW_PARAM_RATE, > @@ -1252,6 +1265,10 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg * > /* Set interrupt masks for critical errors */ > regmap_write(cs35l41->regmap, CS35L41_IRQ1_MASK1, > CS35L41_INT1_MASK_DEFAULT); > + if (cs35l41->hw_cfg.bst_type == CS35L41_SHD_BOOST_PASS || > + cs35l41->hw_cfg.bst_type == CS35L41_SHD_BOOST_ACTV) > + regmap_update_bits(cs35l41->regmap, CS35L41_IRQ1_MASK3, CS35L41_INT3_PLL_LOCK_MASK, > + 0 << CS35L41_INT3_PLL_LOCK_SHIFT); > > ret = devm_request_threaded_irq(cs35l41->dev, cs35l41->irq, NULL, cs35l41_irq, > IRQF_ONESHOT | IRQF_SHARED | irq_pol, > @@ -1275,6 +1292,8 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg * > if (ret < 0) > goto err; > > + init_completion(&cs35l41->pll_lock); > + > pm_runtime_set_autosuspend_delay(cs35l41->dev, 3000); > pm_runtime_use_autosuspend(cs35l41->dev); > pm_runtime_mark_last_busy(cs35l41->dev); > @@ -1317,6 +1336,10 @@ void cs35l41_remove(struct cs35l41_private *cs35l41) > pm_runtime_disable(cs35l41->dev); > > regmap_write(cs35l41->regmap, CS35L41_IRQ1_MASK1, 0xFFFFFFFF); > + if (cs35l41->hw_cfg.bst_type == CS35L41_SHD_BOOST_PASS || > + cs35l41->hw_cfg.bst_type == CS35L41_SHD_BOOST_ACTV) > + regmap_update_bits(cs35l41->regmap, CS35L41_IRQ1_MASK3, CS35L41_INT3_PLL_LOCK_MASK, > + 1 << CS35L41_INT3_PLL_LOCK_SHIFT); > kfree(cs35l41->dsp.system_name); > wm_adsp2_remove(&cs35l41->dsp); > cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type); > diff --git a/sound/soc/codecs/cs35l41.h b/sound/soc/codecs/cs35l41.h > index c85cbc1dd333..34d967d4372b 100644 > --- a/sound/soc/codecs/cs35l41.h > +++ b/sound/soc/codecs/cs35l41.h > @@ -33,6 +33,7 @@ struct cs35l41_private { > int irq; > /* GPIO for /RST */ > struct gpio_desc *reset_gpio; > + struct completion pll_lock; > }; > > int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg *hw_cfg); > -- > 2.39.1 >