Message ID | 20220624104712.1934484-9-daniel@zonque.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | ASoC: max98396: Some assorted fixes and additions | expand |
On 6/24/22 12:47, Daniel Mack wrote: > In TDM mode, the BSEL register value must be set according to table 5 in the > datasheet. This patch adds a lookup function and uses it in > max98396_dai_tdm_slot(). > > As the first 3 entries can also be used for non-TDM setups, the code now > re-uses the same code for such scenarios. > > max98396_set_clock() is folded into its only user for clarity. Sorry, the following hunk is missing from this patch: diff --git a/sound/soc/codecs/max98396.h b/sound/soc/codecs/max98396.h index ff330ef61568..7278c779989a 100644 --- a/sound/soc/codecs/max98396.h +++ b/sound/soc/codecs/max98396.h @@ -306,8 +306,8 @@ struct max98396_priv { unsigned int spkfb_slot; unsigned int bypass_slot; bool interleave_mode; - unsigned int ch_size; bool tdm_mode; + int tdm_max_samplerate; int device_id; }; #endif Will include it in the next round. Thanks, Daniel > > Signed-off-by: Daniel Mack <daniel@zonque.org> > --- > sound/soc/codecs/max98396.c | 124 +++++++++++++++++++++++------------- > 1 file changed, 81 insertions(+), 43 deletions(-) > > diff --git a/sound/soc/codecs/max98396.c b/sound/soc/codecs/max98396.c > index f28831f4e74b..f1657a5f2140 100644 > --- a/sound/soc/codecs/max98396.c > +++ b/sound/soc/codecs/max98396.c > @@ -438,47 +438,55 @@ static int max98396_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) > return 0; > } > > -/* BCLKs per LRCLK */ > -static const int bclk_sel_table[] = { > - 32, 48, 64, 96, 128, 192, 256, 384, 512, 320, > +/* Refer to table 5 in the datasheet */ > +static const struct max98396_pcm_config { > + int in, out, width, bsel, max_sr; > +} max98396_pcm_configs[] = { > + { .in = 2, .out = 4, .width = 16, .bsel = 0x2, /* 32 */ .max_sr = 192000 }, > + { .in = 2, .out = 6, .width = 24, .bsel = 0x3, /* 48 */ .max_sr = 192000 }, > + { .in = 2, .out = 8, .width = 32, .bsel = 0x4, /* 64 */ .max_sr = 192000 }, > + { .in = 3, .out = 15, .width = 32, .bsel = 0xd, /* 125 */ .max_sr = 192000 }, > + { .in = 4, .out = 8, .width = 16, .bsel = 0x4, /* 64 */ .max_sr = 192000 }, > + { .in = 4, .out = 12, .width = 24, .bsel = 0x5, /* 96 */ .max_sr = 192000 }, > + { .in = 4, .out = 16, .width = 32, .bsel = 0x6, /* 128 */ .max_sr = 192000 }, > + { .in = 5, .out = 15, .width = 24, .bsel = 0xd, /* 125 */ .max_sr = 192000 }, > + { .in = 7, .out = 15, .width = 16, .bsel = 0xd, /* 125 */ .max_sr = 192000 }, > + { .in = 2, .out = 4, .width = 16, .bsel = 0x2, /* 32 */ .max_sr = 96000 }, > + { .in = 2, .out = 6, .width = 24, .bsel = 0x3, /* 48 */ .max_sr = 96000 }, > + { .in = 2, .out = 8, .width = 32, .bsel = 0x4, /* 64 */ .max_sr = 96000 }, > + { .in = 3, .out = 15, .width = 32, .bsel = 0xd, /* 125 */ .max_sr = 96000 }, > + { .in = 4, .out = 8, .width = 16, .bsel = 0x4, /* 64 */ .max_sr = 96000 }, > + { .in = 4, .out = 12, .width = 24, .bsel = 0x5, /* 96 */ .max_sr = 96000 }, > + { .in = 4, .out = 16, .width = 32, .bsel = 0x6, /* 128 */ .max_sr = 96000 }, > + { .in = 5, .out = 15, .width = 24, .bsel = 0xd, /* 125 */ .max_sr = 96000 }, > + { .in = 7, .out = 15, .width = 16, .bsel = 0xd, /* 125 */ .max_sr = 96000 }, > + { .in = 7, .out = 31, .width = 32, .bsel = 0xc, /* 250 */ .max_sr = 96000 }, > + { .in = 8, .out = 16, .width = 16, .bsel = 0x6, /* 128 */ .max_sr = 96000 }, > + { .in = 8, .out = 24, .width = 24, .bsel = 0x7, /* 192 */ .max_sr = 96000 }, > + { .in = 8, .out = 32, .width = 32, .bsel = 0x8, /* 256 */ .max_sr = 96000 }, > + { .in = 10, .out = 31, .width = 24, .bsel = 0xc, /* 250 */ .max_sr = 96000 }, > + { .in = 15, .out = 31, .width = 16, .bsel = 0xc, /* 250 */ .max_sr = 96000 }, > + { .in = 16, .out = 32, .width = 16, .bsel = 0x8, /* 256 */ .max_sr = 96000 }, > + { .in = 7, .out = 31, .width = 32, .bsel = 0xc, /* 250 */ .max_sr = 48000 }, > + { .in = 10, .out = 31, .width = 24, .bsel = 0xc, /* 250 */ .max_sr = 48000 }, > + { .in = 10, .out = 40, .width = 32, .bsel = 0xb, /* 320 */ .max_sr = 48000 }, > + { .in = 15, .out = 31, .width = 16, .bsel = 0xc, /* 250 */ .max_sr = 48000 }, > + { .in = 16, .out = 48, .width = 24, .bsel = 0x9, /* 384 */ .max_sr = 48000 }, > + { .in = 16, .out = 64, .width = 32, .bsel = 0xa, /* 512 */ .max_sr = 48000 }, > }; > > -static int max98396_get_bclk_sel(int bclk) > +static int max98396_pcm_config_index(int in_slots, int out_slots, int width) > { > int i; > - /* match BCLKs per LRCLK */ > - for (i = 0; i < ARRAY_SIZE(bclk_sel_table); i++) { > - if (bclk_sel_table[i] == bclk) > - return i + 2; > - } > - return 0; > -} > > -static int max98396_set_clock(struct snd_soc_component *component, > - struct snd_pcm_hw_params *params) > -{ > - struct max98396_priv *max98396 = snd_soc_component_get_drvdata(component); > - /* BCLK/LRCLK ratio calculation */ > - int blr_clk_ratio = params_channels(params) * max98396->ch_size; > - int value; > - > - if (!max98396->tdm_mode) { > - /* BCLK configuration */ > - value = max98396_get_bclk_sel(blr_clk_ratio); > - if (!value) { > - dev_err(component->dev, > - "blr_clk_ratio %d unsupported, format %d\n", > - blr_clk_ratio, params_format(params)); > - return -EINVAL; > - } > + for (i = 0; i < ARRAY_SIZE(max98396_pcm_configs); i++) { > + const struct max98396_pcm_config *c = &max98396_pcm_configs[i]; > > - regmap_update_bits(max98396->regmap, > - MAX98396_R2042_PCM_CLK_SETUP, > - MAX98396_PCM_CLK_SETUP_BSEL_MASK, > - value); > + if (in_slots == c->in && out_slots <= c->out && width == c->width) > + return i; > } > > - return 0; > + return -1; > } > > static int max98396_dai_hw_params(struct snd_pcm_substream *substream, > @@ -489,8 +497,7 @@ static int max98396_dai_hw_params(struct snd_pcm_substream *substream, > struct max98396_priv *max98396 = snd_soc_component_get_drvdata(component); > unsigned int sampling_rate = 0; > unsigned int chan_sz = 0; > - int ret, reg; > - int status; > + int ret, reg, status, bsel; > bool update = false; > > /* pcm mode configuration */ > @@ -510,8 +517,6 @@ static int max98396_dai_hw_params(struct snd_pcm_substream *substream, > goto err; > } > > - max98396->ch_size = snd_pcm_format_width(params_format(params)); > - > dev_dbg(component->dev, "format supported %d", > params_format(params)); > > @@ -559,6 +564,33 @@ static int max98396_dai_hw_params(struct snd_pcm_substream *substream, > goto err; > } > > + if (max98396->tdm_mode) { > + if (params_rate(params) > max98396->tdm_max_samplerate) { > + dev_err(component->dev, "TDM sample rate %d too high", > + params_rate(params)); > + goto err; > + } > + } else { > + /* BCLK configuration */ > + ret = max98396_pcm_config_index(params_channels(params), > + params_channels(params), > + snd_pcm_format_width(params_format(params))); > + if (ret < 0) { > + dev_err(component->dev, > + "no PCM config for %d channels, format %d\n", > + params_channels(params), params_format(params)); > + goto err; > + } > + > + bsel = max98396_pcm_configs[ret].bsel; > + > + if (params_rate(params) > max98396_pcm_configs[ret].max_sr) { > + dev_err(component->dev, "sample rate %d too high", > + params_rate(params)); > + goto err; > + } > + } > + > ret = regmap_read(max98396->regmap, MAX98396_R210F_GLOBAL_EN, &status); > if (ret < 0) > goto err; > @@ -604,12 +636,15 @@ static int max98396_dai_hw_params(struct snd_pcm_substream *substream, > MAX98396_IVADC_SR_MASK, > sampling_rate << MAX98396_IVADC_SR_SHIFT); > > - ret = max98396_set_clock(component, params); > + regmap_update_bits(max98396->regmap, > + MAX98396_R2042_PCM_CLK_SETUP, > + MAX98396_PCM_CLK_SETUP_BSEL_MASK, > + bsel); > > if (status && update) > max98396_global_enable_onoff(max98396->regmap, true); > > - return ret; > + return 0; > > err: > return -EINVAL; > @@ -634,13 +669,16 @@ static int max98396_dai_tdm_slot(struct snd_soc_dai *dai, > max98396->tdm_mode = true; > > /* BCLK configuration */ > - bsel = max98396_get_bclk_sel(slots * slot_width); > - if (bsel == 0) { > - dev_err(component->dev, "BCLK %d not supported\n", > - slots * slot_width); > + ret = max98396_pcm_config_index(slots, slots, slot_width); > + if (ret < 0) { > + dev_err(component->dev, "no TDM config for %d slots %d bits\n", > + slots, slot_width); > return -EINVAL; > } > > + bsel = max98396_pcm_configs[ret].bsel; > + max98396->tdm_max_samplerate = max98396_pcm_configs[ret].max_sr; > + > /* Channel size configuration */ > switch (slot_width) { > case 16:
On Fri, Jun 24, 2022 at 12:47:12PM +0200, Daniel Mack wrote: > In TDM mode, the BSEL register value must be set according to table 5 in the > datasheet. This patch adds a lookup function and uses it in > max98396_dai_tdm_slot(). Similar issue here with fixes.
diff --git a/sound/soc/codecs/max98396.c b/sound/soc/codecs/max98396.c index f28831f4e74b..f1657a5f2140 100644 --- a/sound/soc/codecs/max98396.c +++ b/sound/soc/codecs/max98396.c @@ -438,47 +438,55 @@ static int max98396_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) return 0; } -/* BCLKs per LRCLK */ -static const int bclk_sel_table[] = { - 32, 48, 64, 96, 128, 192, 256, 384, 512, 320, +/* Refer to table 5 in the datasheet */ +static const struct max98396_pcm_config { + int in, out, width, bsel, max_sr; +} max98396_pcm_configs[] = { + { .in = 2, .out = 4, .width = 16, .bsel = 0x2, /* 32 */ .max_sr = 192000 }, + { .in = 2, .out = 6, .width = 24, .bsel = 0x3, /* 48 */ .max_sr = 192000 }, + { .in = 2, .out = 8, .width = 32, .bsel = 0x4, /* 64 */ .max_sr = 192000 }, + { .in = 3, .out = 15, .width = 32, .bsel = 0xd, /* 125 */ .max_sr = 192000 }, + { .in = 4, .out = 8, .width = 16, .bsel = 0x4, /* 64 */ .max_sr = 192000 }, + { .in = 4, .out = 12, .width = 24, .bsel = 0x5, /* 96 */ .max_sr = 192000 }, + { .in = 4, .out = 16, .width = 32, .bsel = 0x6, /* 128 */ .max_sr = 192000 }, + { .in = 5, .out = 15, .width = 24, .bsel = 0xd, /* 125 */ .max_sr = 192000 }, + { .in = 7, .out = 15, .width = 16, .bsel = 0xd, /* 125 */ .max_sr = 192000 }, + { .in = 2, .out = 4, .width = 16, .bsel = 0x2, /* 32 */ .max_sr = 96000 }, + { .in = 2, .out = 6, .width = 24, .bsel = 0x3, /* 48 */ .max_sr = 96000 }, + { .in = 2, .out = 8, .width = 32, .bsel = 0x4, /* 64 */ .max_sr = 96000 }, + { .in = 3, .out = 15, .width = 32, .bsel = 0xd, /* 125 */ .max_sr = 96000 }, + { .in = 4, .out = 8, .width = 16, .bsel = 0x4, /* 64 */ .max_sr = 96000 }, + { .in = 4, .out = 12, .width = 24, .bsel = 0x5, /* 96 */ .max_sr = 96000 }, + { .in = 4, .out = 16, .width = 32, .bsel = 0x6, /* 128 */ .max_sr = 96000 }, + { .in = 5, .out = 15, .width = 24, .bsel = 0xd, /* 125 */ .max_sr = 96000 }, + { .in = 7, .out = 15, .width = 16, .bsel = 0xd, /* 125 */ .max_sr = 96000 }, + { .in = 7, .out = 31, .width = 32, .bsel = 0xc, /* 250 */ .max_sr = 96000 }, + { .in = 8, .out = 16, .width = 16, .bsel = 0x6, /* 128 */ .max_sr = 96000 }, + { .in = 8, .out = 24, .width = 24, .bsel = 0x7, /* 192 */ .max_sr = 96000 }, + { .in = 8, .out = 32, .width = 32, .bsel = 0x8, /* 256 */ .max_sr = 96000 }, + { .in = 10, .out = 31, .width = 24, .bsel = 0xc, /* 250 */ .max_sr = 96000 }, + { .in = 15, .out = 31, .width = 16, .bsel = 0xc, /* 250 */ .max_sr = 96000 }, + { .in = 16, .out = 32, .width = 16, .bsel = 0x8, /* 256 */ .max_sr = 96000 }, + { .in = 7, .out = 31, .width = 32, .bsel = 0xc, /* 250 */ .max_sr = 48000 }, + { .in = 10, .out = 31, .width = 24, .bsel = 0xc, /* 250 */ .max_sr = 48000 }, + { .in = 10, .out = 40, .width = 32, .bsel = 0xb, /* 320 */ .max_sr = 48000 }, + { .in = 15, .out = 31, .width = 16, .bsel = 0xc, /* 250 */ .max_sr = 48000 }, + { .in = 16, .out = 48, .width = 24, .bsel = 0x9, /* 384 */ .max_sr = 48000 }, + { .in = 16, .out = 64, .width = 32, .bsel = 0xa, /* 512 */ .max_sr = 48000 }, }; -static int max98396_get_bclk_sel(int bclk) +static int max98396_pcm_config_index(int in_slots, int out_slots, int width) { int i; - /* match BCLKs per LRCLK */ - for (i = 0; i < ARRAY_SIZE(bclk_sel_table); i++) { - if (bclk_sel_table[i] == bclk) - return i + 2; - } - return 0; -} -static int max98396_set_clock(struct snd_soc_component *component, - struct snd_pcm_hw_params *params) -{ - struct max98396_priv *max98396 = snd_soc_component_get_drvdata(component); - /* BCLK/LRCLK ratio calculation */ - int blr_clk_ratio = params_channels(params) * max98396->ch_size; - int value; - - if (!max98396->tdm_mode) { - /* BCLK configuration */ - value = max98396_get_bclk_sel(blr_clk_ratio); - if (!value) { - dev_err(component->dev, - "blr_clk_ratio %d unsupported, format %d\n", - blr_clk_ratio, params_format(params)); - return -EINVAL; - } + for (i = 0; i < ARRAY_SIZE(max98396_pcm_configs); i++) { + const struct max98396_pcm_config *c = &max98396_pcm_configs[i]; - regmap_update_bits(max98396->regmap, - MAX98396_R2042_PCM_CLK_SETUP, - MAX98396_PCM_CLK_SETUP_BSEL_MASK, - value); + if (in_slots == c->in && out_slots <= c->out && width == c->width) + return i; } - return 0; + return -1; } static int max98396_dai_hw_params(struct snd_pcm_substream *substream, @@ -489,8 +497,7 @@ static int max98396_dai_hw_params(struct snd_pcm_substream *substream, struct max98396_priv *max98396 = snd_soc_component_get_drvdata(component); unsigned int sampling_rate = 0; unsigned int chan_sz = 0; - int ret, reg; - int status; + int ret, reg, status, bsel; bool update = false; /* pcm mode configuration */ @@ -510,8 +517,6 @@ static int max98396_dai_hw_params(struct snd_pcm_substream *substream, goto err; } - max98396->ch_size = snd_pcm_format_width(params_format(params)); - dev_dbg(component->dev, "format supported %d", params_format(params)); @@ -559,6 +564,33 @@ static int max98396_dai_hw_params(struct snd_pcm_substream *substream, goto err; } + if (max98396->tdm_mode) { + if (params_rate(params) > max98396->tdm_max_samplerate) { + dev_err(component->dev, "TDM sample rate %d too high", + params_rate(params)); + goto err; + } + } else { + /* BCLK configuration */ + ret = max98396_pcm_config_index(params_channels(params), + params_channels(params), + snd_pcm_format_width(params_format(params))); + if (ret < 0) { + dev_err(component->dev, + "no PCM config for %d channels, format %d\n", + params_channels(params), params_format(params)); + goto err; + } + + bsel = max98396_pcm_configs[ret].bsel; + + if (params_rate(params) > max98396_pcm_configs[ret].max_sr) { + dev_err(component->dev, "sample rate %d too high", + params_rate(params)); + goto err; + } + } + ret = regmap_read(max98396->regmap, MAX98396_R210F_GLOBAL_EN, &status); if (ret < 0) goto err; @@ -604,12 +636,15 @@ static int max98396_dai_hw_params(struct snd_pcm_substream *substream, MAX98396_IVADC_SR_MASK, sampling_rate << MAX98396_IVADC_SR_SHIFT); - ret = max98396_set_clock(component, params); + regmap_update_bits(max98396->regmap, + MAX98396_R2042_PCM_CLK_SETUP, + MAX98396_PCM_CLK_SETUP_BSEL_MASK, + bsel); if (status && update) max98396_global_enable_onoff(max98396->regmap, true); - return ret; + return 0; err: return -EINVAL; @@ -634,13 +669,16 @@ static int max98396_dai_tdm_slot(struct snd_soc_dai *dai, max98396->tdm_mode = true; /* BCLK configuration */ - bsel = max98396_get_bclk_sel(slots * slot_width); - if (bsel == 0) { - dev_err(component->dev, "BCLK %d not supported\n", - slots * slot_width); + ret = max98396_pcm_config_index(slots, slots, slot_width); + if (ret < 0) { + dev_err(component->dev, "no TDM config for %d slots %d bits\n", + slots, slot_width); return -EINVAL; } + bsel = max98396_pcm_configs[ret].bsel; + max98396->tdm_max_samplerate = max98396_pcm_configs[ret].max_sr; + /* Channel size configuration */ switch (slot_width) { case 16:
In TDM mode, the BSEL register value must be set according to table 5 in the datasheet. This patch adds a lookup function and uses it in max98396_dai_tdm_slot(). As the first 3 entries can also be used for non-TDM setups, the code now re-uses the same code for such scenarios. max98396_set_clock() is folded into its only user for clarity. Signed-off-by: Daniel Mack <daniel@zonque.org> --- sound/soc/codecs/max98396.c | 124 +++++++++++++++++++++++------------- 1 file changed, 81 insertions(+), 43 deletions(-)