summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2025-10-30 19:07:15 +0300
committerMark Brown <broonie@kernel.org>2025-10-30 19:07:15 +0300
commitdb66398fb03ee3599ec7387ceb5121b95e648eb3 (patch)
treee5cabf4ac92400f4690ebae4de2240779ecf2ed4
parent3d8096fd378b0b4dae356e6f037d03da83f559d2 (diff)
parentcf6bf51b53252284bafc7377a4d8dbf10f048b4d (diff)
downloadlinux-db66398fb03ee3599ec7387ceb5121b95e648eb3.tar.xz
Add support for an external Master Clock in the
Merge series from Herve Codina <herve.codina@bootlin.com>: The Cirrus CS4271 codec can have its Master Clock provided by an external clock when no crystal is used. This series adds support for this external Master clock.
-rw-r--r--Documentation/devicetree/bindings/sound/cirrus,cs4271.yaml10
-rw-r--r--sound/soc/codecs/cs4271.c33
2 files changed, 40 insertions, 3 deletions
diff --git a/Documentation/devicetree/bindings/sound/cirrus,cs4271.yaml b/Documentation/devicetree/bindings/sound/cirrus,cs4271.yaml
index 68fbf5cc208f..d286eb169915 100644
--- a/Documentation/devicetree/bindings/sound/cirrus,cs4271.yaml
+++ b/Documentation/devicetree/bindings/sound/cirrus,cs4271.yaml
@@ -25,6 +25,16 @@ properties:
reg:
maxItems: 1
+ clocks:
+ items:
+ - description:
+ Master clock connected to the MCLK pin if MCLK is an input (i.e. no
+ crystal used).
+
+ clock-names:
+ items:
+ - const: mclk
+
spi-cpha: true
spi-cpol: true
diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c
index 0ed73ba3625c..a24e926ba282 100644
--- a/sound/soc/codecs/cs4271.c
+++ b/sound/soc/codecs/cs4271.c
@@ -10,6 +10,7 @@
* DAPM support not implemented.
*/
+#include <linux/clk.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/delay.h>
@@ -163,6 +164,7 @@ struct cs4271_private {
/* enable soft reset workaround */
bool enable_soft_reset;
struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
+ struct clk *clk;
};
static const struct snd_soc_dapm_widget cs4271_dapm_widgets[] = {
@@ -505,6 +507,7 @@ static int cs4271_soc_suspend(struct snd_soc_component *component)
return ret;
regcache_mark_dirty(cs4271->regmap);
+ clk_disable_unprepare(cs4271->clk);
regulator_bulk_disable(ARRAY_SIZE(cs4271->supplies), cs4271->supplies);
return 0;
@@ -522,6 +525,12 @@ static int cs4271_soc_resume(struct snd_soc_component *component)
return ret;
}
+ ret = clk_prepare_enable(cs4271->clk);
+ if (ret) {
+ dev_err(component->dev, "Failed to enable clk: %d\n", ret);
+ return ret;
+ }
+
/* Do a proper reset after power up */
cs4271_reset(component);
@@ -576,22 +585,29 @@ static int cs4271_component_probe(struct snd_soc_component *component)
cs4271->enable_soft_reset = cs4271plat->enable_soft_reset;
}
+ ret = clk_prepare_enable(cs4271->clk);
+ if (ret) {
+ dev_err(component->dev, "Failed to enable clk: %d\n", ret);
+ goto err_disable_regulators;
+ }
+
/* Reset codec */
cs4271_reset(component);
ret = regcache_sync(cs4271->regmap);
if (ret < 0)
- return ret;
+ goto err_disable_clk;
ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,
CS4271_MODE2_PDN | CS4271_MODE2_CPEN,
CS4271_MODE2_PDN | CS4271_MODE2_CPEN);
if (ret < 0)
- return ret;
+ goto err_disable_clk;
ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,
CS4271_MODE2_PDN, 0);
if (ret < 0)
- return ret;
+ goto err_disable_clk;
+
/* Power-up sequence requires 85 uS */
udelay(85);
@@ -601,6 +617,12 @@ static int cs4271_component_probe(struct snd_soc_component *component)
CS4271_MODE2_MUTECAEQUB);
return 0;
+
+err_disable_clk:
+ clk_disable_unprepare(cs4271->clk);
+err_disable_regulators:
+ regulator_bulk_disable(ARRAY_SIZE(cs4271->supplies), cs4271->supplies);
+ return ret;
}
static void cs4271_component_remove(struct snd_soc_component *component)
@@ -612,6 +634,7 @@ static void cs4271_component_remove(struct snd_soc_component *component)
regcache_mark_dirty(cs4271->regmap);
regulator_bulk_disable(ARRAY_SIZE(cs4271->supplies), cs4271->supplies);
+ clk_disable_unprepare(cs4271->clk);
};
static const struct snd_soc_component_driver soc_component_dev_cs4271 = {
@@ -646,6 +669,10 @@ static int cs4271_common_probe(struct device *dev,
"error retrieving RESET GPIO\n");
gpiod_set_consumer_name(cs4271->reset, "CS4271 Reset");
+ cs4271->clk = devm_clk_get_optional(dev, "mclk");
+ if (IS_ERR(cs4271->clk))
+ return dev_err_probe(dev, PTR_ERR(cs4271->clk), "Failed to get mclk\n");
+
for (i = 0; i < ARRAY_SIZE(supply_names); i++)
cs4271->supplies[i].supply = supply_names[i];