[alsa-devel] [PATCH v2 19/23] ASoC: tas2552: Correct the PLL configuration

Peter Ujfalusi peter.ujfalusi at ti.com
Fri Jun 5 08:53:57 CEST 2015


On 06/04/2015 04:04 PM, Peter Ujfalusi wrote:
> Do not restrict the sampling rate to 44.1/48KHz. The pll_clk clock should
> be (sampling rate * 512) in all cases.
> Correct the J.D calculation (the D part was incorrectly calculated).
> Restore PLL enable status after we are done with the configuration.
> Implement hardware constraint handling towards the pll_clkin:
> if D != 0 (in J.D) then 1.1MHz <= pll_clkin <= 9.2MHz needs to be checked.
> If the PLL setup does not met with this constraint, fall back to BCLK as
> reference clock, if BCLK fails, use the internal 1.8MHz clock.
> 
> Signed-off-by: Peter Ujfalusi <peter.ujfalusi at ti.com>
> ---
>  sound/soc/codecs/tas2552.c | 141 ++++++++++++++++++++++++++++++---------------
>  sound/soc/codecs/tas2552.h |   7 +--
>  2 files changed, 96 insertions(+), 52 deletions(-)
> 
> diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c
> index 891e2c529df3..01230395b61d 100644
> --- a/sound/soc/codecs/tas2552.c
> +++ b/sound/soc/codecs/tas2552.c
> @@ -77,7 +77,9 @@ struct tas2552_data {
>  	struct gpio_desc *enable_gpio;
>  	unsigned char regs[TAS2552_VBAT_DATA];
>  	unsigned int pll_clkin;
> +	int pll_clk_id;
>  	unsigned int pdm_clk;
> +	int pdm_clk_id;
>  
>  	unsigned int dai_fmt;
>  	unsigned int tdm_delay;
> @@ -158,16 +160,93 @@ static void tas2552_sw_shutdown(struct tas2552_data *tas_data, int sw_shutdown)
>  }
>  #endif
>  
> +static int tas2552_setup_pll(struct snd_soc_codec *codec,
> +			     struct snd_pcm_hw_params *params)
> +{
> +	struct tas2552_data *tas2552 = dev_get_drvdata(codec->dev);
> +	bool bypass_pll = false;
> +	unsigned int pll_clk = params_rate(params) * 512;
> +	unsigned int pll_clkin = tas2552->pll_clkin;
> +	u8 pll_enable;
> +
> +	if (!pll_clkin) {
> +		if (tas2552->pll_clk_id != TAS2552_PLL_CLKIN_BCLK)
> +			return -EINVAL;
> +
> +		pll_clkin = snd_soc_params_to_bclk(params);
> +		pll_clkin += tas2552->tdm_delay;
> +	}
> +
> +	pll_enable = snd_soc_read(codec, TAS2552_CFG_2) & TAS2552_PLL_ENABLE;
> +	snd_soc_update_bits(codec, TAS2552_CFG_2, TAS2552_PLL_ENABLE, 0);
> +
> +	if (pll_clkin == pll_clk)
> +		bypass_pll = true;
> +
> +	if (bypass_pll) {
> +		/* By pass the PLL configuration */
> +		snd_soc_update_bits(codec, TAS2552_PLL_CTRL_2,
> +				    TAS2552_PLL_BYPASS, TAS2552_PLL_BYPASS);
> +	} else {
> +		/* Fill in the PLL control registers for J & D
> +		 * pll_clk = (.5 * pll_clkin * J.D) / 2^p
> +		 * Need to fill in J and D here based on incoming freq
> +		 */
> +		unsigned int d;
> +		u8 j;
> +		u8 pll_sel = (tas2552->pll_clk_id << 3) & TAS2552_PLL_SRC_MASK;
> +		u8 p = snd_soc_read(codec, TAS2552_PLL_CTRL_1);
> +
> +		p = (p >> 7);
> +
> +recalc:
> +		j = (pll_clk * 2 * (1 << p)) / pll_clkin;
> +		d = (pll_clk * 2 * (1 << p)) % pll_clkin;
> +		d /= (pll_clkin / 10000);
> +
> +		if (d && (pll_clkin < 512000 || pll_clkin > 9200000)) {
> +			if (tas2552->pll_clk_id == TAS2552_PLL_CLKIN_BCLK) {
> +				pll_clkin = 1800000;
> +				pll_sel = (TAS2552_PLL_CLKIN_1_8_FIXED << 3) &
> +							TAS2552_PLL_SRC_MASK;
> +			} else {
> +				pll_clkin = snd_soc_params_to_bclk(params);
> +				pll_clkin += tas2552->tdm_delay;
> +				pll_sel = (TAS2552_PLL_CLKIN_BCLK << 3) &
> +							TAS2552_PLL_SRC_MASK;
> +			}
> +			goto recalc;
> +		}
> +
> +		snd_soc_update_bits(codec, TAS2552_CFG_1, TAS2552_PLL_SRC_MASK,
> +				    pll_sel);
> +
> +		snd_soc_update_bits(codec, TAS2552_PLL_CTRL_1,
> +				    TAS2552_PLL_J_MASK, j);
> +		snd_soc_write(codec, TAS2552_PLL_CTRL_2,
> +			      (d >> 7) & TAS2552_PLL_D_UPPER_MASK);

This bit shift is not correct, it should be 8... I carried it over from the
old code and it worked since In some of my tests I was using bitclock as
reference (D ends up as 0).

Mark, if you apply the series up this patch, I will resend the rest as v3 with
the fixed shift - I will create a macro for upper and lower, it will look a
bit better.


> +		snd_soc_write(codec, TAS2552_PLL_CTRL_3,
> +			      d & TAS2552_PLL_D_LOWER_MASK);
> +
> +		/* PLL in use */
> +		snd_soc_update_bits(codec, TAS2552_PLL_CTRL_2,
> +				    TAS2552_PLL_BYPASS, 0);
> +	}
> +
> +	/* Restore PLL status */
> +	snd_soc_update_bits(codec, TAS2552_CFG_2, TAS2552_PLL_ENABLE,
> +			    pll_enable);
> +
> +	return 0;
> +}
> +
>  static int tas2552_hw_params(struct snd_pcm_substream *substream,
>  			     struct snd_pcm_hw_params *params,
>  			     struct snd_soc_dai *dai)
>  {
>  	struct snd_soc_codec *codec = dai->codec;
>  	struct tas2552_data *tas2552 = dev_get_drvdata(codec->dev);
> -	int sample_rate, pll_clk;
> -	int d;
>  	int cpf;
> -	u8 p, j;
>  	u8 ser_ctrl1_reg, wclk_rate;
>  
>  	switch (params_width(params)) {
> @@ -245,49 +324,7 @@ static int tas2552_hw_params(struct snd_pcm_substream *substream,
>  	snd_soc_update_bits(codec, TAS2552_CFG_3, TAS2552_WCLK_FREQ_MASK,
>  			    wclk_rate);
>  
> -	if (!tas2552->pll_clkin)
> -		return -EINVAL;
> -
> -	snd_soc_update_bits(codec, TAS2552_CFG_2, TAS2552_PLL_ENABLE, 0);
> -
> -	if (tas2552->pll_clkin == TAS2552_245MHZ_CLK ||
> -	    tas2552->pll_clkin == TAS2552_225MHZ_CLK) {
> -		/* By pass the PLL configuration */
> -		snd_soc_update_bits(codec, TAS2552_PLL_CTRL_2,
> -				    TAS2552_PLL_BYPASS_MASK,
> -				    TAS2552_PLL_BYPASS);
> -	} else {
> -		/* Fill in the PLL control registers for J & D
> -		 * PLL_CLK = (.5 * freq * J.D) / 2^p
> -		 * Need to fill in J and D here based on incoming freq
> -		 */
> -		p = snd_soc_read(codec, TAS2552_PLL_CTRL_1);
> -		p = (p >> 7);
> -		sample_rate = params_rate(params);
> -
> -		if (sample_rate == 48000)
> -			pll_clk = TAS2552_245MHZ_CLK;
> -		else if (sample_rate == 44100)
> -			pll_clk = TAS2552_225MHZ_CLK;
> -		else {
> -			dev_vdbg(codec->dev, "Substream sample rate is not found %i\n",
> -					params_rate(params));
> -			return -EINVAL;
> -		}
> -
> -		j = (pll_clk * 2 * (1 << p)) / tas2552->pll_clkin;
> -		d = (pll_clk * 2 * (1 << p)) % tas2552->pll_clkin;
> -
> -		snd_soc_update_bits(codec, TAS2552_PLL_CTRL_1,
> -				TAS2552_PLL_J_MASK, j);
> -		snd_soc_write(codec, TAS2552_PLL_CTRL_2,
> -					(d >> 7) & TAS2552_PLL_D_UPPER_MASK);
> -		snd_soc_write(codec, TAS2552_PLL_CTRL_3,
> -				d & TAS2552_PLL_D_LOWER_MASK);
> -
> -	}
> -
> -	return 0;
> +	return tas2552_setup_pll(codec, params);
>  }
>  
>  #define TAS2552_DAI_FMT_MASK	(TAS2552_BCLKDIR | \
> @@ -370,12 +407,21 @@ static int tas2552_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
>  
>  	switch (clk_id) {
>  	case TAS2552_PLL_CLKIN_MCLK:
> -	case TAS2552_PLL_CLKIN_BCLK:
>  	case TAS2552_PLL_CLKIN_IVCLKIN:
> +		if (freq < 512000 || freq > 24576000) {
> +			/* out of range PLL_CLKIN, fall back to use BCLK */
> +			dev_warn(codec->dev, "Out of range PLL_CLKIN: %u\n",
> +				 freq);
> +			clk_id = TAS2552_PLL_CLKIN_BCLK;
> +			freq = 0;
> +		}
> +		/* fall through */
> +	case TAS2552_PLL_CLKIN_BCLK:
>  	case TAS2552_PLL_CLKIN_1_8_FIXED:
>  		mask = TAS2552_PLL_SRC_MASK;
>  		val = (clk_id << 3) & mask; /* bit 4:5 in the register */
>  		reg = TAS2552_CFG_1;
> +		tas2552->pll_clk_id = clk_id;
>  		tas2552->pll_clkin = freq;
>  		break;
>  	case TAS2552_PDM_CLK_PLL:
> @@ -385,6 +431,7 @@ static int tas2552_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
>  		mask = TAS2552_PDM_CLK_SEL_MASK;
>  		val = (clk_id >> 1) & mask; /* bit 0:1 in the register */
>  		reg = TAS2552_PDM_CFG;
> +		tas2552->pdm_clk_id = clk_id;
>  		tas2552->pdm_clk = freq;
>  		break;
>  	default:
> diff --git a/sound/soc/codecs/tas2552.h b/sound/soc/codecs/tas2552.h
> index bbb820495516..f04d9e6db0aa 100644
> --- a/sound/soc/codecs/tas2552.h
> +++ b/sound/soc/codecs/tas2552.h
> @@ -128,12 +128,9 @@
>  #define TAS2552_APT_THRESH_2_1_7	(0x11 << 2)
>  
>  /* PLL Control Register */
> -#define TAS2552_245MHZ_CLK			24576000
> -#define TAS2552_225MHZ_CLK			22579200
> -#define TAS2552_PLL_J_MASK			0x7f
> +#define TAS2552_PLL_J_MASK		0x7f
>  #define TAS2552_PLL_D_UPPER_MASK	0x3f
>  #define TAS2552_PLL_D_LOWER_MASK	0xff
> -#define TAS2552_PLL_BYPASS_MASK		0x80
> -#define TAS2552_PLL_BYPASS			0x80
> +#define TAS2552_PLL_BYPASS		(1 << 7)
>  
>  #endif
> 


-- 
Péter


More information about the Alsa-devel mailing list