Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4c75225a authored by Adam Thomson's avatar Adam Thomson Committed by Mark Brown
Browse files

ASoC: da7213: Refactor sysclk(), pll() functions to improve handling



Currently the handling of the PLL in the driver is a little clunky,
and not ideal for all modes. This patch updates the code to make it
cleaner and more sensible for the various PLL states.

Key items of note are:
 - MCLK squaring is now handled directly as part of the sysclk()
   function, removing the need for a private flag to set this feature.
 - All PLL modes are defined as an enum, and are handled as a case
   statement in pll() function to clean up configuration. This also
   removes any need for a private flag for SRM.
 - For 32KHz mode, checks are made on codec master mode and correct
   MCLK rates, to avoid incorrect usage of PLL for this operation.
 - For 32KHz mode, SRM flag now correctly enabled and fout set to
   sensible value to achieve appropriate PLL dividers.

Signed-off-by: default avatarAdam Thomson <Adam.Thomson.Opensource@diasemi.com>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent f612680f
Loading
Loading
Loading
Loading
+49 −36
Original line number Original line Diff line number Diff line
@@ -1297,10 +1297,13 @@ static int da7213_set_dai_sysclk(struct snd_soc_dai *codec_dai,


	switch (clk_id) {
	switch (clk_id) {
	case DA7213_CLKSRC_MCLK:
	case DA7213_CLKSRC_MCLK:
		da7213->mclk_squarer_en = false;
		snd_soc_update_bits(codec, DA7213_PLL_CTRL,
				    DA7213_PLL_MCLK_SQR_EN, 0);
		break;
		break;
	case DA7213_CLKSRC_MCLK_SQR:
	case DA7213_CLKSRC_MCLK_SQR:
		da7213->mclk_squarer_en = true;
		snd_soc_update_bits(codec, DA7213_PLL_CTRL,
				    DA7213_PLL_MCLK_SQR_EN,
				    DA7213_PLL_MCLK_SQR_EN);
		break;
		break;
	default:
	default:
		dev_err(codec_dai->dev, "Unknown clock source %d\n", clk_id);
		dev_err(codec_dai->dev, "Unknown clock source %d\n", clk_id);
@@ -1324,7 +1327,7 @@ static int da7213_set_dai_sysclk(struct snd_soc_dai *codec_dai,
	return 0;
	return 0;
}
}


/* Supported PLL input frequencies are 5MHz - 54MHz. */
/* Supported PLL input frequencies are 32KHz, 5MHz - 54MHz. */
static int da7213_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
static int da7213_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
			      int source, unsigned int fref, unsigned int fout)
			      int source, unsigned int fref, unsigned int fout)
{
{
@@ -1336,22 +1339,26 @@ static int da7213_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
	u32 freq_ref;
	u32 freq_ref;
	u64 frac_div;
	u64 frac_div;


	/* Reset PLL configuration */
	snd_soc_write(codec, DA7213_PLL_CTRL, 0);

	pll_ctrl = 0;

	/* Workout input divider based on MCLK rate */
	/* Workout input divider based on MCLK rate */
	if (da7213->mclk_rate == 32768) {
	if (da7213->mclk_rate == 32768) {
		if (!da7213->master) {
			dev_err(codec->dev,
				"32KHz only valid if codec is clock master\n");
			return -EINVAL;
		}

		/* 32KHz PLL Mode */
		/* 32KHz PLL Mode */
		indiv_bits = DA7213_PLL_INDIV_9_TO_18_MHZ;
		indiv_bits = DA7213_PLL_INDIV_9_TO_18_MHZ;
		indiv = DA7213_PLL_INDIV_9_TO_18_MHZ_VAL;
		indiv = DA7213_PLL_INDIV_9_TO_18_MHZ_VAL;
		source = DA7213_SYSCLK_PLL_32KHZ;
		freq_ref = 3750000;
		freq_ref = 3750000;
		pll_ctrl |= DA7213_PLL_32K_MODE;

	} else {
	} else {
		/* 5 - 54MHz MCLK */
		if (da7213->mclk_rate < 5000000) {
		if (da7213->mclk_rate < 5000000) {
			goto pll_err;
			dev_err(codec->dev,
				"PLL input clock %d below valid range\n",
				da7213->mclk_rate);
			return -EINVAL;
		} else if (da7213->mclk_rate <= 9000000) {
		} else if (da7213->mclk_rate <= 9000000) {
			indiv_bits = DA7213_PLL_INDIV_5_TO_9_MHZ;
			indiv_bits = DA7213_PLL_INDIV_5_TO_9_MHZ;
			indiv = DA7213_PLL_INDIV_5_TO_9_MHZ_VAL;
			indiv = DA7213_PLL_INDIV_5_TO_9_MHZ_VAL;
@@ -1365,32 +1372,44 @@ static int da7213_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
			indiv_bits = DA7213_PLL_INDIV_36_TO_54_MHZ;
			indiv_bits = DA7213_PLL_INDIV_36_TO_54_MHZ;
			indiv = DA7213_PLL_INDIV_36_TO_54_MHZ_VAL;
			indiv = DA7213_PLL_INDIV_36_TO_54_MHZ_VAL;
		} else {
		} else {
			goto pll_err;
			dev_err(codec->dev,
				"PLL input clock %d above valid range\n",
				da7213->mclk_rate);
			return -EINVAL;
		}
		}
		freq_ref = (da7213->mclk_rate / indiv);
		freq_ref = (da7213->mclk_rate / indiv);
	}
	}


	pll_ctrl |= indiv_bits;
	pll_ctrl = indiv_bits;


	/* PLL Bypass mode */
	/* Configure PLL */
	if (source == DA7213_SYSCLK_MCLK) {
	switch (source) {
		snd_soc_write(codec, DA7213_PLL_CTRL, pll_ctrl);
	case DA7213_SYSCLK_MCLK:
		snd_soc_update_bits(codec, DA7213_PLL_CTRL,
				    DA7213_PLL_INDIV_MASK |
				    DA7213_PLL_MODE_MASK, pll_ctrl);
		return 0;
		return 0;
	case DA7213_SYSCLK_PLL:
		break;
	case DA7213_SYSCLK_PLL_SRM:
		pll_ctrl |= DA7213_PLL_SRM_EN;
		fout = DA7213_PLL_FREQ_OUT_94310400;
		break;
	case DA7213_SYSCLK_PLL_32KHZ:
		if (da7213->mclk_rate != 32768) {
			dev_err(codec->dev,
				"32KHz mode only valid with 32KHz MCLK\n");
			return -EINVAL;
		}
		}


	/*
		pll_ctrl |= DA7213_PLL_32K_MODE | DA7213_PLL_SRM_EN;
	 * If Codec is slave and SRM enabled,
	 * freq_out is (98304000 + 90316800)/2 = 94310400
	 */
	if (!da7213->master && da7213->srm_en) {
		fout = DA7213_PLL_FREQ_OUT_94310400;
		fout = DA7213_PLL_FREQ_OUT_94310400;
		pll_ctrl |= DA7213_PLL_SRM_EN;
		break;
	default:
		dev_err(codec->dev, "Invalid PLL config\n");
		return -EINVAL;
	}
	}


	/* Enable MCLK squarer if required */
	if (da7213->mclk_squarer_en)
		pll_ctrl |= DA7213_PLL_MCLK_SQR_EN;

	/* Calculate dividers for PLL */
	/* Calculate dividers for PLL */
	pll_integer = fout / freq_ref;
	pll_integer = fout / freq_ref;
	frac_div = (u64)(fout % freq_ref) * 8192ULL;
	frac_div = (u64)(fout % freq_ref) * 8192ULL;
@@ -1405,14 +1424,11 @@ static int da7213_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,


	/* Enable PLL */
	/* Enable PLL */
	pll_ctrl |= DA7213_PLL_EN;
	pll_ctrl |= DA7213_PLL_EN;
	snd_soc_write(codec, DA7213_PLL_CTRL, pll_ctrl);
	snd_soc_update_bits(codec, DA7213_PLL_CTRL,
			    DA7213_PLL_INDIV_MASK | DA7213_PLL_MODE_MASK,
			    pll_ctrl);


	return 0;
	return 0;

pll_err:
	dev_err(codec_dai->dev, "Unsupported PLL input frequency %d\n",
		da7213->mclk_rate);
	return -EINVAL;
}
}


