[PATCHv3 0/5] ASoC: da7213: support for usage with simple-card
Hi,
This extends the da7213 driver to be used with simple-audio-card in combination with a fixed clock. Here is a snippet of the downstream board's DT, that is supposed to be supported by this patchset.
--------------------------------------------------------------------- / { sound { compatible = "simple-audio-card"; simple-audio-card,name = "audio-card"; simple-audio-card,format = "i2s"; simple-audio-card,bitclock-master = <&dailink_master>; simple-audio-card,frame-master = <&dailink_master>;
simple-audio-card,widgets = "Speaker", "Ext Spk"; simple-audio-card,audio-routing = "Ext Spk", "LINE";
simple-audio-card,cpu { sound-dai = <&ssi1>; };
dailink_master: simple-audio-card,codec { sound-dai = <&codec>; }; };
clk_ext_audio_codec: clock-codec { compatible = "fixed-clock"; #clock-cells = <0>; clock-frequency = <12288000>; }; };
&i2c1 { codec: audio-codec@1a { compatible = "dlg,da7212"; reg = <0x1a>; #sound-dai-cells = <0>; VDDA-supply = <®_2v5_audio>; VDDSP-supply = <®_5v0_audio>; VDDMIC-supply = <®_3v3_audio>; VDDIO-supply = <®_3v3_audio>; clocks = <&clk_ext_audio_codec>; clock-names = "mclk"; }; }; ---------------------------------------------------------------------
This is mostly a resend of PATCHv2. There was quite a bit of discussion for the last patch. As far as I can see no better solution was found and the patch is fine as is. Sorry for the delay in sending another revision.
Changes since PATCHv2: * https://lore.kernel.org/alsa-devel/20191120152406.2744-1-sebastian.reichel@c... * dropped patch converting DA7213 into selectable Kconfig option (merged) * fix compatible string in patch 1 (DT binding) as pointed out by Adam Thomson * collected Reviewed-by from Adam Thomson for patch 2-4
Changes since PATCHv1: * https://lore.kernel.org/alsa-devel/20191108174843.11227-1-sebastian.reichel@... * add patch adding da7212 compatible to DT bindings * update regulator patch, so that VDDA is enabled together with VDDIO while the device is enabled to avoid device reset * update clock patch, so that automatic PLL handling is not enabled when PLL is configured manually * update clock patch, so that automatic PLL is disabled when the device is suspended * update clock patch, so that automatic PLL is configured into bypass mode when possible
-- Sebastian
Sebastian Reichel (5): ASoC: da7213: Add da7212 DT compatible ASoC: da7213: Add regulator support ASoC: da7213: move set_sysclk to codec level ASoC: da7213: move set_pll to codec level ASoC: da7213: add default clock handling
.../devicetree/bindings/sound/da7213.txt | 8 +- sound/soc/codecs/da7213.c | 172 ++++++++++++++++-- sound/soc/codecs/da7213.h | 11 ++ 3 files changed, 175 insertions(+), 16 deletions(-)
This adds a compatible for da7212. It's handled exactly the same way as DA7213 and follows the ACPI bindings.
Signed-off-by: Sebastian Reichel sebastian.reichel@collabora.com --- PATCHv2 -> PATCHv3: fixed typo in DT binding file's compatible string --- Documentation/devicetree/bindings/sound/da7213.txt | 4 ++-- sound/soc/codecs/da7213.c | 1 + 2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/sound/da7213.txt b/Documentation/devicetree/bindings/sound/da7213.txt index 58902802d56c..69ed23b25e25 100644 --- a/Documentation/devicetree/bindings/sound/da7213.txt +++ b/Documentation/devicetree/bindings/sound/da7213.txt @@ -1,9 +1,9 @@ -Dialog Semiconductor DA7213 Audio Codec bindings +Dialog Semiconductor DA7212/DA7213 Audio Codec bindings
======
Required properties: -- compatible : Should be "dlg,da7213" +- compatible : Should be "dlg,da7212" or "dlg,da7213" - reg: Specifies the I2C slave address
Optional properties: diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c index 925a03996db4..aff306bb58df 100644 --- a/sound/soc/codecs/da7213.c +++ b/sound/soc/codecs/da7213.c @@ -1571,6 +1571,7 @@ static int da7213_set_bias_level(struct snd_soc_component *component, #if defined(CONFIG_OF) /* DT */ static const struct of_device_id da7213_of_match[] = { + { .compatible = "dlg,da7212", }, { .compatible = "dlg,da7213", }, { } };
This adds support for most regulators of da7212 for improved power management. The only thing skipped was the speaker supply, which has some undocumented dependencies. It's supposed to be either always-enabled or always-disabled.
Reviewed-by: Adam Thomson Adam.Thomson.Opensource@diasemi.com Signed-off-by: Sebastian Reichel sebastian.reichel@collabora.com --- .../devicetree/bindings/sound/da7213.txt | 4 + sound/soc/codecs/da7213.c | 79 ++++++++++++++++++- sound/soc/codecs/da7213.h | 9 +++ 3 files changed, 91 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/sound/da7213.txt b/Documentation/devicetree/bindings/sound/da7213.txt index 69ed23b25e25..94584c96c4ae 100644 --- a/Documentation/devicetree/bindings/sound/da7213.txt +++ b/Documentation/devicetree/bindings/sound/da7213.txt @@ -21,6 +21,10 @@ Optional properties: - dlg,dmic-clkrate : DMIC clock frequency (Hz). [<1500000>, <3000000>]
+ - VDDA-supply : Regulator phandle for Analogue power supply + - VDDMIC-supply : Regulator phandle for Mic Bias + - VDDIO-supply : Regulator phandle for I/O power supply + ======
Example: diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c index aff306bb58df..0359249118d0 100644 --- a/sound/soc/codecs/da7213.c +++ b/sound/soc/codecs/da7213.c @@ -19,6 +19,7 @@ #include <linux/module.h> #include <sound/pcm.h> #include <sound/pcm_params.h> +#include <linux/pm_runtime.h> #include <sound/soc.h> #include <sound/initval.h> #include <sound/tlv.h> @@ -806,6 +807,11 @@ static int da7213_dai_event(struct snd_soc_dapm_widget *w, */
static const struct snd_soc_dapm_widget da7213_dapm_widgets[] = { + /* + * Power Supply + */ + SND_SOC_DAPM_REGULATOR_SUPPLY("VDDMIC", 0, 0), + /* * Input & Output */ @@ -932,6 +938,9 @@ static const struct snd_soc_dapm_route da7213_audio_map[] = { /* Dest Connecting Widget source */
/* Input path */ + {"Mic Bias 1", NULL, "VDDMIC"}, + {"Mic Bias 2", NULL, "VDDMIC"}, + {"MIC1", NULL, "Mic Bias 1"}, {"MIC2", NULL, "Mic Bias 2"},
@@ -1691,6 +1700,8 @@ static int da7213_probe(struct snd_soc_component *component) { struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component);
+ pm_runtime_get_sync(component->dev); + /* Default to using ALC auto offset calibration mode. */ snd_soc_component_update_bits(component, DA7213_ALC_CTRL1, DA7213_ALC_CALIB_MODE_MAN, 0); @@ -1811,6 +1822,8 @@ static int da7213_probe(struct snd_soc_component *component) DA7213_DMIC_CLK_RATE_MASK, dmic_cfg); }
+ pm_runtime_put_sync(component->dev); + /* Check if MCLK provided */ da7213->mclk = devm_clk_get(component->dev, "mclk"); if (IS_ERR(da7213->mclk)) { @@ -1848,11 +1861,22 @@ static const struct regmap_config da7213_regmap_config = { .cache_type = REGCACHE_RBTREE, };
+static void da7213_power_off(void *data) +{ + struct da7213_priv *da7213 = data; + regulator_bulk_disable(DA7213_NUM_SUPPLIES, da7213->supplies); +} + +static const char *da7213_supply_names[DA7213_NUM_SUPPLIES] = { + [DA7213_SUPPLY_VDDA] = "VDDA", + [DA7213_SUPPLY_VDDIO] = "VDDIO", +}; + static int da7213_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct da7213_priv *da7213; - int ret; + int i, ret;
da7213 = devm_kzalloc(&i2c->dev, sizeof(*da7213), GFP_KERNEL); if (!da7213) @@ -1860,6 +1884,25 @@ static int da7213_i2c_probe(struct i2c_client *i2c,
i2c_set_clientdata(i2c, da7213);
+ /* Get required supplies */ + for (i = 0; i < DA7213_NUM_SUPPLIES; ++i) + da7213->supplies[i].supply = da7213_supply_names[i]; + + ret = devm_regulator_bulk_get(&i2c->dev, DA7213_NUM_SUPPLIES, + da7213->supplies); + if (ret) { + dev_err(&i2c->dev, "Failed to get supplies: %d\n", ret); + return ret; + } + + ret = regulator_bulk_enable(DA7213_NUM_SUPPLIES, da7213->supplies); + if (ret < 0) + return ret; + + ret = devm_add_action_or_reset(&i2c->dev, da7213_power_off, da7213); + if (ret < 0) + return ret; + da7213->regmap = devm_regmap_init_i2c(i2c, &da7213_regmap_config); if (IS_ERR(da7213->regmap)) { ret = PTR_ERR(da7213->regmap); @@ -1867,6 +1910,11 @@ static int da7213_i2c_probe(struct i2c_client *i2c, return ret; }
+ pm_runtime_set_autosuspend_delay(&i2c->dev, 100); + pm_runtime_use_autosuspend(&i2c->dev); + pm_runtime_set_active(&i2c->dev); + pm_runtime_enable(&i2c->dev); + ret = devm_snd_soc_register_component(&i2c->dev, &soc_component_dev_da7213, &da7213_dai, 1); if (ret < 0) { @@ -1876,6 +1924,34 @@ static int da7213_i2c_probe(struct i2c_client *i2c, return ret; }
+static int __maybe_unused da7213_runtime_suspend(struct device *dev) +{ + struct da7213_priv *da7213 = dev_get_drvdata(dev); + + regcache_cache_only(da7213->regmap, true); + regcache_mark_dirty(da7213->regmap); + regulator_bulk_disable(DA7213_NUM_SUPPLIES, da7213->supplies); + + return 0; +} + +static int __maybe_unused da7213_runtime_resume(struct device *dev) +{ + struct da7213_priv *da7213 = dev_get_drvdata(dev); + int ret; + + ret = regulator_bulk_enable(DA7213_NUM_SUPPLIES, da7213->supplies); + if (ret < 0) + return ret; + regcache_cache_only(da7213->regmap, false); + regcache_sync(da7213->regmap); + return 0; +} + +static const struct dev_pm_ops da7213_pm = { + SET_RUNTIME_PM_OPS(da7213_runtime_suspend, da7213_runtime_resume, NULL) +}; + static const struct i2c_device_id da7213_i2c_id[] = { { "da7213", 0 }, { } @@ -1888,6 +1964,7 @@ static struct i2c_driver da7213_i2c_driver = { .name = "da7213", .of_match_table = of_match_ptr(da7213_of_match), .acpi_match_table = ACPI_PTR(da7213_acpi_match), + .pm = &da7213_pm, }, .probe = da7213_i2c_probe, .id_table = da7213_i2c_id, diff --git a/sound/soc/codecs/da7213.h b/sound/soc/codecs/da7213.h index 3250a3821fcc..3890829dfb6e 100644 --- a/sound/soc/codecs/da7213.h +++ b/sound/soc/codecs/da7213.h @@ -12,6 +12,7 @@
#include <linux/clk.h> #include <linux/regmap.h> +#include <linux/regulator/consumer.h> #include <sound/da7213.h>
/* @@ -521,9 +522,17 @@ enum da7213_sys_clk { DA7213_SYSCLK_PLL_32KHZ };
+/* Regulators */ +enum da7213_supplies { + DA7213_SUPPLY_VDDA = 0, + DA7213_SUPPLY_VDDIO, + DA7213_NUM_SUPPLIES, +}; + /* Codec private data */ struct da7213_priv { struct regmap *regmap; + struct regulator_bulk_data supplies[DA7213_NUM_SUPPLIES]; struct clk *mclk; unsigned int mclk_rate; int clk_src;
Move set_sysclk function to component level, so that it can be used at both component and DAI level.
Reviewed-by: Adam Thomson Adam.Thomson.Opensource@diasemi.com Signed-off-by: Sebastian Reichel sebastian.reichel@collabora.com --- sound/soc/codecs/da7213.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c index 0359249118d0..9686948b16ea 100644 --- a/sound/soc/codecs/da7213.c +++ b/sound/soc/codecs/da7213.c @@ -1343,10 +1343,10 @@ static int da7213_mute(struct snd_soc_dai *dai, int mute) #define DA7213_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
-static int da7213_set_dai_sysclk(struct snd_soc_dai *codec_dai, - int clk_id, unsigned int freq, int dir) +static int da7213_set_component_sysclk(struct snd_soc_component *component, + int clk_id, int source, + unsigned int freq, int dir) { - struct snd_soc_component *component = codec_dai->component; struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component); int ret = 0;
@@ -1354,7 +1354,7 @@ static int da7213_set_dai_sysclk(struct snd_soc_dai *codec_dai, return 0;
if (((freq < 5000000) && (freq != 32768)) || (freq > 54000000)) { - dev_err(codec_dai->dev, "Unsupported MCLK value %d\n", + dev_err(component->dev, "Unsupported MCLK value %d\n", freq); return -EINVAL; } @@ -1370,7 +1370,7 @@ static int da7213_set_dai_sysclk(struct snd_soc_dai *codec_dai, DA7213_PLL_MCLK_SQR_EN); break; default: - dev_err(codec_dai->dev, "Unknown clock source %d\n", clk_id); + dev_err(component->dev, "Unknown clock source %d\n", clk_id); return -EINVAL; }
@@ -1380,7 +1380,7 @@ static int da7213_set_dai_sysclk(struct snd_soc_dai *codec_dai, freq = clk_round_rate(da7213->mclk, freq); ret = clk_set_rate(da7213->mclk, freq); if (ret) { - dev_err(codec_dai->dev, "Failed to set clock rate %d\n", + dev_err(component->dev, "Failed to set clock rate %d\n", freq); return ret; } @@ -1507,7 +1507,6 @@ static int da7213_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, static const struct snd_soc_dai_ops da7213_dai_ops = { .hw_params = da7213_hw_params, .set_fmt = da7213_set_dai_fmt, - .set_sysclk = da7213_set_dai_sysclk, .set_pll = da7213_set_dai_pll, .digital_mute = da7213_mute, }; @@ -1845,6 +1844,7 @@ static const struct snd_soc_component_driver soc_component_dev_da7213 = { .num_dapm_widgets = ARRAY_SIZE(da7213_dapm_widgets), .dapm_routes = da7213_audio_map, .num_dapm_routes = ARRAY_SIZE(da7213_audio_map), + .set_sysclk = da7213_set_component_sysclk, .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1,
Move set_pll function to component level, so that it can be used at both component and DAI level.
Reviewed-by: Adam Thomson Adam.Thomson.Opensource@diasemi.com Signed-off-by: Sebastian Reichel sebastian.reichel@collabora.com --- sound/soc/codecs/da7213.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c index 9686948b16ea..3e6ad996741b 100644 --- a/sound/soc/codecs/da7213.c +++ b/sound/soc/codecs/da7213.c @@ -1392,10 +1392,10 @@ static int da7213_set_component_sysclk(struct snd_soc_component *component, }
/* Supported PLL input frequencies are 32KHz, 5MHz - 54MHz. */ -static int da7213_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, - int source, unsigned int fref, unsigned int fout) +static int da7213_set_component_pll(struct snd_soc_component *component, + int pll_id, int source, + unsigned int fref, unsigned int fout) { - struct snd_soc_component *component = codec_dai->component; struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component);
u8 pll_ctrl, indiv_bits, indiv; @@ -1507,7 +1507,6 @@ static int da7213_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, static const struct snd_soc_dai_ops da7213_dai_ops = { .hw_params = da7213_hw_params, .set_fmt = da7213_set_dai_fmt, - .set_pll = da7213_set_dai_pll, .digital_mute = da7213_mute, };
@@ -1845,6 +1844,7 @@ static const struct snd_soc_component_driver soc_component_dev_da7213 = { .dapm_routes = da7213_audio_map, .num_dapm_routes = ARRAY_SIZE(da7213_audio_map), .set_sysclk = da7213_set_component_sysclk, + .set_pll = da7213_set_component_pll, .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1,
This adds default clock/PLL configuration to the driver for usage with generic drivers like simple-card for usage with a fixed rate clock.
Signed-off-by: Sebastian Reichel sebastian.reichel@collabora.com --- sound/soc/codecs/da7213.c | 76 ++++++++++++++++++++++++++++++++++++--- sound/soc/codecs/da7213.h | 2 ++ 2 files changed, 73 insertions(+), 5 deletions(-)
diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c index 3e6ad996741b..4a0edd3b7f83 100644 --- a/sound/soc/codecs/da7213.c +++ b/sound/soc/codecs/da7213.c @@ -1156,6 +1156,7 @@ static int da7213_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_component *component = dai->component; + struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component); u8 dai_ctrl = 0; u8 fs;
@@ -1181,33 +1182,43 @@ static int da7213_hw_params(struct snd_pcm_substream *substream, switch (params_rate(params)) { case 8000: fs = DA7213_SR_8000; + da7213->out_rate = DA7213_PLL_FREQ_OUT_98304000; break; case 11025: fs = DA7213_SR_11025; + da7213->out_rate = DA7213_PLL_FREQ_OUT_90316800; break; case 12000: fs = DA7213_SR_12000; + da7213->out_rate = DA7213_PLL_FREQ_OUT_98304000; break; case 16000: fs = DA7213_SR_16000; + da7213->out_rate = DA7213_PLL_FREQ_OUT_98304000; break; case 22050: fs = DA7213_SR_22050; + da7213->out_rate = DA7213_PLL_FREQ_OUT_90316800; break; case 32000: fs = DA7213_SR_32000; + da7213->out_rate = DA7213_PLL_FREQ_OUT_98304000; break; case 44100: fs = DA7213_SR_44100; + da7213->out_rate = DA7213_PLL_FREQ_OUT_90316800; break; case 48000: fs = DA7213_SR_48000; + da7213->out_rate = DA7213_PLL_FREQ_OUT_98304000; break; case 88200: fs = DA7213_SR_88200; + da7213->out_rate = DA7213_PLL_FREQ_OUT_90316800; break; case 96000: fs = DA7213_SR_96000; + da7213->out_rate = DA7213_PLL_FREQ_OUT_98304000; break; default: return -EINVAL; @@ -1392,9 +1403,9 @@ static int da7213_set_component_sysclk(struct snd_soc_component *component, }
/* Supported PLL input frequencies are 32KHz, 5MHz - 54MHz. */ -static int da7213_set_component_pll(struct snd_soc_component *component, - int pll_id, int source, - unsigned int fref, unsigned int fout) +static int _da7213_set_component_pll(struct snd_soc_component *component, + int pll_id, int source, + unsigned int fref, unsigned int fout) { struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component);
@@ -1503,6 +1514,16 @@ static int da7213_set_component_pll(struct snd_soc_component *component, return 0; }
+static int da7213_set_component_pll(struct snd_soc_component *component, + int pll_id, int source, + unsigned int fref, unsigned int fout) +{ + struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component); + da7213->fixed_clk_auto_pll = false; + + return _da7213_set_component_pll(component, pll_id, source, fref, fout); +} + /* DAI operations */ static const struct snd_soc_dai_ops da7213_dai_ops = { .hw_params = da7213_hw_params, @@ -1532,6 +1553,43 @@ static struct snd_soc_dai_driver da7213_dai = { .symmetric_rates = 1, };
+static int da7213_set_auto_pll(struct snd_soc_component *component, bool enable) +{ + struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component); + int mode; + + if (!da7213->fixed_clk_auto_pll) + return 0; + + da7213->mclk_rate = clk_get_rate(da7213->mclk); + + if (enable) + mode = DA7213_SYSCLK_PLL; + else + mode = DA7213_SYSCLK_MCLK; + + switch (da7213->out_rate) { + case DA7213_PLL_FREQ_OUT_90316800: + if (da7213->mclk_rate == 11289600 || + da7213->mclk_rate == 22579200 || + da7213->mclk_rate == 45158400) + mode = DA7213_SYSCLK_MCLK; + break; + case DA7213_PLL_FREQ_OUT_98304000: + if (da7213->mclk_rate == 12288000 || + da7213->mclk_rate == 24576000 || + da7213->mclk_rate == 49152000) + mode = DA7213_SYSCLK_MCLK; + + break; + default: + return -1; + } + + return _da7213_set_component_pll(component, 0, mode, + da7213->mclk_rate, da7213->out_rate); +} + static int da7213_set_bias_level(struct snd_soc_component *component, enum snd_soc_bias_level level) { @@ -1551,6 +1609,8 @@ static int da7213_set_bias_level(struct snd_soc_component *component, "Failed to enable mclk\n"); return ret; } + + da7213_set_auto_pll(component, true); } } break; @@ -1562,8 +1622,10 @@ static int da7213_set_bias_level(struct snd_soc_component *component, DA7213_VMID_EN | DA7213_BIAS_EN); } else { /* Remove MCLK */ - if (da7213->mclk) + if (da7213->mclk) { + da7213_set_auto_pll(component, false); clk_disable_unprepare(da7213->mclk); + } } break; case SND_SOC_BIAS_OFF: @@ -1693,7 +1755,6 @@ static struct da7213_platform_data return pdata; }
- static int da7213_probe(struct snd_soc_component *component) { struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component); @@ -1829,6 +1890,11 @@ static int da7213_probe(struct snd_soc_component *component) return PTR_ERR(da7213->mclk); else da7213->mclk = NULL; + } else { + /* Do automatic PLL handling assuming fixed clock until + * set_pll() has been called. This makes the codec usable + * with the simple-audio-card driver. */ + da7213->fixed_clk_auto_pll = true; }
return 0; diff --git a/sound/soc/codecs/da7213.h b/sound/soc/codecs/da7213.h index 3890829dfb6e..97ccf0ddd2be 100644 --- a/sound/soc/codecs/da7213.h +++ b/sound/soc/codecs/da7213.h @@ -535,10 +535,12 @@ struct da7213_priv { struct regulator_bulk_data supplies[DA7213_NUM_SUPPLIES]; struct clk *mclk; unsigned int mclk_rate; + unsigned int out_rate; int clk_src; bool master; bool alc_calib_auto; bool alc_en; + bool fixed_clk_auto_pll; struct da7213_platform_data *pdata; };
On 11 May 2020 14:26, Sebastian Reichel wrote:
This adds default clock/PLL configuration to the driver for usage with generic drivers like simple-card for usage with a fixed rate clock.
Signed-off-by: Sebastian Reichel sebastian.reichel@collabora.com
sound/soc/codecs/da7213.c | 76 ++++++++++++++++++++++++++++++++++++--- sound/soc/codecs/da7213.h | 2 ++ 2 files changed, 73 insertions(+), 5 deletions(-)
diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c index 3e6ad996741b..4a0edd3b7f83 100644 --- a/sound/soc/codecs/da7213.c +++ b/sound/soc/codecs/da7213.c @@ -1156,6 +1156,7 @@ static int da7213_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_component *component = dai->component;
- struct da7213_priv *da7213 =
snd_soc_component_get_drvdata(component); u8 dai_ctrl = 0; u8 fs;
@@ -1181,33 +1182,43 @@ static int da7213_hw_params(struct snd_pcm_substream *substream, switch (params_rate(params)) { case 8000: fs = DA7213_SR_8000;
break; case 11025: fs = DA7213_SR_11025;da7213->out_rate = DA7213_PLL_FREQ_OUT_98304000;
break; case 12000: fs = DA7213_SR_12000;da7213->out_rate = DA7213_PLL_FREQ_OUT_90316800;
break; case 16000: fs = DA7213_SR_16000;da7213->out_rate = DA7213_PLL_FREQ_OUT_98304000;
break; case 22050: fs = DA7213_SR_22050;da7213->out_rate = DA7213_PLL_FREQ_OUT_98304000;
break; case 32000: fs = DA7213_SR_32000;da7213->out_rate = DA7213_PLL_FREQ_OUT_90316800;
break; case 44100: fs = DA7213_SR_44100;da7213->out_rate = DA7213_PLL_FREQ_OUT_98304000;
break; case 48000: fs = DA7213_SR_48000;da7213->out_rate = DA7213_PLL_FREQ_OUT_90316800;
break; case 88200: fs = DA7213_SR_88200;da7213->out_rate = DA7213_PLL_FREQ_OUT_98304000;
break; case 96000: fs = DA7213_SR_96000;da7213->out_rate = DA7213_PLL_FREQ_OUT_90316800;
break; default: return -EINVAL;da7213->out_rate = DA7213_PLL_FREQ_OUT_98304000;
@@ -1392,9 +1403,9 @@ static int da7213_set_component_sysclk(struct snd_soc_component *component, }
/* Supported PLL input frequencies are 32KHz, 5MHz - 54MHz. */ -static int da7213_set_component_pll(struct snd_soc_component *component,
int pll_id, int source,
unsigned int fref, unsigned int fout)
+static int _da7213_set_component_pll(struct snd_soc_component *component,
int pll_id, int source,
unsigned int fref, unsigned int fout)
{ struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component);
@@ -1503,6 +1514,16 @@ static int da7213_set_component_pll(struct snd_soc_component *component, return 0; }
+static int da7213_set_component_pll(struct snd_soc_component *component,
int pll_id, int source,
unsigned int fref, unsigned int fout)
+{
- struct da7213_priv *da7213 =
snd_soc_component_get_drvdata(component);
- da7213->fixed_clk_auto_pll = false;
- return _da7213_set_component_pll(component, pll_id, source, fref,
fout); +}
/* DAI operations */ static const struct snd_soc_dai_ops da7213_dai_ops = { .hw_params = da7213_hw_params, @@ -1532,6 +1553,43 @@ static struct snd_soc_dai_driver da7213_dai = { .symmetric_rates = 1, };
+static int da7213_set_auto_pll(struct snd_soc_component *component, bool enable) +{
- struct da7213_priv *da7213 =
snd_soc_component_get_drvdata(component);
- int mode;
- if (!da7213->fixed_clk_auto_pll)
return 0;
- da7213->mclk_rate = clk_get_rate(da7213->mclk);
- if (enable)
mode = DA7213_SYSCLK_PLL;
- else
mode = DA7213_SYSCLK_MCLK;
We still need to address the handling of the PLL when the codec is slave, and the MCLK rate is not harmonic. In that scenario we need to use the SRM feature of the PLL to synchronise the PLL with the incoming WCLK signal on the DAI. Right now your code will allow for slave mode where the PLL is enabled without SRM, regardless of whether we're acting as slave or not. Either we just don't allow for slave mode with non-harmonic frequencies or we add a bit more in this function to determine if SRM is required which shouldn't be much more code.
- switch (da7213->out_rate) {
- case DA7213_PLL_FREQ_OUT_90316800:
if (da7213->mclk_rate == 11289600 ||
da7213->mclk_rate == 22579200 ||
da7213->mclk_rate == 45158400)
mode = DA7213_SYSCLK_MCLK;
break;
- case DA7213_PLL_FREQ_OUT_98304000:
if (da7213->mclk_rate == 12288000 ||
da7213->mclk_rate == 24576000 ||
da7213->mclk_rate == 49152000)
mode = DA7213_SYSCLK_MCLK;
break;
- default:
return -1;
- }
- return _da7213_set_component_pll(component, 0, mode,
da7213->mclk_rate, da7213->out_rate);
+}
static int da7213_set_bias_level(struct snd_soc_component *component, enum snd_soc_bias_level level) { @@ -1551,6 +1609,8 @@ static int da7213_set_bias_level(struct snd_soc_component *component, "Failed to enable mclk\n"); return ret; }
} break;da7213_set_auto_pll(component, true); }
@@ -1562,8 +1622,10 @@ static int da7213_set_bias_level(struct snd_soc_component *component, DA7213_VMID_EN | DA7213_BIAS_EN); } else { /* Remove MCLK */
if (da7213->mclk)
if (da7213->mclk) {
da7213_set_auto_pll(component, false); clk_disable_unprepare(da7213->mclk);
} break; case SND_SOC_BIAS_OFF:}
@@ -1693,7 +1755,6 @@ static struct da7213_platform_data return pdata; }
static int da7213_probe(struct snd_soc_component *component) { struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component); @@ -1829,6 +1890,11 @@ static int da7213_probe(struct snd_soc_component *component) return PTR_ERR(da7213->mclk); else da7213->mclk = NULL;
} else {
/* Do automatic PLL handling assuming fixed clock until
* set_pll() has been called. This makes the codec usable
* with the simple-audio-card driver. */
da7213->fixed_clk_auto_pll = true;
}
return 0;
diff --git a/sound/soc/codecs/da7213.h b/sound/soc/codecs/da7213.h index 3890829dfb6e..97ccf0ddd2be 100644 --- a/sound/soc/codecs/da7213.h +++ b/sound/soc/codecs/da7213.h @@ -535,10 +535,12 @@ struct da7213_priv { struct regulator_bulk_data supplies[DA7213_NUM_SUPPLIES]; struct clk *mclk; unsigned int mclk_rate;
- unsigned int out_rate; int clk_src; bool master; bool alc_calib_auto; bool alc_en;
- bool fixed_clk_auto_pll; struct da7213_platform_data *pdata;
};
-- 2.26.2
On Mon, 11 May 2020 15:25:39 +0200, Sebastian Reichel wrote:
This extends the da7213 driver to be used with simple-audio-card in combination with a fixed clock. Here is a snippet of the downstream board's DT, that is supposed to be supported by this patchset.
/ { sound { compatible = "simple-audio-card"; simple-audio-card,name = "audio-card"; simple-audio-card,format = "i2s"; simple-audio-card,bitclock-master = <&dailink_master>; simple-audio-card,frame-master = <&dailink_master>;
[...]
Applied to
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.8
Thanks!
[1/5] ASoC: da7213: Add da7212 DT compatible commit: 95579eaf98f17b97dc174bb31d71902b5895bd85 [2/5] ASoC: da7213: Add regulator support commit: b2a378816d0f6780a5500f4322e5b2542d41532d [3/5] ASoC: da7213: move set_sysclk to codec level commit: 9c5c258438b23cacc4971b94d808ba8af9c5931c [4/5] ASoC: da7213: move set_pll to codec level commit: f7a8ae295ca8e96e287f497506b49b1f4b47deb4 [5/5] ASoC: da7213: add default clock handling (no commit info)
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
This adds default clock/PLL configuration to the driver for usage with generic drivers like simple-card for usage with a fixed rate clock.
Signed-off-by: Sebastian Reichel sebastian.reichel@collabora.com --- Changes since PATCHv3: * rebase to v5.8-rc1 * add SRM support for usage in slave mode with simple-card. I only tested with master mode, though. --- sound/soc/codecs/da7213.c | 83 ++++++++++++++++++++++++++++++++++++--- sound/soc/codecs/da7213.h | 2 + 2 files changed, 80 insertions(+), 5 deletions(-)
diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c index 3e6ad996741b..1a4fece20bcd 100644 --- a/sound/soc/codecs/da7213.c +++ b/sound/soc/codecs/da7213.c @@ -1156,6 +1156,7 @@ static int da7213_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_component *component = dai->component; + struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component); u8 dai_ctrl = 0; u8 fs;
@@ -1181,33 +1182,43 @@ static int da7213_hw_params(struct snd_pcm_substream *substream, switch (params_rate(params)) { case 8000: fs = DA7213_SR_8000; + da7213->out_rate = DA7213_PLL_FREQ_OUT_98304000; break; case 11025: fs = DA7213_SR_11025; + da7213->out_rate = DA7213_PLL_FREQ_OUT_90316800; break; case 12000: fs = DA7213_SR_12000; + da7213->out_rate = DA7213_PLL_FREQ_OUT_98304000; break; case 16000: fs = DA7213_SR_16000; + da7213->out_rate = DA7213_PLL_FREQ_OUT_98304000; break; case 22050: fs = DA7213_SR_22050; + da7213->out_rate = DA7213_PLL_FREQ_OUT_90316800; break; case 32000: fs = DA7213_SR_32000; + da7213->out_rate = DA7213_PLL_FREQ_OUT_98304000; break; case 44100: fs = DA7213_SR_44100; + da7213->out_rate = DA7213_PLL_FREQ_OUT_90316800; break; case 48000: fs = DA7213_SR_48000; + da7213->out_rate = DA7213_PLL_FREQ_OUT_98304000; break; case 88200: fs = DA7213_SR_88200; + da7213->out_rate = DA7213_PLL_FREQ_OUT_90316800; break; case 96000: fs = DA7213_SR_96000; + da7213->out_rate = DA7213_PLL_FREQ_OUT_98304000; break; default: return -EINVAL; @@ -1392,9 +1403,9 @@ static int da7213_set_component_sysclk(struct snd_soc_component *component, }
/* Supported PLL input frequencies are 32KHz, 5MHz - 54MHz. */ -static int da7213_set_component_pll(struct snd_soc_component *component, - int pll_id, int source, - unsigned int fref, unsigned int fout) +static int _da7213_set_component_pll(struct snd_soc_component *component, + int pll_id, int source, + unsigned int fref, unsigned int fout) { struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component);
@@ -1503,6 +1514,16 @@ static int da7213_set_component_pll(struct snd_soc_component *component, return 0; }
+static int da7213_set_component_pll(struct snd_soc_component *component, + int pll_id, int source, + unsigned int fref, unsigned int fout) +{ + struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component); + da7213->fixed_clk_auto_pll = false; + + return _da7213_set_component_pll(component, pll_id, source, fref, fout); +} + /* DAI operations */ static const struct snd_soc_dai_ops da7213_dai_ops = { .hw_params = da7213_hw_params, @@ -1532,6 +1553,50 @@ static struct snd_soc_dai_driver da7213_dai = { .symmetric_rates = 1, };
+static int da7213_set_auto_pll(struct snd_soc_component *component, bool enable) +{ + struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component); + int mode; + + if (!da7213->fixed_clk_auto_pll) + return 0; + + da7213->mclk_rate = clk_get_rate(da7213->mclk); + + if (enable) { + /* Slave mode needs SRM for non-harmonic frequencies */ + if (da7213->master) + mode = DA7213_SYSCLK_PLL; + else + mode = DA7213_SYSCLK_PLL_SRM; + + /* PLL is not required for harmonic frequencies */ + switch (da7213->out_rate) { + case DA7213_PLL_FREQ_OUT_90316800: + if (da7213->mclk_rate == 11289600 || + da7213->mclk_rate == 22579200 || + da7213->mclk_rate == 45158400) + mode = DA7213_SYSCLK_MCLK; + break; + case DA7213_PLL_FREQ_OUT_98304000: + if (da7213->mclk_rate == 12288000 || + da7213->mclk_rate == 24576000 || + da7213->mclk_rate == 49152000) + mode = DA7213_SYSCLK_MCLK; + + break; + default: + return -1; + } + } else { + /* Disable PLL in standby */ + mode = DA7213_SYSCLK_MCLK; + } + + return _da7213_set_component_pll(component, 0, mode, + da7213->mclk_rate, da7213->out_rate); +} + static int da7213_set_bias_level(struct snd_soc_component *component, enum snd_soc_bias_level level) { @@ -1551,6 +1616,8 @@ static int da7213_set_bias_level(struct snd_soc_component *component, "Failed to enable mclk\n"); return ret; } + + da7213_set_auto_pll(component, true); } } break; @@ -1562,8 +1629,10 @@ static int da7213_set_bias_level(struct snd_soc_component *component, DA7213_VMID_EN | DA7213_BIAS_EN); } else { /* Remove MCLK */ - if (da7213->mclk) + if (da7213->mclk) { + da7213_set_auto_pll(component, false); clk_disable_unprepare(da7213->mclk); + } } break; case SND_SOC_BIAS_OFF: @@ -1693,7 +1762,6 @@ static struct da7213_platform_data return pdata; }
- static int da7213_probe(struct snd_soc_component *component) { struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component); @@ -1829,6 +1897,11 @@ static int da7213_probe(struct snd_soc_component *component) return PTR_ERR(da7213->mclk); else da7213->mclk = NULL; + } else { + /* Do automatic PLL handling assuming fixed clock until + * set_pll() has been called. This makes the codec usable + * with the simple-audio-card driver. */ + da7213->fixed_clk_auto_pll = true; }
return 0; diff --git a/sound/soc/codecs/da7213.h b/sound/soc/codecs/da7213.h index 3890829dfb6e..97ccf0ddd2be 100644 --- a/sound/soc/codecs/da7213.h +++ b/sound/soc/codecs/da7213.h @@ -535,10 +535,12 @@ struct da7213_priv { struct regulator_bulk_data supplies[DA7213_NUM_SUPPLIES]; struct clk *mclk; unsigned int mclk_rate; + unsigned int out_rate; int clk_src; bool master; bool alc_calib_auto; bool alc_en; + bool fixed_clk_auto_pll; struct da7213_platform_data *pdata; };
On 26 June 2020 17:46, Sebastian Reichel wrote:
This adds default clock/PLL configuration to the driver for usage with generic drivers like simple-card for usage with a fixed rate clock.
Signed-off-by: Sebastian Reichel sebastian.reichel@collabora.com
Looks good. Thanks for the work here.
Reviewed-by: Adam Thomson Adam.Thomson.Opensource@diasemi.com
Changes since PATCHv3:
- rebase to v5.8-rc1
- add SRM support for usage in slave mode with simple-card. I only tested with master mode, though.
sound/soc/codecs/da7213.c | 83 ++++++++++++++++++++++++++++++++++++--- sound/soc/codecs/da7213.h | 2 + 2 files changed, 80 insertions(+), 5 deletions(-)
diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c index 3e6ad996741b..1a4fece20bcd 100644 --- a/sound/soc/codecs/da7213.c +++ b/sound/soc/codecs/da7213.c @@ -1156,6 +1156,7 @@ static int da7213_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_component *component = dai->component;
- struct da7213_priv *da7213 =
snd_soc_component_get_drvdata(component); u8 dai_ctrl = 0; u8 fs;
@@ -1181,33 +1182,43 @@ static int da7213_hw_params(struct snd_pcm_substream *substream, switch (params_rate(params)) { case 8000: fs = DA7213_SR_8000;
break; case 11025: fs = DA7213_SR_11025;da7213->out_rate = DA7213_PLL_FREQ_OUT_98304000;
break; case 12000: fs = DA7213_SR_12000;da7213->out_rate = DA7213_PLL_FREQ_OUT_90316800;
break; case 16000: fs = DA7213_SR_16000;da7213->out_rate = DA7213_PLL_FREQ_OUT_98304000;
break; case 22050: fs = DA7213_SR_22050;da7213->out_rate = DA7213_PLL_FREQ_OUT_98304000;
break; case 32000: fs = DA7213_SR_32000;da7213->out_rate = DA7213_PLL_FREQ_OUT_90316800;
break; case 44100: fs = DA7213_SR_44100;da7213->out_rate = DA7213_PLL_FREQ_OUT_98304000;
break; case 48000: fs = DA7213_SR_48000;da7213->out_rate = DA7213_PLL_FREQ_OUT_90316800;
break; case 88200: fs = DA7213_SR_88200;da7213->out_rate = DA7213_PLL_FREQ_OUT_98304000;
break; case 96000: fs = DA7213_SR_96000;da7213->out_rate = DA7213_PLL_FREQ_OUT_90316800;
break; default: return -EINVAL;da7213->out_rate = DA7213_PLL_FREQ_OUT_98304000;
@@ -1392,9 +1403,9 @@ static int da7213_set_component_sysclk(struct snd_soc_component *component, }
/* Supported PLL input frequencies are 32KHz, 5MHz - 54MHz. */ -static int da7213_set_component_pll(struct snd_soc_component *component,
int pll_id, int source,
unsigned int fref, unsigned int fout)
+static int _da7213_set_component_pll(struct snd_soc_component *component,
int pll_id, int source,
unsigned int fref, unsigned int fout)
{ struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component);
@@ -1503,6 +1514,16 @@ static int da7213_set_component_pll(struct snd_soc_component *component, return 0; }
+static int da7213_set_component_pll(struct snd_soc_component *component,
int pll_id, int source,
unsigned int fref, unsigned int fout)
+{
- struct da7213_priv *da7213 =
snd_soc_component_get_drvdata(component);
- da7213->fixed_clk_auto_pll = false;
- return _da7213_set_component_pll(component, pll_id, source, fref,
fout); +}
/* DAI operations */ static const struct snd_soc_dai_ops da7213_dai_ops = { .hw_params = da7213_hw_params, @@ -1532,6 +1553,50 @@ static struct snd_soc_dai_driver da7213_dai = { .symmetric_rates = 1, };
+static int da7213_set_auto_pll(struct snd_soc_component *component, bool enable) +{
- struct da7213_priv *da7213 =
snd_soc_component_get_drvdata(component);
- int mode;
- if (!da7213->fixed_clk_auto_pll)
return 0;
- da7213->mclk_rate = clk_get_rate(da7213->mclk);
- if (enable) {
/* Slave mode needs SRM for non-harmonic frequencies */
if (da7213->master)
mode = DA7213_SYSCLK_PLL;
else
mode = DA7213_SYSCLK_PLL_SRM;
/* PLL is not required for harmonic frequencies */
switch (da7213->out_rate) {
case DA7213_PLL_FREQ_OUT_90316800:
if (da7213->mclk_rate == 11289600 ||
da7213->mclk_rate == 22579200 ||
da7213->mclk_rate == 45158400)
mode = DA7213_SYSCLK_MCLK;
break;
case DA7213_PLL_FREQ_OUT_98304000:
if (da7213->mclk_rate == 12288000 ||
da7213->mclk_rate == 24576000 ||
da7213->mclk_rate == 49152000)
mode = DA7213_SYSCLK_MCLK;
break;
default:
return -1;
}
- } else {
/* Disable PLL in standby */
mode = DA7213_SYSCLK_MCLK;
- }
- return _da7213_set_component_pll(component, 0, mode,
da7213->mclk_rate, da7213->out_rate);
+}
static int da7213_set_bias_level(struct snd_soc_component *component, enum snd_soc_bias_level level) { @@ -1551,6 +1616,8 @@ static int da7213_set_bias_level(struct snd_soc_component *component, "Failed to enable mclk\n"); return ret; }
} break;da7213_set_auto_pll(component, true); }
@@ -1562,8 +1629,10 @@ static int da7213_set_bias_level(struct snd_soc_component *component, DA7213_VMID_EN | DA7213_BIAS_EN); } else { /* Remove MCLK */
if (da7213->mclk)
if (da7213->mclk) {
da7213_set_auto_pll(component, false); clk_disable_unprepare(da7213->mclk);
} break; case SND_SOC_BIAS_OFF:}
@@ -1693,7 +1762,6 @@ static struct da7213_platform_data return pdata; }
static int da7213_probe(struct snd_soc_component *component) { struct da7213_priv *da7213 = snd_soc_component_get_drvdata(component); @@ -1829,6 +1897,11 @@ static int da7213_probe(struct snd_soc_component *component) return PTR_ERR(da7213->mclk); else da7213->mclk = NULL;
} else {
/* Do automatic PLL handling assuming fixed clock until
* set_pll() has been called. This makes the codec usable
* with the simple-audio-card driver. */
da7213->fixed_clk_auto_pll = true;
}
return 0;
diff --git a/sound/soc/codecs/da7213.h b/sound/soc/codecs/da7213.h index 3890829dfb6e..97ccf0ddd2be 100644 --- a/sound/soc/codecs/da7213.h +++ b/sound/soc/codecs/da7213.h @@ -535,10 +535,12 @@ struct da7213_priv { struct regulator_bulk_data supplies[DA7213_NUM_SUPPLIES]; struct clk *mclk; unsigned int mclk_rate;
- unsigned int out_rate; int clk_src; bool master; bool alc_calib_auto; bool alc_en;
- bool fixed_clk_auto_pll; struct da7213_platform_data *pdata;
};
-- 2.27.0
On Fri, 26 Jun 2020 18:46:23 +0200, Sebastian Reichel wrote:
This adds default clock/PLL configuration to the driver for usage with generic drivers like simple-card for usage with a fixed rate clock.
Applied to
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next
Thanks!
[1/1] ASoC: da7213: add default clock handling commit: 5146b6a92c1194674f21def93d7025c97ed6977f
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
participants (3)
-
Adam Thomson
-
Mark Brown
-
Sebastian Reichel