ASoC: cs35l41: Support external boost

Add support for external boost voltage, where GPIO1 must control a
switch to isolate CS35L41 from the external Boost Voltage

Signed-off-by: Lucas Tanure <tanureal@opensource.cirrus.com>
Acked-by: Charles Keepax <ckeepax@opensource.cirrus.com>
Acked-by: Mark Brown <broonie@kernel.org>
Link: https://lore.kernel.org/r/20220413083728.10730-17-tanureal@opensource.cirrus.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Lucas Tanure 2022-04-13 09:37:28 +01:00 committed by Takashi Iwai
parent 4b047ec3a1
commit bb06c203f8
3 changed files with 41 additions and 17 deletions

View File

@ -701,6 +701,8 @@
#define CS35L41_GPIO1_CTRL_SHIFT 16
#define CS35L41_GPIO2_CTRL_MASK 0x07000000
#define CS35L41_GPIO2_CTRL_SHIFT 24
#define CS35L41_GPIO_LVL_SHIFT 15
#define CS35L41_GPIO_LVL_MASK BIT(CS35L41_GPIO_LVL_SHIFT)
#define CS35L41_GPIO_POL_MASK 0x1000
#define CS35L41_GPIO_POL_SHIFT 12
@ -802,8 +804,6 @@ int cs35l41_register_errata_patch(struct device *dev, struct regmap *reg, unsign
int cs35l41_set_channels(struct device *dev, struct regmap *reg,
unsigned int tx_num, unsigned int *tx_slot,
unsigned int rx_num, unsigned int *rx_slot);
int cs35l41_boost_config(struct device *dev, struct regmap *regmap, int boost_ind, int boost_cap,
int boost_ipk);
int cs35l41_gpio_config(struct regmap *regmap, struct cs35l41_hw_cfg *hw_cfg);
int cs35l41_init_boost(struct device *dev, struct regmap *regmap,
struct cs35l41_hw_cfg *hw_cfg);

View File

@ -954,8 +954,8 @@ static const unsigned char cs35l41_bst_slope_table[4] = {
0x75, 0x6B, 0x3B, 0x28
};
int cs35l41_boost_config(struct device *dev, struct regmap *regmap, int boost_ind,
int boost_cap, int boost_ipk)
static int cs35l41_boost_config(struct device *dev, struct regmap *regmap, int boost_ind,
int boost_cap, int boost_ipk)
{
unsigned char bst_lbst_val, bst_cbst_range, bst_ipk_scaled;
int ret;
@ -1040,7 +1040,6 @@ int cs35l41_boost_config(struct device *dev, struct regmap *regmap, int boost_in
return 0;
}
EXPORT_SYMBOL_GPL(cs35l41_boost_config);
static const struct reg_sequence cs35l41_safe_to_reset[] = {
{ 0x00000040, 0x00000055 },

View File

@ -578,15 +578,10 @@ static int cs35l41_main_amp_event(struct snd_soc_dapm_widget *w,
cs35l41_pup_patch,
ARRAY_SIZE(cs35l41_pup_patch));
regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL1,
CS35L41_GLOBAL_EN_MASK,
1 << CS35L41_GLOBAL_EN_SHIFT);
usleep_range(1000, 1100);
cs35l41_global_enable(cs35l41->regmap, cs35l41->hw_cfg.bst_type, 1);
break;
case SND_SOC_DAPM_POST_PMD:
regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL1,
CS35L41_GLOBAL_EN_MASK, 0);
cs35l41_global_enable(cs35l41->regmap, cs35l41->hw_cfg.bst_type, 0);
ret = regmap_read_poll_timeout(cs35l41->regmap, CS35L41_IRQ1_STATUS1,
val, val & CS35L41_PDN_DONE_MASK,
@ -1001,13 +996,13 @@ static int cs35l41_set_pdata(struct cs35l41_private *cs35l41)
if (!hw_cfg->valid)
return -EINVAL;
if (hw_cfg->bst_type == CS35L41_EXT_BOOST_NO_VSPK_SWITCH)
return -EINVAL;
/* Required */
ret = cs35l41_boost_config(cs35l41->dev, cs35l41->regmap,
hw_cfg->bst_ind, hw_cfg->bst_cap, hw_cfg->bst_ipk);
if (ret) {
dev_err(cs35l41->dev, "Error in Boost DT config: %d\n", ret);
ret = cs35l41_init_boost(cs35l41->dev, cs35l41->regmap, hw_cfg);
if (ret)
return ret;
}
/* Optional */
if (hw_cfg->dout_hiz <= CS35L41_ASP_DOUT_HIZ_MASK && hw_cfg->dout_hiz >= 0)
@ -1017,9 +1012,31 @@ static int cs35l41_set_pdata(struct cs35l41_private *cs35l41)
return 0;
}
static const struct snd_soc_dapm_route cs35l41_ext_bst_routes[] = {
{"Main AMP", NULL, "VSPK"},
};
static const struct snd_soc_dapm_widget cs35l41_ext_bst_widget[] = {
SND_SOC_DAPM_SUPPLY("VSPK", CS35L41_GPIO1_CTRL1, CS35L41_GPIO_LVL_SHIFT, 0, NULL, 0),
};
static int cs35l41_component_probe(struct snd_soc_component *component)
{
struct cs35l41_private *cs35l41 = snd_soc_component_get_drvdata(component);
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
int ret;
if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST) {
ret = snd_soc_dapm_new_controls(dapm, cs35l41_ext_bst_widget,
ARRAY_SIZE(cs35l41_ext_bst_widget));
if (ret)
return ret;
ret = snd_soc_dapm_add_routes(dapm, cs35l41_ext_bst_routes,
ARRAY_SIZE(cs35l41_ext_bst_routes));
if (ret)
return ret;
}
return wm_adsp2_component_probe(&cs35l41->dsp, component);
}
@ -1084,6 +1101,10 @@ static int cs35l41_handle_pdata(struct device *dev, struct cs35l41_hw_cfg *hw_cf
unsigned int val;
int ret;
ret = device_property_read_u32(dev, "cirrus,boost-type", &val);
if (ret >= 0)
hw_cfg->bst_type = val;
ret = device_property_read_u32(dev, "cirrus,boost-peak-milliamp", &val);
if (ret >= 0)
hw_cfg->bst_ipk = val;
@ -1376,6 +1397,7 @@ err_pm:
wm_adsp2_remove(&cs35l41->dsp);
err:
cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type);
regulator_bulk_disable(CS35L41_NUM_SUPPLIES, cs35l41->supplies);
gpiod_set_value_cansleep(cs35l41->reset_gpio, 0);
@ -1390,6 +1412,7 @@ void cs35l41_remove(struct cs35l41_private *cs35l41)
regmap_write(cs35l41->regmap, CS35L41_IRQ1_MASK1, 0xFFFFFFFF);
wm_adsp2_remove(&cs35l41->dsp);
cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type);
pm_runtime_put_noidle(cs35l41->dev);
@ -1409,6 +1432,7 @@ static int __maybe_unused cs35l41_runtime_suspend(struct device *dev)
dev_dbg(cs35l41->dev, "Enter hibernate\n");
cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type);
regmap_write(cs35l41->regmap, CS35L41_WAKESRC_CTL, 0x0088);
regmap_write(cs35l41->regmap, CS35L41_WAKESRC_CTL, 0x0188);
@ -1505,6 +1529,7 @@ static int __maybe_unused cs35l41_runtime_resume(struct device *dev)
dev_err(cs35l41->dev, "Failed to restore register cache: %d\n", ret);
return ret;
}
cs35l41_init_boost(cs35l41->dev, cs35l41->regmap, &cs35l41->hw_cfg);
return 0;
}