diff options
author | Igor Grinberg <grinberg@compulab.co.il> | 2012-01-06 18:59:58 +1100 |
---|---|---|
committer | Paul Kocialkowski <contact@paulk.fr> | 2013-05-05 23:42:36 +0200 |
commit | 0112d0991ad02ee78af5bfd325a9543f1a99bf7f (patch) | |
tree | dc513f294d0c437bff4de8feb31cf76bd35f10ec | |
parent | b7e6d3ba0a71caa4581db68e1a8475e3239d7abc (diff) | |
download | kernel_goldelico_gta04-0112d0991ad02ee78af5bfd325a9543f1a99bf7f.zip kernel_goldelico_gta04-0112d0991ad02ee78af5bfd325a9543f1a99bf7f.tar.gz kernel_goldelico_gta04-0112d0991ad02ee78af5bfd325a9543f1a99bf7f.tar.bz2 |
MFD: TWL: add power off functionality
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: NeilBrown <neilb@suse.de>
-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 a764676..d905f51 100644 --- a/drivers/mfd/twl4030-power.c +++ b/drivers/mfd/twl4030-power.c @@ -34,7 +34,8 @@ static u8 twl4030_start_script_address = 0x2b; #define PWR_P1_SW_EVENTS 0x10 -#define PWR_DEVOFF (1<<0) +#define PWR_DEVOFF (1 << 0) +#define SEQ_OFFSYNC (1 << 0) #define PHY_TO_OFF_PM_MASTER(p) (p - 0x36) #define PHY_TO_OFF_PM_RECEIVER(p) (p - 0x5b) @@ -511,12 +512,27 @@ int twl4030_remove_script(u8 flags) return err; } +/* + * In master mode, start the power off sequence. + * After a successful execution, TWL shuts down the power to the SoC + * and all peripherals connected to it. + */ +void twl4030_power_off(void) +{ + int err; + + err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, PWR_DEVOFF, + TWL4030_PM_MASTER_P1_SW_EVENTS); + if (err) + pr_err("TWL4030 Unable to power off\n"); +} + void __init twl4030_power_init(struct twl4030_power_data *twl4030_scripts) { int err = 0; int i; struct twl4030_resconfig *resconfig; - u8 address = twl4030_start_script_address; + u8 val, address = twl4030_start_script_address; err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, TWL4030_PM_MASTER_KEY_CFG1, @@ -548,6 +564,28 @@ void __init twl4030_power_init(struct twl4030_power_data *twl4030_scripts) } } + /* Board has to be wired properly to use this feature */ + if (twl4030_scripts->use_poweroff && !pm_power_off) { + /* Default for SEQ_OFFSYNC is set, lets ensure this */ + err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &val, + TWL4030_PM_MASTER_CFG_P123_TRANSITION); + if (err) { + pr_warning("TWL4030 Unable to read registers\n"); + + } else if (!(val & SEQ_OFFSYNC)) { + val |= SEQ_OFFSYNC; + err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, val, + TWL4030_PM_MASTER_CFG_P123_TRANSITION); + if (err) { + pr_err("TWL4030 Unable to setup SEQ_OFFSYNC\n"); + goto relock; + } + } + + pm_power_off = twl4030_power_off; + } + +relock: err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, TWL4030_PM_MASTER_PROTECT_KEY); if (err) diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h index ba4f886..52d451b 100644 --- a/include/linux/i2c/twl.h +++ b/include/linux/i2c/twl.h @@ -652,10 +652,12 @@ struct twl4030_power_data { unsigned num; struct twl4030_resconfig *resource_config; #define TWL4030_RESCONFIG_UNDEF ((u8)-1) + bool use_poweroff; /* Board is wired for TWL poweroff */ }; extern void twl4030_power_init(struct twl4030_power_data *triton2_scripts); extern int twl4030_remove_script(u8 flags); +extern void twl4030_power_off(void); struct twl4030_codec_audio_data { unsigned int digimic_delay; /* in ms */ |