[PATCH 05/12] ASoC: cs42l42: Set correct SRC MCLK

From: Richard Fitzgerald
Date: Tue Aug 10 2021 - 11:40:10 EST


According to the datasheet the SRC MCLK must be as near as possible to
(125 * sample rate). This means it should be ~6MHz for rates up to 48k
and ~12MHz for rates above that. As per datasheet table 4-21.

Signed-off-by: Richard Fitzgerald <rf@xxxxxxxxxxxxxxxxxxxxx>
---
sound/soc/codecs/cs42l42.c | 60 ++++++++++++++++++++++++++++++----------------
sound/soc/codecs/cs42l42.h | 1 +
2 files changed, 40 insertions(+), 21 deletions(-)

diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c
index 1893d3694570..14fd70c56891 100644
--- a/sound/soc/codecs/cs42l42.c
+++ b/sound/soc/codecs/cs42l42.c
@@ -663,22 +663,6 @@ static int cs42l42_pll_config(struct snd_soc_component *component)
CS42L42_FSYNC_PULSE_WIDTH_MASK,
CS42L42_FRAC1_VAL(fsync - 1) <<
CS42L42_FSYNC_PULSE_WIDTH_SHIFT);
- /* Set the sample rates (96k or lower) */
- snd_soc_component_update_bits(component, CS42L42_FS_RATE_EN,
- CS42L42_FS_EN_MASK,
- (CS42L42_FS_EN_IASRC_96K |
- CS42L42_FS_EN_OASRC_96K) <<
- CS42L42_FS_EN_SHIFT);
- /* Set the input/output internal MCLK clock ~12 MHz */
- snd_soc_component_update_bits(component, CS42L42_IN_ASRC_CLK,
- CS42L42_CLK_IASRC_SEL_MASK,
- CS42L42_CLK_IASRC_SEL_12 <<
- CS42L42_CLK_IASRC_SEL_SHIFT);
- snd_soc_component_update_bits(component,
- CS42L42_OUT_ASRC_CLK,
- CS42L42_CLK_OASRC_SEL_MASK,
- CS42L42_CLK_OASRC_SEL_12 <<
- CS42L42_CLK_OASRC_SEL_SHIFT);
if (pll_ratio_table[i].mclk_src_sel == 0) {
/* Pass the clock straight through */
snd_soc_component_update_bits(component,
@@ -741,6 +725,34 @@ static int cs42l42_pll_config(struct snd_soc_component *component)
return -EINVAL;
}

+static void cs42l42_src_config(struct snd_soc_component *component, unsigned int sample_rate)
+{
+ unsigned int fs;
+
+ /* SRC MCLK must be as close as possible to 125 * sample rate */
+ if (sample_rate <= 48000)
+ fs = CS42L42_CLK_IASRC_SEL_6;
+ else
+ fs = CS42L42_CLK_IASRC_SEL_12;
+
+ /* Set the sample rates (96k or lower) */
+ snd_soc_component_update_bits(component,
+ CS42L42_FS_RATE_EN,
+ CS42L42_FS_EN_MASK,
+ (CS42L42_FS_EN_IASRC_96K |
+ CS42L42_FS_EN_OASRC_96K) <<
+ CS42L42_FS_EN_SHIFT);
+
+ snd_soc_component_update_bits(component,
+ CS42L42_IN_ASRC_CLK,
+ CS42L42_CLK_IASRC_SEL_MASK,
+ fs << CS42L42_CLK_IASRC_SEL_SHIFT);
+ snd_soc_component_update_bits(component,
+ CS42L42_OUT_ASRC_CLK,
+ CS42L42_CLK_OASRC_SEL_MASK,
+ fs << CS42L42_CLK_OASRC_SEL_SHIFT);
+}
+
static int cs42l42_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
{
struct snd_soc_component *component = codec_dai->component;
@@ -831,6 +843,7 @@ static int cs42l42_pcm_hw_params(struct snd_pcm_substream *substream,
unsigned int channels = params_channels(params);
unsigned int width = (params_width(params) / 8) - 1;
unsigned int val = 0;
+ int ret;

cs42l42->srate = params_rate(params);
cs42l42->bclk = snd_soc_params_to_bclk(params);
@@ -884,11 +897,16 @@ static int cs42l42_pcm_hw_params(struct snd_pcm_substream *substream,
break;
}

- /* Configure the PLL if this is the first active stream */
- if (!cs42l42->stream_use)
- return cs42l42_pll_config(component);
- else
- return 0;
+ /* Configure clocking only if this is the first active stream */
+ if (!cs42l42->stream_use) {
+ ret = cs42l42_pll_config(component);
+ if (ret)
+ return ret;
+
+ cs42l42_src_config(component, params_rate(params));
+ }
+
+ return 0;
}

static int cs42l42_set_sysclk(struct snd_soc_dai *dai,
diff --git a/sound/soc/codecs/cs42l42.h b/sound/soc/codecs/cs42l42.h
index 8734f6828f3e..addb6560c649 100644
--- a/sound/soc/codecs/cs42l42.h
+++ b/sound/soc/codecs/cs42l42.h
@@ -288,6 +288,7 @@
#define CS42L42_IN_ASRC_CLK (CS42L42_PAGE_12 + 0x0A)
#define CS42L42_CLK_IASRC_SEL_SHIFT 0
#define CS42L42_CLK_IASRC_SEL_MASK (1 << CS42L42_CLK_IASRC_SEL_SHIFT)
+#define CS42L42_CLK_IASRC_SEL_6 0
#define CS42L42_CLK_IASRC_SEL_12 1

#define CS42L42_OUT_ASRC_CLK (CS42L42_PAGE_12 + 0x0B)
--
2.11.0