diff options
Diffstat (limited to 'drivers/regulator/twl-regulator.c')
| -rw-r--r-- | drivers/regulator/twl-regulator.c | 564 | 
1 files changed, 497 insertions, 67 deletions
| diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c index 6a292852a358..87fe0f75a56e 100644 --- a/drivers/regulator/twl-regulator.c +++ b/drivers/regulator/twl-regulator.c @@ -51,8 +51,13 @@ struct twlreg_info {  	u16			min_mV;  	u16			max_mV; +	u8			flags; +  	/* used by regulator core */  	struct regulator_desc	desc; + +	/* chip specific features */ +	unsigned long 		features;  }; @@ -70,12 +75,35 @@ struct twlreg_info {  #define VREG_TRANS		1  #define VREG_STATE		2  #define VREG_VOLTAGE		3 +#define VREG_VOLTAGE_SMPS	4  /* TWL6030 Misc register offsets */  #define VREG_BC_ALL		1  #define VREG_BC_REF		2  #define VREG_BC_PROC		3  #define VREG_BC_CLK_RST		4 +/* TWL6030 LDO register values for CFG_STATE */ +#define TWL6030_CFG_STATE_OFF	0x00 +#define TWL6030_CFG_STATE_ON	0x01 +#define TWL6030_CFG_STATE_OFF2	0x02 +#define TWL6030_CFG_STATE_SLEEP	0x03 +#define TWL6030_CFG_STATE_GRP_SHIFT	5 +#define TWL6030_CFG_STATE_APP_SHIFT	2 +#define TWL6030_CFG_STATE_APP_MASK	(0x03 << TWL6030_CFG_STATE_APP_SHIFT) +#define TWL6030_CFG_STATE_APP(v)	(((v) & TWL6030_CFG_STATE_APP_MASK) >>\ +						TWL6030_CFG_STATE_APP_SHIFT) + +/* Flags for SMPS Voltage reading */ +#define SMPS_OFFSET_EN		BIT(0) +#define SMPS_EXTENDED_EN	BIT(1) + +/* twl6025 SMPS EPROM values */ +#define TWL6030_SMPS_OFFSET		0xB0 +#define TWL6030_SMPS_MULT		0xB3 +#define SMPS_MULTOFFSET_SMPS4	BIT(0) +#define SMPS_MULTOFFSET_VIO	BIT(1) +#define SMPS_MULTOFFSET_SMPS3	BIT(6) +  static inline int  twlreg_read(struct twlreg_info *info, unsigned slave_subgp, unsigned offset)  { @@ -118,21 +146,38 @@ static int twlreg_grp(struct regulator_dev *rdev)  #define P2_GRP_6030	BIT(1)		/* "peripherals" */  #define P1_GRP_6030	BIT(0)		/* CPU/Linux */ -static int twlreg_is_enabled(struct regulator_dev *rdev) +static int twl4030reg_is_enabled(struct regulator_dev *rdev)  {  	int	state = twlreg_grp(rdev);  	if (state < 0)  		return state; -	if (twl_class_is_4030()) -		state &= P1_GRP_4030; +	return state & P1_GRP_4030; +} + +static int twl6030reg_is_enabled(struct regulator_dev *rdev) +{ +	struct twlreg_info	*info = rdev_get_drvdata(rdev); +	int			grp = 0, val; + +	if (!(twl_class_is_6030() && (info->features & TWL6025_SUBCLASS))) +		grp = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_GRP); +	if (grp < 0) +		return grp; + +	if (!(twl_class_is_6030() && (info->features & TWL6025_SUBCLASS))) +		grp &= P1_GRP_6030;  	else -		state &= P1_GRP_6030; -	return state; +		grp = 1; + +	val = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_STATE); +	val = TWL6030_CFG_STATE_APP(val); + +	return grp && (val == TWL6030_CFG_STATE_ON);  } -static int twlreg_enable(struct regulator_dev *rdev) +static int twl4030reg_enable(struct regulator_dev *rdev)  {  	struct twlreg_info	*info = rdev_get_drvdata(rdev);  	int			grp; @@ -142,10 +187,7 @@ static int twlreg_enable(struct regulator_dev *rdev)  	if (grp < 0)  		return grp; -	if (twl_class_is_4030()) -		grp |= P1_GRP_4030; -	else -		grp |= P1_GRP_6030; +	grp |= P1_GRP_4030;  	ret = twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_GRP, grp); @@ -154,29 +196,63 @@ static int twlreg_enable(struct regulator_dev *rdev)  	return ret;  } -static int twlreg_disable(struct regulator_dev *rdev) +static int twl6030reg_enable(struct regulator_dev *rdev) +{ +	struct twlreg_info	*info = rdev_get_drvdata(rdev); +	int			grp = 0; +	int			ret; + +	if (!(twl_class_is_6030() && (info->features & TWL6025_SUBCLASS))) +		grp = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_GRP); +	if (grp < 0) +		return grp; + +	ret = twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_STATE, +			grp << TWL6030_CFG_STATE_GRP_SHIFT | +			TWL6030_CFG_STATE_ON); + +	udelay(info->delay); + +	return ret; +} + +static int twl4030reg_disable(struct regulator_dev *rdev)  {  	struct twlreg_info	*info = rdev_get_drvdata(rdev);  	int			grp; +	int			ret;  	grp = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_GRP);  	if (grp < 0)  		return grp; -	if (twl_class_is_4030()) -		grp &= ~(P1_GRP_4030 | P2_GRP_4030 | P3_GRP_4030); -	else -		grp &= ~(P1_GRP_6030 | P2_GRP_6030 | P3_GRP_6030); +	grp &= ~(P1_GRP_4030 | P2_GRP_4030 | P3_GRP_4030); -	return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_GRP, grp); +	ret = twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_GRP, grp); + +	return ret;  } -static int twlreg_get_status(struct regulator_dev *rdev) +static int twl6030reg_disable(struct regulator_dev *rdev)  { -	int	state = twlreg_grp(rdev); +	struct twlreg_info	*info = rdev_get_drvdata(rdev); +	int			grp = 0; +	int			ret; + +	if (!(twl_class_is_6030() && (info->features & TWL6025_SUBCLASS))) +		grp = P1_GRP_6030 | P2_GRP_6030 | P3_GRP_6030; + +	/* For 6030, set the off state for all grps enabled */ +	ret = twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_STATE, +			(grp) << TWL6030_CFG_STATE_GRP_SHIFT | +			TWL6030_CFG_STATE_OFF); + +	return ret; +} -	if (twl_class_is_6030()) -		return 0; /* FIXME return for 6030 regulator */ +static int twl4030reg_get_status(struct regulator_dev *rdev) +{ +	int	state = twlreg_grp(rdev);  	if (state < 0)  		return state; @@ -190,15 +266,39 @@ static int twlreg_get_status(struct regulator_dev *rdev)  		: REGULATOR_STATUS_STANDBY;  } -static int twlreg_set_mode(struct regulator_dev *rdev, unsigned mode) +static int twl6030reg_get_status(struct regulator_dev *rdev) +{ +	struct twlreg_info	*info = rdev_get_drvdata(rdev); +	int			val; + +	val = twlreg_grp(rdev); +	if (val < 0) +		return val; + +	val = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_STATE); + +	switch (TWL6030_CFG_STATE_APP(val)) { +	case TWL6030_CFG_STATE_ON: +		return REGULATOR_STATUS_NORMAL; + +	case TWL6030_CFG_STATE_SLEEP: +		return REGULATOR_STATUS_STANDBY; + +	case TWL6030_CFG_STATE_OFF: +	case TWL6030_CFG_STATE_OFF2: +	default: +		break; +	} + +	return REGULATOR_STATUS_OFF; +} + +static int twl4030reg_set_mode(struct regulator_dev *rdev, unsigned mode)  {  	struct twlreg_info	*info = rdev_get_drvdata(rdev);  	unsigned		message;  	int			status; -	if (twl_class_is_6030()) -		return 0; /* FIXME return for 6030 regulator */ -  	/* We can only set the mode through state machine commands... */  	switch (mode) {  	case REGULATOR_MODE_NORMAL: @@ -227,6 +327,36 @@ static int twlreg_set_mode(struct regulator_dev *rdev, unsigned mode)  			message & 0xff, TWL4030_PM_MASTER_PB_WORD_LSB);  } +static int twl6030reg_set_mode(struct regulator_dev *rdev, unsigned mode) +{ +	struct twlreg_info	*info = rdev_get_drvdata(rdev); +	int grp = 0; +	int val; + +	if (!(twl_class_is_6030() && (info->features & TWL6025_SUBCLASS))) +		grp = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_GRP); + +	if (grp < 0) +		return grp; + +	/* Compose the state register settings */ +	val = grp << TWL6030_CFG_STATE_GRP_SHIFT; +	/* We can only set the mode through state machine commands... */ +	switch (mode) { +	case REGULATOR_MODE_NORMAL: +		val |= TWL6030_CFG_STATE_ON; +		break; +	case REGULATOR_MODE_STANDBY: +		val |= TWL6030_CFG_STATE_SLEEP; +		break; + +	default: +		return -EINVAL; +	} + +	return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_STATE, val); +} +  /*----------------------------------------------------------------------*/  /* @@ -375,13 +505,13 @@ static struct regulator_ops twl4030ldo_ops = {  	.set_voltage	= twl4030ldo_set_voltage,  	.get_voltage	= twl4030ldo_get_voltage, -	.enable		= twlreg_enable, -	.disable	= twlreg_disable, -	.is_enabled	= twlreg_is_enabled, +	.enable		= twl4030reg_enable, +	.disable	= twl4030reg_disable, +	.is_enabled	= twl4030reg_is_enabled, -	.set_mode	= twlreg_set_mode, +	.set_mode	= twl4030reg_set_mode, -	.get_status	= twlreg_get_status, +	.get_status	= twl4030reg_get_status,  };  static int twl6030ldo_list_voltage(struct regulator_dev *rdev, unsigned index) @@ -433,13 +563,13 @@ static struct regulator_ops twl6030ldo_ops = {  	.set_voltage	= twl6030ldo_set_voltage,  	.get_voltage	= twl6030ldo_get_voltage, -	.enable		= twlreg_enable, -	.disable	= twlreg_disable, -	.is_enabled	= twlreg_is_enabled, +	.enable		= twl6030reg_enable, +	.disable	= twl6030reg_disable, +	.is_enabled	= twl6030reg_is_enabled, -	.set_mode	= twlreg_set_mode, +	.set_mode	= twl6030reg_set_mode, -	.get_status	= twlreg_get_status, +	.get_status	= twl6030reg_get_status,  };  /*----------------------------------------------------------------------*/ @@ -461,25 +591,242 @@ static int twlfixed_get_voltage(struct regulator_dev *rdev)  	return info->min_mV * 1000;  } -static struct regulator_ops twlfixed_ops = { +static struct regulator_ops twl4030fixed_ops = { +	.list_voltage	= twlfixed_list_voltage, + +	.get_voltage	= twlfixed_get_voltage, + +	.enable		= twl4030reg_enable, +	.disable	= twl4030reg_disable, +	.is_enabled	= twl4030reg_is_enabled, + +	.set_mode	= twl4030reg_set_mode, + +	.get_status	= twl4030reg_get_status, +}; + +static struct regulator_ops twl6030fixed_ops = {  	.list_voltage	= twlfixed_list_voltage,  	.get_voltage	= twlfixed_get_voltage, -	.enable		= twlreg_enable, -	.disable	= twlreg_disable, -	.is_enabled	= twlreg_is_enabled, +	.enable		= twl6030reg_enable, +	.disable	= twl6030reg_disable, +	.is_enabled	= twl6030reg_is_enabled, -	.set_mode	= twlreg_set_mode, +	.set_mode	= twl6030reg_set_mode, -	.get_status	= twlreg_get_status, +	.get_status	= twl6030reg_get_status,  };  static struct regulator_ops twl6030_fixed_resource = { -	.enable		= twlreg_enable, -	.disable	= twlreg_disable, -	.is_enabled	= twlreg_is_enabled, -	.get_status	= twlreg_get_status, +	.enable		= twl6030reg_enable, +	.disable	= twl6030reg_disable, +	.is_enabled	= twl6030reg_is_enabled, +	.get_status	= twl6030reg_get_status, +}; + +/* + * SMPS status and control + */ + +static int twl6030smps_list_voltage(struct regulator_dev *rdev, unsigned index) +{ +	struct twlreg_info	*info = rdev_get_drvdata(rdev); + +	int voltage = 0; + +	switch (info->flags) { +	case SMPS_OFFSET_EN: +		voltage = 100000; +		/* fall through */ +	case 0: +		switch (index) { +		case 0: +			voltage = 0; +			break; +		case 58: +			voltage = 1350 * 1000; +			break; +		case 59: +			voltage = 1500 * 1000; +			break; +		case 60: +			voltage = 1800 * 1000; +			break; +		case 61: +			voltage = 1900 * 1000; +			break; +		case 62: +			voltage = 2100 * 1000; +			break; +		default: +			voltage += (600000 + (12500 * (index - 1))); +		} +		break; +	case SMPS_EXTENDED_EN: +		switch (index) { +		case 0: +			voltage = 0; +			break; +		case 58: +			voltage = 2084 * 1000; +			break; +		case 59: +			voltage = 2315 * 1000; +			break; +		case 60: +			voltage = 2778 * 1000; +			break; +		case 61: +			voltage = 2932 * 1000; +			break; +		case 62: +			voltage = 3241 * 1000; +			break; +		default: +			voltage = (1852000 + (38600 * (index - 1))); +		} +		break; +	case SMPS_OFFSET_EN | SMPS_EXTENDED_EN: +		switch (index) { +		case 0: +			voltage = 0; +			break; +		case 58: +			voltage = 4167 * 1000; +			break; +		case 59: +			voltage = 2315 * 1000; +			break; +		case 60: +			voltage = 2778 * 1000; +			break; +		case 61: +			voltage = 2932 * 1000; +			break; +		case 62: +			voltage = 3241 * 1000; +			break; +		default: +			voltage = (2161000 + (38600 * (index - 1))); +		} +		break; +	} + +	return voltage; +} + +static int +twl6030smps_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV, +			unsigned int *selector) +{ +	struct twlreg_info	*info = rdev_get_drvdata(rdev); +	int	vsel = 0; + +	switch (info->flags) { +	case 0: +		if (min_uV == 0) +			vsel = 0; +		else if ((min_uV >= 600000) && (max_uV <= 1300000)) { +			vsel = (min_uV - 600000) / 125; +			if (vsel % 100) +				vsel += 100; +			vsel /= 100; +			vsel++; +		} +		/* Values 1..57 for vsel are linear and can be calculated +		 * values 58..62 are non linear. +		 */ +		else if ((min_uV > 1900000) && (max_uV >= 2100000)) +			vsel = 62; +		else if ((min_uV > 1800000) && (max_uV >= 1900000)) +			vsel = 61; +		else if ((min_uV > 1500000) && (max_uV >= 1800000)) +			vsel = 60; +		else if ((min_uV > 1350000) && (max_uV >= 1500000)) +			vsel = 59; +		else if ((min_uV > 1300000) && (max_uV >= 1350000)) +			vsel = 58; +		else +			return -EINVAL; +		break; +	case SMPS_OFFSET_EN: +		if (min_uV == 0) +			vsel = 0; +		else if ((min_uV >= 700000) && (max_uV <= 1420000)) { +			vsel = (min_uV - 700000) / 125; +			if (vsel % 100) +				vsel += 100; +			vsel /= 100; +			vsel++; +		} +		/* Values 1..57 for vsel are linear and can be calculated +		 * values 58..62 are non linear. +		 */ +		else if ((min_uV > 1900000) && (max_uV >= 2100000)) +			vsel = 62; +		else if ((min_uV > 1800000) && (max_uV >= 1900000)) +			vsel = 61; +		else if ((min_uV > 1350000) && (max_uV >= 1800000)) +			vsel = 60; +		else if ((min_uV > 1350000) && (max_uV >= 1500000)) +			vsel = 59; +		else if ((min_uV > 1300000) && (max_uV >= 1350000)) +			vsel = 58; +		else +			return -EINVAL; +		break; +	case SMPS_EXTENDED_EN: +		if (min_uV == 0) +			vsel = 0; +		else if ((min_uV >= 1852000) && (max_uV <= 4013600)) { +			vsel = (min_uV - 1852000) / 386; +			if (vsel % 100) +				vsel += 100; +			vsel /= 100; +			vsel++; +		} +		break; +	case SMPS_OFFSET_EN|SMPS_EXTENDED_EN: +		if (min_uV == 0) +			vsel = 0; +		else if ((min_uV >= 2161000) && (max_uV <= 4321000)) { +			vsel = (min_uV - 1852000) / 386; +			if (vsel % 100) +				vsel += 100; +			vsel /= 100; +			vsel++; +		} +		break; +	} + +	*selector = vsel; + +	return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE_SMPS, +							vsel); +} + +static int twl6030smps_get_voltage_sel(struct regulator_dev *rdev) +{ +	struct twlreg_info	*info = rdev_get_drvdata(rdev); + +	return twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE_SMPS); +} + +static struct regulator_ops twlsmps_ops = { +	.list_voltage		= twl6030smps_list_voltage, + +	.set_voltage		= twl6030smps_set_voltage, +	.get_voltage_sel	= twl6030smps_get_voltage_sel, + +	.enable			= twl6030reg_enable, +	.disable		= twl6030reg_disable, +	.is_enabled		= twl6030reg_is_enabled, + +	.set_mode		= twl6030reg_set_mode, + +	.get_status		= twl6030reg_get_status,  };  /*----------------------------------------------------------------------*/ @@ -487,11 +834,10 @@ static struct regulator_ops twl6030_fixed_resource = {  #define TWL4030_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \  			remap_conf) \  		TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \ -			remap_conf, TWL4030) -#define TWL6030_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \ -			remap_conf) \ +			remap_conf, TWL4030, twl4030fixed_ops) +#define TWL6030_FIXED_LDO(label, offset, mVolts, num, turnon_delay) \  		TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \ -			remap_conf, TWL6030) +			0x0, TWL6030, twl6030fixed_ops)  #define TWL4030_ADJUSTABLE_LDO(label, offset, num, turnon_delay, remap_conf) { \  	.base = offset, \ @@ -510,13 +856,11 @@ static struct regulator_ops twl6030_fixed_resource = {  		}, \  	} -#define TWL6030_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts, num, \ -		remap_conf) { \ +#define TWL6030_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts, num) { \  	.base = offset, \  	.id = num, \  	.min_mV = min_mVolts, \  	.max_mV = max_mVolts, \ -	.remap = remap_conf, \  	.desc = { \  		.name = #label, \  		.id = TWL6030_REG_##label, \ @@ -527,9 +871,23 @@ static struct regulator_ops twl6030_fixed_resource = {  		}, \  	} +#define TWL6025_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts, num) { \ +	.base = offset, \ +	.id = num, \ +	.min_mV = min_mVolts, \ +	.max_mV = max_mVolts, \ +	.desc = { \ +		.name = #label, \ +		.id = TWL6025_REG_##label, \ +		.n_voltages = ((max_mVolts - min_mVolts)/100) + 1, \ +		.ops = &twl6030ldo_ops, \ +		.type = REGULATOR_VOLTAGE, \ +		.owner = THIS_MODULE, \ +		}, \ +	}  #define TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, remap_conf, \ -		family) { \ +		family, operations) { \  	.base = offset, \  	.id = num, \  	.min_mV = mVolts, \ @@ -539,17 +897,16 @@ static struct regulator_ops twl6030_fixed_resource = {  		.name = #label, \  		.id = family##_REG_##label, \  		.n_voltages = 1, \ -		.ops = &twlfixed_ops, \ +		.ops = &operations, \  		.type = REGULATOR_VOLTAGE, \  		.owner = THIS_MODULE, \  		}, \  	} -#define TWL6030_FIXED_RESOURCE(label, offset, num, turnon_delay, remap_conf) { \ +#define TWL6030_FIXED_RESOURCE(label, offset, num, turnon_delay) { \  	.base = offset, \  	.id = num, \  	.delay = turnon_delay, \ -	.remap = remap_conf, \  	.desc = { \  		.name = #label, \  		.id = TWL6030_REG_##label, \ @@ -559,6 +916,21 @@ static struct regulator_ops twl6030_fixed_resource = {  		}, \  	} +#define TWL6025_ADJUSTABLE_SMPS(label, offset, num) { \ +	.base = offset, \ +	.id = num, \ +	.min_mV = 600, \ +	.max_mV = 2100, \ +	.desc = { \ +		.name = #label, \ +		.id = TWL6025_REG_##label, \ +		.n_voltages = 63, \ +		.ops = &twlsmps_ops, \ +		.type = REGULATOR_VOLTAGE, \ +		.owner = THIS_MODULE, \ +		}, \ +	} +  /*   * We list regulators here if systems need some level of   * software control over them after boot. @@ -589,19 +961,52 @@ 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, 0x21), -	TWL6030_ADJUSTABLE_LDO(VAUX2_6030, 0x58, 1000, 3300, 2, 0x21), -	TWL6030_ADJUSTABLE_LDO(VAUX3_6030, 0x5c, 1000, 3300, 3, 0x21), -	TWL6030_ADJUSTABLE_LDO(VMMC, 0x68, 1000, 3300, 4, 0x21), -	TWL6030_ADJUSTABLE_LDO(VPP, 0x6c, 1000, 3300, 5, 0x21), -	TWL6030_ADJUSTABLE_LDO(VUSIM, 0x74, 1000, 3300, 7, 0x21), -	TWL6030_FIXED_LDO(VANA, 0x50, 2100, 15, 0, 0x21), -	TWL6030_FIXED_LDO(VCXIO, 0x60, 1800, 16, 0, 0x21), -	TWL6030_FIXED_LDO(VDAC, 0x64, 1800, 17, 0, 0x21), -	TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 18, 0, 0x21), -	TWL6030_FIXED_RESOURCE(CLK32KG, 0x8C, 48, 0, 0x21), +	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), + +	/* 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),  }; +static u8 twl_get_smps_offset(void) +{ +	u8 value; + +	twl_i2c_read_u8(TWL_MODULE_PM_RECEIVER, &value, +			TWL6030_SMPS_OFFSET); +	return value; +} + +static u8 twl_get_smps_mult(void) +{ +	u8 value; + +	twl_i2c_read_u8(TWL_MODULE_PM_RECEIVER, &value, +			TWL6030_SMPS_MULT); +	return value; +} +  static int __devinit twlreg_probe(struct platform_device *pdev)  {  	int				i; @@ -623,6 +1028,9 @@ static int __devinit twlreg_probe(struct platform_device *pdev)  	if (!initdata)  		return -EINVAL; +	/* copy the features into regulator data */ +	info->features = (unsigned long)initdata->driver_data; +  	/* Constrain board-specific capabilities according to what  	 * this driver and the chip itself can actually do.  	 */ @@ -645,6 +1053,27 @@ static int __devinit twlreg_probe(struct platform_device *pdev)  		break;  	} +	switch (pdev->id) { +	case TWL6025_REG_SMPS3: +		if (twl_get_smps_mult() & SMPS_MULTOFFSET_SMPS3) +			info->flags |= SMPS_EXTENDED_EN; +		if (twl_get_smps_offset() & SMPS_MULTOFFSET_SMPS3) +			info->flags |= SMPS_OFFSET_EN; +		break; +	case TWL6025_REG_SMPS4: +		if (twl_get_smps_mult() & SMPS_MULTOFFSET_SMPS4) +			info->flags |= SMPS_EXTENDED_EN; +		if (twl_get_smps_offset() & SMPS_MULTOFFSET_SMPS4) +			info->flags |= SMPS_OFFSET_EN; +		break; +	case TWL6025_REG_VIO: +		if (twl_get_smps_mult() & SMPS_MULTOFFSET_VIO) +			info->flags |= SMPS_EXTENDED_EN; +		if (twl_get_smps_offset() & SMPS_MULTOFFSET_VIO) +			info->flags |= SMPS_OFFSET_EN; +		break; +	} +  	rdev = regulator_register(&info->desc, &pdev->dev, initdata, info);  	if (IS_ERR(rdev)) {  		dev_err(&pdev->dev, "can't register %s, %ld\n", @@ -653,7 +1082,8 @@ static int __devinit twlreg_probe(struct platform_device *pdev)  	}  	platform_set_drvdata(pdev, rdev); -	twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_REMAP, +	if (twl_class_is_4030()) +		twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_REMAP,  						info->remap);  	/* NOTE:  many regulators support short-circuit IRQs (presentable |