diff options
-rw-r--r-- | drivers/mfd/twl6040-core.c | 125 |
1 files changed, 74 insertions, 51 deletions
diff --git a/drivers/mfd/twl6040-core.c b/drivers/mfd/twl6040-core.c index c2088f4c4547..b2d8e512d3cb 100644 --- a/drivers/mfd/twl6040-core.c +++ b/drivers/mfd/twl6040-core.c | |||
@@ -326,23 +326,38 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id, | |||
326 | hppllctl = twl6040_reg_read(twl6040, TWL6040_REG_HPPLLCTL); | 326 | hppllctl = twl6040_reg_read(twl6040, TWL6040_REG_HPPLLCTL); |
327 | lppllctl = twl6040_reg_read(twl6040, TWL6040_REG_LPPLLCTL); | 327 | lppllctl = twl6040_reg_read(twl6040, TWL6040_REG_LPPLLCTL); |
328 | 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 | |||
329 | switch (pll_id) { | 335 | switch (pll_id) { |
330 | case TWL6040_SYSCLK_SEL_LPPLL: | 336 | case TWL6040_SYSCLK_SEL_LPPLL: |
331 | /* low-power PLL divider */ | 337 | /* low-power PLL divider */ |
332 | switch (freq_out) { | 338 | /* Change the sysclk configuration only if it has been canged */ |
333 | case 17640000: | 339 | if (twl6040->sysclk != freq_out) { |
334 | lppllctl |= TWL6040_LPLLFIN; | 340 | switch (freq_out) { |
335 | break; | 341 | case 17640000: |
336 | case 19200000: | 342 | lppllctl |= TWL6040_LPLLFIN; |
337 | lppllctl &= ~TWL6040_LPLLFIN; | 343 | break; |
338 | break; | 344 | case 19200000: |
339 | default: | 345 | lppllctl &= ~TWL6040_LPLLFIN; |
340 | dev_err(twl6040->dev, | 346 | break; |
341 | "freq_out %d not supported\n", freq_out); | 347 | default: |
342 | ret = -EINVAL; | 348 | dev_err(twl6040->dev, |
343 | 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); | ||
344 | } | 356 | } |
345 | 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; | ||
346 | 361 | ||
347 | switch (freq_in) { | 362 | switch (freq_in) { |
348 | case 32768: | 363 | case 32768: |
@@ -373,48 +388,56 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id, | |||
373 | goto pll_out; | 388 | goto pll_out; |
374 | } | 389 | } |
375 | 390 | ||
376 | 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 | } | ||
377 | 424 | ||
378 | switch (freq_in) { | ||
379 | case 12000000: | ||
380 | /* PLL enabled, active mode */ | ||
381 | hppllctl |= TWL6040_MCLK_12000KHZ | | ||
382 | TWL6040_HPLLENA; | ||
383 | break; | ||
384 | case 19200000: | ||
385 | /* | 425 | /* |
386 | * PLL disabled | 426 | * enable clock slicer to ensure input waveform is |
387 | * (enable PLL if MCLK jitter quality | 427 | * square |
388 | * doesn't meet specification) | ||
389 | */ | 428 | */ |
390 | hppllctl |= TWL6040_MCLK_19200KHZ; | 429 | hppllctl |= TWL6040_HPLLSQRENA; |
391 | break; | ||
392 | case 26000000: | ||
393 | /* PLL enabled, active mode */ | ||
394 | hppllctl |= TWL6040_MCLK_26000KHZ | | ||
395 | TWL6040_HPLLENA; | ||
396 | break; | ||
397 | case 38400000: | ||
398 | /* PLL enabled, active mode */ | ||
399 | hppllctl |= TWL6040_MCLK_38400KHZ | | ||
400 | TWL6040_HPLLENA; | ||
401 | break; | ||
402 | default: | ||
403 | dev_err(twl6040->dev, | ||
404 | "freq_in %d not supported\n", freq_in); | ||
405 | ret = -EINVAL; | ||
406 | goto pll_out; | ||
407 | } | ||
408 | 430 | ||
409 | /* enable clock slicer to ensure input waveform is square */ | 431 | twl6040_reg_write(twl6040, TWL6040_REG_HPPLLCTL, |
410 | hppllctl |= TWL6040_HPLLSQRENA; | 432 | hppllctl); |
411 | 433 | usleep_range(500, 700); | |
412 | twl6040_reg_write(twl6040, TWL6040_REG_HPPLLCTL, hppllctl); | 434 | lppllctl |= TWL6040_HPLLSEL; |
413 | usleep_range(500, 700); | 435 | twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, |
414 | lppllctl |= TWL6040_HPLLSEL; | 436 | lppllctl); |
415 | twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, lppllctl); | 437 | lppllctl &= ~TWL6040_LPLLENA; |
416 | lppllctl &= ~TWL6040_LPLLENA; | 438 | twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, |
417 | twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, lppllctl); | 439 | lppllctl); |
440 | } | ||
418 | break; | 441 | break; |
419 | default: | 442 | default: |
420 | dev_err(twl6040->dev, "unknown pll id %d\n", pll_id); | 443 | dev_err(twl6040->dev, "unknown pll id %d\n", pll_id); |