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

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
...@@ -1297,10 +1297,13 @@ static int da7213_set_dai_sysclk(struct snd_soc_dai *codec_dai, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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);
......
...@@ -172,6 +172,7 @@ ...@@ -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 @@ ...@@ -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 { ...@@ -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 { ...@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment