diff options
Diffstat (limited to 'drivers/regulator/twl-regulator.c')
-rw-r--r-- | drivers/regulator/twl-regulator.c | 184 |
1 files changed, 147 insertions, 37 deletions
diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c index 87fe0f7..f34ae3a 100644 --- a/drivers/regulator/twl-regulator.c +++ b/drivers/regulator/twl-regulator.c @@ -82,6 +82,18 @@ struct twlreg_info { #define VREG_BC_PROC 3 #define VREG_BC_CLK_RST 4 +/* TWL6030 LDO register values for CFG_TRANS */ +#define TWL6030_CFG_TRANS_STATE_MASK 0x03 +#define TWL6030_CFG_TRANS_STATE_OFF 0x00 +/* + * Auto means the following: + * SMPS: AUTO(PWM/PFM) + * LDO: AMS(SLP/ACT) + * resource: ON + */ +#define TWL6030_CFG_TRANS_STATE_AUTO 0x01 +#define TWL6030_CFG_TRANS_SLEEP_SHIFT 2 + /* TWL6030 LDO register values for CFG_STATE */ #define TWL6030_CFG_STATE_OFF 0x00 #define TWL6030_CFG_STATE_ON 0x01 @@ -104,6 +116,18 @@ struct twlreg_info { #define SMPS_MULTOFFSET_VIO BIT(1) #define SMPS_MULTOFFSET_SMPS3 BIT(6) +/* TWL6030 VUSB supplemental config registers */ +#define TWL6030_MISC2 0xE5 +#define TWL6030_CFG_LDO_PD2 0xF5 + +/* + * TWL603X SMPS has 6 bits xxxx_CFG_VOLTAGE.VSEL[5:0] to configure voltages and + * each bit combination corresponds to a particular voltage (value 63 is + * reserved). + */ +#define TWL603X_SMPS_VSEL_MASK 0x3F +#define TWL603X_SMPS_NUMBER_VOLTAGES TWL603X_SMPS_VSEL_MASK + static inline int twlreg_read(struct twlreg_info *info, unsigned slave_subgp, unsigned offset) { @@ -177,6 +201,32 @@ static int twl6030reg_is_enabled(struct regulator_dev *rdev) return grp && (val == TWL6030_CFG_STATE_ON); } +static int twl6030reg_set_trans_state(struct regulator_dev *rdev, + u8 shift, u8 val) +{ + struct twlreg_info *info = rdev_get_drvdata(rdev); + int rval; + u8 mask; + + /* Read CFG_TRANS register of TWL6030 */ + rval = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_TRANS); + + if (rval < 0) + return rval; + + mask = TWL6030_CFG_TRANS_STATE_MASK << shift; + val = (val << shift) & mask; + + /* If value is already set, no need to write to reg */ + if (val == (rval & mask)) + return 0; + + rval &= ~mask; + rval |= val; + + return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_TRANS, rval); +} + static int twl4030reg_enable(struct regulator_dev *rdev) { struct twlreg_info *info = rdev_get_drvdata(rdev); @@ -210,7 +260,14 @@ static int twl6030reg_enable(struct regulator_dev *rdev) ret = twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_STATE, grp << TWL6030_CFG_STATE_GRP_SHIFT | TWL6030_CFG_STATE_ON); - + /* + * Ensure it stays in Auto mode when we enter suspend state. + * (TWL6030 in sleep mode). + */ + if (!ret) + ret = twl6030reg_set_trans_state(rdev, + TWL6030_CFG_TRANS_SLEEP_SHIFT, + TWL6030_CFG_TRANS_STATE_AUTO); udelay(info->delay); return ret; @@ -247,6 +304,11 @@ static int twl6030reg_disable(struct regulator_dev *rdev) (grp) << TWL6030_CFG_STATE_GRP_SHIFT | TWL6030_CFG_STATE_OFF); + /* Ensure it remains OFF when we enter suspend (TWL6030 in sleep). */ + if (!ret) + ret = twl6030reg_set_trans_state(rdev, + TWL6030_CFG_TRANS_SLEEP_SHIFT, + TWL6030_CFG_TRANS_STATE_OFF); return ret; } @@ -357,6 +419,18 @@ static int twl6030reg_set_mode(struct regulator_dev *rdev, unsigned mode) return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_STATE, val); } +static int twl6030ldo_suspend_enable(struct regulator_dev *rdev) +{ + return twl6030reg_set_trans_state(rdev, TWL6030_CFG_TRANS_SLEEP_SHIFT, + TWL6030_CFG_TRANS_STATE_AUTO); +} + +static int twl6030ldo_suspend_disable(struct regulator_dev *rdev) +{ + return twl6030reg_set_trans_state(rdev, TWL6030_CFG_TRANS_SLEEP_SHIFT, + TWL6030_CFG_TRANS_STATE_OFF); +} + /*----------------------------------------------------------------------*/ /* @@ -570,6 +644,9 @@ static struct regulator_ops twl6030ldo_ops = { .set_mode = twl6030reg_set_mode, .get_status = twl6030reg_get_status, + + .set_suspend_enable = twl6030ldo_suspend_enable, + .set_suspend_disable = twl6030ldo_suspend_disable, }; /*----------------------------------------------------------------------*/ @@ -617,6 +694,9 @@ static struct regulator_ops twl6030fixed_ops = { .set_mode = twl6030reg_set_mode, .get_status = twl6030reg_get_status, + + .set_suspend_enable = twl6030ldo_suspend_enable, + .set_suspend_disable = twl6030ldo_suspend_disable, }; static struct regulator_ops twl6030_fixed_resource = { @@ -827,6 +907,9 @@ static struct regulator_ops twlsmps_ops = { .set_mode = twl6030reg_set_mode, .get_status = twl6030reg_get_status, + + .set_suspend_enable = twl6030ldo_suspend_enable, + .set_suspend_disable = twl6030ldo_suspend_disable, }; /*----------------------------------------------------------------------*/ @@ -835,8 +918,8 @@ static struct regulator_ops twlsmps_ops = { remap_conf) \ TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \ remap_conf, TWL4030, twl4030fixed_ops) -#define TWL6030_FIXED_LDO(label, offset, mVolts, num, turnon_delay) \ - TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \ +#define TWL6030_FIXED_LDO(label, offset, mVolts, turnon_delay) \ + TWL_FIXED_LDO(label, offset, mVolts, 0x0, turnon_delay, \ 0x0, TWL6030, twl6030fixed_ops) #define TWL4030_ADJUSTABLE_LDO(label, offset, num, turnon_delay, remap_conf) { \ @@ -856,24 +939,22 @@ static struct regulator_ops twlsmps_ops = { }, \ } -#define TWL6030_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts, num) { \ +#define TWL6030_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts) { \ .base = offset, \ - .id = num, \ .min_mV = min_mVolts, \ .max_mV = max_mVolts, \ .desc = { \ .name = #label, \ .id = TWL6030_REG_##label, \ - .n_voltages = (max_mVolts - min_mVolts)/100, \ + .n_voltages = (max_mVolts - min_mVolts)/100 + 1, \ .ops = &twl6030ldo_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ }, \ } -#define TWL6025_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts, num) { \ +#define TWL6025_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts) { \ .base = offset, \ - .id = num, \ .min_mV = min_mVolts, \ .max_mV = max_mVolts, \ .desc = { \ @@ -903,9 +984,8 @@ static struct regulator_ops twlsmps_ops = { }, \ } -#define TWL6030_FIXED_RESOURCE(label, offset, num, turnon_delay) { \ +#define TWL6030_FIXED_RESOURCE(label, offset, turnon_delay) { \ .base = offset, \ - .id = num, \ .delay = turnon_delay, \ .desc = { \ .name = #label, \ @@ -916,15 +996,28 @@ static struct regulator_ops twlsmps_ops = { }, \ } -#define TWL6025_ADJUSTABLE_SMPS(label, offset, num) { \ +#define TWL6030_ADJUSTABLE_SMPS(label, offset, min_mVolts, max_mVolts) { \ + .base = offset, \ + .min_mV = min_mVolts, \ + .max_mV = max_mVolts, \ + .desc = { \ + .name = #label, \ + .id = TWL6030_REG_##label, \ + .n_voltages = TWL603X_SMPS_NUMBER_VOLTAGES, \ + .ops = &twlsmps_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + }, \ + } + +#define TWL6025_ADJUSTABLE_SMPS(label, offset) { \ .base = offset, \ - .id = num, \ .min_mV = 600, \ .max_mV = 2100, \ .desc = { \ .name = #label, \ .id = TWL6025_REG_##label, \ - .n_voltages = 63, \ + .n_voltages = TWL603X_SMPS_NUMBER_VOLTAGES, \ .ops = &twlsmps_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ @@ -961,32 +1054,36 @@ static struct twlreg_info twl_regs[] = { /* 6030 REG with base as PMC Slave Misc : 0x0030 */ /* Turnon-delay and remap configuration values for 6030 are not verified since the specification is not public */ - TWL6030_ADJUSTABLE_LDO(VAUX1_6030, 0x54, 1000, 3300, 1), - TWL6030_ADJUSTABLE_LDO(VAUX2_6030, 0x58, 1000, 3300, 2), - TWL6030_ADJUSTABLE_LDO(VAUX3_6030, 0x5c, 1000, 3300, 3), - TWL6030_ADJUSTABLE_LDO(VMMC, 0x68, 1000, 3300, 4), - TWL6030_ADJUSTABLE_LDO(VPP, 0x6c, 1000, 3300, 5), - TWL6030_ADJUSTABLE_LDO(VUSIM, 0x74, 1000, 3300, 7), - TWL6030_FIXED_LDO(VANA, 0x50, 2100, 15, 0), - TWL6030_FIXED_LDO(VCXIO, 0x60, 1800, 16, 0), - TWL6030_FIXED_LDO(VDAC, 0x64, 1800, 17, 0), - TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 18, 0), - TWL6030_FIXED_RESOURCE(CLK32KG, 0x8C, 48, 0), + TWL6030_ADJUSTABLE_LDO(VAUX1_6030, 0x54, 1000, 3300), + TWL6030_ADJUSTABLE_LDO(VAUX2_6030, 0x58, 1000, 3300), + TWL6030_ADJUSTABLE_LDO(VAUX3_6030, 0x5c, 1000, 3300), + TWL6030_ADJUSTABLE_LDO(VMMC, 0x68, 1000, 3300), + TWL6030_ADJUSTABLE_LDO(VPP, 0x6c, 1000, 3300), + TWL6030_ADJUSTABLE_LDO(VUSIM, 0x74, 1000, 3300), + TWL6030_FIXED_LDO(VANA, 0x50, 2100, 0), + TWL6030_FIXED_LDO(VCXIO, 0x60, 1800, 0), + TWL6030_FIXED_LDO(VDAC, 0x64, 1800, 0), + TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 0), + TWL6030_FIXED_RESOURCE(CLK32KG, 0x8C, 0), + TWL6030_FIXED_RESOURCE(CLK32KAUDIO, 0x8F, 0), + TWL6030_ADJUSTABLE_SMPS(VDD3, 0x2e, 600, 4000), + TWL6030_ADJUSTABLE_SMPS(VMEM, 0x34, 600, 4000), + TWL6030_ADJUSTABLE_SMPS(V2V1, 0x1c, 1800, 2100), /* 6025 are renamed compared to 6030 versions */ - TWL6025_ADJUSTABLE_LDO(LDO2, 0x54, 1000, 3300, 1), - TWL6025_ADJUSTABLE_LDO(LDO4, 0x58, 1000, 3300, 2), - TWL6025_ADJUSTABLE_LDO(LDO3, 0x5c, 1000, 3300, 3), - TWL6025_ADJUSTABLE_LDO(LDO5, 0x68, 1000, 3300, 4), - TWL6025_ADJUSTABLE_LDO(LDO1, 0x6c, 1000, 3300, 5), - TWL6025_ADJUSTABLE_LDO(LDO7, 0x74, 1000, 3300, 7), - TWL6025_ADJUSTABLE_LDO(LDO6, 0x60, 1000, 3300, 16), - TWL6025_ADJUSTABLE_LDO(LDOLN, 0x64, 1000, 3300, 17), - TWL6025_ADJUSTABLE_LDO(LDOUSB, 0x70, 1000, 3300, 18), - - TWL6025_ADJUSTABLE_SMPS(SMPS3, 0x34, 1), - TWL6025_ADJUSTABLE_SMPS(SMPS4, 0x10, 2), - TWL6025_ADJUSTABLE_SMPS(VIO, 0x16, 3), + TWL6025_ADJUSTABLE_LDO(LDO2, 0x54, 1000, 3300), + TWL6025_ADJUSTABLE_LDO(LDO4, 0x58, 1000, 3300), + TWL6025_ADJUSTABLE_LDO(LDO3, 0x5c, 1000, 3300), + TWL6025_ADJUSTABLE_LDO(LDO5, 0x68, 1000, 3300), + TWL6025_ADJUSTABLE_LDO(LDO1, 0x6c, 1000, 3300), + TWL6025_ADJUSTABLE_LDO(LDO7, 0x74, 1000, 3300), + TWL6025_ADJUSTABLE_LDO(LDO6, 0x60, 1000, 3300), + TWL6025_ADJUSTABLE_LDO(LDOLN, 0x64, 1000, 3300), + TWL6025_ADJUSTABLE_LDO(LDOUSB, 0x70, 1000, 3300), + + TWL6025_ADJUSTABLE_SMPS(SMPS3, 0x34), + TWL6025_ADJUSTABLE_SMPS(SMPS4, 0x10), + TWL6025_ADJUSTABLE_SMPS(VIO, 0x16), }; static u8 twl_get_smps_offset(void) @@ -1014,6 +1111,7 @@ static int __devinit twlreg_probe(struct platform_device *pdev) struct regulator_init_data *initdata; struct regulation_constraints *c; struct regulator_dev *rdev; + int ret; for (i = 0, info = NULL; i < ARRAY_SIZE(twl_regs); i++) { if (twl_regs[i].desc.id != pdev->id) @@ -1049,6 +1147,18 @@ static int __devinit twlreg_probe(struct platform_device *pdev) case TWL4030_REG_VINTDIG: c->always_on = true; break; + case TWL6030_REG_VUSB: + /* Program CFG_LDO_PD2 register and set VUSB bit */ + ret = twl_i2c_write_u8(TWL6030_MODULE_ID0, 0x1, + TWL6030_CFG_LDO_PD2); + if (ret < 0) + return ret; + + /* Program MISC2 register and set bit VUSB_IN_VBAT */ + ret = twl_i2c_write_u8(TWL6030_MODULE_ID0, 0x10, TWL6030_MISC2); + if (ret < 0) + return ret; + break; default: break; } |