diff options
author | Marcel Ziswiler <marcel.ziswiler@toradex.com> | 2012-11-12 15:28:39 +0100 |
---|---|---|
committer | Marcel Ziswiler <marcel.ziswiler@toradex.com> | 2012-11-12 15:28:39 +0100 |
commit | f987e832a9e79d2ce8009a5ea9c7b677624b3b30 (patch) | |
tree | 0dd09a5e6b4c60ee0a9916907dfc2cda83f3e496 /drivers/regulator | |
parent | f737b7f46a72c099cf8ac88baff02fbf61b1a47c (diff) | |
parent | fc993d9bc48f772133d8cd156c67c296477db070 (diff) |
Merge branch 'l4t/l4t-r16-r2' into colibri
Conflicts:
arch/arm/mach-tegra/tegra3_usb_phy.c
arch/arm/mach-tegra/usb_phy.c
drivers/usb/gadget/tegra_udc.c
drivers/usb/otg/Makefile
drivers/video/tegra/fb.c
sound/soc/tegra/tegra_pcm.c
Diffstat (limited to 'drivers/regulator')
-rw-r--r-- | drivers/regulator/Kconfig | 22 | ||||
-rw-r--r-- | drivers/regulator/Makefile | 1 | ||||
-rw-r--r-- | drivers/regulator/core.c | 14 | ||||
-rw-r--r-- | drivers/regulator/tps51632-regulator.c | 307 | ||||
-rw-r--r-- | drivers/regulator/tps62360-regulator.c | 6 | ||||
-rw-r--r-- | drivers/regulator/tps65090-regulator.c | 296 | ||||
-rw-r--r-- | drivers/regulator/tps80031-regulator.c | 397 |
7 files changed, 830 insertions, 213 deletions
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 28c58a1c19b1..88d36153ec70 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -332,12 +332,28 @@ config REGULATOR_DB8500_PRCMU This driver supports the voltage domain regulators controlled by the DB8500 PRCMU +config REGULATOR_TPS51632 + tristate "TI TPS51632 Power Regulator" + depends on I2C + select REGMAP_I2C + help + This driver supports TPS51632 voltage regulator chip. + The TPS52632 is 3-2-1 Phase D-Cap+ Step Down Driverless Controller + with Serial VID control and DVFS. + config REGULATOR_TPS6586X tristate "TI TPS6586X Power regulators" depends on MFD_TPS6586X help This driver supports TPS6586X voltage regulator chips. +config REGULATOR_TPS65090 + tristate "TI TPS65090 Power regulator" + depends on MFD_TPS65090 + help + This driver provides support for the voltage regulators on the + TI TPS65090 PMIC. + config REGULATOR_TPS6524X tristate "TI TPS6524X Power regulators" depends on SPI @@ -388,12 +404,6 @@ config REGULATOR_TPS6591X help This driver supports TPS6591X voltage regulator chips. -config REGULATOR_TPS65090 - tristate "TI TPS65090 Power regulators" - depends on MFD_TPS65090 - help - This driver supports TPS65090 voltage regulator chips. - config REGULATOR_TPS80031 tristate "TI TPS80031 Power regulators" depends on MFD_TPS80031 diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index a25ff34afcbc..4265ea06992c 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -41,6 +41,7 @@ obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o obj-$(CONFIG_REGULATOR_RC5T583) += rc5t583-regulator.o +obj-$(CONFIG_REGULATOR_TPS51632) += tps51632-regulator.o obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o obj-$(CONFIG_REGULATOR_TPS6507X) += tps6507x-regulator.o diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index cbe36b93639b..26f8776f8eee 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2654,6 +2654,7 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, static atomic_t regulator_no = ATOMIC_INIT(0); struct regulator_dev *rdev; int ret, i; + const char *supply = NULL; if (regulator_desc == NULL) return ERR_PTR(-EINVAL); @@ -2728,21 +2729,24 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, if (ret < 0) goto scrub; - if (init_data->supply_regulator) { + if (init_data->supply_regulator) + supply = init_data->supply_regulator; + else if (regulator_desc->supply_name) + supply = regulator_desc->supply_name; + + if (supply) { struct regulator_dev *r; int found = 0; list_for_each_entry(r, ®ulator_list, list) { - if (strcmp(rdev_get_name(r), - init_data->supply_regulator) == 0) { + if (strcmp(rdev_get_name(r), supply) == 0) { found = 1; break; } } if (!found) { - dev_err(dev, "Failed to find supply %s\n", - init_data->supply_regulator); + dev_err(dev, "Failed to find supply %s\n", supply); ret = -ENODEV; goto scrub; } diff --git a/drivers/regulator/tps51632-regulator.c b/drivers/regulator/tps51632-regulator.c new file mode 100644 index 000000000000..420362b5f116 --- /dev/null +++ b/drivers/regulator/tps51632-regulator.c @@ -0,0 +1,307 @@ +/* + * tps51632-regulator.c -- Maxim tps51632 + * + * Regulator driver for TPS51632 3-2-1 Phase D-Cap Step Down Driverless + * Controller with serial VID control and DVFS. + * + * Copyright (c) 2012, NVIDIA Corporation. + * + * Author: Laxman Dewangan <ldewangan@nvidia.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, + * whether express or implied; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307, USA + */ + +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/tps51632-regulator.h> +#include <linux/slab.h> + +/* Register definitions */ +#define TPS51632_VOLTAGE_SELECT_REG 0x0 +#define TPS51632_VOLTAGE_BASE_REG 0x1 +#define TPS51632_OFFSET_REG 0x2 +#define TPS51632_IMON_REG 0x3 +#define TPS51632_VMAX_REG 0x4 +#define TPS51632_DVFS_CONTROL_REG 0x5 +#define TPS51632_POWER_STATE_REG 0x6 +#define TPS51632_SLEW_REGS 0x7 +#define TPS51632_FAULT_REG 0x14 + +#define TPS51632_MAX_REG 0x15 + +#define TPS51632_VOUT_MASK 0x7F +#define TPS51632_VOUT_OFFSET_MASK 0x1F +#define TPS51632_VMAX_MASK 0x7F +#define TPS51632_VMAX_LOCK 0x80 + +/* TPS51632_DVFS_CONTROL_REG */ +#define TPS51632_DVFS_PWMEN 0x1 +#define TPS51632_DVFS_STEP_20 0x2 +#define TPS51632_DVFS_VMAX_PG 0x4 +#define TPS51632_DVFS_PWMRST 0x8 +#define TPS51632_DVFS_OCA_EN 0x10 +#define TPS51632_DVFS_FCCM 0x20 + +/* TPS51632_POWER_STATE_REG */ +#define TPS51632_POWER_STATE_MASK 0x03 +#define TPS51632_POWER_STATE_MULTI_PHASE_CCM 0x0 +#define TPS51632_POWER_STATE_SINGLE_PHASE_CCM 0x1 +#define TPS51632_POWER_STATE_SINGLE_PHASE_DCM 0x2 + +#define TPS51632_MIN_VOLATGE 500000 +#define TPS51632_MAX_VOLATGE 1520000 +#define TPS51632_VOLATGE_STEP 10000 +#define TPS51632_MAX_SEL 0x7F + +/* TPS51632 chip information */ +struct tps51632_chip { + struct device *dev; + struct regulator_desc desc; + struct regulator_dev *rdev; + struct regmap *regmap; + + bool pwm_enabled; + unsigned int change_uv_per_us; +}; + +static int tps51632_dcdc_get_voltage_sel(struct regulator_dev *rdev) +{ + struct tps51632_chip *tps = rdev_get_drvdata(rdev); + unsigned int data; + int ret; + unsigned int reg = TPS51632_VOLTAGE_SELECT_REG; + + if (tps->pwm_enabled) + reg = TPS51632_VOLTAGE_BASE_REG; + ret = regmap_read(tps->regmap, reg, &data); + if (ret < 0) { + dev_err(tps->dev, "reg read failed, err %d\n", ret); + return ret; + } + return data & TPS51632_VOUT_MASK; +} + +static int tps51632_dcdc_set_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV, unsigned *selector) +{ + struct tps51632_chip *tps = rdev_get_drvdata(rdev); + int vsel; + int ret; + + if ((max_uV < min_uV) || (max_uV < TPS51632_MIN_VOLATGE) || + (min_uV > TPS51632_MAX_VOLATGE)) + return -EINVAL; + + vsel = DIV_ROUND_UP(min_uV - TPS51632_MIN_VOLATGE, + TPS51632_VOLATGE_STEP) + 0x19; + if (selector) + *selector = (vsel & TPS51632_VOUT_MASK); + + ret = regmap_write(tps->regmap, TPS51632_VOLTAGE_SELECT_REG, vsel); + if (ret < 0) + dev_err(tps->dev, "reg write failed, err %d\n", ret); + return ret; +} + +static int tps51632_dcdc_list_voltage(struct regulator_dev *rdev, + unsigned selector) +{ + if (selector > TPS51632_MAX_SEL) + return -EINVAL; + + return TPS51632_MIN_VOLATGE + (selector - 0x19) * TPS51632_VOLATGE_STEP; +} + +static int tps51632_dcdc_set_voltage_time_sel(struct regulator_dev *rdev, + unsigned int old_selector, unsigned int new_selector) +{ + struct tps51632_chip *tps = rdev_get_drvdata(rdev); + int old_uV, new_uV; + + old_uV = tps51632_dcdc_list_voltage(rdev, old_selector); + if (old_uV < 0) + return old_uV; + + new_uV = tps51632_dcdc_list_voltage(rdev, new_selector); + if (new_uV < 0) + return new_uV; + + return DIV_ROUND_UP(abs(old_uV - new_uV), tps->change_uv_per_us); +} + +static struct regulator_ops tps51632_dcdc_ops = { + .get_voltage_sel = tps51632_dcdc_get_voltage_sel, + .set_voltage = tps51632_dcdc_set_voltage, + .list_voltage = tps51632_dcdc_list_voltage, + .set_voltage_time_sel = tps51632_dcdc_set_voltage_time_sel, +}; + +static int __devinit tps51632_init_dcdc(struct tps51632_chip *tps, + struct tps51632_regulator_platform_data *pdata) +{ + int ret; + uint8_t control = 0; + int vsel; + + if (pdata->enable_pwm) { + control = TPS51632_DVFS_PWMEN; + tps->pwm_enabled = pdata->enable_pwm; + vsel = DIV_ROUND_UP(pdata->base_voltage_uV - + TPS51632_MIN_VOLATGE, TPS51632_VOLATGE_STEP) + 0x19; + ret = regmap_write(tps->regmap, TPS51632_VOLTAGE_BASE_REG, + vsel); + if (ret < 0) { + dev_err(tps->dev, "BASE reg write failed, err %d\n", + ret); + return ret; + } + } + if (pdata->dvfs_step_20mV) + control = TPS51632_DVFS_STEP_20; + if (pdata->enable_vmax_alarm) + control = TPS51632_DVFS_VMAX_PG; + if (pdata->enable_overcurrent_alram) + control = TPS51632_DVFS_OCA_EN; + if (pdata->max_voltage_uV) { + vsel = DIV_ROUND_UP(pdata->max_voltage_uV - + TPS51632_MIN_VOLATGE, TPS51632_VOLATGE_STEP) + 0x19; + ret = regmap_write(tps->regmap, TPS51632_VMAX_REG, vsel); + if (ret < 0) { + dev_err(tps->dev, "VMAX write failed, err %d\n", ret); + return ret; + } + } + ret = regmap_write(tps->regmap, TPS51632_DVFS_CONTROL_REG, control); + if (ret < 0) { + dev_err(tps->dev, "DVFS reg write failed, err %d\n", ret); + return ret; + } + + tps->change_uv_per_us = max(6000u, pdata->slew_rate_uv_per_us); + + vsel = BIT(tps->change_uv_per_us/6000 - 1); + + ret = regmap_write(tps->regmap, TPS51632_SLEW_REGS, vsel); + if (ret < 0) + dev_err(tps->dev, "SLEW reg write failed, err %d\n", ret); + return ret; +} + +static const struct regmap_config tps51632_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = TPS51632_MAX_REG - 1, + .cache_type = REGCACHE_RBTREE, +}; + +static int __devinit tps51632_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct tps51632_regulator_platform_data *pdata; + struct regulator_dev *rdev; + struct tps51632_chip *tps; + int ret; + + pdata = client->dev.platform_data; + if (!pdata) { + dev_err(&client->dev, "No Platform data\n"); + return -EINVAL; + } + + tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL); + if (!tps) { + dev_err(&client->dev, "Memory allocation failed\n"); + return -ENOMEM; + } + + tps->dev = &client->dev; + tps->desc.name = id->name; + tps->desc.id = 0; + tps->desc.ops = &tps51632_dcdc_ops; + tps->desc.type = REGULATOR_VOLTAGE; + tps->desc.owner = THIS_MODULE; + tps->regmap = devm_regmap_init_i2c(client, &tps51632_regmap_config); + if (IS_ERR(tps->regmap)) { + ret = PTR_ERR(tps->regmap); + dev_err(&client->dev, "regmap init failed, err %d\n", ret); + return ret; + } + i2c_set_clientdata(client, tps); + + ret = tps51632_init_dcdc(tps, pdata); + if (ret < 0) { + dev_err(tps->dev, "Init failed, err = %d\n", ret); + return ret; + } + + /* Register the regulators */ + rdev = regulator_register(&tps->desc, &client->dev, + pdata->reg_init_data, tps); + if (IS_ERR(rdev)) { + dev_err(tps->dev, "regulator register failed\n"); + return PTR_ERR(rdev); + } + + tps->rdev = rdev; + return 0; +} + +static int __devexit tps51632_remove(struct i2c_client *client) +{ + struct tps51632_chip *tps = i2c_get_clientdata(client); + + regulator_unregister(tps->rdev); + return 0; +} + +static const struct i2c_device_id tps51632_id[] = { + {.name = "tps51632",}, + {}, +}; + +MODULE_DEVICE_TABLE(i2c, tps51632_id); + +static struct i2c_driver tps51632_i2c_driver = { + .driver = { + .name = "tps51632", + .owner = THIS_MODULE, + }, + .probe = tps51632_probe, + .remove = __devexit_p(tps51632_remove), + .id_table = tps51632_id, +}; + +static int __init tps51632_init(void) +{ + return i2c_add_driver(&tps51632_i2c_driver); +} +subsys_initcall(tps51632_init); + +static void __exit tps51632_cleanup(void) +{ + i2c_del_driver(&tps51632_i2c_driver); +} +module_exit(tps51632_cleanup); + +MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); +MODULE_DESCRIPTION("TPS51632 voltage regulator driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/tps62360-regulator.c b/drivers/regulator/tps62360-regulator.c index 7db148202436..095104f73b57 100644 --- a/drivers/regulator/tps62360-regulator.c +++ b/drivers/regulator/tps62360-regulator.c @@ -323,9 +323,15 @@ static int __devinit tps62360_init_dcdc(struct tps62360_chip *tps, return ret; } +static bool is_volatile_reg(struct device *dev, unsigned int reg) +{ + return false; +} + static const struct regmap_config tps62360_regmap_config = { .reg_bits = 8, .val_bits = 8, + .volatile_reg = is_volatile_reg, .max_register = REG_CHIPID, .cache_type = REGCACHE_RBTREE, }; diff --git a/drivers/regulator/tps65090-regulator.c b/drivers/regulator/tps65090-regulator.c index 8249a4b7ded2..aca2f56aa172 100644 --- a/drivers/regulator/tps65090-regulator.c +++ b/drivers/regulator/tps65090-regulator.c @@ -1,29 +1,25 @@ /* - * drivers/regulator/tps65090-regulator.c - * * Regulator driver for tps65090 power management chip. * - * Copyright (C) 2012 NVIDIA Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. + + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + + * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/> */ #include <linux/module.h> #include <linux/delay.h> #include <linux/init.h> +#include <linux/gpio.h> #include <linux/slab.h> #include <linux/err.h> #include <linux/platform_device.h> @@ -32,7 +28,7 @@ #include <linux/mfd/tps65090.h> #include <linux/regulator/tps65090-regulator.h> -struct tps65090_regulator { +struct tps65090_regulator_info { int id; /* Regulator register address.*/ u8 reg_en_reg; @@ -40,30 +36,51 @@ struct tps65090_regulator { /* used by regulator core */ struct regulator_desc desc; - - /* Device */ - struct device *dev; }; +struct tps65090_regulator { + struct tps65090_regulator_info *rinfo; + struct device *dev; + struct regulator_dev *rdev; + bool enable_ext_control; + int gpio; + int gpio_state; +}; static inline struct device *to_tps65090_dev(struct regulator_dev *rdev) { return rdev_get_dev(rdev)->parent->parent; } + +static inline bool is_dcdc(int id) +{ + if ((id == TPS65090_REGULATOR_DCDC1) || + (id == TPS65090_REGULATOR_DCDC2) || + (id == TPS65090_REGULATOR_DCDC2)) + return true; + return false; +} + static int tps65090_reg_is_enabled(struct regulator_dev *rdev) { struct tps65090_regulator *ri = rdev_get_drvdata(rdev); struct device *parent = to_tps65090_dev(rdev); - uint8_t control; + uint8_t control = 0; int ret; - ret = tps65090_read(parent, ri->reg_en_reg, &control); + if (is_dcdc(ri->rinfo->desc.id) && ri->enable_ext_control) { + if (gpio_is_valid(ri->gpio)) + return ri->gpio_state; + return 1; + } + + ret = tps65090_read(parent, ri->rinfo->reg_en_reg, &control); if (ret < 0) { dev_err(&rdev->dev, "Error in reading reg 0x%x\n", - ri->reg_en_reg); + ri->rinfo->reg_en_reg); return ret; } - return (((control >> ri->en_bit) & 1) == 1); + return (((control >> ri->rinfo->en_bit) & 1) == 1); } static int tps65090_reg_enable(struct regulator_dev *rdev) @@ -72,10 +89,19 @@ static int tps65090_reg_enable(struct regulator_dev *rdev) struct device *parent = to_tps65090_dev(rdev); int ret; - ret = tps65090_set_bits(parent, ri->reg_en_reg, ri->en_bit); + if (is_dcdc(ri->rinfo->desc.id) && ri->enable_ext_control) { + if (gpio_is_valid(ri->gpio)) { + gpio_set_value(ri->gpio, 1); + ri->gpio_state = 1; + } + return 0; + } + + ret = tps65090_set_bits(parent, ri->rinfo->reg_en_reg, + ri->rinfo->en_bit); if (ret < 0) dev_err(&rdev->dev, "Error in updating reg 0x%x\n", - ri->reg_en_reg); + ri->rinfo->reg_en_reg); return ret; } @@ -85,10 +111,19 @@ static int tps65090_reg_disable(struct regulator_dev *rdev) struct device *parent = to_tps65090_dev(rdev); int ret; - ret = tps65090_clr_bits(parent, ri->reg_en_reg, ri->en_bit); + if (is_dcdc(ri->rinfo->desc.id) && ri->enable_ext_control) { + if (gpio_is_valid(ri->gpio)) { + gpio_set_value(ri->gpio, 0); + ri->gpio_state = 0; + } + return 0; + } + + ret = tps65090_clr_bits(parent, ri->rinfo->reg_en_reg, + ri->rinfo->en_bit); if (ret < 0) dev_err(&rdev->dev, "Error in updating reg 0x%x\n", - ri->reg_en_reg); + ri->rinfo->reg_en_reg); return ret; } @@ -99,84 +134,209 @@ static struct regulator_ops tps65090_ops = { .is_enabled = tps65090_reg_is_enabled, }; -#define tps65090_REG(_id, _en_reg, _en_bit, _ops) \ +static struct regulator_ops tps65090_ldo_ops = { +}; + +#define tps65090_REG(_id, _sname, _en_reg, _en_bit, _ops) \ { \ .reg_en_reg = _en_reg, \ .en_bit = _en_bit, \ - .id = TPS65090_ID_##_id, \ + .id = TPS65090_REGULATOR_##_id, \ .desc = { \ .name = tps65090_rails(_id), \ - .id = TPS65090_ID_##_id, \ + .supply_name = _sname, \ + .id = TPS65090_REGULATOR_##_id, \ .ops = &_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ }, \ } -static struct tps65090_regulator TPS65090_regulator[] = { - tps65090_REG(DCDC1, 12, 0, tps65090_ops), - tps65090_REG(DCDC2, 13, 0, tps65090_ops), - tps65090_REG(DCDC3, 14, 0, tps65090_ops), - tps65090_REG(FET1, 15, 0, tps65090_ops), - tps65090_REG(FET2, 16, 0, tps65090_ops), - tps65090_REG(FET3, 17, 0, tps65090_ops), - tps65090_REG(FET4, 18, 0, tps65090_ops), - tps65090_REG(FET5, 19, 0, tps65090_ops), - tps65090_REG(FET6, 20, 0, tps65090_ops), - tps65090_REG(FET7, 21, 0, tps65090_ops), +static struct tps65090_regulator_info TPS65090_regulator_info[] = { + tps65090_REG(DCDC1, "VSYS1", 12, 0, tps65090_ops), + tps65090_REG(DCDC2, "VSYS2", 13, 0, tps65090_ops), + tps65090_REG(DCDC3, "VSYS3", 14, 0, tps65090_ops), + tps65090_REG(LDO1, "VSYS_L1", 0, 0, tps65090_ldo_ops), + tps65090_REG(LDO2, "VSYS_L2", 0, 0, tps65090_ldo_ops), + tps65090_REG(FET1, "INFET1", 15, 0, tps65090_ops), + tps65090_REG(FET2, "INFET2", 16, 0, tps65090_ops), + tps65090_REG(FET3, "INFET3", 17, 0, tps65090_ops), + tps65090_REG(FET4, "INFET4", 18, 0, tps65090_ops), + tps65090_REG(FET5, "INFET5", 19, 0, tps65090_ops), + tps65090_REG(FET6, "INFET6", 20, 0, tps65090_ops), + tps65090_REG(FET7, "INFET7", 21, 0, tps65090_ops), }; -static inline struct tps65090_regulator *find_regulator_info(int id) + +static inline struct tps65090_regulator_info *find_regulator_info(int id) { - struct tps65090_regulator *ri; + struct tps65090_regulator_info *rinfo; int i; - for (i = 0; i < ARRAY_SIZE(TPS65090_regulator); i++) { - ri = &TPS65090_regulator[i]; - if (ri->desc.id == id) - return ri; + for (i = 0; i < ARRAY_SIZE(TPS65090_regulator_info); i++) { + rinfo = &TPS65090_regulator_info[i]; + if (rinfo->desc.id == id) + return rinfo; } return NULL; } + +static int __devinit tps65090_regulator_preinit(int id, + struct tps65090_regulator *ri, + struct tps65090_regulator_platform_data *tps_pdata) +{ + int ret = 0; + struct device *parent = ri->dev->parent; + + if (!tps_pdata->enable_ext_control) { + ret = tps65090_clr_bits(parent, + ri->rinfo->reg_en_reg, 1); + if (ret < 0) { + dev_err(ri->dev, "Error in clr reg 0x%x\n", + ri->rinfo->reg_en_reg); + return ret; + } + } + + if (gpio_is_valid(tps_pdata->gpio)) { + int gpio_flag = GPIOF_OUT_INIT_LOW; + const char *sname; + + sname = tps_pdata->reg_init_data->constraints.name; + if (!sname) + sname = ri->rinfo->desc.name; + ri->gpio_state = 0; + if (tps_pdata->reg_init_data->constraints.always_on || + tps_pdata->reg_init_data->constraints.boot_on) { + gpio_flag = GPIOF_OUT_INIT_HIGH; + ri->gpio_state = 1; + } + + ret = gpio_request_one(tps_pdata->gpio, gpio_flag, sname); + if (ret < 0) { + dev_err(ri->dev, "gpio request failed, e %d\n", ret); + return ret; + } + } + ret = tps65090_set_bits(parent, ri->rinfo->reg_en_reg, 1); + if (ret < 0) { + dev_err(ri->dev, "Error in setting reg 0x%x\n", + ri->rinfo->reg_en_reg); + return ret; + } + ri->enable_ext_control = true; + ri->gpio = tps_pdata->gpio; + return ret; +} + static int __devinit tps65090_regulator_probe(struct platform_device *pdev) { - struct tps65090_regulator *ri = NULL; + struct tps65090_regulator_info *rinfo = NULL; + struct tps65090_regulator *ri; + struct tps65090_regulator *pmic; struct regulator_dev *rdev; struct tps65090_regulator_platform_data *tps_pdata; - int id = pdev->id; + struct tps65090_platform_data *tps65090_pdata; + int id; + int num; + int ret; - dev_dbg(&pdev->dev, "Probing regulator %d\n", id); + dev_dbg(&pdev->dev, "Probing regulator\n"); - ri = find_regulator_info(id); - if (ri == NULL) { - dev_err(&pdev->dev, "invalid regulator ID specified\n"); + tps65090_pdata = dev_get_platdata(pdev->dev.parent); + if (!tps65090_pdata || !tps65090_pdata->num_reg_pdata) { + dev_err(&pdev->dev, "Proper platform data missing\n"); return -EINVAL; } - tps_pdata = pdev->dev.platform_data; - ri->dev = &pdev->dev; - - rdev = regulator_register(&ri->desc, &pdev->dev, - &tps_pdata->regulator, ri); - if (IS_ERR_OR_NULL(rdev)) { - dev_err(&pdev->dev, "failed to register regulator %s\n", - ri->desc.name); - return PTR_ERR(rdev); + + pmic = devm_kzalloc(&pdev->dev, + tps65090_pdata->num_reg_pdata * sizeof(*pmic), + GFP_KERNEL); + if (!pmic) { + dev_err(&pdev->dev, "mem alloc for pmic failed\n"); + return -ENOMEM; + } + + for (num = 0; num < tps65090_pdata->num_reg_pdata; ++num) { + tps_pdata = tps65090_pdata->reg_pdata[num]; + if (!tps_pdata || !tps_pdata->reg_init_data) { + dev_err(&pdev->dev, + "Null platform data for regultor %d\n", num); + ret = -EINVAL; + goto scrub; + } + + id = tps_pdata->id; + rinfo = find_regulator_info(id); + if (!rinfo) { + dev_err(&pdev->dev, + "invalid regulator ID %d specified\n", id); + ret = -EINVAL; + goto scrub; + } + + ri = &pmic[num]; + ri->dev = &pdev->dev; + ri->rinfo = rinfo; + + if (is_dcdc(id)) { + ret = tps65090_regulator_preinit(id, ri, tps_pdata); + if (ret < 0) { + dev_err(&pdev->dev, + "failed to preinit regulator %d\n", id); + goto scrub; + } + } + rdev = regulator_register(&ri->rinfo->desc, &pdev->dev, + tps_pdata->reg_init_data, ri); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, "failed to register regulator %s\n", + ri->rinfo->desc.name); + ret = PTR_ERR(rdev); + goto scrub; + } + ri->rdev = rdev; } - platform_set_drvdata(pdev, rdev); + platform_set_drvdata(pdev, pmic); return 0; + +scrub: + while (--num >= 0) { + ri = &pmic[num]; + regulator_unregister(ri->rdev); + if (is_dcdc(ri->rinfo->desc.id) && (ri->enable_ext_control)) { + if (gpio_is_valid(ri->gpio)) + gpio_free(ri->gpio); + } + } + return ret; } static int __devexit tps65090_regulator_remove(struct platform_device *pdev) { - struct regulator_dev *rdev = platform_get_drvdata(pdev); + struct tps65090_regulator *pmic = platform_get_drvdata(pdev); + struct tps65090_platform_data *tps65090_pdata; + struct tps65090_regulator *ri; + int num; + + tps65090_pdata = dev_get_platdata(pdev->dev.parent); + if (!tps65090_pdata || !tps65090_pdata->num_reg_pdata) + return 0; - regulator_unregister(rdev); + for (num = 0; num < tps65090_pdata->num_reg_pdata; ++num) { + ri = &pmic[num]; + regulator_unregister(ri->rdev); + if (is_dcdc(ri->rinfo->desc.id) && (ri->enable_ext_control)) { + if (gpio_is_valid(ri->gpio)) + gpio_free(ri->gpio); + } + } return 0; } static struct platform_driver tps65090_regulator_driver = { .driver = { - .name = "tps65090-regulator", + .name = "tps65090-pmic", .owner = THIS_MODULE, }, .probe = tps65090_regulator_probe, @@ -196,5 +356,5 @@ static void __exit tps65090_regulator_exit(void) module_exit(tps65090_regulator_exit); MODULE_DESCRIPTION("tps65090 regulator driver"); -MODULE_ALIAS("platform:tps65090-regulator"); -MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Venu Byravarasu <vbyravarasu@nvidia.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/tps80031-regulator.c b/drivers/regulator/tps80031-regulator.c index efc608c936ea..39b5f452692a 100644 --- a/drivers/regulator/tps80031-regulator.c +++ b/drivers/regulator/tps80031-regulator.c @@ -81,44 +81,48 @@ #define EXT_PWR_REQ (PWR_REQ_INPUT_PREQ1 | PWR_REQ_INPUT_PREQ2 | \ PWR_REQ_INPUT_PREQ3) -struct tps80031_regulator { - +struct tps80031_regulator_info { /* Regulator register address.*/ u8 trans_reg; u8 state_reg; u8 force_reg; u8 volt_reg; u8 volt_id; - uint8_t trans_reg_cache; - uint8_t state_reg_cache; - uint8_t force_reg_cache; - uint8_t volt_reg_cache; - - /* twl resource ID, for resource control state machine */ - u8 id; /* chip constraints on regulator behavior */ u16 min_mV; u16 max_mV; - unsigned int tolerance_uv; - /* regulator specific turn-on delay */ + /* regulator specific turn-on delay as per datasheet*/ int delay; - u8 flags; - unsigned int platform_flags; - unsigned int ext_ctrl_flag; - /* used by regulator core */ struct regulator_desc desc; - /* Device */ - struct device *dev; - /*Power request bits */ int preq_bit; }; +struct tps80031_regulator { + struct device *dev; + struct regulator_dev *rdev; + struct tps80031_regulator_info *rinfo; + unsigned int tolerance_uv; + + /* Regulator specific turn-on delay if board file provided */ + int delay; + + u8 flags; + unsigned int platform_flags; + unsigned int ext_ctrl_flag; + + /* Cached register */ + uint8_t trans_reg_cache; + uint8_t state_reg_cache; + uint8_t force_reg_cache; + uint8_t volt_reg_cache; +}; + static inline struct device *to_tps80031_dev(struct regulator_dev *rdev) { return rdev_get_dev(rdev)->parent->parent; @@ -178,7 +182,7 @@ static int tps80031_reg_enable(struct regulator_dev *rdev) reg_val = (ri->state_reg_cache & ~STATE_MASK) | (STATE_ON & STATE_MASK); - ret = tps80031_write(parent, SLAVE_ID1, ri->state_reg, reg_val); + ret = tps80031_write(parent, SLAVE_ID1, ri->rinfo->state_reg, reg_val); if (ret < 0) { dev_err(&rdev->dev, "Error in writing the STATE register\n"); return ret; @@ -200,7 +204,7 @@ static int tps80031_reg_disable(struct regulator_dev *rdev) reg_val = (ri->state_reg_cache & ~STATE_MASK) | (STATE_OFF & STATE_MASK); - ret = tps80031_write(parent, SLAVE_ID1, ri->state_reg, reg_val); + ret = tps80031_write(parent, SLAVE_ID1, ri->rinfo->state_reg, reg_val); if (ret < 0) dev_err(&rdev->dev, "Error in writing the STATE register\n"); else @@ -297,10 +301,11 @@ static int __tps80031_dcdc_set_voltage(struct device *parent, int vsel = 0; int ret; - min_uV = min_uV - ri->tolerance_uv; - switch (ri->flags) { case 0: + if (min_uV >= (607700 + ri->tolerance_uv)) + min_uV = min_uV - ri->tolerance_uv; + if (min_uV == 0) vsel = 0; else if ((min_uV >= 607700) && (min_uV <= 1300000)) { @@ -328,6 +333,8 @@ static int __tps80031_dcdc_set_voltage(struct device *parent, break; case DCDC_OFFSET_EN: + if (min_uV >= (700000 + ri->tolerance_uv)) + min_uV = min_uV - ri->tolerance_uv; if (min_uV == 0) vsel = 0; else if ((min_uV >= 700000) && (min_uV <= 1420000)) { @@ -355,6 +362,8 @@ static int __tps80031_dcdc_set_voltage(struct device *parent, break; case DCDC_EXTENDED_EN: + if (min_uV >= (1852000 + ri->tolerance_uv)) + min_uV = min_uV - ri->tolerance_uv; if (min_uV == 0) vsel = 0; else if ((min_uV >= 1852000) && (max_uV <= 4013600)) { @@ -366,6 +375,8 @@ static int __tps80031_dcdc_set_voltage(struct device *parent, break; case DCDC_OFFSET_EN|DCDC_EXTENDED_EN: + if (min_uV >= (2161000 + ri->tolerance_uv)) + min_uV = min_uV - ri->tolerance_uv; if (min_uV == 0) vsel = 0; else if ((min_uV >= 2161000) && (max_uV <= 4321000)) { @@ -381,10 +392,10 @@ static int __tps80031_dcdc_set_voltage(struct device *parent, if (selector) *selector = vsel; - if (ri->force_reg) { + if (ri->rinfo->force_reg) { if (((ri->force_reg_cache >> 6) & 0x3) == 0) { - ret = tps80031_write(parent, ri->volt_id, - ri->force_reg, vsel); + ret = tps80031_write(parent, ri->rinfo->volt_id, + ri->rinfo->force_reg, vsel); if (ret < 0) dev_err(ri->dev, "Error in writing the " "force register\n"); @@ -393,7 +404,8 @@ static int __tps80031_dcdc_set_voltage(struct device *parent, return ret; } } - ret = tps80031_write(parent, ri->volt_id, ri->volt_reg, vsel); + ret = tps80031_write(parent, ri->rinfo->volt_id, + ri->rinfo->volt_reg, vsel); if (ret < 0) dev_err(ri->dev, "Error in writing the Voltage register\n"); else @@ -416,7 +428,7 @@ static int tps80031dcdc_get_voltage(struct regulator_dev *rdev) uint8_t vsel = 0; int voltage = 0; - if (ri->force_reg) { + if (ri->rinfo->force_reg) { vsel = ri->force_reg_cache; if ((vsel & SMPS_CMD_MASK) == 0) goto decode; @@ -507,11 +519,11 @@ static int tps80031ldo_list_voltage(struct regulator_dev *rdev, unsigned index) if (index == 0) return 0; - if ((ri->desc.id == TPS80031_ID_LDO2) && + if ((ri->rinfo->desc.id == TPS80031_REGULATOR_LDO2) && (ri->flags & TRACK_MODE_ENABLE)) - return (ri->min_mV + (((index - 1) * 125))/10) * 1000; + return (ri->rinfo->min_mV + (((index - 1) * 125))/10) * 1000; - return (ri->min_mV + ((index - 1) * 100)) * 1000; + return (ri->rinfo->min_mV + ((index - 1) * 100)) * 1000; } static int __tps80031_ldo2_set_voltage_track_mode(struct device *parent, @@ -545,7 +557,8 @@ static int __tps80031_ldo2_set_voltage_track_mode(struct device *parent, } } - ret = tps80031_write(parent, ri->volt_id, ri->volt_reg, vsel); + ret = tps80031_write(parent, ri->rinfo->volt_id, + ri->rinfo->volt_reg, vsel); if (ret < 0) dev_err(ri->dev, "Error in writing the Voltage register\n"); else @@ -562,10 +575,11 @@ static int __tps80031_ldo_set_voltage(struct device *parent, int vsel; int ret; - if ((min_uV/1000 < ri->min_mV) || (max_uV/1000 > ri->max_mV)) + if ((min_uV/1000 < ri->rinfo->min_mV) || + (max_uV/1000 > ri->rinfo->max_mV)) return -EDOM; - if ((ri->desc.id == TPS80031_ID_LDO2) && + if ((ri->rinfo->desc.id == TPS80031_REGULATOR_LDO2) && (ri->flags & TRACK_MODE_ENABLE)) return __tps80031_ldo2_set_voltage_track_mode(parent, ri, min_uV, max_uV); @@ -577,7 +591,8 @@ static int __tps80031_ldo_set_voltage(struct device *parent, vsel = (min_uV/1000 - 1000)/100 + 1; if (selector) *selector = vsel; - ret = tps80031_write(parent, ri->volt_id, ri->volt_reg, vsel); + ret = tps80031_write(parent, ri->rinfo->volt_id, + ri->rinfo->volt_reg, vsel); if (ret < 0) dev_err(ri->dev, "Error in writing the Voltage register\n"); else @@ -601,10 +616,10 @@ static int tps80031ldo_get_voltage(struct regulator_dev *rdev) uint8_t vsel; - if ((ri->desc.id == TPS80031_ID_LDO2) && + if ((ri->rinfo->desc.id == TPS80031_REGULATOR_LDO2) && (ri->flags & TRACK_MODE_ENABLE)) { vsel = ri->volt_reg_cache & 0x3F; - return (ri->min_mV + (((vsel - 1) * 125))/10) * 1000; + return (ri->rinfo->min_mV + (((vsel - 1) * 125))/10) * 1000; } vsel = ri->volt_reg_cache & LDO_VSEL_MASK; @@ -712,6 +727,22 @@ static int tps80031vbus_get_voltage(struct regulator_dev *rdev) return ret; } +static int tps80031_extreg_enable_time(struct regulator_dev *rdev) +{ + struct tps80031_regulator *ri = rdev_get_drvdata(rdev); + return ri->delay; +} + +static int tps80031_extreg_get_voltage(struct regulator_dev *rdev) +{ + struct tps80031_regulator *ri = rdev_get_drvdata(rdev); + int ret; + ret = tps80031_reg_is_enabled(rdev); + if (ret > 0) + return ri->rinfo->max_mV * 1000; + return 0; +} + static struct regulator_ops tps80031dcdc_ops = { .list_voltage = tps80031dcdc_list_voltage, .set_voltage = tps80031dcdc_set_voltage, @@ -740,6 +771,16 @@ static struct regulator_ops tps80031vbus_ops = { .enable_time = tps80031_vbus_enable_time, }; +static struct regulator_ops tps80031_ext_reg_ops = { + .enable = tps80031_reg_enable, + .disable = tps80031_reg_disable, + .is_enabled = tps80031_reg_is_enabled, + .enable_time = tps80031_extreg_enable_time, + .get_voltage = tps80031_extreg_get_voltage, +}; + + + #define TPS80031_REG(_id, _trans_reg, _state_reg, _force_reg, _volt_reg, \ _volt_id, min_mVolts, max_mVolts, _ops, _n_volt, _delay, \ _preq_bit) \ @@ -749,12 +790,11 @@ static struct regulator_ops tps80031vbus_ops = { .force_reg = _force_reg, \ .volt_reg = _volt_reg, \ .volt_id = _volt_id, \ - .id = TPS80031_ID_##_id, \ .min_mV = min_mVolts, \ .max_mV = max_mVolts, \ .desc = { \ .name = tps80031_rails(_id), \ - .id = TPS80031_ID_##_id, \ + .id = TPS80031_REGULATOR_##_id, \ .n_voltages = _n_volt, \ .ops = &_ops, \ .type = REGULATOR_VOLTAGE, \ @@ -764,7 +804,7 @@ static struct regulator_ops tps80031vbus_ops = { .preq_bit = _preq_bit, \ } -static struct tps80031_regulator tps80031_regulator[] = { +static struct tps80031_regulator_info tps80031_regulator_info[] = { TPS80031_REG(VIO, 0x47, 0x48, 0x49, 0x4A, SLAVE_ID0, 600, 2100, tps80031dcdc_ops, 63, 500, 4), TPS80031_REG(SMPS1, 0x53, 0x54, 0x55, 0x56, SLAVE_ID0, 600, 2100, @@ -798,6 +838,12 @@ static struct tps80031_regulator tps80031_regulator[] = { tps80031ldo_ops, 25, 500, -1), TPS80031_REG(VBUS, 0x0, 0x0, 0x00, 0x0, SLAVE_ID1, 0, 5000, tps80031vbus_ops, 2, 200000, -1), + TPS80031_REG(REGEN1, 0xAE, 0xAF, 0x00, 0x0, SLAVE_ID1, 0, 3300, + tps80031_ext_reg_ops, 2, 500, 16), + TPS80031_REG(REGEN2, 0xB1, 0xB2, 0x00, 0x0, SLAVE_ID1, 0, 3300, + tps80031_ext_reg_ops, 2, 500, 17), + TPS80031_REG(SYSEN, 0xB4, 0xB5, 0x00, 0x0, SLAVE_ID1, 0, 3300, + tps80031_ext_reg_ops, 2, 500, 18), }; static int tps80031_power_req_config(struct device *parent, @@ -807,17 +853,18 @@ static int tps80031_power_req_config(struct device *parent, int ret = 0; uint8_t reg_val; - if (ri->preq_bit < 0) + if (ri->rinfo->preq_bit < 0) goto skip_pwr_req_config; ret = tps80031_ext_power_req_config(parent, ri->ext_ctrl_flag, - ri->preq_bit, ri->state_reg, ri->trans_reg); + ri->rinfo->preq_bit, ri->rinfo->state_reg, + ri->rinfo->trans_reg); if (!ret) - ret = tps80031_read(parent, SLAVE_ID1, ri->trans_reg, + ret = tps80031_read(parent, SLAVE_ID1, ri->rinfo->trans_reg, &ri->trans_reg_cache); - if (!ret && ri->state_reg) - ret = tps80031_read(parent, SLAVE_ID1, ri->state_reg, + if (!ret && ri->rinfo->state_reg) + ret = tps80031_read(parent, SLAVE_ID1, ri->rinfo->state_reg, &ri->state_reg_cache); if (ret < 0) { dev_err(ri->dev, "%s() fails\n", __func__); @@ -831,11 +878,11 @@ skip_pwr_req_config: if (tps80031_pdata->ext_ctrl_flag & PWR_ON_ON_SLEEP) reg_val |= 0x4; - ret = tps80031_write(parent, SLAVE_ID1, ri->trans_reg, + ret = tps80031_write(parent, SLAVE_ID1, ri->rinfo->trans_reg, reg_val); if (ret < 0) dev_err(ri->dev, "Not able to write reg 0x%02x\n", - ri->trans_reg); + ri->rinfo->trans_reg); else ri->trans_reg_cache = reg_val; } @@ -849,7 +896,7 @@ static int tps80031_regulator_preinit(struct device *parent, int ret = 0; uint8_t reg_val; - if (ri->desc.id == TPS80031_ID_LDOUSB) { + if (ri->rinfo->desc.id == TPS80031_REGULATOR_LDOUSB) { if (ri->platform_flags & USBLDO_INPUT_VSYS) ret = tps80031_update(parent, SLAVE_ID1, TPS80031_MISC2_ADD, @@ -865,7 +912,7 @@ static int tps80031_regulator_preinit(struct device *parent, } } - if (ri->desc.id == TPS80031_ID_LDO3) { + if (ri->rinfo->desc.id == TPS80031_REGULATOR_LDO3) { if (ri->platform_flags & LDO3_OUTPUT_VIB) ret = tps80031_update(parent, SLAVE_ID1, TPS80031_MISC2_ADD, @@ -878,31 +925,59 @@ static int tps80031_regulator_preinit(struct device *parent, } } + switch (ri->rinfo->desc.id) { + case TPS80031_REGULATOR_REGEN1: + case TPS80031_REGULATOR_REGEN2: + case TPS80031_REGULATOR_SYSEN: + if (tps80031_pdata->reg_init_data->constraints.always_on || + tps80031_pdata->reg_init_data->constraints.boot_on) + ret = tps80031_update(parent, SLAVE_ID1, + ri->rinfo->state_reg, STATE_ON, STATE_MASK); + else + ret = tps80031_update(parent, SLAVE_ID1, + ri->rinfo->state_reg, STATE_OFF, STATE_MASK); + if (ret < 0) { + dev_err(ri->dev, + "state reg update failed, e %d\n", ret); + return ret; + } + ret = tps80031_update(parent, SLAVE_ID1, + ri->rinfo->trans_reg, 1, 0x3); + if (ret < 0) { + dev_err(ri->dev, + "trans reg update failed, e %d\n", ret); + return ret; + } + break; + default: + break; + } + if (!tps80031_pdata->init_apply) return 0; if (tps80031_pdata->init_uV >= 0) { - switch (ri->desc.id) { - case TPS80031_ID_VIO: - case TPS80031_ID_SMPS1: - case TPS80031_ID_SMPS2: - case TPS80031_ID_SMPS3: - case TPS80031_ID_SMPS4: + switch (ri->rinfo->desc.id) { + case TPS80031_REGULATOR_VIO: + case TPS80031_REGULATOR_SMPS1: + case TPS80031_REGULATOR_SMPS2: + case TPS80031_REGULATOR_SMPS3: + case TPS80031_REGULATOR_SMPS4: ret = __tps80031_dcdc_set_voltage(parent, ri, tps80031_pdata->init_uV, tps80031_pdata->init_uV, 0); break; - case TPS80031_ID_LDO1: - case TPS80031_ID_LDO2: - case TPS80031_ID_LDO3: - case TPS80031_ID_LDO4: - case TPS80031_ID_LDO5: - case TPS80031_ID_LDO6: - case TPS80031_ID_LDO7: - case TPS80031_ID_LDOUSB: - case TPS80031_ID_LDOLN: - case TPS80031_ID_VANA: + case TPS80031_REGULATOR_LDO1: + case TPS80031_REGULATOR_LDO2: + case TPS80031_REGULATOR_LDO3: + case TPS80031_REGULATOR_LDO4: + case TPS80031_REGULATOR_LDO5: + case TPS80031_REGULATOR_LDO6: + case TPS80031_REGULATOR_LDO7: + case TPS80031_REGULATOR_LDOUSB: + case TPS80031_REGULATOR_LDOLN: + case TPS80031_REGULATOR_VANA: ret = __tps80031_ldo_set_voltage(parent, ri, tps80031_pdata->init_uV, tps80031_pdata->init_uV, 0); @@ -915,7 +990,7 @@ static int tps80031_regulator_preinit(struct device *parent, if (ret < 0) { dev_err(ri->dev, "Not able to initialize voltage %d " "for rail %d err %d\n", tps80031_pdata->init_uV, - ri->desc.id, ret); + ri->rinfo->desc.id, ret); return ret; } } @@ -927,25 +1002,25 @@ static int tps80031_regulator_preinit(struct device *parent, reg_val = (ri->state_reg_cache & ~STATE_MASK) | (STATE_OFF & STATE_MASK); - ret = tps80031_write(parent, SLAVE_ID1, ri->state_reg, reg_val); + ret = tps80031_write(parent, SLAVE_ID1, ri->rinfo->state_reg, reg_val); if (ret < 0) dev_err(ri->dev, "Not able to %s rail %d err %d\n", (tps80031_pdata->init_enable) ? "enable" : "disable", - ri->desc.id, ret); + ri->rinfo->desc.id, ret); else ri->state_reg_cache = reg_val; return ret; } -static inline struct tps80031_regulator *find_regulator_info(int id) +static inline struct tps80031_regulator_info *find_regulator_info(int id) { - struct tps80031_regulator *ri; + struct tps80031_regulator_info *rinfo; int i; - for (i = 0; i < ARRAY_SIZE(tps80031_regulator); i++) { - ri = &tps80031_regulator[i]; - if (ri->desc.id == id) - return ri; + for (i = 0; i < ARRAY_SIZE(tps80031_regulator_info); i++) { + rinfo = &tps80031_regulator_info[i]; + if (rinfo->desc.id == id) + return rinfo; } return NULL; } @@ -953,30 +1028,30 @@ static void check_smps_mode_mult(struct device *parent, struct tps80031_regulator *ri) { int mult_offset; - switch (ri->desc.id) { - case TPS80031_ID_VIO: + switch (ri->rinfo->desc.id) { + case TPS80031_REGULATOR_VIO: mult_offset = SMPS_MULTOFFSET_VIO; break; - case TPS80031_ID_SMPS1: + case TPS80031_REGULATOR_SMPS1: mult_offset = SMPS_MULTOFFSET_SMPS1; break; - case TPS80031_ID_SMPS2: + case TPS80031_REGULATOR_SMPS2: mult_offset = SMPS_MULTOFFSET_SMPS2; break; - case TPS80031_ID_SMPS3: + case TPS80031_REGULATOR_SMPS3: mult_offset = SMPS_MULTOFFSET_SMPS3; break; - case TPS80031_ID_SMPS4: + case TPS80031_REGULATOR_SMPS4: mult_offset = SMPS_MULTOFFSET_SMPS4; break; - case TPS80031_ID_LDO2: + case TPS80031_REGULATOR_LDO2: ri->flags = (tps80031_get_smps_mult(parent) & (1 << 5)) ? TRACK_MODE_ENABLE : 0; /* TRACK mode the ldo2 varies from 600mV to 1300mV */ if (ri->flags & TRACK_MODE_ENABLE) { - ri->min_mV = 600; - ri->max_mV = 1300; - ri->desc.n_voltages = 57; + ri->rinfo->min_mV = 600; + ri->rinfo->max_mV = 1300; + ri->rinfo->desc.n_voltages = 57; } return; default: @@ -995,82 +1070,136 @@ static inline int tps80031_cache_regulator_register(struct device *parent, { int ret; - ret = tps80031_read(parent, SLAVE_ID1, ri->trans_reg, + ret = tps80031_read(parent, SLAVE_ID1, ri->rinfo->trans_reg, &ri->trans_reg_cache); - if (!ret && ri->state_reg) - ret = tps80031_read(parent, SLAVE_ID1, ri->state_reg, + if (!ret && ri->rinfo->state_reg) + ret = tps80031_read(parent, SLAVE_ID1, ri->rinfo->state_reg, &ri->state_reg_cache); - if (!ret && ri->force_reg) - ret = tps80031_read(parent, ri->volt_id, ri->force_reg, - &ri->force_reg_cache); - if (!ret && ri->volt_reg) - ret = tps80031_read(parent, ri->volt_id, ri->volt_reg, - &ri->volt_reg_cache); + if (!ret && ri->rinfo->force_reg) + ret = tps80031_read(parent, ri->rinfo->volt_id, + ri->rinfo->force_reg, &ri->force_reg_cache); + if (!ret && ri->rinfo->volt_reg) + ret = tps80031_read(parent, ri->rinfo->volt_id, + ri->rinfo->volt_reg, &ri->volt_reg_cache); return ret; } static int __devinit tps80031_regulator_probe(struct platform_device *pdev) { - struct tps80031_regulator *ri = NULL; - struct regulator_dev *rdev; + struct tps80031_platform_data *pdata = dev_get_platdata(pdev->dev.parent); struct tps80031_regulator_platform_data *tps_pdata; - int id = pdev->id; - int err; - - dev_dbg(&pdev->dev, "Probing reulator %d\n", id); + struct tps80031_regulator_info *rinfo; + struct tps80031_regulator *ri; + struct tps80031_regulator *pmic; + struct regulator_dev *rdev; + int id; + int ret; + int num; - ri = find_regulator_info(id); - if (ri == NULL) { - dev_err(&pdev->dev, "invalid regulator ID specified\n"); + if (!pdata || !pdata->num_regulator_pdata) { + dev_err(&pdev->dev, "Number of regulator is 0\n"); return -EINVAL; } - tps_pdata = pdev->dev.platform_data; - ri->dev = &pdev->dev; - if (tps_pdata->delay_us > 0) - ri->delay = tps_pdata->delay_us; - ri->tolerance_uv = tps_pdata->tolerance_uv; - - check_smps_mode_mult(pdev->dev.parent, ri); - ri->platform_flags = tps_pdata->flags; - ri->ext_ctrl_flag = tps_pdata->ext_ctrl_flag; - - err = tps80031_cache_regulator_register(pdev->dev.parent, ri); - if (err) { - dev_err(&pdev->dev, "Register access for caching is failed\n"); - return err; - } - err = tps80031_regulator_preinit(pdev->dev.parent, ri, tps_pdata); - if (err) - return err; - - err = tps80031_power_req_config(pdev->dev.parent, ri, tps_pdata); - if (err) - return err; - - rdev = regulator_register(&ri->desc, &pdev->dev, - &tps_pdata->regulator, ri); - if (IS_ERR_OR_NULL(rdev)) { - dev_err(&pdev->dev, "failed to register regulator %s\n", - ri->desc.name); - return PTR_ERR(rdev); + + pmic = devm_kzalloc(&pdev->dev, + pdata->num_regulator_pdata * sizeof(*pmic), GFP_KERNEL); + if (!pmic) { + dev_err(&pdev->dev, "mem alloc for pmic failed\n"); + return -ENOMEM; } - platform_set_drvdata(pdev, rdev); + for (num = 0; num < pdata->num_regulator_pdata; ++num) { + tps_pdata = pdata->regulator_pdata[num]; + if (!tps_pdata->reg_init_data) { + dev_err(&pdev->dev, + "No regulator init data for index %d\n", num); + ret = -EINVAL; + goto fail; + } + + id = tps_pdata->regulator_id; + rinfo = find_regulator_info(id); + if (!rinfo) { + dev_err(&pdev->dev, "invalid regulator ID specified\n"); + ret = -EINVAL; + goto fail; + } + + ri = &pmic[num]; + ri->rinfo = rinfo; + ri->dev = &pdev->dev; + if (tps_pdata->delay_us) + ri->delay = tps_pdata->delay_us; + else + ri->delay = rinfo->delay; + ri->tolerance_uv = tps_pdata->tolerance_uv; + + check_smps_mode_mult(pdev->dev.parent, ri); + ri->platform_flags = tps_pdata->flags; + ri->ext_ctrl_flag = tps_pdata->ext_ctrl_flag; + + ret = tps80031_cache_regulator_register(pdev->dev.parent, ri); + if (ret < 0) { + dev_err(&pdev->dev, + "Register cache failed, err %d\n", ret); + goto fail; + } + ret = tps80031_regulator_preinit(pdev->dev.parent, ri, tps_pdata); + if (ret < 0) { + dev_err(&pdev->dev, + "regulator preinit failed, err %d\n", ret); + goto fail; + } + + ret = tps80031_power_req_config(pdev->dev.parent, ri, tps_pdata); + if (ret < 0) { + dev_err(&pdev->dev, + "power req config failed, err %d\n", ret); + goto fail; + } + + rdev = regulator_register(&ri->rinfo->desc, &pdev->dev, + tps_pdata->reg_init_data, ri); + if (IS_ERR_OR_NULL(rdev)) { + dev_err(&pdev->dev, + "register regulator failed %s\n", + ri->rinfo->desc.name); + ret = PTR_ERR(rdev); + goto fail; + } + ri->rdev = rdev; + } + platform_set_drvdata(pdev, pmic); return 0; +fail: + while(--num >= 0) { + ri = &pmic[num]; + regulator_unregister(ri->rdev); + } + return ret; } static int __devexit tps80031_regulator_remove(struct platform_device *pdev) { - struct regulator_dev *rdev = platform_get_drvdata(pdev); + struct tps80031_platform_data *pdata = pdev->dev.parent->platform_data; + struct tps80031_regulator *pmic = platform_get_drvdata(pdev); + struct tps80031_regulator *ri = NULL; + int num; - regulator_unregister(rdev); + if (!pdata || !pdata->num_regulator_pdata) + return 0; + + for (num = 0; num < pdata->num_regulator_pdata; ++num) { + ri = &pmic[num]; + regulator_unregister(ri->rdev); + } return 0; } static struct platform_driver tps80031_regulator_driver = { .driver = { - .name = "tps80031-regulator", + .name = "tps80031-regulators", .owner = THIS_MODULE, }, .probe = tps80031_regulator_probe, |