RE: [PATCHv2 6/6] ASoC: da7213: Add default clock handling

From: Adam Thomson
Date: Tue Nov 26 2019 - 11:55:49 EST


On 21 November 2019 21:49, Adam Thomson wrote:

> On 20 November 2019 15:24, 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@xxxxxxxxxxxxx>
> > ---
> > sound/soc/codecs/da7213.c | 75
> > ++++++++++++++++++++++++++++++++++++---
> > sound/soc/codecs/da7213.h | 2 ++
> > 2 files changed, 73 insertions(+), 4 deletions(-)
> >
> > diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c
> > index 3e6ad996741b..ff1a936240be 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;
>
> If we're the clock slave, and we're using an MCLK that's not a harmonic then
> SRM is required to synchronise the PLL to the incoming WCLK signal. I assume
> simple sound card should allow for both master and slave modes? If so we'll
> need to do something here to determine this as well.
>
> > +
> > + 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);
>
> I've thought more about this and for the scenario where a machine driver
> controls the PLL through a DAPM widget associated with this codec (like some
> Intel boards do), then the PLL will be configured once here and then again
> when the relevant widget is called. I don't think that will matter but I will
> take a further look just in case this might cause some oddities.

So I don't see any issues per say with the PLL function being called twice in
the example I mentioned. However it still feels a bit clunky; You either live
with it or you have something in the machine driver to call the codec's PLL
function early doors to prevent the bias_level() code of the codec controlling
the PLL automatically. Am wondering though if there would be some use in having
an indicator that simple-card is being used so we can avoid this? I guess we
could check the parent sound card instance's OF node to look at the compatible
string and see if it's a simple-card instantiation. Bit messy maybe.
Alternatively would it be worthwhile storing in the snd_soc_card instance that
this is a simple-card instantiation? We could then use that to determine
whether the codec driver should automatically deal with the PLL or not. This
would of course require an update to the snd_soc_card structure to add the new
flag and then some update to simple-card.c to flag this.

I think relying on the timing of the call to the codec's PLL configuration
function from a machine driver isn't ideal.

>
> > }
> > }
> > 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:
> > @@ -1829,6 +1891,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.24.0