summaryrefslogtreecommitdiff
path: root/drivers/regulator
diff options
context:
space:
mode:
authorMarcel Ziswiler <marcel.ziswiler@toradex.com>2012-11-12 15:28:39 +0100
committerMarcel Ziswiler <marcel.ziswiler@toradex.com>2012-11-12 15:28:39 +0100
commitf987e832a9e79d2ce8009a5ea9c7b677624b3b30 (patch)
tree0dd09a5e6b4c60ee0a9916907dfc2cda83f3e496 /drivers/regulator
parentf737b7f46a72c099cf8ac88baff02fbf61b1a47c (diff)
parentfc993d9bc48f772133d8cd156c67c296477db070 (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/Kconfig22
-rw-r--r--drivers/regulator/Makefile1
-rw-r--r--drivers/regulator/core.c14
-rw-r--r--drivers/regulator/tps51632-regulator.c307
-rw-r--r--drivers/regulator/tps62360-regulator.c6
-rw-r--r--drivers/regulator/tps65090-regulator.c296
-rw-r--r--drivers/regulator/tps80031-regulator.c397
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, &regulator_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,