aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Ujfalusi <peter.ujfalusi@ti.com>2015-06-08 08:19:48 -0400
committerMark Brown <broonie@kernel.org>2015-06-08 13:53:18 -0400
commit1014f7eff9a1d4f3f796c83e933adf2462c79005 (patch)
tree59ca30454a1d0dfe14c675e40ad15e8dbd5d0f91
parenta571cb17acb6156e6ea8d5fe2ff824e713416bae (diff)
ASoC: tas2552: Correct the PLL configuration
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@ti.com> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--sound/soc/codecs/tas2552.c138
-rw-r--r--sound/soc/codecs/tas2552.h11
2 files changed, 95 insertions, 54 deletions
diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c
index 891e2c529df3..0ca55aaeaaf2 100644
--- a/sound/soc/codecs/tas2552.c
+++ b/sound/soc/codecs/tas2552.c
@@ -77,7 +77,9 @@ struct tas2552_data {
77 struct gpio_desc *enable_gpio; 77 struct gpio_desc *enable_gpio;
78 unsigned char regs[TAS2552_VBAT_DATA]; 78 unsigned char regs[TAS2552_VBAT_DATA];
79 unsigned int pll_clkin; 79 unsigned int pll_clkin;
80 int pll_clk_id;
80 unsigned int pdm_clk; 81 unsigned int pdm_clk;
82 int pdm_clk_id;
81 83
82 unsigned int dai_fmt; 84 unsigned int dai_fmt;
83 unsigned int tdm_delay; 85 unsigned int tdm_delay;
@@ -158,16 +160,90 @@ static void tas2552_sw_shutdown(struct tas2552_data *tas_data, int sw_shutdown)
158} 160}
159#endif 161#endif
160 162
163static int tas2552_setup_pll(struct snd_soc_codec *codec,
164 struct snd_pcm_hw_params *params)
165{
166 struct tas2552_data *tas2552 = dev_get_drvdata(codec->dev);
167 bool bypass_pll = false;
168 unsigned int pll_clk = params_rate(params) * 512;
169 unsigned int pll_clkin = tas2552->pll_clkin;
170 u8 pll_enable;
171
172 if (!pll_clkin) {
173 if (tas2552->pll_clk_id != TAS2552_PLL_CLKIN_BCLK)
174 return -EINVAL;
175
176 pll_clkin = snd_soc_params_to_bclk(params);
177 pll_clkin += tas2552->tdm_delay;
178 }
179
180 pll_enable = snd_soc_read(codec, TAS2552_CFG_2) & TAS2552_PLL_ENABLE;
181 snd_soc_update_bits(codec, TAS2552_CFG_2, TAS2552_PLL_ENABLE, 0);
182
183 if (pll_clkin == pll_clk)
184 bypass_pll = true;
185
186 if (bypass_pll) {
187 /* By pass the PLL configuration */
188 snd_soc_update_bits(codec, TAS2552_PLL_CTRL_2,
189 TAS2552_PLL_BYPASS, TAS2552_PLL_BYPASS);
190 } else {
191 /* Fill in the PLL control registers for J & D
192 * pll_clk = (.5 * pll_clkin * J.D) / 2^p
193 * Need to fill in J and D here based on incoming freq
194 */
195 unsigned int d;
196 u8 j;
197 u8 pll_sel = (tas2552->pll_clk_id << 3) & TAS2552_PLL_SRC_MASK;
198 u8 p = snd_soc_read(codec, TAS2552_PLL_CTRL_1);
199
200 p = (p >> 7);
201
202recalc:
203 j = (pll_clk * 2 * (1 << p)) / pll_clkin;
204 d = (pll_clk * 2 * (1 << p)) % pll_clkin;
205 d /= (pll_clkin / 10000);
206
207 if (d && (pll_clkin < 512000 || pll_clkin > 9200000)) {
208 if (tas2552->pll_clk_id == TAS2552_PLL_CLKIN_BCLK) {
209 pll_clkin = 1800000;
210 pll_sel = (TAS2552_PLL_CLKIN_1_8_FIXED << 3) &
211 TAS2552_PLL_SRC_MASK;
212 } else {
213 pll_clkin = snd_soc_params_to_bclk(params);
214 pll_clkin += tas2552->tdm_delay;
215 pll_sel = (TAS2552_PLL_CLKIN_BCLK << 3) &
216 TAS2552_PLL_SRC_MASK;
217 }
218 goto recalc;
219 }
220
221 snd_soc_update_bits(codec, TAS2552_CFG_1, TAS2552_PLL_SRC_MASK,
222 pll_sel);
223
224 snd_soc_update_bits(codec, TAS2552_PLL_CTRL_1,
225 TAS2552_PLL_J_MASK, j);
226 /* Will clear the PLL_BYPASS bit */
227 snd_soc_write(codec, TAS2552_PLL_CTRL_2,
228 TAS2552_PLL_D_UPPER(d));
229 snd_soc_write(codec, TAS2552_PLL_CTRL_3,
230 TAS2552_PLL_D_LOWER(d));
231 }
232
233 /* Restore PLL status */
234 snd_soc_update_bits(codec, TAS2552_CFG_2, TAS2552_PLL_ENABLE,
235 pll_enable);
236
237 return 0;
238}
239
161static int tas2552_hw_params(struct snd_pcm_substream *substream, 240static int tas2552_hw_params(struct snd_pcm_substream *substream,
162 struct snd_pcm_hw_params *params, 241 struct snd_pcm_hw_params *params,
163 struct snd_soc_dai *dai) 242 struct snd_soc_dai *dai)
164{ 243{
165 struct snd_soc_codec *codec = dai->codec; 244 struct snd_soc_codec *codec = dai->codec;
166 struct tas2552_data *tas2552 = dev_get_drvdata(codec->dev); 245 struct tas2552_data *tas2552 = dev_get_drvdata(codec->dev);
167 int sample_rate, pll_clk;
168 int d;
169 int cpf; 246 int cpf;
170 u8 p, j;
171 u8 ser_ctrl1_reg, wclk_rate; 247 u8 ser_ctrl1_reg, wclk_rate;
172 248
173 switch (params_width(params)) { 249 switch (params_width(params)) {
@@ -245,49 +321,7 @@ static int tas2552_hw_params(struct snd_pcm_substream *substream,
245 snd_soc_update_bits(codec, TAS2552_CFG_3, TAS2552_WCLK_FREQ_MASK, 321 snd_soc_update_bits(codec, TAS2552_CFG_3, TAS2552_WCLK_FREQ_MASK,
246 wclk_rate); 322 wclk_rate);
247 323
248 if (!tas2552->pll_clkin) 324 return tas2552_setup_pll(codec, params);
249 return -EINVAL;
250
251 snd_soc_update_bits(codec, TAS2552_CFG_2, TAS2552_PLL_ENABLE, 0);
252
253 if (tas2552->pll_clkin == TAS2552_245MHZ_CLK ||
254 tas2552->pll_clkin == TAS2552_225MHZ_CLK) {
255 /* By pass the PLL configuration */
256 snd_soc_update_bits(codec, TAS2552_PLL_CTRL_2,
257 TAS2552_PLL_BYPASS_MASK,
258 TAS2552_PLL_BYPASS);
259 } else {
260 /* Fill in the PLL control registers for J & D
261 * PLL_CLK = (.5 * freq * J.D) / 2^p
262 * Need to fill in J and D here based on incoming freq
263 */
264 p = snd_soc_read(codec, TAS2552_PLL_CTRL_1);
265 p = (p >> 7);
266 sample_rate = params_rate(params);
267
268 if (sample_rate == 48000)
269 pll_clk = TAS2552_245MHZ_CLK;
270 else if (sample_rate == 44100)
271 pll_clk = TAS2552_225MHZ_CLK;
272 else {
273 dev_vdbg(codec->dev, "Substream sample rate is not found %i\n",
274 params_rate(params));
275 return -EINVAL;
276 }
277
278 j = (pll_clk * 2 * (1 << p)) / tas2552->pll_clkin;
279 d = (pll_clk * 2 * (1 << p)) % tas2552->pll_clkin;
280
281 snd_soc_update_bits(codec, TAS2552_PLL_CTRL_1,
282 TAS2552_PLL_J_MASK, j);
283 snd_soc_write(codec, TAS2552_PLL_CTRL_2,
284 (d >> 7) & TAS2552_PLL_D_UPPER_MASK);
285 snd_soc_write(codec, TAS2552_PLL_CTRL_3,
286 d & TAS2552_PLL_D_LOWER_MASK);
287
288 }
289
290 return 0;
291} 325}
292 326
293#define TAS2552_DAI_FMT_MASK (TAS2552_BCLKDIR | \ 327#define TAS2552_DAI_FMT_MASK (TAS2552_BCLKDIR | \
@@ -370,12 +404,21 @@ static int tas2552_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
370 404
371 switch (clk_id) { 405 switch (clk_id) {
372 case TAS2552_PLL_CLKIN_MCLK: 406 case TAS2552_PLL_CLKIN_MCLK:
373 case TAS2552_PLL_CLKIN_BCLK:
374 case TAS2552_PLL_CLKIN_IVCLKIN: 407 case TAS2552_PLL_CLKIN_IVCLKIN:
408 if (freq < 512000 || freq > 24576000) {
409 /* out of range PLL_CLKIN, fall back to use BCLK */
410 dev_warn(codec->dev, "Out of range PLL_CLKIN: %u\n",
411 freq);
412 clk_id = TAS2552_PLL_CLKIN_BCLK;
413 freq = 0;
414 }
415 /* fall through */
416 case TAS2552_PLL_CLKIN_BCLK:
375 case TAS2552_PLL_CLKIN_1_8_FIXED: 417 case TAS2552_PLL_CLKIN_1_8_FIXED:
376 mask = TAS2552_PLL_SRC_MASK; 418 mask = TAS2552_PLL_SRC_MASK;
377 val = (clk_id << 3) & mask; /* bit 4:5 in the register */ 419 val = (clk_id << 3) & mask; /* bit 4:5 in the register */
378 reg = TAS2552_CFG_1; 420 reg = TAS2552_CFG_1;
421 tas2552->pll_clk_id = clk_id;
379 tas2552->pll_clkin = freq; 422 tas2552->pll_clkin = freq;
380 break; 423 break;
381 case TAS2552_PDM_CLK_PLL: 424 case TAS2552_PDM_CLK_PLL:
@@ -385,6 +428,7 @@ static int tas2552_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
385 mask = TAS2552_PDM_CLK_SEL_MASK; 428 mask = TAS2552_PDM_CLK_SEL_MASK;
386 val = (clk_id >> 1) & mask; /* bit 0:1 in the register */ 429 val = (clk_id >> 1) & mask; /* bit 0:1 in the register */
387 reg = TAS2552_PDM_CFG; 430 reg = TAS2552_PDM_CFG;
431 tas2552->pdm_clk_id = clk_id;
388 tas2552->pdm_clk = freq; 432 tas2552->pdm_clk = freq;
389 break; 433 break;
390 default: 434 default:
diff --git a/sound/soc/codecs/tas2552.h b/sound/soc/codecs/tas2552.h
index bbb820495516..6806516a62cd 100644
--- a/sound/soc/codecs/tas2552.h
+++ b/sound/soc/codecs/tas2552.h
@@ -128,12 +128,9 @@
128#define TAS2552_APT_THRESH_2_1_7 (0x11 << 2) 128#define TAS2552_APT_THRESH_2_1_7 (0x11 << 2)
129 129
130/* PLL Control Register */ 130/* PLL Control Register */
131#define TAS2552_245MHZ_CLK 24576000 131#define TAS2552_PLL_J_MASK 0x7f
132#define TAS2552_225MHZ_CLK 22579200 132#define TAS2552_PLL_D_UPPER(x) (((x) >> 8) & 0x3f)
133#define TAS2552_PLL_J_MASK 0x7f 133#define TAS2552_PLL_D_LOWER(x) ((x) & 0xff)
134#define TAS2552_PLL_D_UPPER_MASK 0x3f 134#define TAS2552_PLL_BYPASS (1 << 7)
135#define TAS2552_PLL_D_LOWER_MASK 0xff
136#define TAS2552_PLL_BYPASS_MASK 0x80
137#define TAS2552_PLL_BYPASS 0x80
138 135
139#endif 136#endif