Move the support for CS35L41 external boost to its shared library
for ASoC use.
This move resulted in cs35l41_hda_reg_sequence being removed,
and its steps were broken down into regmap writes or functions
from the library. And hardware configuration struct was unified
for its use in the shared lib.
While at it, some minor bugs were found and fixed it.
v3 changelog:
- Remove patches already accepted
- Improved logic in documentation patch
- Documentation patch goes before its code
- Fixed missing Signed-off-by
- Fixed subject for HDA patches
v2 changelog:
- Instead of removing the log, playback actions will log the last regmap access.
- Documentation patch with the correct subject line and fixed bug reported by Rob Herring on the
provided example.
Previous versions:
v1: https://lkml.org/lkml/2022/3/3/759
v2: https://lkml.org/lkml/2022/3/4/743
David Rhodes (1):
ASoC: dt-bindings: cs35l41: Document CS35l41 External Boost
Lucas Tanure (15):
sound: cs35l41: Unify hardware configuration
sound: cs35l41: Check hw_config before using it
sound: cs35l41: Move cs35l41_gpio_config to shared lib
ALSA: hda: cs35l41: Fix I2S params comments
ALSA: hda: cs35l41: Always configure the DAI
ALSA: hda: cs35l41: Add Boost type flag
hda: cs35l41: Put the device into safe mode for external boost
hda: cs35l41: Mute the device before shutdown
sound: cs35l41: Enable Internal Boost in shared lib
ALSA: hda: cs35l41: Move boost config to initialization code
ALSA: hda: cs35l41: Remove cs35l41_hda_reg_sequence struct
ALSA: hda: cs35l41: Reorganize log for playback actions
ALSA: hda: cs35l41: Handle all external boost setups the same way
ALSA: hda: cs35l41: Move external boost handling to lib for ASoC use
ASoC: cs35l41: Support external boost
.../bindings/sound/cirrus,cs35l41.yaml | 44 ++-
include/sound/cs35l41.h | 53 +++-
sound/pci/hda/cs35l41_hda.c | 295 ++++++------------
sound/pci/hda/cs35l41_hda.h | 27 +-
sound/soc/codecs/cs35l41-i2c.c | 4 +-
sound/soc/codecs/cs35l41-lib.c | 190 ++++++++++-
sound/soc/codecs/cs35l41-spi.c | 4 +-
sound/soc/codecs/cs35l41.c | 166 +++++-----
sound/soc/codecs/cs35l41.h | 5 +-
9 files changed, 437 insertions(+), 351 deletions(-)
--
2.35.1
The dai configuration is always the same and should always configured
during the opening the stream.
Signed-off-by: Lucas Tanure <[email protected]>
---
sound/pci/hda/cs35l41_hda.c | 10 ++--------
1 file changed, 2 insertions(+), 8 deletions(-)
diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c
index fe6f6a208d29..4c99dcac2dd7 100644
--- a/sound/pci/hda/cs35l41_hda.c
+++ b/sound/pci/hda/cs35l41_hda.c
@@ -111,8 +111,6 @@ static const struct reg_sequence cs35l41_reset_to_safe[] = {
static const struct cs35l41_hda_reg_sequence cs35l41_hda_reg_seq_no_bst = {
.probe = cs35l41_reset_to_safe,
.num_probe = ARRAY_SIZE(cs35l41_reset_to_safe),
- .open = cs35l41_hda_config,
- .num_open = ARRAY_SIZE(cs35l41_hda_config),
.prepare = cs35l41_safe_to_active,
.num_prepare = ARRAY_SIZE(cs35l41_safe_to_active),
.cleanup = cs35l41_active_to_safe,
@@ -120,8 +118,6 @@ static const struct cs35l41_hda_reg_sequence cs35l41_hda_reg_seq_no_bst = {
};
static const struct cs35l41_hda_reg_sequence cs35l41_hda_reg_seq_ext_bst = {
- .open = cs35l41_hda_config,
- .num_open = ARRAY_SIZE(cs35l41_hda_config),
.prepare = cs35l41_start_ext_vspk,
.num_prepare = ARRAY_SIZE(cs35l41_start_ext_vspk),
.cleanup = cs35l41_stop_ext_vspk,
@@ -129,8 +125,6 @@ static const struct cs35l41_hda_reg_sequence cs35l41_hda_reg_seq_ext_bst = {
};
static const struct cs35l41_hda_reg_sequence cs35l41_hda_reg_seq_int_bst = {
- .open = cs35l41_hda_config,
- .num_open = ARRAY_SIZE(cs35l41_hda_config),
.prepare = cs35l41_hda_start_bst,
.num_prepare = ARRAY_SIZE(cs35l41_hda_start_bst),
.cleanup = cs35l41_hda_stop_bst,
@@ -146,8 +140,8 @@ static void cs35l41_hda_playback_hook(struct device *dev, int action)
switch (action) {
case HDA_GEN_PCM_ACT_OPEN:
- if (reg_seq->open)
- ret = regmap_multi_reg_write(reg, reg_seq->open, reg_seq->num_open);
+ ret = regmap_multi_reg_write(reg, cs35l41_hda_config,
+ ARRAY_SIZE(cs35l41_hda_config));
break;
case HDA_GEN_PCM_ACT_PREPARE:
if (reg_seq->prepare)
--
2.35.1
From: David Rhodes <[email protected]>
Document internal and external boost feature for ASoC CS35L41.
For internal boost the following properties are required:
- cirrus,boost-peak-milliamp
- cirrus,boost-ind-nanohenry
- cirrus,boost-cap-microfarad
For external boost, the GPIO1 must be configured as output,
so the following properties are required:
- cirrus,gpio1-src-select = <1>
- cirrus,gpio1-output-enable
Signed-off-by: David Rhodes <[email protected]>
Signed-off-by: Lucas Tanure <[email protected]>
---
.../bindings/sound/cirrus,cs35l41.yaml | 44 +++++++++++++++++--
1 file changed, 41 insertions(+), 3 deletions(-)
diff --git a/Documentation/devicetree/bindings/sound/cirrus,cs35l41.yaml b/Documentation/devicetree/bindings/sound/cirrus,cs35l41.yaml
index 3235702ce402..09b515924c59 100644
--- a/Documentation/devicetree/bindings/sound/cirrus,cs35l41.yaml
+++ b/Documentation/devicetree/bindings/sound/cirrus,cs35l41.yaml
@@ -75,6 +75,19 @@ properties:
maximum: 3
default: 2
+ cirrus,boost-type:
+ description:
+ Configures the type of Boost being used.
+ Internal boost requires boost-peak-milliamp, boost-ind-nanohenry and
+ boost-cap-microfarad.
+ External Boost must have GPIO1 as GPIO output. GPIO1 will be set high to
+ enable boost voltage.
+ 0 = Internal Boost
+ 1 = External Boost
+ $ref: "/schemas/types.yaml#/definitions/uint32"
+ minimum: 0
+ maximum: 1
+
cirrus,gpio1-polarity-invert:
description:
Boolean which specifies whether the GPIO1
@@ -131,9 +144,32 @@ required:
- compatible
- reg
- "#sound-dai-cells"
- - cirrus,boost-peak-milliamp
- - cirrus,boost-ind-nanohenry
- - cirrus,boost-cap-microfarad
+
+allOf:
+ - if:
+ properties:
+ cirrus,boost-type:
+ const: 0
+ then:
+ required:
+ - cirrus,boost-peak-milliamp
+ - cirrus,boost-ind-nanohenry
+ - cirrus,boost-cap-microfarad
+ else:
+ if:
+ properties:
+ cirrus,boost-type:
+ const: 1
+ then:
+ required:
+ - cirrus,gpio1-output-enable
+ - cirrus,gpio1-src-select
+ properties:
+ cirrus,boost-peak-milliamp: false
+ cirrus,boost-ind-nanohenry: false
+ cirrus,boost-cap-microfarad: false
+ cirrus,gpio1-src-select:
+ enum: [1]
additionalProperties: false
@@ -150,6 +186,8 @@ examples:
VA-supply = <&dummy_vreg>;
VP-supply = <&dummy_vreg>;
reset-gpios = <&gpio 110 0>;
+
+ cirrus,boost-type = <0>;
cirrus,boost-peak-milliamp = <4500>;
cirrus,boost-ind-nanohenry = <1000>;
cirrus,boost-cap-microfarad = <15>;
--
2.35.1
To add support for external boost for ASoC move the HDA external
boost implementation to the shared lib.
Signed-off-by: Lucas Tanure <[email protected]>
---
include/sound/cs35l41.h | 4 +
sound/pci/hda/cs35l41_hda.c | 119 ++----------------------------
sound/soc/codecs/cs35l41-lib.c | 129 ++++++++++++++++++++++++++++++++-
3 files changed, 137 insertions(+), 115 deletions(-)
diff --git a/include/sound/cs35l41.h b/include/sound/cs35l41.h
index a8537bccedcf..2b2d1d17e552 100644
--- a/include/sound/cs35l41.h
+++ b/include/sound/cs35l41.h
@@ -799,5 +799,9 @@ int cs35l41_set_channels(struct device *dev, struct regmap *reg,
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);
+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);
#endif /* __CS35L41_H */
diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c
index 2ae074c8613e..190002cdd429 100644
--- a/sound/pci/hda/cs35l41_hda.c
+++ b/sound/pci/hda/cs35l41_hda.c
@@ -32,94 +32,6 @@ static const struct reg_sequence cs35l41_hda_mute[] = {
{ CS35L41_AMP_DIG_VOL_CTRL, 0x0000A678 }, // AMP_VOL_PCM Mute
};
-static const struct reg_sequence cs35l41_safe_to_reset[] = {
- { 0x00000040, 0x00000055 },
- { 0x00000040, 0x000000AA },
- { 0x0000393C, 0x000000C0, 6000},
- { 0x0000393C, 0x00000000 },
- { 0x00007414, 0x00C82222 },
- { 0x0000742C, 0x00000000 },
- { 0x00000040, 0x000000CC },
- { 0x00000040, 0x00000033 },
-};
-
-static const struct reg_sequence cs35l41_safe_to_active[] = {
- { 0x00000040, 0x00000055 },
- { 0x00000040, 0x000000AA },
- { 0x0000742C, 0x0000000F },
- { 0x0000742C, 0x00000079 },
- { 0x00007438, 0x00585941 },
- { CS35L41_PWR_CTRL1, 0x00000001, 3000 }, // GLOBAL_EN = 1
- { 0x0000742C, 0x000000F9 },
- { 0x00007438, 0x00580941 },
- { 0x00000040, 0x000000CC },
- { 0x00000040, 0x00000033 },
-};
-
-static const struct reg_sequence cs35l41_active_to_safe[] = {
- { 0x00000040, 0x00000055 },
- { 0x00000040, 0x000000AA },
- { 0x00007438, 0x00585941 },
- { CS35L41_PWR_CTRL1, 0x00000000 },
- { 0x0000742C, 0x00000009, 3000 },
- { 0x00007438, 0x00580941 },
- { 0x00000040, 0x000000CC },
- { 0x00000040, 0x00000033 },
-};
-
-static const struct reg_sequence cs35l41_reset_to_safe[] = {
- { 0x00000040, 0x00000055 },
- { 0x00000040, 0x000000AA },
- { 0x00007438, 0x00585941 },
- { 0x00007414, 0x08C82222 },
- { 0x0000742C, 0x00000009 },
- { 0x00000040, 0x000000CC },
- { 0x00000040, 0x00000033 },
-};
-
-static bool cs35l41_hda_safe_reset(struct cs35l41_hda *cs35l41)
-{
- switch (cs35l41->hw_cfg.bst_type) {
- case CS35L41_EXT_BOOST:
- regmap_write(cs35l41->regmap, CS35L41_GPIO1_CTRL1, 0x00000001);
- regmap_multi_reg_write(cs35l41->regmap, cs35l41_safe_to_reset,
- ARRAY_SIZE(cs35l41_safe_to_reset));
- return true;
- case CS35L41_EXT_BOOST_NO_VSPK_SWITCH:
- return false;
- default:
- return true;
- }
-};
-
-static int cs35l41_hda_global_enable(struct cs35l41_hda *cs35l41, int enable)
-{
- int ret;
-
- switch (cs35l41->hw_cfg.bst_type) {
- case CS35L41_INT_BOOST:
- ret = regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL1,
- CS35L41_GLOBAL_EN_MASK,
- enable << CS35L41_GLOBAL_EN_SHIFT);
- usleep_range(3000, 3100);
- break;
- case CS35L41_EXT_BOOST:
- case CS35L41_EXT_BOOST_NO_VSPK_SWITCH:
- if (enable)
- ret = regmap_multi_reg_write(cs35l41->regmap, cs35l41_safe_to_active,
- ARRAY_SIZE(cs35l41_safe_to_active));
- else
- ret = regmap_multi_reg_write(cs35l41->regmap, cs35l41_active_to_safe,
- ARRAY_SIZE(cs35l41_active_to_safe));
- break;
- default:
- ret = -EINVAL;
- break;
- }
-
- return ret;
-};
-
static void cs35l41_hda_playback_hook(struct device *dev, int action)
{
struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
@@ -135,11 +47,11 @@ static void cs35l41_hda_playback_hook(struct device *dev, int action)
regmap_write(reg, CS35L41_GPIO1_CTRL1, 0x00008001);
break;
case HDA_GEN_PCM_ACT_PREPARE:
- ret = cs35l41_hda_global_enable(cs35l41, 1);
+ ret = cs35l41_global_enable(reg, cs35l41->hw_cfg.bst_type, 1);
break;
case HDA_GEN_PCM_ACT_CLEANUP:
regmap_multi_reg_write(reg, cs35l41_hda_mute, ARRAY_SIZE(cs35l41_hda_mute));
- ret = cs35l41_hda_global_enable(cs35l41, 0);
+ ret = cs35l41_global_enable(reg, cs35l41->hw_cfg.bst_type, 0);
break;
case HDA_GEN_PCM_ACT_CLOSE:
ret = regmap_update_bits(reg, CS35L41_PWR_CTRL2,
@@ -207,26 +119,9 @@ static int cs35l41_hda_apply_properties(struct cs35l41_hda *cs35l41)
if (!cs35l41->hw_cfg.valid)
return -EINVAL;
- switch (hw_cfg->bst_type) {
- case CS35L41_INT_BOOST:
- ret = cs35l41_boost_config(cs35l41->dev, cs35l41->regmap,
- hw_cfg->bst_ind, hw_cfg->bst_cap, hw_cfg->bst_ipk);
- if (ret)
- return ret;
- break;
- case CS35L41_EXT_BOOST:
- case CS35L41_EXT_BOOST_NO_VSPK_SWITCH:
- regmap_multi_reg_write(cs35l41->regmap, cs35l41_reset_to_safe,
- ARRAY_SIZE(cs35l41_reset_to_safe));
- ret = regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL2, CS35L41_BST_EN_MASK,
- CS35L41_BST_DIS_FET_OFF << CS35L41_BST_EN_SHIFT);
- if (ret)
- return ret;
- break;
- default:
- dev_err(cs35l41->dev, "Boost type %d not supported\n", hw_cfg->bst_type);
- return -EINVAL;
- }
+ ret = cs35l41_init_boost(cs35l41->dev, cs35l41->regmap, hw_cfg);
+ if (ret)
+ return ret;
if (hw_cfg->gpio1.valid) {
switch (hw_cfg->gpio1.func) {
@@ -505,7 +400,7 @@ int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int i
return 0;
err:
- if (cs35l41_hda_safe_reset(cs35l41))
+ if (cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type))
gpiod_set_value_cansleep(cs35l41->reset_gpio, 0);
gpiod_put(cs35l41->reset_gpio);
@@ -519,7 +414,7 @@ void cs35l41_hda_remove(struct device *dev)
component_del(cs35l41->dev, &cs35l41_hda_comp_ops);
- if (cs35l41_hda_safe_reset(cs35l41))
+ if (cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type))
gpiod_set_value_cansleep(cs35l41->reset_gpio, 0);
gpiod_put(cs35l41->reset_gpio);
}
diff --git a/sound/soc/codecs/cs35l41-lib.c b/sound/soc/codecs/cs35l41-lib.c
index 34ba163874a6..91270047bf35 100644
--- a/sound/soc/codecs/cs35l41-lib.c
+++ b/sound/soc/codecs/cs35l41-lib.c
@@ -954,9 +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)
+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;
@@ -1043,6 +1042,130 @@ int cs35l41_boost_config(struct device *dev, struct regmap *regmap, int boost_in
}
EXPORT_SYMBOL_GPL(cs35l41_boost_config);
+static const struct reg_sequence cs35l41_safe_to_reset[] = {
+ { 0x00000040, 0x00000055 },
+ { 0x00000040, 0x000000AA },
+ { 0x0000393C, 0x000000C0, 6000},
+ { 0x0000393C, 0x00000000 },
+ { 0x00007414, 0x00C82222 },
+ { 0x0000742C, 0x00000000 },
+ { 0x00000040, 0x000000CC },
+ { 0x00000040, 0x00000033 },
+};
+
+static const struct reg_sequence cs35l41_active_to_safe[] = {
+ { 0x00000040, 0x00000055 },
+ { 0x00000040, 0x000000AA },
+ { 0x00007438, 0x00585941 },
+ { CS35L41_PWR_CTRL1, 0x00000000 },
+ { 0x0000742C, 0x00000009, 3000 },
+ { 0x00007438, 0x00580941 },
+ { 0x00000040, 0x000000CC },
+ { 0x00000040, 0x00000033 },
+};
+
+static const struct reg_sequence cs35l41_safe_to_active[] = {
+ { 0x00000040, 0x00000055 },
+ { 0x00000040, 0x000000AA },
+ { 0x0000742C, 0x0000000F },
+ { 0x0000742C, 0x00000079 },
+ { 0x00007438, 0x00585941 },
+ { CS35L41_PWR_CTRL1, 0x00000001, 3000 }, // GLOBAL_EN = 1
+ { 0x0000742C, 0x000000F9 },
+ { 0x00007438, 0x00580941 },
+ { 0x00000040, 0x000000CC },
+ { 0x00000040, 0x00000033 },
+};
+
+static const struct reg_sequence cs35l41_reset_to_safe[] = {
+ { 0x00000040, 0x00000055 },
+ { 0x00000040, 0x000000AA },
+ { 0x00007438, 0x00585941 },
+ { 0x00007414, 0x08C82222 },
+ { 0x0000742C, 0x00000009 },
+ { 0x00000040, 0x000000CC },
+ { 0x00000040, 0x00000033 },
+};
+
+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_INT_BOOST:
+ ret = cs35l41_boost_config(dev, regmap, hw_cfg->bst_ind,
+ hw_cfg->bst_cap, hw_cfg->bst_ipk);
+ if (ret)
+ dev_err(dev, "Error in Boost DT config: %d\n", ret);
+ break;
+ case CS35L41_EXT_BOOST:
+ case CS35L41_EXT_BOOST_NO_VSPK_SWITCH:
+ /* Only CLSA0100 doesn't use GPIO as VSPK switch, but even on that laptop we can
+ * toggle GPIO1 as is not connected to anything.
+ * There will be no other device without VSPK switch.
+ */
+ regmap_write(regmap, CS35L41_GPIO1_CTRL1, 0x00000001);
+ regmap_multi_reg_write(regmap, cs35l41_reset_to_safe,
+ ARRAY_SIZE(cs35l41_reset_to_safe));
+ ret = regmap_update_bits(regmap, CS35L41_PWR_CTRL2, CS35L41_BST_EN_MASK,
+ CS35L41_BST_DIS_FET_OFF << CS35L41_BST_EN_SHIFT);
+ break;
+ default:
+ dev_err(dev, "Boost type %d not supported\n", hw_cfg->bst_type);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(cs35l41_init_boost);
+
+bool cs35l41_safe_reset(struct regmap *regmap, enum cs35l41_boost_type b_type)
+{
+ switch (b_type) {
+ /* There is only one laptop that doesn't have VSPK switch. */
+ case CS35L41_EXT_BOOST_NO_VSPK_SWITCH:
+ return false;
+ case CS35L41_EXT_BOOST:
+ regmap_write(regmap, CS35L41_GPIO1_CTRL1, 0x00000001);
+ regmap_multi_reg_write(regmap, cs35l41_safe_to_reset,
+ ARRAY_SIZE(cs35l41_safe_to_reset));
+ return true;
+ default:
+ return true;
+ }
+}
+EXPORT_SYMBOL_GPL(cs35l41_safe_reset);
+
+int cs35l41_global_enable(struct regmap *regmap, enum cs35l41_boost_type b_type, int enable)
+{
+ int ret;
+
+ switch (b_type) {
+ case CS35L41_INT_BOOST:
+ ret = regmap_update_bits(regmap, CS35L41_PWR_CTRL1, CS35L41_GLOBAL_EN_MASK,
+ enable << CS35L41_GLOBAL_EN_SHIFT);
+ 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));
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(cs35l41_global_enable);
+
int cs35l41_gpio_config(struct regmap *regmap, struct cs35l41_hw_cfg *hw_cfg)
{
struct cs35l41_gpio_cfg *gpio1 = &hw_cfg->gpio1;
--
2.35.1
To facilitate the configuration of external boost devices, put all
devices, with or without VSPK switch, into safe mode from the start.
That allows the following parts of the driver to handle all external
boost devices in the same way.
Signed-off-by: Lucas Tanure <[email protected]>
---
sound/pci/hda/cs35l41_hda.c | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c
index 17660ce71f93..3b9515ed871d 100644
--- a/sound/pci/hda/cs35l41_hda.c
+++ b/sound/pci/hda/cs35l41_hda.c
@@ -109,8 +109,6 @@ static const struct reg_sequence cs35l41_reset_to_safe[] = {
};
static const struct cs35l41_hda_reg_sequence cs35l41_hda_reg_seq_no_bst = {
- .probe = cs35l41_reset_to_safe,
- .num_probe = ARRAY_SIZE(cs35l41_reset_to_safe),
.prepare = cs35l41_safe_to_active,
.num_prepare = ARRAY_SIZE(cs35l41_safe_to_active),
.cleanup = cs35l41_active_to_safe,
@@ -224,10 +222,15 @@ static int cs35l41_hda_apply_properties(struct cs35l41_hda *cs35l41)
return ret;
break;
case CS35L41_EXT_BOOST:
- cs35l41->reg_seq = &cs35l41_hda_reg_seq_ext_bst;
- break;
case CS35L41_EXT_BOOST_NO_VSPK_SWITCH:
- cs35l41->reg_seq = &cs35l41_hda_reg_seq_no_bst;
+ if (hw_cfg->bst_type == CS35L41_EXT_BOOST)
+ cs35l41->reg_seq = &cs35l41_hda_reg_seq_ext_bst;
+ else
+ cs35l41->reg_seq = &cs35l41_hda_reg_seq_no_bst;
+ ret = regmap_multi_reg_write(cs35l41->regmap, cs35l41_reset_to_safe,
+ ARRAY_SIZE(cs35l41_reset_to_safe));
+ if (ret)
+ return ret;
break;
default:
dev_err(cs35l41->dev, "Boost type %d not supported\n", hw_cfg->bst_type);
--
2.35.1
Fix clock and slot size comments
Signed-off-by: Lucas Tanure <[email protected]>
---
sound/pci/hda/cs35l41_hda.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c
index 81cdbd84cf7d..fe6f6a208d29 100644
--- a/sound/pci/hda/cs35l41_hda.c
+++ b/sound/pci/hda/cs35l41_hda.c
@@ -17,11 +17,11 @@
#include "cs35l41_hda.h"
static const struct reg_sequence cs35l41_hda_config[] = {
- { CS35L41_PLL_CLK_CTRL, 0x00000430 }, // 3200000Hz, BCLK Input, PLL_REFCLK_EN = 1
+ { CS35L41_PLL_CLK_CTRL, 0x00000430 }, // 3072000Hz, BCLK Input, PLL_REFCLK_EN = 1
{ CS35L41_GLOBAL_CLK_CTRL, 0x00000003 }, // GLOBAL_FS = 48 kHz
{ CS35L41_SP_ENABLES, 0x00010000 }, // ASP_RX1_EN = 1
{ CS35L41_SP_RATE_CTRL, 0x00000021 }, // ASP_BCLK_FREQ = 3.072 MHz
- { CS35L41_SP_FORMAT, 0x20200200 }, // 24 bits, I2S, BCLK Slave, FSYNC Slave
+ { CS35L41_SP_FORMAT, 0x20200200 }, // 32 bits RX/TX slots, I2S, clk consumer
{ CS35L41_DAC_PCM1_SRC, 0x00000008 }, // DACPCM1_SRC = ASPRX1
{ CS35L41_AMP_DIG_VOL_CTRL, 0x00000000 }, // AMP_VOL_PCM 0.0 dB
{ CS35L41_AMP_GAIN_CTRL, 0x00000084 }, // AMP_GAIN_PCM 4.5 dB
--
2.35.1
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 <[email protected]>
---
include/sound/cs35l41.h | 4 +--
sound/soc/codecs/cs35l41-lib.c | 5 ++--
sound/soc/codecs/cs35l41.c | 49 +++++++++++++++++++++++++---------
3 files changed, 41 insertions(+), 17 deletions(-)
diff --git a/include/sound/cs35l41.h b/include/sound/cs35l41.h
index 2b2d1d17e552..dad05d57cd74 100644
--- a/include/sound/cs35l41.h
+++ b/include/sound/cs35l41.h
@@ -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
@@ -796,8 +798,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);
diff --git a/sound/soc/codecs/cs35l41-lib.c b/sound/soc/codecs/cs35l41-lib.c
index 91270047bf35..e206970876fe 100644
--- a/sound/soc/codecs/cs35l41-lib.c
+++ b/sound/soc/codecs/cs35l41-lib.c
@@ -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 },
diff --git a/sound/soc/codecs/cs35l41.c b/sound/soc/codecs/cs35l41.c
index d25689fe0c60..912196f45648 100644
--- a/sound/soc/codecs/cs35l41.c
+++ b/sound/soc/codecs/cs35l41.c
@@ -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 @@ int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg *
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;
}
--
2.35.1
External boost enables sequences for devices with or without GPIO1 as
VSPK switch are the same if devices are put in safe mode from reset.
As a previous patch put all external boost devices into safe mode
from reset, all external boost devices can be handled in the same way
for stream open and close.
The only difference is that devices without an VSPK switch can not be
put in reset and devices with it can be put into reset if a
configuration is applied.
The function cs35l41_hda_safe_reset is created to handle the safe reset
of the chip, and as systems without VSPK switch are not supported
anymore, only the CS35L41 HDA driver should check its return.
Signed-off-by: Lucas Tanure <[email protected]>
---
sound/pci/hda/cs35l41_hda.c | 60 +++++++++++++++----------------------
1 file changed, 24 insertions(+), 36 deletions(-)
diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c
index fda4af323c32..2ae074c8613e 100644
--- a/sound/pci/hda/cs35l41_hda.c
+++ b/sound/pci/hda/cs35l41_hda.c
@@ -32,33 +32,9 @@ static const struct reg_sequence cs35l41_hda_mute[] = {
{ CS35L41_AMP_DIG_VOL_CTRL, 0x0000A678 }, // AMP_VOL_PCM Mute
};
-// only on amps where GPIO1 is used to control ext. VSPK switch
-static const struct reg_sequence cs35l41_start_ext_vspk[] = {
+static const struct reg_sequence cs35l41_safe_to_reset[] = {
{ 0x00000040, 0x00000055 },
{ 0x00000040, 0x000000AA },
- { 0x00007438, 0x00585941 },
- { 0x00007414, 0x08C82222 },
- { 0x0000742C, 0x00000009 },
- { 0x00011008, 0x00008001 },
- { 0x0000742C, 0x0000000F },
- { 0x0000742C, 0x00000079 },
- { 0x00007438, 0x00585941 },
- { CS35L41_PWR_CTRL1, 0x00000001, 3000}, // set GLOBAL_EN = 1
- { 0x0000742C, 0x000000F9 },
- { 0x00007438, 0x00580941 },
- { 0x00000040, 0x000000CC },
- { 0x00000040, 0x00000033 },
-};
-
-//only on amps where GPIO1 is used to control ext. VSPK switch
-static const struct reg_sequence cs35l41_stop_ext_vspk[] = {
- { 0x00000040, 0x00000055 },
- { 0x00000040, 0x000000AA },
- { 0x00007438, 0x00585941 },
- { 0x00002014, 0x00000000, 3000}, // set GLOBAL_EN = 0
- { 0x0000742C, 0x00000009 },
- { 0x00007438, 0x00580941 },
- { 0x00011008, 0x00000001 },
{ 0x0000393C, 0x000000C0, 6000},
{ 0x0000393C, 0x00000000 },
{ 0x00007414, 0x00C82222 },
@@ -73,7 +49,7 @@ static const struct reg_sequence cs35l41_safe_to_active[] = {
{ 0x0000742C, 0x0000000F },
{ 0x0000742C, 0x00000079 },
{ 0x00007438, 0x00585941 },
- { CS35L41_PWR_CTRL1, 0x00000001, 2000 }, // GLOBAL_EN = 1
+ { CS35L41_PWR_CTRL1, 0x00000001, 3000 }, // GLOBAL_EN = 1
{ 0x0000742C, 0x000000F9 },
{ 0x00007438, 0x00580941 },
{ 0x00000040, 0x000000CC },
@@ -85,7 +61,7 @@ static const struct reg_sequence cs35l41_active_to_safe[] = {
{ 0x00000040, 0x000000AA },
{ 0x00007438, 0x00585941 },
{ CS35L41_PWR_CTRL1, 0x00000000 },
- { 0x0000742C, 0x00000009, 2000 },
+ { 0x0000742C, 0x00000009, 3000 },
{ 0x00007438, 0x00580941 },
{ 0x00000040, 0x000000CC },
{ 0x00000040, 0x00000033 },
@@ -101,6 +77,21 @@ static const struct reg_sequence cs35l41_reset_to_safe[] = {
{ 0x00000040, 0x00000033 },
};
+static bool cs35l41_hda_safe_reset(struct cs35l41_hda *cs35l41)
+{
+ switch (cs35l41->hw_cfg.bst_type) {
+ case CS35L41_EXT_BOOST:
+ regmap_write(cs35l41->regmap, CS35L41_GPIO1_CTRL1, 0x00000001);
+ regmap_multi_reg_write(cs35l41->regmap, cs35l41_safe_to_reset,
+ ARRAY_SIZE(cs35l41_safe_to_reset));
+ return true;
+ case CS35L41_EXT_BOOST_NO_VSPK_SWITCH:
+ return false;
+ default:
+ return true;
+ }
+};
+
static int cs35l41_hda_global_enable(struct cs35l41_hda *cs35l41, int enable)
{
int ret;
@@ -113,13 +104,6 @@ static int cs35l41_hda_global_enable(struct cs35l41_hda *cs35l41, int enable)
usleep_range(3000, 3100);
break;
case CS35L41_EXT_BOOST:
- if (enable)
- ret = regmap_multi_reg_write(cs35l41->regmap, cs35l41_start_ext_vspk,
- ARRAY_SIZE(cs35l41_start_ext_vspk));
- else
- ret = regmap_multi_reg_write(cs35l41->regmap, cs35l41_stop_ext_vspk,
- ARRAY_SIZE(cs35l41_stop_ext_vspk));
- break;
case CS35L41_EXT_BOOST_NO_VSPK_SWITCH:
if (enable)
ret = regmap_multi_reg_write(cs35l41->regmap, cs35l41_safe_to_active,
@@ -147,6 +131,8 @@ static void cs35l41_hda_playback_hook(struct device *dev, int action)
regmap_multi_reg_write(reg, cs35l41_hda_config, ARRAY_SIZE(cs35l41_hda_config));
ret = regmap_update_bits(reg, CS35L41_PWR_CTRL2,
CS35L41_AMP_EN_MASK, 1 << CS35L41_AMP_EN_SHIFT);
+ if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST)
+ regmap_write(reg, CS35L41_GPIO1_CTRL1, 0x00008001);
break;
case HDA_GEN_PCM_ACT_PREPARE:
ret = cs35l41_hda_global_enable(cs35l41, 1);
@@ -158,6 +144,8 @@ static void cs35l41_hda_playback_hook(struct device *dev, int action)
case HDA_GEN_PCM_ACT_CLOSE:
ret = regmap_update_bits(reg, CS35L41_PWR_CTRL2,
CS35L41_AMP_EN_MASK, 0 << CS35L41_AMP_EN_SHIFT);
+ if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST)
+ regmap_write(reg, CS35L41_GPIO1_CTRL1, 0x00000001);
break;
default:
dev_warn(cs35l41->dev, "Playback action not supported: %d\n", action);
@@ -517,7 +505,7 @@ int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int i
return 0;
err:
- if (cs35l41->hw_cfg.bst_type != CS35L41_EXT_BOOST_NO_VSPK_SWITCH)
+ if (cs35l41_hda_safe_reset(cs35l41))
gpiod_set_value_cansleep(cs35l41->reset_gpio, 0);
gpiod_put(cs35l41->reset_gpio);
@@ -531,7 +519,7 @@ void cs35l41_hda_remove(struct device *dev)
component_del(cs35l41->dev, &cs35l41_hda_comp_ops);
- if (cs35l41->hw_cfg.bst_type != CS35L41_EXT_BOOST_NO_VSPK_SWITCH)
+ if (cs35l41_hda_safe_reset(cs35l41))
gpiod_set_value_cansleep(cs35l41->reset_gpio, 0);
gpiod_put(cs35l41->reset_gpio);
}
--
2.35.1
For each case, only log the last regmap access, so it doesn't get
overwritten, and as all regmap access should show the same issues
logging the last one should be enough.
Change to dev_err to log this error.
Also, differentiate between a regmap access failure and invalid
playback action.
Signed-off-by: Lucas Tanure <[email protected]>
---
sound/pci/hda/cs35l41_hda.c | 15 +++++++--------
1 file changed, 7 insertions(+), 8 deletions(-)
diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c
index 08ce9b8005ec..fda4af323c32 100644
--- a/sound/pci/hda/cs35l41_hda.c
+++ b/sound/pci/hda/cs35l41_hda.c
@@ -144,10 +144,9 @@ static void cs35l41_hda_playback_hook(struct device *dev, int action)
switch (action) {
case HDA_GEN_PCM_ACT_OPEN:
- ret = regmap_multi_reg_write(reg, cs35l41_hda_config,
- ARRAY_SIZE(cs35l41_hda_config));
- regmap_update_bits(reg, CS35L41_PWR_CTRL2,
- CS35L41_AMP_EN_MASK, 1 << CS35L41_AMP_EN_SHIFT);
+ regmap_multi_reg_write(reg, cs35l41_hda_config, ARRAY_SIZE(cs35l41_hda_config));
+ ret = regmap_update_bits(reg, CS35L41_PWR_CTRL2,
+ CS35L41_AMP_EN_MASK, 1 << CS35L41_AMP_EN_SHIFT);
break;
case HDA_GEN_PCM_ACT_PREPARE:
ret = cs35l41_hda_global_enable(cs35l41, 1);
@@ -157,16 +156,16 @@ static void cs35l41_hda_playback_hook(struct device *dev, int action)
ret = cs35l41_hda_global_enable(cs35l41, 0);
break;
case HDA_GEN_PCM_ACT_CLOSE:
- regmap_update_bits(reg, CS35L41_PWR_CTRL2,
- CS35L41_AMP_EN_MASK, 0 << CS35L41_AMP_EN_SHIFT);
+ ret = regmap_update_bits(reg, CS35L41_PWR_CTRL2,
+ CS35L41_AMP_EN_MASK, 0 << CS35L41_AMP_EN_SHIFT);
break;
default:
- ret = -EINVAL;
+ dev_warn(cs35l41->dev, "Playback action not supported: %d\n", action);
break;
}
if (ret)
- dev_warn(cs35l41->dev, "Failed to apply multi reg write: %d\n", ret);
+ dev_err(cs35l41->dev, "Regmap access fail: %d\n", ret);
}
static int cs35l41_hda_channel_map(struct device *dev, unsigned int tx_num, unsigned int *tx_slot,
--
2.35.1
Replace vspk_always_on by a enum that better characterizes the boost
type, as there is 3 types of boost hardware.
And with the new boost type other parts of the driver can better handle
the configuration of the chip.
Signed-off-by: Lucas Tanure <[email protected]>
---
include/sound/cs35l41.h | 9 ++++++--
sound/pci/hda/cs35l41_hda.c | 43 +++++++++++++++++++++----------------
2 files changed, 31 insertions(+), 21 deletions(-)
diff --git a/include/sound/cs35l41.h b/include/sound/cs35l41.h
index e3ec0f422fff..fbf38f32e36d 100644
--- a/include/sound/cs35l41.h
+++ b/include/sound/cs35l41.h
@@ -725,6 +725,12 @@
#define CS35L41_SPI_MAX_FREQ 4000000
#define CS35L41_REGSTRIDE 4
+enum cs35l41_boost_type {
+ CS35L41_INT_BOOST,
+ CS35L41_EXT_BOOST,
+ CS35L41_EXT_BOOST_NO_VSPK_SWITCH,
+};
+
enum cs35l41_clk_ids {
CS35L41_CLKID_SCLK = 0,
CS35L41_CLKID_LRCLK = 1,
@@ -762,8 +768,7 @@ struct cs35l41_hw_cfg {
struct cs35l41_gpio_cfg gpio2;
unsigned int spk_pos;
- /* Don't put the AMP in reset if VSPK can not be turned off */
- bool vspk_always_on;
+ enum cs35l41_boost_type bst_type;
};
struct cs35l41_otp_packed_element_t {
diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c
index 4c99dcac2dd7..17660ce71f93 100644
--- a/sound/pci/hda/cs35l41_hda.c
+++ b/sound/pci/hda/cs35l41_hda.c
@@ -210,20 +210,30 @@ static const struct component_ops cs35l41_hda_comp_ops = {
static int cs35l41_hda_apply_properties(struct cs35l41_hda *cs35l41)
{
struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg;
- bool internal_boost = false;
int ret;
if (!cs35l41->hw_cfg.valid)
return -EINVAL;
- if (hw_cfg->vspk_always_on) {
+ switch (hw_cfg->bst_type) {
+ case CS35L41_INT_BOOST:
+ cs35l41->reg_seq = &cs35l41_hda_reg_seq_int_bst;
+ ret = cs35l41_boost_config(cs35l41->dev, cs35l41->regmap,
+ hw_cfg->bst_ind, hw_cfg->bst_cap, hw_cfg->bst_ipk);
+ if (ret)
+ return ret;
+ break;
+ case CS35L41_EXT_BOOST:
+ cs35l41->reg_seq = &cs35l41_hda_reg_seq_ext_bst;
+ break;
+ case CS35L41_EXT_BOOST_NO_VSPK_SWITCH:
cs35l41->reg_seq = &cs35l41_hda_reg_seq_no_bst;
- return 0;
+ break;
+ default:
+ dev_err(cs35l41->dev, "Boost type %d not supported\n", hw_cfg->bst_type);
+ return -EINVAL;
}
- if (hw_cfg->bst_ind > 0 || hw_cfg->bst_cap > 0 || hw_cfg->bst_ipk > 0)
- internal_boost = true;
-
if (hw_cfg->gpio1.valid) {
switch (hw_cfg->gpio1.func) {
case CS35L41_NOT_USED:
@@ -256,16 +266,6 @@ static int cs35l41_hda_apply_properties(struct cs35l41_hda *cs35l41)
cs35l41_gpio_config(cs35l41->regmap, hw_cfg);
- if (internal_boost) {
- cs35l41->reg_seq = &cs35l41_hda_reg_seq_int_bst;
- ret = cs35l41_boost_config(cs35l41->dev, cs35l41->regmap,
- hw_cfg->bst_ind, hw_cfg->bst_cap, hw_cfg->bst_ipk);
- if (ret)
- return ret;
- } else {
- cs35l41->reg_seq = &cs35l41_hda_reg_seq_ext_bst;
- }
-
return cs35l41_hda_channel_map(cs35l41->dev, 0, NULL, 1, &hw_cfg->spk_pos);
}
@@ -363,6 +363,11 @@ static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, i
else
hw_cfg->bst_cap = -1;
+ if (hw_cfg->bst_ind > 0 || hw_cfg->bst_cap > 0 || hw_cfg->bst_ipk > 0)
+ hw_cfg->bst_type = CS35L41_INT_BOOST;
+ else
+ hw_cfg->bst_type = CS35L41_EXT_BOOST;
+
hw_cfg->valid = true;
put_device(physdev);
@@ -388,7 +393,7 @@ static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, i
/* check I2C address to assign the index */
cs35l41->index = id == 0x40 ? 0 : 1;
cs35l41->reset_gpio = gpiod_get_index(physdev, NULL, 0, GPIOD_OUT_HIGH);
- cs35l41->hw_cfg.vspk_always_on = true;
+ cs35l41->hw_cfg.bst_type = CS35L41_EXT_BOOST_NO_VSPK_SWITCH;
cs35l41->hw_cfg.valid = true;
put_device(physdev);
@@ -515,7 +520,7 @@ int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int i
return 0;
err:
- if (!cs35l41->hw_cfg.vspk_always_on)
+ if (cs35l41->hw_cfg.bst_type != CS35L41_EXT_BOOST_NO_VSPK_SWITCH)
gpiod_set_value_cansleep(cs35l41->reset_gpio, 0);
gpiod_put(cs35l41->reset_gpio);
@@ -529,7 +534,7 @@ void cs35l41_hda_remove(struct device *dev)
component_del(cs35l41->dev, &cs35l41_hda_comp_ops);
- if (!cs35l41->hw_cfg.vspk_always_on)
+ if (cs35l41->hw_cfg.bst_type != CS35L41_EXT_BOOST_NO_VSPK_SWITCH)
gpiod_set_value_cansleep(cs35l41->reset_gpio, 0);
gpiod_put(cs35l41->reset_gpio);
}
--
2.35.1
Internal Boost enable is the default option from reset, but with
external boost support, internal boost must be disabled.
Add the enable of internal boost in cs35l41_boost_config to
centralize the internal boost configuration.
Signed-off-by: Lucas Tanure <[email protected]>
Acked-by: Charles Keepax <[email protected]>
---
sound/soc/codecs/cs35l41-lib.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/sound/soc/codecs/cs35l41-lib.c b/sound/soc/codecs/cs35l41-lib.c
index 3fae34a232cd..34ba163874a6 100644
--- a/sound/soc/codecs/cs35l41-lib.c
+++ b/sound/soc/codecs/cs35l41-lib.c
@@ -1036,6 +1036,9 @@ int cs35l41_boost_config(struct device *dev, struct regmap *regmap, int boost_in
return ret;
}
+ regmap_update_bits(regmap, CS35L41_PWR_CTRL2, CS35L41_BST_EN_MASK,
+ CS35L41_BST_EN_DEFAULT << CS35L41_BST_EN_SHIFT);
+
return 0;
}
EXPORT_SYMBOL_GPL(cs35l41_boost_config);
--
2.35.1
Mute the device before shutdown to avoid pops and clicks for all types
of boost.
Signed-off-by: Lucas Tanure <[email protected]>
---
sound/pci/hda/cs35l41_hda.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c
index 3b9515ed871d..b3cc7db3fc42 100644
--- a/sound/pci/hda/cs35l41_hda.c
+++ b/sound/pci/hda/cs35l41_hda.c
@@ -28,6 +28,11 @@ static const struct reg_sequence cs35l41_hda_config[] = {
{ CS35L41_PWR_CTRL2, 0x00000001 }, // AMP_EN = 1
};
+static const struct reg_sequence cs35l41_hda_mute[] = {
+ { CS35L41_AMP_GAIN_CTRL, 0x00000000 }, // AMP_GAIN_PCM 0.5 dB
+ { CS35L41_AMP_DIG_VOL_CTRL, 0x0000A678 }, // AMP_VOL_PCM Mute
+};
+
static const struct reg_sequence cs35l41_hda_start_bst[] = {
{ CS35L41_PWR_CTRL2, 0x00000021 }, // BST_EN = 10, AMP_EN = 1
{ CS35L41_PWR_CTRL1, 0x00000001, 3000}, // set GLOBAL_EN = 1
@@ -89,7 +94,6 @@ static const struct reg_sequence cs35l41_active_to_safe[] = {
{ 0x00000040, 0x00000055 },
{ 0x00000040, 0x000000AA },
{ 0x00007438, 0x00585941 },
- { CS35L41_AMP_DIG_VOL_CTRL, 0x0000A678 }, // AMP_VOL_PCM Mute
{ CS35L41_PWR_CTRL2, 0x00000000 }, // AMP_EN = 0
{ CS35L41_PWR_CTRL1, 0x00000000 },
{ 0x0000742C, 0x00000009, 2000 },
@@ -146,6 +150,7 @@ static void cs35l41_hda_playback_hook(struct device *dev, int action)
ret = regmap_multi_reg_write(reg, reg_seq->prepare, reg_seq->num_prepare);
break;
case HDA_GEN_PCM_ACT_CLEANUP:
+ regmap_multi_reg_write(reg, cs35l41_hda_mute, ARRAY_SIZE(cs35l41_hda_mute));
if (reg_seq->cleanup)
ret = regmap_multi_reg_write(reg, reg_seq->cleanup, reg_seq->num_cleanup);
break;
--
2.35.1
The driver can receive an empty hw_config, so mark as valid if
successfully read from device tree/ACPI or set by the driver itself.
Platforms not marked with a valid hw config will not be supported.
Signed-off-by: Lucas Tanure <[email protected]>
Acked-by: Charles Keepax <[email protected]>
---
include/sound/cs35l41.h | 3 +-
sound/pci/hda/cs35l41_hda.c | 70 +++++++++++++++++++------------
sound/soc/codecs/cs35l41-lib.c | 16 ++++---
sound/soc/codecs/cs35l41.c | 77 +++++++++++++++++++++-------------
4 files changed, 105 insertions(+), 61 deletions(-)
diff --git a/include/sound/cs35l41.h b/include/sound/cs35l41.h
index 262c75109c9e..57c47636c223 100644
--- a/include/sound/cs35l41.h
+++ b/include/sound/cs35l41.h
@@ -538,7 +538,6 @@
#define CS35L41_OTP_SIZE_WORDS 32
#define CS35L41_NUM_OTP_ELEM 100
-#define CS35L41_VALID_PDATA 0x80000000
#define CS35L41_NUM_SUPPLIES 2
#define CS35L41_SCLK_MSTR_MASK 0x10
@@ -747,12 +746,14 @@ enum cs35l41_gpio_func {
};
struct cs35l41_gpio_cfg {
+ bool valid;
bool pol_inv;
bool out_en;
enum cs35l41_gpio_func func;
};
struct cs35l41_hw_cfg {
+ bool valid;
int bst_ind;
int bst_ipk;
int bst_cap;
diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c
index b79d6ad4b4f5..a14ad3b0d516 100644
--- a/sound/pci/hda/cs35l41_hda.c
+++ b/sound/pci/hda/cs35l41_hda.c
@@ -219,46 +219,52 @@ static int cs35l41_hda_apply_properties(struct cs35l41_hda *cs35l41)
bool internal_boost = false;
int ret;
+ if (!cs35l41->hw_cfg.valid)
+ return -EINVAL;
+
if (hw_cfg->vspk_always_on) {
cs35l41->reg_seq = &cs35l41_hda_reg_seq_no_bst;
return 0;
}
- if (hw_cfg->bst_ind || hw_cfg->bst_cap || hw_cfg->bst_ipk)
+ if (hw_cfg->bst_ind > 0 || hw_cfg->bst_cap > 0 || hw_cfg->bst_ipk > 0)
internal_boost = true;
- switch (hw_cfg->gpio1.func) {
- case CS35L41_NOT_USED:
- break;
- case CS35l41_VSPK_SWITCH:
- regmap_update_bits(cs35l41->regmap, CS35L41_GPIO_PAD_CONTROL,
- CS35L41_GPIO1_CTRL_MASK, 1 << CS35L41_GPIO1_CTRL_SHIFT);
- break;
- case CS35l41_SYNC:
- regmap_update_bits(cs35l41->regmap, CS35L41_GPIO_PAD_CONTROL,
- CS35L41_GPIO1_CTRL_MASK, 2 << CS35L41_GPIO1_CTRL_SHIFT);
- break;
- default:
- dev_err(cs35l41->dev, "Invalid function %d for GPIO1\n", hw_cfg->gpio1.func);
- return -EINVAL;
+ if (hw_cfg->gpio1.valid) {
+ switch (hw_cfg->gpio1.func) {
+ case CS35L41_NOT_USED:
+ break;
+ case CS35l41_VSPK_SWITCH:
+ regmap_update_bits(cs35l41->regmap, CS35L41_GPIO_PAD_CONTROL,
+ CS35L41_GPIO1_CTRL_MASK, 1 << CS35L41_GPIO1_CTRL_SHIFT);
+ break;
+ case CS35l41_SYNC:
+ regmap_update_bits(cs35l41->regmap, CS35L41_GPIO_PAD_CONTROL,
+ CS35L41_GPIO1_CTRL_MASK, 2 << CS35L41_GPIO1_CTRL_SHIFT);
+ break;
+ default:
+ dev_err(cs35l41->dev, "Invalid function %d for GPIO1\n",
+ hw_cfg->gpio1.func);
+ return -EINVAL;
+ }
}
- switch (hw_cfg->gpio2.func) {
- case CS35L41_NOT_USED:
- break;
- case CS35L41_INTERRUPT:
- regmap_update_bits(cs35l41->regmap, CS35L41_GPIO_PAD_CONTROL,
- CS35L41_GPIO2_CTRL_MASK, 2 << CS35L41_GPIO2_CTRL_SHIFT);
- break;
- default:
- dev_err(cs35l41->dev, "Invalid function %d for GPIO2\n", hw_cfg->gpio2.func);
- return -EINVAL;
+ if (hw_cfg->gpio2.valid) {
+ switch (hw_cfg->gpio2.func) {
+ case CS35L41_NOT_USED:
+ break;
+ case CS35L41_INTERRUPT:
+ regmap_update_bits(cs35l41->regmap, CS35L41_GPIO_PAD_CONTROL,
+ CS35L41_GPIO2_CTRL_MASK, 2 << CS35L41_GPIO2_CTRL_SHIFT);
+ break;
+ default:
+ dev_err(cs35l41->dev, "Invalid GPIO2 function %d\n", hw_cfg->gpio2.func);
+ return -EINVAL;
+ }
}
if (internal_boost) {
cs35l41->reg_seq = &cs35l41_hda_reg_seq_int_bst;
- if (!(hw_cfg->bst_ind && hw_cfg->bst_cap && hw_cfg->bst_ipk))
- return -EINVAL;
ret = cs35l41_boost_config(cs35l41->dev, cs35l41->regmap,
hw_cfg->bst_ind, hw_cfg->bst_cap, hw_cfg->bst_ipk);
if (ret)
@@ -334,28 +340,37 @@ static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, i
if (ret)
goto err;
hw_cfg->gpio1.func = values[cs35l41->index];
+ hw_cfg->gpio1.valid = true;
property = "cirrus,gpio2-func";
ret = device_property_read_u32_array(physdev, property, values, nval);
if (ret)
goto err;
hw_cfg->gpio2.func = values[cs35l41->index];
+ hw_cfg->gpio2.valid = true;
property = "cirrus,boost-peak-milliamp";
ret = device_property_read_u32_array(physdev, property, values, nval);
if (ret == 0)
hw_cfg->bst_ipk = values[cs35l41->index];
+ else
+ hw_cfg->bst_ipk = -1;
property = "cirrus,boost-ind-nanohenry";
ret = device_property_read_u32_array(physdev, property, values, nval);
if (ret == 0)
hw_cfg->bst_ind = values[cs35l41->index];
+ else
+ hw_cfg->bst_ind = -1;
property = "cirrus,boost-cap-microfarad";
ret = device_property_read_u32_array(physdev, property, values, nval);
if (ret == 0)
hw_cfg->bst_cap = values[cs35l41->index];
+ else
+ hw_cfg->bst_cap = -1;
+ hw_cfg->valid = true;
put_device(physdev);
return 0;
@@ -381,6 +396,7 @@ static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, i
cs35l41->index = id == 0x40 ? 0 : 1;
cs35l41->reset_gpio = gpiod_get_index(physdev, NULL, 0, GPIOD_OUT_HIGH);
cs35l41->hw_cfg.vspk_always_on = true;
+ cs35l41->hw_cfg.valid = true;
put_device(physdev);
return 0;
diff --git a/sound/soc/codecs/cs35l41-lib.c b/sound/soc/codecs/cs35l41-lib.c
index e5a56bcbb223..905c648a8f49 100644
--- a/sound/soc/codecs/cs35l41-lib.c
+++ b/sound/soc/codecs/cs35l41-lib.c
@@ -992,10 +992,20 @@ int cs35l41_boost_config(struct device *dev, struct regmap *regmap, int boost_in
case 101 ... 200:
bst_cbst_range = 3;
break;
- default: /* 201 uF and greater */
+ default:
+ if (boost_cap < 0) {
+ dev_err(dev, "Invalid boost capacitor value: %d nH\n", boost_cap);
+ return -EINVAL;
+ }
+ /* 201 uF and greater */
bst_cbst_range = 4;
}
+ if (boost_ipk < 1600 || boost_ipk > 4500) {
+ dev_err(dev, "Invalid boost inductor peak current: %d mA\n", boost_ipk);
+ return -EINVAL;
+ }
+
ret = regmap_update_bits(regmap, CS35L41_BSTCVRT_COEFF,
CS35L41_BST_K1_MASK | CS35L41_BST_K2_MASK,
cs35l41_bst_k1_table[bst_lbst_val][bst_cbst_range]
@@ -1017,10 +1027,6 @@ int cs35l41_boost_config(struct device *dev, struct regmap *regmap, int boost_in
return ret;
}
- if (boost_ipk < 1600 || boost_ipk > 4500) {
- dev_err(dev, "Invalid boost inductor peak current: %d mA\n", boost_ipk);
- return -EINVAL;
- }
bst_ipk_scaled = ((boost_ipk - 1600) / 50) + 0x10;
ret = regmap_update_bits(regmap, CS35L41_BSTCVRT_PEAK_CUR, CS35L41_BST_IPK_MASK,
diff --git a/sound/soc/codecs/cs35l41.c b/sound/soc/codecs/cs35l41.c
index 67b33c5c3d44..5dbc2147209a 100644
--- a/sound/soc/codecs/cs35l41.c
+++ b/sound/soc/codecs/cs35l41.c
@@ -995,28 +995,24 @@ static int cs35l41_dai_set_sysclk(struct snd_soc_dai *dai,
static int cs35l41_set_pdata(struct cs35l41_private *cs35l41)
{
+ struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg;
int ret;
- /* Set Platform Data */
- /* Required */
- if (cs35l41->hw_cfg.bst_ipk &&
- cs35l41->hw_cfg.bst_ind && cs35l41->hw_cfg.bst_cap) {
- ret = cs35l41_boost_config(cs35l41->dev, cs35l41->regmap, cs35l41->hw_cfg.bst_ind,
- cs35l41->hw_cfg.bst_cap, cs35l41->hw_cfg.bst_ipk);
- if (ret) {
- dev_err(cs35l41->dev, "Error in Boost DT config: %d\n", ret);
- return ret;
- }
- } else {
- dev_err(cs35l41->dev, "Incomplete Boost component DT config\n");
+ if (!hw_cfg->valid)
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);
+ return ret;
}
/* Optional */
- if (cs35l41->hw_cfg.dout_hiz <= CS35L41_ASP_DOUT_HIZ_MASK &&
- cs35l41->hw_cfg.dout_hiz >= 0)
+ if (hw_cfg->dout_hiz <= CS35L41_ASP_DOUT_HIZ_MASK && hw_cfg->dout_hiz >= 0)
regmap_update_bits(cs35l41->regmap, CS35L41_SP_HIZ_CTRL, CS35L41_ASP_DOUT_HIZ_MASK,
- cs35l41->hw_cfg.dout_hiz);
+ hw_cfg->dout_hiz);
return 0;
}
@@ -1037,16 +1033,29 @@ static int cs35l41_gpio_config(struct cs35l41_private *cs35l41)
gpio2->pol_inv << CS35L41_GPIO_POL_SHIFT |
!gpio2->out_en << CS35L41_GPIO_DIR_SHIFT);
- regmap_update_bits(cs35l41->regmap, CS35L41_GPIO_PAD_CONTROL,
- CS35L41_GPIO1_CTRL_MASK | CS35L41_GPIO2_CTRL_MASK,
- gpio1->func << CS35L41_GPIO1_CTRL_SHIFT |
- gpio2->func << CS35L41_GPIO2_CTRL_SHIFT);
- if ((gpio2->func == (CS35L41_INT_PUSH_PULL_LOW_GPIO2 | CS35L41_VALID_PDATA)) ||
- (gpio2->func == (CS35L41_INT_OPEN_DRAIN_GPIO2 | CS35L41_VALID_PDATA)))
- irq_pol = IRQF_TRIGGER_LOW;
- else if (gpio2->func == (CS35L41_INT_PUSH_PULL_HIGH_GPIO2 | CS35L41_VALID_PDATA))
- irq_pol = IRQF_TRIGGER_HIGH;
+ if (gpio1->valid)
+ regmap_update_bits(cs35l41->regmap, CS35L41_GPIO_PAD_CONTROL,
+ CS35L41_GPIO1_CTRL_MASK,
+ gpio1->func << CS35L41_GPIO1_CTRL_SHIFT);
+
+ if (gpio2->valid) {
+ regmap_update_bits(cs35l41->regmap, CS35L41_GPIO_PAD_CONTROL,
+ CS35L41_GPIO2_CTRL_MASK,
+ gpio2->func << CS35L41_GPIO2_CTRL_SHIFT);
+
+ switch (gpio2->func) {
+ case CS35L41_INT_PUSH_PULL_LOW_GPIO2:
+ case CS35L41_INT_OPEN_DRAIN_GPIO2:
+ irq_pol = IRQF_TRIGGER_LOW;
+ break;
+ case CS35L41_INT_PUSH_PULL_HIGH_GPIO2:
+ irq_pol = IRQF_TRIGGER_HIGH;
+ break;
+ default:
+ break;
+ }
+ }
return irq_pol;
}
@@ -1121,14 +1130,20 @@ static int cs35l41_handle_pdata(struct device *dev, struct cs35l41_hw_cfg *hw_cf
ret = device_property_read_u32(dev, "cirrus,boost-peak-milliamp", &val);
if (ret >= 0)
hw_cfg->bst_ipk = val;
+ else
+ hw_cfg->bst_ipk = -1;
ret = device_property_read_u32(dev, "cirrus,boost-ind-nanohenry", &val);
if (ret >= 0)
hw_cfg->bst_ind = val;
+ else
+ hw_cfg->bst_ind = -1;
ret = device_property_read_u32(dev, "cirrus,boost-cap-microfarad", &val);
if (ret >= 0)
hw_cfg->bst_cap = val;
+ else
+ hw_cfg->bst_cap = -1;
ret = device_property_read_u32(dev, "cirrus,asp-sdout-hiz", &val);
if (ret >= 0)
@@ -1140,15 +1155,21 @@ static int cs35l41_handle_pdata(struct device *dev, struct cs35l41_hw_cfg *hw_cf
gpio1->pol_inv = device_property_read_bool(dev, "cirrus,gpio1-polarity-invert");
gpio1->out_en = device_property_read_bool(dev, "cirrus,gpio1-output-enable");
ret = device_property_read_u32(dev, "cirrus,gpio1-src-select", &val);
- if (ret >= 0)
- gpio1->func = val | CS35L41_VALID_PDATA;
+ if (ret >= 0) {
+ gpio1->func = val;
+ gpio1->valid = true;
+ }
/* GPIO2 Pin Config */
gpio2->pol_inv = device_property_read_bool(dev, "cirrus,gpio2-polarity-invert");
gpio2->out_en = device_property_read_bool(dev, "cirrus,gpio2-output-enable");
ret = device_property_read_u32(dev, "cirrus,gpio2-src-select", &val);
- if (ret >= 0)
- gpio2->func = val | CS35L41_VALID_PDATA;
+ if (ret >= 0) {
+ gpio2->func = val;
+ gpio2->valid = true;
+ }
+
+ hw_cfg->valid = true;
return 0;
}
--
2.35.1
Having CS35L41_PWR_CTRL2 on cs35l41_hda_config overwrites the boost
configuration for internal boost.
So move it to the initialization part and use regmap_update_bits to
only change the correct bits.
Signed-off-by: Lucas Tanure <[email protected]>
---
include/sound/cs35l41.h | 1 +
sound/pci/hda/cs35l41_hda.c | 13 ++++++++-----
2 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/include/sound/cs35l41.h b/include/sound/cs35l41.h
index fbf38f32e36d..a8537bccedcf 100644
--- a/include/sound/cs35l41.h
+++ b/include/sound/cs35l41.h
@@ -661,6 +661,7 @@
#define CS35L41_GLOBAL_EN_SHIFT 0
#define CS35L41_BST_EN_MASK 0x0030
#define CS35L41_BST_EN_SHIFT 4
+#define CS35L41_BST_DIS_FET_OFF 0x00
#define CS35L41_BST_EN_DEFAULT 0x2
#define CS35L41_AMP_EN_SHIFT 0
#define CS35L41_AMP_EN_MASK 1
diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c
index b3cc7db3fc42..3b8167d1ccc1 100644
--- a/sound/pci/hda/cs35l41_hda.c
+++ b/sound/pci/hda/cs35l41_hda.c
@@ -25,7 +25,6 @@ static const struct reg_sequence cs35l41_hda_config[] = {
{ CS35L41_DAC_PCM1_SRC, 0x00000008 }, // DACPCM1_SRC = ASPRX1
{ CS35L41_AMP_DIG_VOL_CTRL, 0x00000000 }, // AMP_VOL_PCM 0.0 dB
{ CS35L41_AMP_GAIN_CTRL, 0x00000084 }, // AMP_GAIN_PCM 4.5 dB
- { CS35L41_PWR_CTRL2, 0x00000001 }, // AMP_EN = 1
};
static const struct reg_sequence cs35l41_hda_mute[] = {
@@ -34,7 +33,6 @@ static const struct reg_sequence cs35l41_hda_mute[] = {
};
static const struct reg_sequence cs35l41_hda_start_bst[] = {
- { CS35L41_PWR_CTRL2, 0x00000021 }, // BST_EN = 10, AMP_EN = 1
{ CS35L41_PWR_CTRL1, 0x00000001, 3000}, // set GLOBAL_EN = 1
};
@@ -94,7 +92,6 @@ static const struct reg_sequence cs35l41_active_to_safe[] = {
{ 0x00000040, 0x00000055 },
{ 0x00000040, 0x000000AA },
{ 0x00007438, 0x00585941 },
- { CS35L41_PWR_CTRL2, 0x00000000 }, // AMP_EN = 0
{ CS35L41_PWR_CTRL1, 0x00000000 },
{ 0x0000742C, 0x00000009, 2000 },
{ 0x00007438, 0x00580941 },
@@ -144,6 +141,8 @@ static void cs35l41_hda_playback_hook(struct device *dev, int action)
case HDA_GEN_PCM_ACT_OPEN:
ret = regmap_multi_reg_write(reg, cs35l41_hda_config,
ARRAY_SIZE(cs35l41_hda_config));
+ regmap_update_bits(reg, CS35L41_PWR_CTRL2,
+ CS35L41_AMP_EN_MASK, 1 << CS35L41_AMP_EN_SHIFT);
break;
case HDA_GEN_PCM_ACT_PREPARE:
if (reg_seq->prepare)
@@ -155,6 +154,8 @@ static void cs35l41_hda_playback_hook(struct device *dev, int action)
ret = regmap_multi_reg_write(reg, reg_seq->cleanup, reg_seq->num_cleanup);
break;
case HDA_GEN_PCM_ACT_CLOSE:
+ regmap_update_bits(reg, CS35L41_PWR_CTRL2,
+ CS35L41_AMP_EN_MASK, 0 << CS35L41_AMP_EN_SHIFT);
if (reg_seq->close)
ret = regmap_multi_reg_write(reg, reg_seq->close, reg_seq->num_close);
break;
@@ -232,8 +233,10 @@ static int cs35l41_hda_apply_properties(struct cs35l41_hda *cs35l41)
cs35l41->reg_seq = &cs35l41_hda_reg_seq_ext_bst;
else
cs35l41->reg_seq = &cs35l41_hda_reg_seq_no_bst;
- ret = regmap_multi_reg_write(cs35l41->regmap, cs35l41_reset_to_safe,
- ARRAY_SIZE(cs35l41_reset_to_safe));
+ regmap_multi_reg_write(cs35l41->regmap, cs35l41_reset_to_safe,
+ ARRAY_SIZE(cs35l41_reset_to_safe));
+ ret = regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL2, CS35L41_BST_EN_MASK,
+ CS35L41_BST_DIS_FET_OFF << CS35L41_BST_EN_SHIFT);
if (ret)
return ret;
break;
--
2.35.1
On Tue, 08 Mar 2022 17:17:29 +0000, Lucas Tanure wrote:
> From: David Rhodes <[email protected]>
>
> Document internal and external boost feature for ASoC CS35L41.
> For internal boost the following properties are required:
> - cirrus,boost-peak-milliamp
> - cirrus,boost-ind-nanohenry
> - cirrus,boost-cap-microfarad
>
> For external boost, the GPIO1 must be configured as output,
> so the following properties are required:
> - cirrus,gpio1-src-select = <1>
> - cirrus,gpio1-output-enable
>
> Signed-off-by: David Rhodes <[email protected]>
> Signed-off-by: Lucas Tanure <[email protected]>
> ---
> .../bindings/sound/cirrus,cs35l41.yaml | 44 +++++++++++++++++--
> 1 file changed, 41 insertions(+), 3 deletions(-)
>
My bot found errors running 'make DT_CHECKER_FLAGS=-m dt_binding_check'
on your patch (DT_CHECKER_FLAGS is new in v5.13):
yamllint warnings/errors:
./Documentation/devicetree/bindings/sound/cirrus,cs35l41.yaml:152:13: [warning] wrong indentation: expected 10 but found 12 (indentation)
dtschema/dtc warnings/errors:
doc reference errors (make refcheckdocs):
See https://patchwork.ozlabs.org/patch/1603100
This check can fail if there are any dependencies. The base for a patch
series is generally the most recent rc1.
If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:
pip3 install dtschema --upgrade
Please check and re-submit.
Remove cs35l41_hd_reg_sequence as it adds a layer of flexibility not needed.
As cs35l41_hda_(start/stop)_bst is a single register, it can be replaced by
regmap_update_bits with usleep_range to wait for the same 3000us that
reg_sequence had.
Signed-off-by: Lucas Tanure <[email protected]>
---
sound/pci/hda/cs35l41_hda.c | 79 ++++++++++++++++---------------------
sound/pci/hda/cs35l41_hda.h | 14 -------
2 files changed, 33 insertions(+), 60 deletions(-)
diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c
index 3b8167d1ccc1..08ce9b8005ec 100644
--- a/sound/pci/hda/cs35l41_hda.c
+++ b/sound/pci/hda/cs35l41_hda.c
@@ -32,14 +32,6 @@ static const struct reg_sequence cs35l41_hda_mute[] = {
{ CS35L41_AMP_DIG_VOL_CTRL, 0x0000A678 }, // AMP_VOL_PCM Mute
};
-static const struct reg_sequence cs35l41_hda_start_bst[] = {
- { CS35L41_PWR_CTRL1, 0x00000001, 3000}, // set GLOBAL_EN = 1
-};
-
-static const struct reg_sequence cs35l41_hda_stop_bst[] = {
- { CS35L41_PWR_CTRL1, 0x00000000, 3000}, // set GLOBAL_EN = 0
-};
-
// only on amps where GPIO1 is used to control ext. VSPK switch
static const struct reg_sequence cs35l41_start_ext_vspk[] = {
{ 0x00000040, 0x00000055 },
@@ -109,31 +101,44 @@ static const struct reg_sequence cs35l41_reset_to_safe[] = {
{ 0x00000040, 0x00000033 },
};
-static const struct cs35l41_hda_reg_sequence cs35l41_hda_reg_seq_no_bst = {
- .prepare = cs35l41_safe_to_active,
- .num_prepare = ARRAY_SIZE(cs35l41_safe_to_active),
- .cleanup = cs35l41_active_to_safe,
- .num_cleanup = ARRAY_SIZE(cs35l41_active_to_safe),
-};
+static int cs35l41_hda_global_enable(struct cs35l41_hda *cs35l41, int enable)
+{
+ int ret;
-static const struct cs35l41_hda_reg_sequence cs35l41_hda_reg_seq_ext_bst = {
- .prepare = cs35l41_start_ext_vspk,
- .num_prepare = ARRAY_SIZE(cs35l41_start_ext_vspk),
- .cleanup = cs35l41_stop_ext_vspk,
- .num_cleanup = ARRAY_SIZE(cs35l41_stop_ext_vspk),
-};
+ switch (cs35l41->hw_cfg.bst_type) {
+ case CS35L41_INT_BOOST:
+ ret = regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL1,
+ CS35L41_GLOBAL_EN_MASK,
+ enable << CS35L41_GLOBAL_EN_SHIFT);
+ usleep_range(3000, 3100);
+ break;
+ case CS35L41_EXT_BOOST:
+ if (enable)
+ ret = regmap_multi_reg_write(cs35l41->regmap, cs35l41_start_ext_vspk,
+ ARRAY_SIZE(cs35l41_start_ext_vspk));
+ else
+ ret = regmap_multi_reg_write(cs35l41->regmap, cs35l41_stop_ext_vspk,
+ ARRAY_SIZE(cs35l41_stop_ext_vspk));
+ break;
+ case CS35L41_EXT_BOOST_NO_VSPK_SWITCH:
+ if (enable)
+ ret = regmap_multi_reg_write(cs35l41->regmap, cs35l41_safe_to_active,
+ ARRAY_SIZE(cs35l41_safe_to_active));
+ else
+ ret = regmap_multi_reg_write(cs35l41->regmap, cs35l41_active_to_safe,
+ ARRAY_SIZE(cs35l41_active_to_safe));
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
-static const struct cs35l41_hda_reg_sequence cs35l41_hda_reg_seq_int_bst = {
- .prepare = cs35l41_hda_start_bst,
- .num_prepare = ARRAY_SIZE(cs35l41_hda_start_bst),
- .cleanup = cs35l41_hda_stop_bst,
- .num_cleanup = ARRAY_SIZE(cs35l41_hda_stop_bst),
+ return ret;
};
static void cs35l41_hda_playback_hook(struct device *dev, int action)
{
struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
- const struct cs35l41_hda_reg_sequence *reg_seq = cs35l41->reg_seq;
struct regmap *reg = cs35l41->regmap;
int ret = 0;
@@ -145,19 +150,15 @@ static void cs35l41_hda_playback_hook(struct device *dev, int action)
CS35L41_AMP_EN_MASK, 1 << CS35L41_AMP_EN_SHIFT);
break;
case HDA_GEN_PCM_ACT_PREPARE:
- if (reg_seq->prepare)
- ret = regmap_multi_reg_write(reg, reg_seq->prepare, reg_seq->num_prepare);
+ ret = cs35l41_hda_global_enable(cs35l41, 1);
break;
case HDA_GEN_PCM_ACT_CLEANUP:
regmap_multi_reg_write(reg, cs35l41_hda_mute, ARRAY_SIZE(cs35l41_hda_mute));
- if (reg_seq->cleanup)
- ret = regmap_multi_reg_write(reg, reg_seq->cleanup, reg_seq->num_cleanup);
+ ret = cs35l41_hda_global_enable(cs35l41, 0);
break;
case HDA_GEN_PCM_ACT_CLOSE:
regmap_update_bits(reg, CS35L41_PWR_CTRL2,
CS35L41_AMP_EN_MASK, 0 << CS35L41_AMP_EN_SHIFT);
- if (reg_seq->close)
- ret = regmap_multi_reg_write(reg, reg_seq->close, reg_seq->num_close);
break;
default:
ret = -EINVAL;
@@ -221,7 +222,6 @@ static int cs35l41_hda_apply_properties(struct cs35l41_hda *cs35l41)
switch (hw_cfg->bst_type) {
case CS35L41_INT_BOOST:
- cs35l41->reg_seq = &cs35l41_hda_reg_seq_int_bst;
ret = cs35l41_boost_config(cs35l41->dev, cs35l41->regmap,
hw_cfg->bst_ind, hw_cfg->bst_cap, hw_cfg->bst_ipk);
if (ret)
@@ -229,10 +229,6 @@ static int cs35l41_hda_apply_properties(struct cs35l41_hda *cs35l41)
break;
case CS35L41_EXT_BOOST:
case CS35L41_EXT_BOOST_NO_VSPK_SWITCH:
- if (hw_cfg->bst_type == CS35L41_EXT_BOOST)
- cs35l41->reg_seq = &cs35l41_hda_reg_seq_ext_bst;
- else
- cs35l41->reg_seq = &cs35l41_hda_reg_seq_no_bst;
regmap_multi_reg_write(cs35l41->regmap, cs35l41_reset_to_safe,
ARRAY_SIZE(cs35l41_reset_to_safe));
ret = regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL2, CS35L41_BST_EN_MASK,
@@ -511,15 +507,6 @@ int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int i
if (ret)
goto err;
- if (cs35l41->reg_seq->probe) {
- ret = regmap_multi_reg_write(cs35l41->regmap, cs35l41->reg_seq->probe,
- cs35l41->reg_seq->num_probe);
- if (ret) {
- dev_err(cs35l41->dev, "Fail to apply probe reg patch: %d\n", ret);
- goto err;
- }
- }
-
ret = component_add(cs35l41->dev, &cs35l41_hda_comp_ops);
if (ret) {
dev_err(cs35l41->dev, "Register component failed: %d\n", ret);
diff --git a/sound/pci/hda/cs35l41_hda.h b/sound/pci/hda/cs35l41_hda.h
index 17f10764f174..44d9204ffdf1 100644
--- a/sound/pci/hda/cs35l41_hda.h
+++ b/sound/pci/hda/cs35l41_hda.h
@@ -27,24 +27,10 @@ enum cs35l41_hda_gpio_function {
CS35l41_SYNC,
};
-struct cs35l41_hda_reg_sequence {
- const struct reg_sequence *probe;
- unsigned int num_probe;
- const struct reg_sequence *open;
- unsigned int num_open;
- const struct reg_sequence *prepare;
- unsigned int num_prepare;
- const struct reg_sequence *cleanup;
- unsigned int num_cleanup;
- const struct reg_sequence *close;
- unsigned int num_close;
-};
-
struct cs35l41_hda {
struct device *dev;
struct regmap *regmap;
struct gpio_desc *reset_gpio;
- const struct cs35l41_hda_reg_sequence *reg_seq;
struct cs35l41_hw_cfg hw_cfg;
int irq;
--
2.35.1
On Tue, Mar 08, 2022 at 05:17:29PM +0000, Lucas Tanure wrote:
> From: David Rhodes <[email protected]>
>
> Document internal and external boost feature for ASoC CS35L41.
> For internal boost the following properties are required:
> - cirrus,boost-peak-milliamp
> - cirrus,boost-ind-nanohenry
> - cirrus,boost-cap-microfarad
>
> For external boost, the GPIO1 must be configured as output,
> so the following properties are required:
> - cirrus,gpio1-src-select = <1>
> - cirrus,gpio1-output-enable
>
> Signed-off-by: David Rhodes <[email protected]>
> Signed-off-by: Lucas Tanure <[email protected]>
> ---
> .../bindings/sound/cirrus,cs35l41.yaml | 44 +++++++++++++++++--
> 1 file changed, 41 insertions(+), 3 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/sound/cirrus,cs35l41.yaml b/Documentation/devicetree/bindings/sound/cirrus,cs35l41.yaml
> index 3235702ce402..09b515924c59 100644
> --- a/Documentation/devicetree/bindings/sound/cirrus,cs35l41.yaml
> +++ b/Documentation/devicetree/bindings/sound/cirrus,cs35l41.yaml
> @@ -75,6 +75,19 @@ properties:
> maximum: 3
> default: 2
>
> + cirrus,boost-type:
> + description:
> + Configures the type of Boost being used.
> + Internal boost requires boost-peak-milliamp, boost-ind-nanohenry and
> + boost-cap-microfarad.
> + External Boost must have GPIO1 as GPIO output. GPIO1 will be set high to
> + enable boost voltage.
> + 0 = Internal Boost
> + 1 = External Boost
> + $ref: "/schemas/types.yaml#/definitions/uint32"
> + minimum: 0
> + maximum: 1
What does not present mean? Might be better to make this boolean depending
on what you are trying to accomplish.
> +
> cirrus,gpio1-polarity-invert:
> description:
> Boolean which specifies whether the GPIO1
> @@ -131,9 +144,32 @@ required:
> - compatible
> - reg
> - "#sound-dai-cells"
> - - cirrus,boost-peak-milliamp
> - - cirrus,boost-ind-nanohenry
> - - cirrus,boost-cap-microfarad
> +
> +allOf:
> + - if:
> + properties:
> + cirrus,boost-type:
> + const: 0
Note that this will be true if cirrus,boost-type is not present. You
probably want to add 'required'.
> + then:
> + required:
> + - cirrus,boost-peak-milliamp
> + - cirrus,boost-ind-nanohenry
> + - cirrus,boost-cap-microfarad
> + else:
> + if:
> + properties:
> + cirrus,boost-type:
> + const: 1
> + then:
> + required:
> + - cirrus,gpio1-output-enable
> + - cirrus,gpio1-src-select
> + properties:
> + cirrus,boost-peak-milliamp: false
> + cirrus,boost-ind-nanohenry: false
> + cirrus,boost-cap-microfarad: false
> + cirrus,gpio1-src-select:
> + enum: [1]
>
> additionalProperties: false
>
> @@ -150,6 +186,8 @@ examples:
> VA-supply = <&dummy_vreg>;
> VP-supply = <&dummy_vreg>;
> reset-gpios = <&gpio 110 0>;
> +
> + cirrus,boost-type = <0>;
> cirrus,boost-peak-milliamp = <4500>;
> cirrus,boost-ind-nanohenry = <1000>;
> cirrus,boost-cap-microfarad = <15>;
> --
> 2.35.1
>
>
On 3/9/22 01:20, Rob Herring wrote:
> On Tue, Mar 08, 2022 at 05:17:29PM +0000, Lucas Tanure wrote:
>> From: David Rhodes <[email protected]>
>>
>> Document internal and external boost feature for ASoC CS35L41.
>> For internal boost the following properties are required:
>> - cirrus,boost-peak-milliamp
>> - cirrus,boost-ind-nanohenry
>> - cirrus,boost-cap-microfarad
>>
>> For external boost, the GPIO1 must be configured as output,
>> so the following properties are required:
>> - cirrus,gpio1-src-select = <1>
>> - cirrus,gpio1-output-enable
>>
>> Signed-off-by: David Rhodes <[email protected]>
>> Signed-off-by: Lucas Tanure <[email protected]>
>> ---
>> .../bindings/sound/cirrus,cs35l41.yaml | 44 +++++++++++++++++--
>> 1 file changed, 41 insertions(+), 3 deletions(-)
>>
>> diff --git a/Documentation/devicetree/bindings/sound/cirrus,cs35l41.yaml b/Documentation/devicetree/bindings/sound/cirrus,cs35l41.yaml
>> index 3235702ce402..09b515924c59 100644
>> --- a/Documentation/devicetree/bindings/sound/cirrus,cs35l41.yaml
>> +++ b/Documentation/devicetree/bindings/sound/cirrus,cs35l41.yaml
>> @@ -75,6 +75,19 @@ properties:
>> maximum: 3
>> default: 2
>>
>> + cirrus,boost-type:
>> + description:
>> + Configures the type of Boost being used.
>> + Internal boost requires boost-peak-milliamp, boost-ind-nanohenry and
>> + boost-cap-microfarad.
>> + External Boost must have GPIO1 as GPIO output. GPIO1 will be set high to
>> + enable boost voltage.
>> + 0 = Internal Boost
>> + 1 = External Boost
>> + $ref: "/schemas/types.yaml#/definitions/uint32"
>> + minimum: 0
>> + maximum: 1
>
> What does not present mean? Might be better to make this boolean depending
> on what you are trying to accomplish.
Not present means Internal boost. There will be other types of boost in
the future, so I would like to keep it as is.
>
>> +
>> cirrus,gpio1-polarity-invert:
>> description:
>> Boolean which specifies whether the GPIO1
>> @@ -131,9 +144,32 @@ required:
>> - compatible
>> - reg
>> - "#sound-dai-cells"
>> - - cirrus,boost-peak-milliamp
>> - - cirrus,boost-ind-nanohenry
>> - - cirrus,boost-cap-microfarad
>> +
>> +allOf:
>> + - if:
>> + properties:
>> + cirrus,boost-type:
>> + const: 0
>
> Note that this will be true if cirrus,boost-type is not present. You
> probably want to add 'required'.
Yes, that's expected. We want to continue to support old device trees
without boost type, and for that case it sets to internal boost.
>
>> + then:
>> + required:
>> + - cirrus,boost-peak-milliamp
>> + - cirrus,boost-ind-nanohenry
>> + - cirrus,boost-cap-microfarad
>> + else:
>> + if:
>> + properties:
>> + cirrus,boost-type:
>> + const: 1
>> + then:
>> + required:
>> + - cirrus,gpio1-output-enable
>> + - cirrus,gpio1-src-select
>> + properties:
>> + cirrus,boost-peak-milliamp: false
>> + cirrus,boost-ind-nanohenry: false
>> + cirrus,boost-cap-microfarad: false
>> + cirrus,gpio1-src-select:
>> + enum: [1]
>>
>> additionalProperties: false
>>
>> @@ -150,6 +186,8 @@ examples:
>> VA-supply = <&dummy_vreg>;
>> VP-supply = <&dummy_vreg>;
>> reset-gpios = <&gpio 110 0>;
>> +
>> + cirrus,boost-type = <0>;
>> cirrus,boost-peak-milliamp = <4500>;
>> cirrus,boost-ind-nanohenry = <1000>;
>> cirrus,boost-cap-microfarad = <15>;
>> --
>> 2.35.1
>>
>>
On Tue, Mar 08, 2022 at 05:17:30PM +0000, Lucas Tanure wrote:
> 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 <[email protected]>
> ---
Acked-by: Charles Keepax <[email protected]>
Thanks,
Charles
On Tue, Mar 08, 2022 at 05:17:29PM +0000, Lucas Tanure wrote:
> From: David Rhodes <[email protected]>
>
> Document internal and external boost feature for ASoC CS35L41.
> For internal boost the following properties are required:
> - cirrus,boost-peak-milliamp
> - cirrus,boost-ind-nanohenry
> - cirrus,boost-cap-microfarad
>
> For external boost, the GPIO1 must be configured as output,
> so the following properties are required:
> - cirrus,gpio1-src-select = <1>
> - cirrus,gpio1-output-enable
>
> Signed-off-by: David Rhodes <[email protected]>
> Signed-off-by: Lucas Tanure <[email protected]>
> ---
Acked-by: Charles Keepax <[email protected]>
Thanks,
Charles