aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Ujfalusi <peter.ujfalusi@ti.com>2016-06-20 10:07:18 -0400
committerLee Jones <lee.jones@linaro.org>2016-06-29 05:16:43 -0400
commit0a58da1e2f25f213fb72d7d6a18dff9562621215 (patch)
tree8a6751f3090f1946f33ac1974b5f7d5f5fd957c0
parent1db3ba2830bc2cd174f1b60da156d77214bed681 (diff)
mfd: twl6040: Handle mclk used for HPPLL and optional internal clock source
On some boards, like omap5-uevm the MCLK is gated by default and in order to be able to use the High performance modes of twl6040 it need to be enabled by SW. Add support for handling the MCLK source clock via CCF. At the same time lower the print priority of the notification that the 32K clock is not provided and it is not going to be handled by the driver. Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com> Acked-by: Rob Herring <robh@kernel.org> Signed-off-by: Lee Jones <lee.jones@linaro.org>
-rw-r--r--Documentation/devicetree/bindings/mfd/twl6040.txt4
-rw-r--r--drivers/mfd/twl6040.c41
-rw-r--r--include/linux/mfd/twl6040.h5
3 files changed, 34 insertions, 16 deletions
diff --git a/Documentation/devicetree/bindings/mfd/twl6040.txt b/Documentation/devicetree/bindings/mfd/twl6040.txt
index a41157b5d930..e6afdfa3543d 100644
--- a/Documentation/devicetree/bindings/mfd/twl6040.txt
+++ b/Documentation/devicetree/bindings/mfd/twl6040.txt
@@ -19,8 +19,8 @@ Required properties:
19 19
20Optional properties, nodes: 20Optional properties, nodes:
21- enable-active-high: To power on the twl6040 during boot. 21- enable-active-high: To power on the twl6040 during boot.
22- clocks: phandle to the clk32k clock provider 22- clocks: phandle to the clk32k and/or to mclk clock provider
23- clock-names: Must be "clk32k" 23- clock-names: Must be "clk32k" for the 32K clock and "mclk" for the MCLK.
24 24
25Vibra functionality 25Vibra functionality
26Required properties: 26Required properties:
diff --git a/drivers/mfd/twl6040.c b/drivers/mfd/twl6040.c
index 852d5874aabb..ab328ec49353 100644
--- a/drivers/mfd/twl6040.c
+++ b/drivers/mfd/twl6040.c
@@ -323,8 +323,7 @@ int twl6040_power(struct twl6040 *twl6040, int on)
323 323
324 /* Default PLL configuration after power up */ 324 /* Default PLL configuration after power up */
325 twl6040->pll = TWL6040_SYSCLK_SEL_LPPLL; 325 twl6040->pll = TWL6040_SYSCLK_SEL_LPPLL;
326 twl6040->sysclk = 19200000; 326 twl6040->sysclk_rate = 19200000;
327 twl6040->mclk = 32768;
328 } else { 327 } else {
329 /* already powered-down */ 328 /* already powered-down */
330 if (!twl6040->power_count) { 329 if (!twl6040->power_count) {
@@ -352,8 +351,12 @@ int twl6040_power(struct twl6040 *twl6040, int on)
352 regcache_cache_only(twl6040->regmap, true); 351 regcache_cache_only(twl6040->regmap, true);
353 regcache_mark_dirty(twl6040->regmap); 352 regcache_mark_dirty(twl6040->regmap);
354 353
355 twl6040->sysclk = 0; 354 twl6040->sysclk_rate = 0;
356 twl6040->mclk = 0; 355
356 if (twl6040->pll == TWL6040_SYSCLK_SEL_HPPLL) {
357 clk_disable_unprepare(twl6040->mclk);
358 twl6040->mclk_rate = 0;
359 }
357 360
358 clk_disable_unprepare(twl6040->clk32k); 361 clk_disable_unprepare(twl6040->clk32k);
359 } 362 }
@@ -377,15 +380,15 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id,
377 380
378 /* Force full reconfiguration when switching between PLL */ 381 /* Force full reconfiguration when switching between PLL */
379 if (pll_id != twl6040->pll) { 382 if (pll_id != twl6040->pll) {
380 twl6040->sysclk = 0; 383 twl6040->sysclk_rate = 0;
381 twl6040->mclk = 0; 384 twl6040->mclk_rate = 0;
382 } 385 }
383 386
384 switch (pll_id) { 387 switch (pll_id) {
385 case TWL6040_SYSCLK_SEL_LPPLL: 388 case TWL6040_SYSCLK_SEL_LPPLL:
386 /* low-power PLL divider */ 389 /* low-power PLL divider */
387 /* Change the sysclk configuration only if it has been canged */ 390 /* Change the sysclk configuration only if it has been canged */
388 if (twl6040->sysclk != freq_out) { 391 if (twl6040->sysclk_rate != freq_out) {
389 switch (freq_out) { 392 switch (freq_out) {
390 case 17640000: 393 case 17640000:
391 lppllctl |= TWL6040_LPLLFIN; 394 lppllctl |= TWL6040_LPLLFIN;
@@ -427,6 +430,8 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id,
427 ret = -EINVAL; 430 ret = -EINVAL;
428 goto pll_out; 431 goto pll_out;
429 } 432 }
433
434 clk_disable_unprepare(twl6040->mclk);
430 break; 435 break;
431 case TWL6040_SYSCLK_SEL_HPPLL: 436 case TWL6040_SYSCLK_SEL_HPPLL:
432 /* high-performance PLL can provide only 19.2 MHz */ 437 /* high-performance PLL can provide only 19.2 MHz */
@@ -437,7 +442,7 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id,
437 goto pll_out; 442 goto pll_out;
438 } 443 }
439 444
440 if (twl6040->mclk != freq_in) { 445 if (twl6040->mclk_rate != freq_in) {
441 hppllctl &= ~TWL6040_MCLK_MSK; 446 hppllctl &= ~TWL6040_MCLK_MSK;
442 447
443 switch (freq_in) { 448 switch (freq_in) {
@@ -468,6 +473,9 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id,
468 goto pll_out; 473 goto pll_out;
469 } 474 }
470 475
476 /* When switching to HPPLL, enable the mclk first */
477 if (pll_id != twl6040->pll)
478 clk_prepare_enable(twl6040->mclk);
471 /* 479 /*
472 * enable clock slicer to ensure input waveform is 480 * enable clock slicer to ensure input waveform is
473 * square 481 * square
@@ -483,6 +491,8 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id,
483 lppllctl &= ~TWL6040_LPLLENA; 491 lppllctl &= ~TWL6040_LPLLENA;
484 twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, 492 twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL,
485 lppllctl); 493 lppllctl);
494
495 twl6040->mclk_rate = freq_in;
486 } 496 }
487 break; 497 break;
488 default: 498 default:
@@ -491,8 +501,7 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id,
491 goto pll_out; 501 goto pll_out;
492 } 502 }
493 503
494 twl6040->sysclk = freq_out; 504 twl6040->sysclk_rate = freq_out;
495 twl6040->mclk = freq_in;
496 twl6040->pll = pll_id; 505 twl6040->pll = pll_id;
497 506
498pll_out: 507pll_out:
@@ -512,7 +521,7 @@ EXPORT_SYMBOL(twl6040_get_pll);
512 521
513unsigned int twl6040_get_sysclk(struct twl6040 *twl6040) 522unsigned int twl6040_get_sysclk(struct twl6040 *twl6040)
514{ 523{
515 return twl6040->sysclk; 524 return twl6040->sysclk_rate;
516} 525}
517EXPORT_SYMBOL(twl6040_get_sysclk); 526EXPORT_SYMBOL(twl6040_get_sysclk);
518 527
@@ -655,10 +664,18 @@ static int twl6040_probe(struct i2c_client *client,
655 if (IS_ERR(twl6040->clk32k)) { 664 if (IS_ERR(twl6040->clk32k)) {
656 if (PTR_ERR(twl6040->clk32k) == -EPROBE_DEFER) 665 if (PTR_ERR(twl6040->clk32k) == -EPROBE_DEFER)
657 return -EPROBE_DEFER; 666 return -EPROBE_DEFER;
658 dev_info(&client->dev, "clk32k is not handled\n"); 667 dev_dbg(&client->dev, "clk32k is not handled\n");
659 twl6040->clk32k = NULL; 668 twl6040->clk32k = NULL;
660 } 669 }
661 670
671 twl6040->mclk = devm_clk_get(&client->dev, "mclk");
672 if (IS_ERR(twl6040->mclk)) {
673 if (PTR_ERR(twl6040->mclk) == -EPROBE_DEFER)
674 return -EPROBE_DEFER;
675 dev_dbg(&client->dev, "mclk is not handled\n");
676 twl6040->mclk = NULL;
677 }
678
662 twl6040->supplies[0].supply = "vio"; 679 twl6040->supplies[0].supply = "vio";
663 twl6040->supplies[1].supply = "v2v1"; 680 twl6040->supplies[1].supply = "v2v1";
664 ret = devm_regulator_bulk_get(&client->dev, TWL6040_NUM_SUPPLIES, 681 ret = devm_regulator_bulk_get(&client->dev, TWL6040_NUM_SUPPLIES,
diff --git a/include/linux/mfd/twl6040.h b/include/linux/mfd/twl6040.h
index 8e95cd87cd74..36795a1be479 100644
--- a/include/linux/mfd/twl6040.h
+++ b/include/linux/mfd/twl6040.h
@@ -226,6 +226,7 @@ struct twl6040 {
226 struct regmap_irq_chip_data *irq_data; 226 struct regmap_irq_chip_data *irq_data;
227 struct regulator_bulk_data supplies[2]; /* supplies for vio, v2v1 */ 227 struct regulator_bulk_data supplies[2]; /* supplies for vio, v2v1 */
228 struct clk *clk32k; 228 struct clk *clk32k;
229 struct clk *mclk;
229 struct mutex mutex; 230 struct mutex mutex;
230 struct mutex irq_mutex; 231 struct mutex irq_mutex;
231 struct mfd_cell cells[TWL6040_CELLS]; 232 struct mfd_cell cells[TWL6040_CELLS];
@@ -237,8 +238,8 @@ struct twl6040 {
237 238
238 /* PLL configuration */ 239 /* PLL configuration */
239 int pll; 240 int pll;
240 unsigned int sysclk; 241 unsigned int sysclk_rate;
241 unsigned int mclk; 242 unsigned int mclk_rate;
242 243
243 unsigned int irq; 244 unsigned int irq;
244 unsigned int irq_ready; 245 unsigned int irq_ready;