aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd/twl6040-core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mfd/twl6040-core.c')
-rw-r--r--drivers/mfd/twl6040-core.c128
1 files changed, 77 insertions, 51 deletions
diff --git a/drivers/mfd/twl6040-core.c b/drivers/mfd/twl6040-core.c
index dda86293dc9f..b2d8e512d3cb 100644
--- a/drivers/mfd/twl6040-core.c
+++ b/drivers/mfd/twl6040-core.c
@@ -282,6 +282,7 @@ int twl6040_power(struct twl6040 *twl6040, int on)
282 /* Default PLL configuration after power up */ 282 /* Default PLL configuration after power up */
283 twl6040->pll = TWL6040_SYSCLK_SEL_LPPLL; 283 twl6040->pll = TWL6040_SYSCLK_SEL_LPPLL;
284 twl6040->sysclk = 19200000; 284 twl6040->sysclk = 19200000;
285 twl6040->mclk = 32768;
285 } else { 286 } else {
286 /* already powered-down */ 287 /* already powered-down */
287 if (!twl6040->power_count) { 288 if (!twl6040->power_count) {
@@ -305,6 +306,7 @@ int twl6040_power(struct twl6040 *twl6040, int on)
305 twl6040_power_down(twl6040); 306 twl6040_power_down(twl6040);
306 } 307 }
307 twl6040->sysclk = 0; 308 twl6040->sysclk = 0;
309 twl6040->mclk = 0;
308 } 310 }
309 311
310out: 312out:
@@ -324,23 +326,38 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id,
324 hppllctl = twl6040_reg_read(twl6040, TWL6040_REG_HPPLLCTL); 326 hppllctl = twl6040_reg_read(twl6040, TWL6040_REG_HPPLLCTL);
325 lppllctl = twl6040_reg_read(twl6040, TWL6040_REG_LPPLLCTL); 327 lppllctl = twl6040_reg_read(twl6040, TWL6040_REG_LPPLLCTL);
326 328
329 /* Force full reconfiguration when switching between PLL */
330 if (pll_id != twl6040->pll) {
331 twl6040->sysclk = 0;
332 twl6040->mclk = 0;
333 }
334
327 switch (pll_id) { 335 switch (pll_id) {
328 case TWL6040_SYSCLK_SEL_LPPLL: 336 case TWL6040_SYSCLK_SEL_LPPLL:
329 /* low-power PLL divider */ 337 /* low-power PLL divider */
330 switch (freq_out) { 338 /* Change the sysclk configuration only if it has been canged */
331 case 17640000: 339 if (twl6040->sysclk != freq_out) {
332 lppllctl |= TWL6040_LPLLFIN; 340 switch (freq_out) {
333 break; 341 case 17640000:
334 case 19200000: 342 lppllctl |= TWL6040_LPLLFIN;
335 lppllctl &= ~TWL6040_LPLLFIN; 343 break;
336 break; 344 case 19200000:
337 default: 345 lppllctl &= ~TWL6040_LPLLFIN;
338 dev_err(twl6040->dev, 346 break;
339 "freq_out %d not supported\n", freq_out); 347 default:
340 ret = -EINVAL; 348 dev_err(twl6040->dev,
341 goto pll_out; 349 "freq_out %d not supported\n",
350 freq_out);
351 ret = -EINVAL;
352 goto pll_out;
353 }
354 twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL,
355 lppllctl);
342 } 356 }
343 twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, lppllctl); 357
358 /* The PLL in use has not been change, we can exit */
359 if (twl6040->pll == pll_id)
360 break;
344 361
345 switch (freq_in) { 362 switch (freq_in) {
346 case 32768: 363 case 32768:
@@ -371,48 +388,56 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id,
371 goto pll_out; 388 goto pll_out;
372 } 389 }
373 390
374 hppllctl &= ~TWL6040_MCLK_MSK; 391 if (twl6040->mclk != freq_in) {
392 hppllctl &= ~TWL6040_MCLK_MSK;
393
394 switch (freq_in) {
395 case 12000000:
396 /* PLL enabled, active mode */
397 hppllctl |= TWL6040_MCLK_12000KHZ |
398 TWL6040_HPLLENA;
399 break;
400 case 19200000:
401 /*
402 * PLL disabled
403 * (enable PLL if MCLK jitter quality
404 * doesn't meet specification)
405 */
406 hppllctl |= TWL6040_MCLK_19200KHZ;
407 break;
408 case 26000000:
409 /* PLL enabled, active mode */
410 hppllctl |= TWL6040_MCLK_26000KHZ |
411 TWL6040_HPLLENA;
412 break;
413 case 38400000:
414 /* PLL enabled, active mode */
415 hppllctl |= TWL6040_MCLK_38400KHZ |
416 TWL6040_HPLLENA;
417 break;
418 default:
419 dev_err(twl6040->dev,
420 "freq_in %d not supported\n", freq_in);
421 ret = -EINVAL;
422 goto pll_out;
423 }
375 424
376 switch (freq_in) {
377 case 12000000:
378 /* PLL enabled, active mode */
379 hppllctl |= TWL6040_MCLK_12000KHZ |
380 TWL6040_HPLLENA;
381 break;
382 case 19200000:
383 /* 425 /*
384 * PLL disabled 426 * enable clock slicer to ensure input waveform is
385 * (enable PLL if MCLK jitter quality 427 * square
386 * doesn't meet specification)
387 */ 428 */
388 hppllctl |= TWL6040_MCLK_19200KHZ; 429 hppllctl |= TWL6040_HPLLSQRENA;
389 break;
390 case 26000000:
391 /* PLL enabled, active mode */
392 hppllctl |= TWL6040_MCLK_26000KHZ |
393 TWL6040_HPLLENA;
394 break;
395 case 38400000:
396 /* PLL enabled, active mode */
397 hppllctl |= TWL6040_MCLK_38400KHZ |
398 TWL6040_HPLLENA;
399 break;
400 default:
401 dev_err(twl6040->dev,
402 "freq_in %d not supported\n", freq_in);
403 ret = -EINVAL;
404 goto pll_out;
405 }
406 430
407 /* enable clock slicer to ensure input waveform is square */ 431 twl6040_reg_write(twl6040, TWL6040_REG_HPPLLCTL,
408 hppllctl |= TWL6040_HPLLSQRENA; 432 hppllctl);
409 433 usleep_range(500, 700);
410 twl6040_reg_write(twl6040, TWL6040_REG_HPPLLCTL, hppllctl); 434 lppllctl |= TWL6040_HPLLSEL;
411 usleep_range(500, 700); 435 twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL,
412 lppllctl |= TWL6040_HPLLSEL; 436 lppllctl);
413 twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, lppllctl); 437 lppllctl &= ~TWL6040_LPLLENA;
414 lppllctl &= ~TWL6040_LPLLENA; 438 twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL,
415 twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, lppllctl); 439 lppllctl);
440 }
416 break; 441 break;
417 default: 442 default:
418 dev_err(twl6040->dev, "unknown pll id %d\n", pll_id); 443 dev_err(twl6040->dev, "unknown pll id %d\n", pll_id);
@@ -421,6 +446,7 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id,
421 } 446 }
422 447
423 twl6040->sysclk = freq_out; 448 twl6040->sysclk = freq_out;
449 twl6040->mclk = freq_in;
424 twl6040->pll = pll_id; 450 twl6040->pll = pll_id;
425 451
426pll_out: 452pll_out: