summaryrefslogtreecommitdiff
path: root/drivers/mfd
diff options
context:
space:
mode:
authornagesh Penumarty <vpenumarty@nvidia.com>2011-04-11 14:59:28 +0530
committerDan Willemsen <dwillemsen@nvidia.com>2011-04-26 15:56:15 -0700
commit381c0a99479488414096284a084025999c87ef05 (patch)
tree9694d8345cf5f6adf32f8784dfee80ad0405101d /drivers/mfd
parente368a0f6b76140c70672bfefbd9902a15d3aa779 (diff)
drivers: regulator: Adding the regulator driver
Adding the TI 6025 PMU regulator driver. Original-Change-Id: I8ad675711bbe2ae942bcc0e32b711883eae215b4 Reviewed-on: http://git-master/r/27342 Tested-by: Venkata Nageswara Penumarty <vpenumarty@nvidia.com> Reviewed-by: Laxman Dewangan <ldewangan@nvidia.com> Change-Id: Ib91f033c557bb7f4c87522ae4f5c7922a62f71f8
Diffstat (limited to 'drivers/mfd')
-rw-r--r--drivers/mfd/twl-core.c254
1 files changed, 227 insertions, 27 deletions
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index 720e099e506d..d5d6b0b50833 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -58,6 +58,14 @@
#define DRIVER_NAME "twl"
+#if defined(CONFIG_TWL4030_BCI_BATTERY) || \
+ defined(CONFIG_TWL4030_BCI_BATTERY_MODULE) || \
+ defined(CONFIG_TWL6030_BCI_BATTERY) || \
+ defined(CONFIG_TWL6030_BCI_BATTERY_MODULE)
+#define twl_has_bci() true
+#else
+#define twl_has_bci() false
+#endif
#if defined(CONFIG_KEYBOARD_TWL4030) || defined(CONFIG_KEYBOARD_TWL4030_MODULE)
#define twl_has_keypad() true
#else
@@ -77,7 +85,8 @@
#define twl_has_regulator() false
#endif
-#if defined(CONFIG_TWL4030_MADC) || defined(CONFIG_TWL4030_MADC_MODULE)
+#if defined(CONFIG_TWL4030_MADC) || defined(CONFIG_TWL4030_MADC_MODULE) ||\
+ defined(CONFIG_TWL6030_GPADC) || defined(CONFIG_TWL6030_GPADC_MODULE)
#define twl_has_madc() true
#else
#define twl_has_madc() false
@@ -95,7 +104,8 @@
#define twl_has_rtc() false
#endif
-#if defined(CONFIG_TWL4030_USB) || defined(CONFIG_TWL4030_USB_MODULE)
+#if defined(CONFIG_TWL4030_USB) || defined(CONFIG_TWL4030_USB_MODULE) ||\
+ defined(CONFIG_TWL6030_USB) || defined(CONFIG_TWL6030_USB_MODULE)
#define twl_has_usb() true
#else
#define twl_has_usb() false
@@ -118,7 +128,7 @@
/* Triton Core internal information (BEGIN) */
/* Last - for index max*/
-#define TWL4030_MODULE_LAST TWL4030_MODULE_SECURED_REG
+#define TWL4030_MODULE_LAST TWL6025_MODULE_CHARGER
#define TWL_NUM_SLAVES 4
@@ -191,6 +201,7 @@
#define TWL6030_BASEADD_GASGAUGE 0x00C0
#define TWL6030_BASEADD_PIH 0x00D0
#define TWL6030_BASEADD_CHARGER 0x00E0
+#define TWL6025_BASEADD_CHARGER 0x00DA
/* subchip/slave 2 0x4A - DFT */
#define TWL6030_BASEADD_DIEID 0x00C0
@@ -200,6 +211,10 @@
#define TWL6030_BASEADD_RSV 0x0000
#define TWL6030_BASEADD_ZERO 0x0000
+/* twl6030 SMPS EPROM values */
+#define TWL6030_SMPS_OFFSET 0xB0
+#define TWL6030_SMPS_MULT 0xB3
+
/* Few power values */
#define R_CFG_BOOT 0x05
#define R_PROTECT_KEY 0x0E
@@ -235,6 +250,33 @@ unsigned int twl_rev(void)
}
EXPORT_SYMBOL(twl_rev);
+static unsigned int twl_feat;
+unsigned int twl_features(void)
+{
+ return twl_feat;
+}
+EXPORT_SYMBOL(twl_features);
+
+u8 twl_get_smps_offset(void)
+{
+ u8 value;
+
+ twl_i2c_read_u8(TWL_MODULE_PM_RECEIVER, &value,
+ TWL6030_SMPS_OFFSET);
+ return value;
+}
+EXPORT_SYMBOL(twl_get_smps_offset);
+
+u8 twl_get_smps_mult(void)
+{
+ u8 value;
+
+ twl_i2c_read_u8(TWL_MODULE_PM_RECEIVER, &value,
+ TWL6030_SMPS_MULT);
+ return value;
+}
+EXPORT_SYMBOL(twl_get_smps_mult);
+
/* Structure for each TWL4030/TWL6030 Slave */
struct twl_client {
struct i2c_client *client;
@@ -255,7 +297,7 @@ struct twl_mapping {
unsigned char sid; /* Slave ID */
unsigned char base; /* base address */
};
-struct twl_mapping *twl_map;
+static struct twl_mapping *twl_map;
static struct twl_mapping twl4030_map[TWL4030_MODULE_LAST + 1] = {
/*
@@ -327,6 +369,7 @@ static struct twl_mapping twl6030_map[] = {
{ SUB_CHIP_ID0, TWL6030_BASEADD_RTC },
{ SUB_CHIP_ID0, TWL6030_BASEADD_MEM },
+ { SUB_CHIP_ID1, TWL6025_BASEADD_CHARGER },
};
/*----------------------------------------------------------------------*/
@@ -383,12 +426,12 @@ int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes)
pr_err("%s: i2c_write failed to transfer all messages\n",
DRIVER_NAME);
if (ret < 0)
- return ret;
+ return ret;
else
return -EIO;
} else {
return 0;
- }
+}
}
EXPORT_SYMBOL(twl_i2c_write);
@@ -484,6 +527,19 @@ int twl_i2c_read_u8(u8 mod_no, u8 *value, u8 reg)
}
EXPORT_SYMBOL(twl_i2c_read_u8);
+
+void twl_reg_dump(int module, int start, int end)
+{
+ int i;
+ u8 val;
+
+ for (i = start; i < end; i++) {
+ twl_i2c_read_u8(module, &val, i);
+ printk(KERN_ERR "reg 0x%2x val 0x%2x\n", i, val);
+ }
+}
+EXPORT_SYMBOL(twl_reg_dump);
+
/*----------------------------------------------------------------------*/
static struct device *
@@ -599,8 +655,16 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
if (IS_ERR(child))
return PTR_ERR(child);
}
+ if (twl_has_bci() && pdata->bci &&
+ (features & TWL6030_CLASS)) {
+ child = add_child(1, "twl6030_bci",
+ pdata->bci, sizeof(*pdata->bci),
+ false,
+ pdata->irq_base + CHARGER_INTR_OFFSET,
+ pdata->irq_base + CHARGERFAULT_INTR_OFFSET);
+ }
- if (twl_has_madc() && pdata->madc) {
+ if (twl_has_madc() && pdata->madc && twl_class_is_4030()) {
child = add_child(2, "twl4030_madc",
pdata->madc, sizeof(*pdata->madc),
true, pdata->irq_base + MADC_INTR_OFFSET, 0);
@@ -608,6 +672,15 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
return PTR_ERR(child);
}
+ if (twl_has_madc() && pdata->madc && twl_class_is_6030()) {
+ child = add_child(1, "twl6030_gpadc",
+ pdata->madc, sizeof(*pdata->madc),
+ true, pdata->irq_base + MADC_INTR_OFFSET,
+ pdata->irq_base + GPADCSW_INTR_OFFSET);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+ }
+
if (twl_has_rtc()) {
/*
* REVISIT platform_data here currently might expose the
@@ -638,15 +711,15 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
/* First add the regulators so that they can be used by transceiver */
if (twl_has_regulator()) {
- /* this is a template that gets copied */
- struct regulator_init_data usb_fixed = {
- .constraints.valid_modes_mask =
- REGULATOR_MODE_NORMAL
- | REGULATOR_MODE_STANDBY,
- .constraints.valid_ops_mask =
- REGULATOR_CHANGE_MODE
- | REGULATOR_CHANGE_STATUS,
- };
+ /* this is a template that gets copied */
+ struct regulator_init_data usb_fixed = {
+ .constraints.valid_modes_mask =
+ REGULATOR_MODE_NORMAL
+ | REGULATOR_MODE_STANDBY,
+ .constraints.valid_ops_mask =
+ REGULATOR_CHANGE_MODE
+ | REGULATOR_CHANGE_STATUS,
+ };
child = add_regulator_linked(TWL4030_REG_VUSB1V5,
&usb_fixed, &usb1v5, 1);
@@ -682,6 +755,52 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
usb3v1.dev = child;
}
}
+ if (twl_has_usb() && pdata->usb && twl_class_is_6030()) {
+
+ static struct regulator_consumer_supply usb3v3;
+
+ /* this is a template that gets copied */
+ struct regulator_init_data usb_fixed = {
+ .constraints.valid_modes_mask =
+ REGULATOR_MODE_NORMAL | REGULATOR_MODE_STANDBY,
+ .constraints.valid_ops_mask =
+ REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_STATUS,
+ };
+
+ if (features & TWL6025_SUBCLASS) {
+ usb3v3.supply = "ldousb";
+ if (twl_has_regulator()) {
+
+ child = add_regulator_linked(TWL6025_REG_LDOUSB,
+ &usb_fixed, &usb3v3, 1);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+ }
+ } else {
+ usb3v3.supply = "vusb";
+
+ if (twl_has_regulator()) {
+
+ child = add_regulator_linked(TWL6030_REG_VUSB,
+ &usb_fixed, &usb3v3, 1);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+ }
+ }
+
+ child = add_child(0, "twl6030_usb",
+ pdata->usb, sizeof(*pdata->usb),
+ true,
+ /* irq1 = VBUS_PRES, irq0 = USB ID */
+ pdata->irq_base + USBOTG_INTR_OFFSET,
+ pdata->irq_base + USB_PRES_INTR_OFFSET);
+
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+ /* we need to connect regulators to this transceiver */
+ if (twl_has_regulator() && child)
+ usb3v3.dev = child;
+ }
if (twl_has_watchdog()) {
child = add_child(0, "twl4030_wdt", NULL, 0, false, 0, 0);
@@ -698,17 +817,17 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
if (twl_has_codec() && pdata->codec && twl_class_is_4030()) {
sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid;
- child = add_child(sub_chip_id, "twl4030_codec",
+ child = add_child(sub_chip_id, "twl4030-audio",
pdata->codec, sizeof(*pdata->codec),
false, 0, 0);
if (IS_ERR(child))
return PTR_ERR(child);
}
- /* Phoenix*/
+ /* Phoenix codec driver is probed directly atm */
if (twl_has_codec() && pdata->codec && twl_class_is_6030()) {
sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid;
- child = add_child(sub_chip_id, "twl6040_codec",
+ child = add_child(sub_chip_id, "twl6040-codec",
pdata->codec, sizeof(*pdata->codec),
false, 0, 0);
if (IS_ERR(child))
@@ -790,7 +909,8 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
}
/* twl6030 regulators */
- if (twl_has_regulator() && twl_class_is_6030()) {
+ if (twl_has_regulator() && twl_class_is_6030() &&
+ !(features & TWL6025_SUBCLASS)) {
child = add_regulator(TWL6030_REG_VMMC, pdata->vmmc);
if (IS_ERR(child))
return PTR_ERR(child);
@@ -832,6 +952,73 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
return PTR_ERR(child);
}
+ /* 6030 and 6025 share this regulator */
+ if (twl_has_regulator() && twl_class_is_6030()) {
+ child = add_regulator(TWL6030_REG_VANA, pdata->vana);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+ }
+
+ /* twl6025 regulators */
+ if (twl_has_regulator() && twl_class_is_6030() &&
+ (features & TWL6025_SUBCLASS)) {
+ child = add_regulator(TWL6025_REG_LDO5, pdata->ldo5);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+
+ child = add_regulator(TWL6025_REG_LDO1, pdata->ldo1);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+
+ child = add_regulator(TWL6025_REG_LDO7, pdata->ldo7);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+
+ child = add_regulator(TWL6025_REG_LDO6, pdata->ldo6);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+
+ child = add_regulator(TWL6025_REG_LDOLN, pdata->ldoln);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+
+ child = add_regulator(TWL6025_REG_LDO2, pdata->ldo2);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+
+ child = add_regulator(TWL6025_REG_LDO4, pdata->ldo4);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+
+ child = add_regulator(TWL6025_REG_LDO3, pdata->ldo3);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+
+ child = add_regulator(TWL6025_REG_SMPS3, pdata->smps3);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+
+ child = add_regulator(TWL6025_REG_SMPS4, pdata->smps4);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+
+ child = add_regulator(TWL6025_REG_VIO, pdata->vio6025);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+
+ }
+
+ if (twl_has_bci() && pdata->bci &&
+ !(features & (TPS_SUBSET | TWL5031))) {
+ child = add_child(3, "twl4030_bci",
+ pdata->bci, sizeof(*pdata->bci), false,
+ /* irq0 = CHG_PRES, irq1 = BCI */
+ pdata->irq_base + BCI_PRES_INTR_OFFSET,
+ pdata->irq_base + BCI_INTR_OFFSET);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+ }
+
return 0;
}
@@ -846,8 +1033,8 @@ static inline int __init protect_pm_master(void)
{
int e = 0;
- e = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, KEY_LOCK,
- R_PROTECT_KEY);
+ e = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0,
+ TWL4030_PM_MASTER_PROTECT_KEY);
return e;
}
@@ -855,10 +1042,13 @@ static inline int __init unprotect_pm_master(void)
{
int e = 0;
- e |= twl_i2c_write_u8(TWL_MODULE_PM_MASTER, KEY_UNLOCK1,
- R_PROTECT_KEY);
- e |= twl_i2c_write_u8(TWL_MODULE_PM_MASTER, KEY_UNLOCK2,
- R_PROTECT_KEY);
+ e |= twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER,
+ TWL4030_PM_MASTER_KEY_CFG1,
+ TWL4030_PM_MASTER_PROTECT_KEY);
+ e |= twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER,
+ TWL4030_PM_MASTER_KEY_CFG2,
+ TWL4030_PM_MASTER_PROTECT_KEY);
+
return e;
}
@@ -1010,7 +1200,7 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
/* load power event scripts */
if (twl_has_power() && pdata->power)
- twl4030_power_init(pdata->power);
+ twl4030_power_init(pdata->power);
/* Maybe init the T2 Interrupt subsystem */
if (client->irq
@@ -1041,7 +1231,16 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
twl_i2c_write_u8(TWL4030_MODULE_INTBR, temp, REG_GPPUPDCTR1);
}
+ twl_feat = id->driver_data;
+
status = add_children(pdata, id->driver_data);
+ if (status < 0 )
+ goto fail;
+
+ /* Board Specific Init Callback */
+ if(pdata->init)
+ status = pdata->init();
+
fail:
if (status < 0)
twl_remove(client);
@@ -1056,6 +1255,7 @@ static const struct i2c_device_id twl_ids[] = {
{ "tps65930", TPS_SUBSET }, /* fewer LDOs and DACs; no charger */
{ "tps65920", TPS_SUBSET }, /* fewer LDOs; no codec or charger */
{ "twl6030", TWL6030_CLASS }, /* "Phoenix power chip" */
+ { "twl6025", TWL6030_CLASS | TWL6025_SUBCLASS }, /* "Phoenix lite" */
{ /* end of list */ },
};
MODULE_DEVICE_TABLE(i2c, twl_ids);