diff options
Diffstat (limited to 'drivers/mfd/twl4030-power.c')
-rw-r--r-- | drivers/mfd/twl4030-power.c | 52 |
1 files changed, 52 insertions, 0 deletions
diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c index cf92a6d1c532..50f9091bcd38 100644 --- a/drivers/mfd/twl4030-power.c +++ b/drivers/mfd/twl4030-power.c | |||
@@ -44,6 +44,15 @@ static u8 twl4030_start_script_address = 0x2b; | |||
44 | #define PWR_DEVSLP BIT(1) | 44 | #define PWR_DEVSLP BIT(1) |
45 | #define PWR_DEVOFF BIT(0) | 45 | #define PWR_DEVOFF BIT(0) |
46 | 46 | ||
47 | /* Register bits for CFG_P1_TRANSITION (also for P2 and P3) */ | ||
48 | #define STARTON_SWBUG BIT(7) /* Start on watchdog */ | ||
49 | #define STARTON_VBUS BIT(5) /* Start on VBUS */ | ||
50 | #define STARTON_VBAT BIT(4) /* Start on battery insert */ | ||
51 | #define STARTON_RTC BIT(3) /* Start on RTC */ | ||
52 | #define STARTON_USB BIT(2) /* Start on USB host */ | ||
53 | #define STARTON_CHG BIT(1) /* Start on charger */ | ||
54 | #define STARTON_PWON BIT(0) /* Start on PWRON button */ | ||
55 | |||
47 | #define SEQ_OFFSYNC (1 << 0) | 56 | #define SEQ_OFFSYNC (1 << 0) |
48 | 57 | ||
49 | #define PHY_TO_OFF_PM_MASTER(p) (p - 0x36) | 58 | #define PHY_TO_OFF_PM_MASTER(p) (p - 0x36) |
@@ -606,6 +615,44 @@ twl4030_power_configure_resources(const struct twl4030_power_data *pdata) | |||
606 | return 0; | 615 | return 0; |
607 | } | 616 | } |
608 | 617 | ||
618 | static int twl4030_starton_mask_and_set(u8 bitmask, u8 bitvalues) | ||
619 | { | ||
620 | u8 regs[3] = { TWL4030_PM_MASTER_CFG_P1_TRANSITION, | ||
621 | TWL4030_PM_MASTER_CFG_P2_TRANSITION, | ||
622 | TWL4030_PM_MASTER_CFG_P3_TRANSITION, }; | ||
623 | u8 val; | ||
624 | int i, err; | ||
625 | |||
626 | err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, TWL4030_PM_MASTER_KEY_CFG1, | ||
627 | TWL4030_PM_MASTER_PROTECT_KEY); | ||
628 | if (err) | ||
629 | goto relock; | ||
630 | err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, | ||
631 | TWL4030_PM_MASTER_KEY_CFG2, | ||
632 | TWL4030_PM_MASTER_PROTECT_KEY); | ||
633 | if (err) | ||
634 | goto relock; | ||
635 | |||
636 | for (i = 0; i < sizeof(regs); i++) { | ||
637 | err = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, | ||
638 | &val, regs[i]); | ||
639 | if (err) | ||
640 | break; | ||
641 | val = (~bitmask & val) | (bitmask & bitvalues); | ||
642 | err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, | ||
643 | val, regs[i]); | ||
644 | if (err) | ||
645 | break; | ||
646 | } | ||
647 | |||
648 | if (err) | ||
649 | pr_err("TWL4030 Register access failed: %i\n", err); | ||
650 | |||
651 | relock: | ||
652 | return twl_i2c_write_u8(TWL_MODULE_PM_MASTER, 0, | ||
653 | TWL4030_PM_MASTER_PROTECT_KEY); | ||
654 | } | ||
655 | |||
609 | /* | 656 | /* |
610 | * In master mode, start the power off sequence. | 657 | * In master mode, start the power off sequence. |
611 | * After a successful execution, TWL shuts down the power to the SoC | 658 | * After a successful execution, TWL shuts down the power to the SoC |
@@ -615,6 +662,11 @@ void twl4030_power_off(void) | |||
615 | { | 662 | { |
616 | int err; | 663 | int err; |
617 | 664 | ||
665 | /* Disable start on charger or VBUS as it can break poweroff */ | ||
666 | err = twl4030_starton_mask_and_set(STARTON_VBUS | STARTON_CHG, 0); | ||
667 | if (err) | ||
668 | pr_err("TWL4030 Unable to configure start-up\n"); | ||
669 | |||
618 | err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, PWR_DEVOFF, | 670 | err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, PWR_DEVOFF, |
619 | TWL4030_PM_MASTER_P1_SW_EVENTS); | 671 | TWL4030_PM_MASTER_P1_SW_EVENTS); |
620 | if (err) | 672 | if (err) |