diff options
Diffstat (limited to 'sound/soc')
-rw-r--r-- | sound/soc/codecs/cs35l41-lib.c | 73 | ||||
-rw-r--r-- | sound/soc/codecs/cs35l41.c | 27 | ||||
-rw-r--r-- | sound/soc/codecs/cs35l41.h | 1 |
3 files changed, 98 insertions, 3 deletions
diff --git a/sound/soc/codecs/cs35l41-lib.c b/sound/soc/codecs/cs35l41-lib.c index 04be71435491..8538e2871c5f 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 = 1; SYNC_BST_CTL_TX_EN = 1 */ + {CS35L41_MDSYNC_EN, 0x00003000}, + /* BST_CTL_SEL = MDSYNC */ + {CS35L41_BSTCVRT_VCTRL2, 0x00000002}, +}; + +static const struct reg_sequence cs35l41_pass_seq[] = { + /* SYNC_BST_CTL_RX_EN = 0; SYNC_BST_CTL_TX_EN = 1 */ + {CS35L41_MDSYNC_EN, 0x00001000}, + /* 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); |