ASoC: cs35l41: Support external boost
authorLucas Tanure <tanureal@opensource.cirrus.com>
Wed, 13 Apr 2022 08:37:28 +0000 (09:37 +0100)
committerTakashi Iwai <tiwai@suse.de>
Wed, 13 Apr 2022 08:42:34 +0000 (10:42 +0200)
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>
include/sound/cs35l41.h
sound/soc/codecs/cs35l41-lib.c
sound/soc/codecs/cs35l41.c

index ac629f8..dbe8d9c 100644 (file)
 #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);
index 2d3b577..491616c 100644 (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 },
index d25689f..912196f 100644 (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;
 }