diff options
author | nagesh Penumarty <vpenumarty@nvidia.com> | 2011-04-11 14:59:28 +0530 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2011-04-26 15:56:15 -0700 |
commit | 381c0a99479488414096284a084025999c87ef05 (patch) | |
tree | 9694d8345cf5f6adf32f8784dfee80ad0405101d /drivers/mfd | |
parent | e368a0f6b76140c70672bfefbd9902a15d3aa779 (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.c | 254 |
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); |