diff options
author | Igor Grinberg <grinberg@compulab.co.il> | 2011-11-13 04:49:50 -0500 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2012-01-08 18:37:40 -0500 |
commit | 26cc3ab984cd00e95cb58ba5aaea4238ea56c700 (patch) | |
tree | 472a56db7678b50e3d6bba59c2f04a09e40635be | |
parent | aeb5032b3f8b9ab69daa545777433fa94b3494c4 (diff) |
mfd: Add power off functionality to TWL
TWL family of PMICs, used in master mode, have a power off
functionality. The resulting power off sequence shuts down all the SoC
supplies, LDOs, etc. The sequence is described in the datasheets
chapter "Power-Off Sequence".
Note, that board must be wired correctly for the power off to work as
expected.
Signed-off-by: Igor Grinberg <grinberg@compulab.co.il>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
-rw-r--r-- | drivers/mfd/twl4030-power.c | 42 | ||||
-rw-r--r-- | include/linux/i2c/twl.h | 2 |
2 files changed, 42 insertions, 2 deletions
diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c index a764676f0922..d905f5171153 100644 --- a/drivers/mfd/twl4030-power.c +++ b/drivers/mfd/twl4030-power.c | |||
@@ -34,7 +34,8 @@ | |||
34 | static u8 twl4030_start_script_address = 0x2b; | 34 | static u8 twl4030_start_script_address = 0x2b; |
35 | 35 | ||
36 | #define PWR_P1_SW_EVENTS 0x10 | 36 | #define PWR_P1_SW_EVENTS 0x10 |
37 | #define PWR_DEVOFF (1<<0) | 37 | #define PWR_DEVOFF (1 << 0) |
38 | #define SEQ_OFFSYNC (1 << 0) | ||
38 | 39 | ||
39 | #define PHY_TO_OFF_PM_MASTER(p) (p - 0x36) | 40 | #define PHY_TO_OFF_PM_MASTER(p) (p - 0x36) |
40 | #define PHY_TO_OFF_PM_RECEIVER(p) (p - 0x5b) | 41 | #define PHY_TO_OFF_PM_RECEIVER(p) (p - 0x5b) |
@@ -511,12 +512,27 @@ int twl4030_remove_script(u8 flags) | |||
511 | return err; | 512 | return err; |
512 | } | 513 | } |
513 | 514 | ||
515 | /* | ||
516 | * In master mode, start the power off sequence. | ||
517 | * After a successful execution, TWL shuts down the power to the SoC | ||
518 | * and all peripherals connected to it. | ||
519 | */ | ||
520 | void twl4030_power_off(void) | ||
521 | { | ||
522 | int err; | ||
523 | |||
524 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, PWR_DEVOFF, | ||
525 | TWL4030_PM_MASTER_P1_SW_EVENTS); | ||
526 | if (err) | ||
527 | pr_err("TWL4030 Unable to power off\n"); | ||
528 | } | ||
529 | |||
514 | void __init twl4030_power_init(struct twl4030_power_data *twl4030_scripts) | 530 | void __init twl4030_power_init(struct twl4030_power_data *twl4030_scripts) |
515 | { | 531 | { |
516 | int err = 0; | 532 | int err = 0; |
517 | int i; | 533 | int i; |
518 | struct twl4030_resconfig *resconfig; | 534 | struct twl4030_resconfig *resconfig; |
519 | u8 address = twl4030_start_script_address; | 535 | u8 val, address = twl4030_start_script_address; |
520 | 536 | ||
521 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, | 537 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, |
522 | TWL4030_PM_MASTER_KEY_CFG1, | 538 | TWL4030_PM_MASTER_KEY_CFG1, |
@@ -548,6 +564,28 @@ void __init twl4030_power_init(struct twl4030_power_data *twl4030_scripts) | |||
548 | } | 564 | } |
549 | } | 565 | } |
550 | 566 | ||
567 | /* Board has to be wired properly to use this feature */ | ||
568 | if (twl4030_scripts->use_poweroff && !pm_power_off) { | ||
569 | /* Default for SEQ_OFFSYNC is set, lets ensure this */ | ||
570 | err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &val, | ||
571 | TWL4030_PM_MASTER_CFG_P123_TRANSITION); | ||
572 | if (err) { | ||
573 | pr_warning("TWL4030 Unable to read registers\n"); | ||
574 | |||
575 | } else if (!(val & SEQ_OFFSYNC)) { | ||
576 | val |= SEQ_OFFSYNC; | ||
577 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, val, | ||
578 | TWL4030_PM_MASTER_CFG_P123_TRANSITION); | ||
579 | if (err) { | ||
580 | pr_err("TWL4030 Unable to setup SEQ_OFFSYNC\n"); | ||
581 | goto relock; | ||
582 | } | ||
583 | } | ||
584 | |||
585 | pm_power_off = twl4030_power_off; | ||
586 | } | ||
587 | |||
588 | relock: | ||
551 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, | 589 | err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, |
552 | TWL4030_PM_MASTER_PROTECT_KEY); | 590 | TWL4030_PM_MASTER_PROTECT_KEY); |
553 | if (err) | 591 | if (err) |
diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h index 114c0f6fc63d..78d3465251d6 100644 --- a/include/linux/i2c/twl.h +++ b/include/linux/i2c/twl.h | |||
@@ -652,10 +652,12 @@ struct twl4030_power_data { | |||
652 | unsigned num; | 652 | unsigned num; |
653 | struct twl4030_resconfig *resource_config; | 653 | struct twl4030_resconfig *resource_config; |
654 | #define TWL4030_RESCONFIG_UNDEF ((u8)-1) | 654 | #define TWL4030_RESCONFIG_UNDEF ((u8)-1) |
655 | bool use_poweroff; /* Board is wired for TWL poweroff */ | ||
655 | }; | 656 | }; |
656 | 657 | ||
657 | extern void twl4030_power_init(struct twl4030_power_data *triton2_scripts); | 658 | extern void twl4030_power_init(struct twl4030_power_data *triton2_scripts); |
658 | extern int twl4030_remove_script(u8 flags); | 659 | extern int twl4030_remove_script(u8 flags); |
660 | extern void twl4030_power_off(void); | ||
659 | 661 | ||
660 | struct twl4030_codec_data { | 662 | struct twl4030_codec_data { |
661 | unsigned int digimic_delay; /* in ms */ | 663 | unsigned int digimic_delay; /* in ms */ |