aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd
diff options
context:
space:
mode:
authorTony Lindgren <tony@atomide.com>2014-05-20 14:17:54 -0400
committerLee Jones <lee.jones@linaro.org>2014-05-28 03:05:32 -0400
commite7cd1d1eb16fcdf53001b926187a82f1f3e1a7e6 (patch)
tree2dac768a3fe773e824f5dd9a744defdc0af57a55 /drivers/mfd
parent320572813ded2cc17581b22cdc5dc775aaf83f53 (diff)
mfd: twl4030-power: Add generic reset configuration
The twl4030 PMIC needs to be configured properly for things like warm reset and deeper idle states so the PMIC manages the regulators properly based on the hardware triggers from the SoC. Earlier we have configured twl4030 using platform data, but we want to do it for device tree based booting also. In some cases configuring twl4030 is needed for things to work. For example, when rebooting an OMAP3530 at 125 MHz, it hangs. With this patch, TWL4030 will be reset when a warm reset occures, and OMAP3530 does not hang on reboot. Let's add device tree support and configure things for warm reset as the default when compatible = "ti,twl4030-power". More complicated configurations can be added to the driver based on other compatible flags. Note we now also make the pdata const like it should be. This allows use it for match->data with the device tree related functions. Based on earlier patch by Matthias Brugger <matthias.bgg@gmail.com> and Lesly A M <leslyam@ti.com>. Signed-off-by: Tony Lindgren <tony@atomide.com> Signed-off-by: Lee Jones <lee.jones@linaro.org>
Diffstat (limited to 'drivers/mfd')
-rw-r--r--drivers/mfd/twl4030-power.c109
1 files changed, 96 insertions, 13 deletions
diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c
index 0b037dca46a8..cb5b0cb8f933 100644
--- a/drivers/mfd/twl4030-power.c
+++ b/drivers/mfd/twl4030-power.c
@@ -29,6 +29,7 @@
29#include <linux/i2c/twl.h> 29#include <linux/i2c/twl.h>
30#include <linux/platform_device.h> 30#include <linux/platform_device.h>
31#include <linux/of.h> 31#include <linux/of.h>
32#include <linux/of_device.h>
32 33
33#include <asm/mach-types.h> 34#include <asm/mach-types.h>
34 35
@@ -128,6 +129,40 @@ static u8 res_config_addrs[] = {
128 [RES_MAIN_REF] = 0x94, 129 [RES_MAIN_REF] = 0x94,
129}; 130};
130 131
132/*
133 * Usable values for .remap_sleep and .remap_off
134 * Based on table "5.3.3 Resource Operating modes"
135 */
136enum {
137 TWL_REMAP_OFF = 0,
138 TWL_REMAP_SLEEP = 8,
139 TWL_REMAP_ACTIVE = 9,
140};
141
142/*
143 * Macros to configure the PM register states for various resources.
144 * Note that we can make MSG_SINGULAR etc private to this driver once
145 * omap3 has been made DT only.
146 */
147#define TWL_DFLT_DELAY 2 /* typically 2 32 KiHz cycles */
148#define TWL_RESOURCE_SET(res, state) \
149 { MSG_SINGULAR(DEV_GRP_NULL, (res), (state)), TWL_DFLT_DELAY }
150#define TWL_RESOURCE_ON(res) TWL_RESOURCE_SET(res, RES_STATE_ACTIVE)
151#define TWL_RESOURCE_OFF(res) TWL_RESOURCE_SET(res, RES_STATE_OFF)
152#define TWL_RESOURCE_RESET(res) TWL_RESOURCE_SET(res, RES_STATE_WRST)
153/*
154 * It seems that type1 and type2 is just the resource init order
155 * number for the type1 and type2 group.
156 */
157#define TWL_RESOURCE_GROUP_RESET(group, type1, type2) \
158 { MSG_BROADCAST(DEV_GRP_NULL, (group), (type1), (type2), \
159 RES_STATE_WRST), TWL_DFLT_DELAY }
160#define TWL_REMAP_SLEEP(res, devgrp, typ, typ2) \
161 { .resource = (res), .devgroup = (devgrp), \
162 .type = (typ), .type2 = (typ2), \
163 .remap_off = TWL_REMAP_OFF, \
164 .remap_sleep = TWL_REMAP_SLEEP, }
165
131static int twl4030_write_script_byte(u8 address, u8 byte) 166static int twl4030_write_script_byte(u8 address, u8 byte)
132{ 167{
133 int err; 168 int err;
@@ -502,7 +537,8 @@ int twl4030_remove_script(u8 flags)
502 return err; 537 return err;
503} 538}
504 539
505static int twl4030_power_configure_scripts(struct twl4030_power_data *pdata) 540static int
541twl4030_power_configure_scripts(const struct twl4030_power_data *pdata)
506{ 542{
507 int err; 543 int err;
508 int i; 544 int i;
@@ -518,7 +554,8 @@ static int twl4030_power_configure_scripts(struct twl4030_power_data *pdata)
518 return 0; 554 return 0;
519} 555}
520 556
521static int twl4030_power_configure_resources(struct twl4030_power_data *pdata) 557static int
558twl4030_power_configure_resources(const struct twl4030_power_data *pdata)
522{ 559{
523 struct twl4030_resconfig *resconfig = pdata->resource_config; 560 struct twl4030_resconfig *resconfig = pdata->resource_config;
524 int err; 561 int err;
@@ -550,7 +587,7 @@ void twl4030_power_off(void)
550 pr_err("TWL4030 Unable to power off\n"); 587 pr_err("TWL4030 Unable to power off\n");
551} 588}
552 589
553static bool twl4030_power_use_poweroff(struct twl4030_power_data *pdata, 590static bool twl4030_power_use_poweroff(const struct twl4030_power_data *pdata,
554 struct device_node *node) 591 struct device_node *node)
555{ 592{
556 if (pdata && pdata->use_poweroff) 593 if (pdata && pdata->use_poweroff)
@@ -562,10 +599,60 @@ static bool twl4030_power_use_poweroff(struct twl4030_power_data *pdata,
562 return false; 599 return false;
563} 600}
564 601
602#ifdef CONFIG_OF
603
604/* Generic warm reset configuration for omap3 */
605
606static struct twl4030_ins omap3_wrst_seq[] = {
607 TWL_RESOURCE_OFF(RES_NRES_PWRON),
608 TWL_RESOURCE_OFF(RES_RESET),
609 TWL_RESOURCE_RESET(RES_MAIN_REF),
610 TWL_RESOURCE_GROUP_RESET(RES_GRP_ALL, RES_TYPE_R0, RES_TYPE2_R2),
611 TWL_RESOURCE_RESET(RES_VUSB_3V1),
612 TWL_RESOURCE_GROUP_RESET(RES_GRP_ALL, RES_TYPE_R0, RES_TYPE2_R1),
613 TWL_RESOURCE_GROUP_RESET(RES_GRP_RC, RES_TYPE_ALL, RES_TYPE2_R0),
614 TWL_RESOURCE_ON(RES_RESET),
615 TWL_RESOURCE_ON(RES_NRES_PWRON),
616};
617
618static struct twl4030_script omap3_wrst_script = {
619 .script = omap3_wrst_seq,
620 .size = ARRAY_SIZE(omap3_wrst_seq),
621 .flags = TWL4030_WRST_SCRIPT,
622};
623
624static struct twl4030_script *omap3_reset_scripts[] = {
625 &omap3_wrst_script,
626};
627
628static struct twl4030_resconfig omap3_rconfig[] = {
629 TWL_REMAP_SLEEP(RES_HFCLKOUT, DEV_GRP_P3, -1, -1),
630 TWL_REMAP_SLEEP(RES_VDD1, DEV_GRP_P1, -1, -1),
631 TWL_REMAP_SLEEP(RES_VDD2, DEV_GRP_P1, -1, -1),
632 { 0, 0 },
633};
634
635static struct twl4030_power_data omap3_reset = {
636 .scripts = omap3_reset_scripts,
637 .num = ARRAY_SIZE(omap3_reset_scripts),
638 .resource_config = omap3_rconfig,
639};
640
641static struct of_device_id twl4030_power_of_match[] = {
642 {
643 .compatible = "ti,twl4030-power-reset",
644 .data = &omap3_reset,
645 },
646 { },
647};
648MODULE_DEVICE_TABLE(of, twl4030_power_of_match);
649#endif /* CONFIG_OF */
650
565static int twl4030_power_probe(struct platform_device *pdev) 651static int twl4030_power_probe(struct platform_device *pdev)
566{ 652{
567 struct twl4030_power_data *pdata = dev_get_platdata(&pdev->dev); 653 const struct twl4030_power_data *pdata = dev_get_platdata(&pdev->dev);
568 struct device_node *node = pdev->dev.of_node; 654 struct device_node *node = pdev->dev.of_node;
655 const struct of_device_id *match;
569 int err = 0; 656 int err = 0;
570 int err2 = 0; 657 int err2 = 0;
571 u8 val; 658 u8 val;
@@ -586,8 +673,12 @@ static int twl4030_power_probe(struct platform_device *pdev)
586 return err; 673 return err;
587 } 674 }
588 675
676 match = of_match_device(of_match_ptr(twl4030_power_of_match),
677 &pdev->dev);
678 if (match && match->data)
679 pdata = match->data;
680
589 if (pdata) { 681 if (pdata) {
590 /* TODO: convert to device tree */
591 err = twl4030_power_configure_scripts(pdata); 682 err = twl4030_power_configure_scripts(pdata);
592 if (err) { 683 if (err) {
593 pr_err("TWL4030 failed to load scripts\n"); 684 pr_err("TWL4030 failed to load scripts\n");
@@ -637,14 +728,6 @@ static int twl4030_power_remove(struct platform_device *pdev)
637 return 0; 728 return 0;
638} 729}
639 730
640#ifdef CONFIG_OF
641static const struct of_device_id twl4030_power_of_match[] = {
642 {.compatible = "ti,twl4030-power", },
643 { },
644};
645MODULE_DEVICE_TABLE(of, twl4030_power_of_match);
646#endif
647
648static struct platform_driver twl4030_power_driver = { 731static struct platform_driver twl4030_power_driver = {
649 .driver = { 732 .driver = {
650 .name = "twl4030_power", 733 .name = "twl4030_power",