/* DAI operations */
/* DAI operations */
@@ -1607,9 +1623,6 @@ static int da7213_probe(struct snd_soc_codec *codec)
			    DA7213_ALC_CALIB_MODE_MAN, 0);
			    DA7213_ALC_CALIB_MODE_MAN, 0);
	da7213->alc_calib_auto = true;
	da7213->alc_calib_auto = true;


	/* Default to using SRM for slave mode */
	da7213->srm_en = true;

	/* Default PC counter to free-running */
	/* Default PC counter to free-running */
	snd_soc_update_bits(codec, DA7213_PC_COUNT, DA7213_PC_FREERUN_MASK,
	snd_soc_update_bits(codec, DA7213_PC_COUNT, DA7213_PC_FREERUN_MASK,
			    DA7213_PC_FREERUN_MASK);
			    DA7213_PC_FREERUN_MASK);
+8 −4
Original line number Original line Diff line number Diff line
@@ -172,6 +172,7 @@
#define DA7213_PLL_32K_MODE					(0x1 << 5)
#define DA7213_PLL_32K_MODE					(0x1 << 5)
#define DA7213_PLL_SRM_EN					(0x1 << 6)
#define DA7213_PLL_SRM_EN					(0x1 << 6)
#define DA7213_PLL_EN						(0x1 << 7)
#define DA7213_PLL_EN						(0x1 << 7)
#define DA7213_PLL_MODE_MASK					(0x7 << 5)


/* DA7213_DAI_CLK_MODE = 0x28 */
/* DA7213_DAI_CLK_MODE = 0x28 */
#define DA7213_DAI_BCLKS_PER_WCLK_32				(0x0 << 0)
#define DA7213_DAI_BCLKS_PER_WCLK_32				(0x0 << 0)
@@ -499,8 +500,6 @@
#define DA7213_ALC_AVG_ITERATIONS	5
#define DA7213_ALC_AVG_ITERATIONS	5


/* PLL related */
/* PLL related */
#define DA7213_SYSCLK_MCLK			0
#define DA7213_SYSCLK_PLL			1
#define DA7213_PLL_FREQ_OUT_90316800		90316800
#define DA7213_PLL_FREQ_OUT_90316800		90316800
#define DA7213_PLL_FREQ_OUT_98304000		98304000
#define DA7213_PLL_FREQ_OUT_98304000		98304000
#define DA7213_PLL_FREQ_OUT_94310400		94310400
#define DA7213_PLL_FREQ_OUT_94310400		94310400
@@ -515,6 +514,13 @@ enum da7213_clk_src {
	DA7213_CLKSRC_MCLK_SQR,
	DA7213_CLKSRC_MCLK_SQR,
};
};


enum da7213_sys_clk {
	DA7213_SYSCLK_MCLK = 0,
	DA7213_SYSCLK_PLL,
	DA7213_SYSCLK_PLL_SRM,
	DA7213_SYSCLK_PLL_32KHZ
};

/* Codec private data */
/* Codec private data */
struct da7213_priv {
struct da7213_priv {
	struct regmap *regmap;
	struct regmap *regmap;
@@ -522,8 +528,6 @@ struct da7213_priv {
	unsigned int mclk_rate;
	unsigned int mclk_rate;
	int clk_src;
	int clk_src;
	bool master;
	bool master;
	bool mclk_squarer_en;
	bool srm_en;
	bool alc_calib_auto;
	bool alc_calib_auto;
	bool alc_en;
	bool alc_en;
	struct da7213_platform_data *pdata;
	struct da7213_platform_data *pdata;