From 62780102a97ec81f8db2b3e9ceacf99843fb6530 Mon Sep 17 00:00:00 2001 From: Jinyoung Park Date: Wed, 28 Mar 2012 12:32:41 +0900 Subject: regulator: max77663: fix fps update condition Fix fps update condition in max77663_regulator_set_fps(). Bug 930883 Change-Id: I2f57603320a91b2727932586fc3c66d9de347d64 signed-off-by: Jinyoung Park Reviewed-on: http://git-master/r/92707 Reviewed-by: Simone Willett Tested-by: Simone Willett --- drivers/regulator/max77663-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/max77663-regulator.c b/drivers/regulator/max77663-regulator.c index c9001c0a3e9f..55d2526b4490 100644 --- a/drivers/regulator/max77663-regulator.c +++ b/drivers/regulator/max77663-regulator.c @@ -280,7 +280,7 @@ static int max77663_regulator_set_fps(struct max77663_regulator *reg) fps_mask |= FPS_PD_PERIOD_MASK; } - if (fps_val) + if (fps_val || fps_mask) ret = max77663_regulator_cache_write(reg, reg->regs[FPS_REG].addr, fps_mask, fps_val, ®->regs[FPS_REG].val); -- cgit v1.2.3 From df29290d57d9cb94616885063714a841a32b16d3 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Sat, 5 May 2012 01:26:56 +0530 Subject: regulator: TPS6238X0: Add tps6238X0 regulator driver The regulator module consists of 1 DCDC. The output voltage is configurable and is meant for supply power to the core voltage of Soc. Change-Id: Ic62d100a588f7b6f1b30c11fd44a925c97393069 Signed-off-by: Laxman Dewangan Reviewed-on: http://git-master/r/100653 Reviewed-by: Automatic_Commit_Validation_User Tested-by: Pradeep Goudagunta Reviewed-by: Bitan Biswas --- drivers/regulator/Kconfig | 10 + drivers/regulator/Makefile | 1 + drivers/regulator/tps6238x0-regulator.c | 488 ++++++++++++++++++++++++++++++++ 3 files changed, 499 insertions(+) create mode 100644 drivers/regulator/tps6238x0-regulator.c (limited to 'drivers/regulator') diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index d3cb8e6ff099..8d7161b3313f 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -345,6 +345,16 @@ config REGULATOR_TPS62360 high-frequency synchronous step down dc-dc converter optimized for battery-powered portable applications. +config REGULATOR_TPS6238X0 + tristate "TI TPS623850/TPS623860/TPS623870 Power Regulator" + depends on I2C + select REGMAP_I2C + help + This driver supports TPS6238X0 voltage regulator chip. This + regulator is meant for processor core supply. This chip is + high-frequency synchronous step down dc-dc converter optimized + for battery-powered portable applications. + config REGULATOR_AAT2870 tristate "AnalogicTech AAT2870 Regulators" depends on MFD_AAT2870_CORE diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 4fc5c3f275ab..7cca6bd64d6c 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -52,6 +52,7 @@ obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o obj-$(CONFIG_REGULATOR_DB8500_PRCMU) += db8500-prcmu.o obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o obj-$(CONFIG_REGULATOR_TPS62360) += tps62360-regulator.o +obj-$(CONFIG_REGULATOR_TPS6238X0) += tps6238x0-regulator.o obj-$(CONFIG_REGULATOR_AAT2870) += aat2870-regulator.o obj-$(CONFIG_REGULATOR_FAN53555) += fan53555-regulator.o ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG diff --git a/drivers/regulator/tps6238x0-regulator.c b/drivers/regulator/tps6238x0-regulator.c new file mode 100644 index 000000000000..880249627ab6 --- /dev/null +++ b/drivers/regulator/tps6238x0-regulator.c @@ -0,0 +1,488 @@ +/* + * tps6238x0-regulator.c -- TI tps623850/tps623860/tps623870 + * + * Driver for processor core supply tps623850, tps623860 and tps623870 + * + * Copyright (c) 2012, NVIDIA Corporation. + * + * Author: Laxman Dewangan + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Register definitions */ +#define REG_VSET0 0 +#define REG_VSET1 1 +#define REG_MODE0 2 +#define REG_MODE1 3 +#define REG_CONTROL 4 +#define REG_EXCEPTION 5 +#define REG_RAMPCTRL 6 +#define REG_IOUT 7 +#define REG_CHIPID 8 + +#define TPS6238X0_BASE_VOLTAGE 500000 +#define TPS6238X0_N_VOLTAGES 128 +#define TPS6238X0_MAX_VSET 2 +#define TPS6238X0_VOUT_MASK 0x7F + +/* tps 6238x0 chip information */ +struct tps6238x0_chip { + const char *name; + struct device *dev; + struct regulator_desc desc; + struct regulator_dev *rdev; + struct regmap *regmap; + int vsel_gpio; + int change_uv_per_us; + bool en_internal_pulldn; + bool en_discharge; + bool valid_gpios; + int lru_index[TPS6238X0_MAX_VSET]; + int curr_vset_vsel[TPS6238X0_MAX_VSET]; + int curr_vset_id; +}; + +/* + * find_voltage_set_register: Find new voltage configuration register + * (VSET) id. + * The finding of the new VSET register will be based on the LRU mechanism. + * Each VSET register will have different voltage configured . This + * Function will look if any of the VSET register have requested voltage set + * or not. + * - If it is already there then it will make that register as most + * recently used and return as found so that caller need not to set + * the VSET register but need to set the proper gpios to select this + * VSET register. + * - If requested voltage is not found then it will use the least + * recently mechanism to get new VSET register for new configuration + * and will return not_found so that caller need to set new VSET + * register and then gpios (both). + */ +static bool find_voltage_set_register(struct tps6238x0_chip *tps, + int req_vsel, int *vset_reg_id) +{ + int i; + bool found = false; + int new_vset_reg = tps->lru_index[1]; + int found_index = 1; + for (i = 0; i < TPS6238X0_MAX_VSET; ++i) { + if (tps->curr_vset_vsel[tps->lru_index[i]] == req_vsel) { + new_vset_reg = tps->lru_index[i]; + found_index = i; + found = true; + goto update_lru_index; + } + } + +update_lru_index: + for (i = found_index; i > 0; i--) + tps->lru_index[i] = tps->lru_index[i - 1]; + + tps->lru_index[0] = new_vset_reg; + *vset_reg_id = new_vset_reg; + return found; +} + +static int tps6238x0_get_voltage_sel(struct regulator_dev *dev) +{ + struct tps6238x0_chip *tps = rdev_get_drvdata(dev); + unsigned int data; + int ret; + + ret = regmap_read(tps->regmap, REG_VSET0 + tps->curr_vset_id, &data); + if (ret < 0) { + dev_err(tps->dev, "%s: Error in reading register %d\n", + __func__, REG_VSET0 + tps->curr_vset_id); + return ret; + } + return data & TPS6238X0_VOUT_MASK; +} + +static int tps6238x0_set_voltage(struct regulator_dev *dev, + int min_uV, int max_uV, unsigned *selector) +{ + struct tps6238x0_chip *tps = rdev_get_drvdata(dev); + int vsel; + int ret; + bool found = false; + int new_vset_id = tps->curr_vset_id; + + if (min_uV > + ((TPS6238X0_BASE_VOLTAGE + (TPS6238X0_N_VOLTAGES - 1) * 10000))) + return -EINVAL; + + if ((max_uV < min_uV) || (max_uV < TPS6238X0_BASE_VOLTAGE)) + return -EINVAL; + + vsel = DIV_ROUND_UP(min_uV - TPS6238X0_BASE_VOLTAGE, 10000); + if (selector) + *selector = (vsel & TPS6238X0_VOUT_MASK); + + /* + * If gpios are available to select the VSET register then least + * recently used register for new configuration. + */ + if (tps->valid_gpios) + found = find_voltage_set_register(tps, vsel, &new_vset_id); + + if (!found) { + ret = regmap_update_bits(tps->regmap, REG_VSET0 + new_vset_id, + TPS6238X0_VOUT_MASK, vsel); + if (ret < 0) { + dev_err(tps->dev, "%s: Error in updating register %d\n", + __func__, REG_VSET0 + new_vset_id); + return ret; + } + tps->curr_vset_id = new_vset_id; + tps->curr_vset_vsel[new_vset_id] = vsel; + } + + /* Select proper VSET register vio gpios */ + if (tps->valid_gpios) + gpio_set_value_cansleep(tps->vsel_gpio, new_vset_id & 0x1); + return 0; +} + +static int tps6238x0_list_voltage(struct regulator_dev *dev, + unsigned selector) +{ + struct tps6238x0_chip *tps = rdev_get_drvdata(dev); + + if ((selector < 0) || (selector >= tps->desc.n_voltages)) + return -EINVAL; + + return TPS6238X0_BASE_VOLTAGE + selector * 10000; +} + +static int tps6238x0_regulator_enable_time(struct regulator_dev *rdev) +{ + return 300; +} + +static int tps6238x0_set_voltage_time_sel(struct regulator_dev *rdev, + unsigned int old_selector, unsigned int new_selector) +{ + struct tps6238x0_chip *tps = rdev_get_drvdata(rdev); + int old_uV, new_uV; + old_uV = tps6238x0_list_voltage(rdev, old_selector); + + if (old_uV < 0) + return old_uV; + + new_uV = tps6238x0_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 int tps6238x0_is_enable(struct regulator_dev *rdev) +{ + struct tps6238x0_chip *tps = rdev_get_drvdata(rdev); + unsigned int data; + int ret; + + ret = regmap_read(tps->regmap, REG_VSET0 + tps->curr_vset_id, &data); + if (ret < 0) { + dev_err(tps->dev, "%s: Error in reading register %d\n", + __func__, REG_VSET0 + tps->curr_vset_id); + return ret; + } + return !!(data & BIT(7)); +} + +static int tps6238x0_enable(struct regulator_dev *rdev) +{ + struct tps6238x0_chip *tps = rdev_get_drvdata(rdev); + int ret; + int i; + + /* Enable required VSET configuration */ + for (i = 0; i < TPS6238X0_MAX_VSET; ++i) { + unsigned int en = 0; + if (tps->valid_gpios || (i == tps->curr_vset_id)) + en = BIT(7); + + ret = regmap_update_bits(tps->regmap, REG_VSET0 + i, + BIT(7), en); + if (ret < 0) { + dev_err(tps->dev, "%s() fails in updating reg %d\n", + __func__, REG_VSET0 + i); + return ret; + } + } + return ret; +} + +static int tps6238x0_disable(struct regulator_dev *rdev) +{ + struct tps6238x0_chip *tps = rdev_get_drvdata(rdev); + int ret; + int i; + + /* Disable required VSET configuration */ + for (i = 0; i < TPS6238X0_MAX_VSET; ++i) { + ret = regmap_update_bits(tps->regmap, REG_VSET0 + i, + BIT(7), 0); + if (ret < 0) { + dev_err(tps->dev, "%s() fails in updating reg %d\n", + __func__, REG_VSET0 + i); + return ret; + } + } + return ret; +} + +static struct regulator_ops tps6238x0_ops = { + .is_enabled = tps6238x0_is_enable, + .enable = tps6238x0_enable, + .disable = tps6238x0_disable, + .enable_time = tps6238x0_regulator_enable_time, + .set_voltage_time_sel = tps6238x0_set_voltage_time_sel, + .get_voltage_sel = tps6238x0_get_voltage_sel, + .set_voltage = tps6238x0_set_voltage, + .list_voltage = tps6238x0_list_voltage, +}; + +static int __devinit tps6238x0_configure(struct tps6238x0_chip *tps, + struct tps6238x0_regulator_platform_data *pdata) +{ + int ret; + int i; + + /* Initailize internal pull up/down control */ + if (tps->en_internal_pulldn) + ret = regmap_write(tps->regmap, REG_CONTROL, 0xC0); + else + ret = regmap_write(tps->regmap, REG_CONTROL, 0x0); + if (ret < 0) { + dev_err(tps->dev, "%s() fails in writing reg %d\n", + __func__, REG_CONTROL); + return ret; + } + + /* Enable required VSET configuration */ + for (i = 0; i < TPS6238X0_MAX_VSET; ++i) { + unsigned int en = 0; + if (tps->valid_gpios || (i == tps->curr_vset_id)) + en = BIT(7); + + ret = regmap_update_bits(tps->regmap, REG_VSET0 + i, + BIT(7), en); + if (ret < 0) { + dev_err(tps->dev, "%s() fails in updating reg %d\n", + __func__, REG_VSET0 + i); + return ret; + } + } + + /* Reset output discharge path to reduce power consumption */ + ret = regmap_update_bits(tps->regmap, REG_RAMPCTRL, BIT(2), 0); + if (ret < 0) + dev_err(tps->dev, "%s() fails in updating reg %d\n", + __func__, REG_RAMPCTRL); + tps->change_uv_per_us = 312; + return ret; +} + +static const struct regmap_config tps6238x0_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = REG_CHIPID, + .num_reg_defaults_raw = REG_CHIPID + 1, + .cache_type = REGCACHE_RBTREE, +}; + +static int __devinit tps6238x0_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct tps6238x0_regulator_platform_data *pdata; + struct regulator_dev *rdev; + struct tps6238x0_chip *tps; + int ret; + int i; + + pdata = client->dev.platform_data; + if (!pdata) { + dev_err(&client->dev, "%s() Err: Platform data not found\n", + __func__); + return -EIO; + } + + tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL); + if (!tps) { + dev_err(&client->dev, "%s() Err: Memory allocation fails\n", + __func__); + return -ENOMEM; + } + + tps->en_discharge = pdata->en_discharge; + tps->en_internal_pulldn = pdata->en_internal_pulldn; + tps->vsel_gpio = pdata->vsel_gpio; + tps->dev = &client->dev; + + tps->desc.name = id->name; + tps->desc.id = 0; + tps->desc.n_voltages = TPS6238X0_N_VOLTAGES; + tps->desc.ops = &tps6238x0_ops; + tps->desc.type = REGULATOR_VOLTAGE; + tps->desc.owner = THIS_MODULE; + tps->regmap = devm_regmap_init_i2c(client, &tps6238x0_regmap_config); + if (IS_ERR(tps->regmap)) { + ret = PTR_ERR(tps->regmap); + dev_err(&client->dev, "%s() Err: Failed to allocate register" + "map: %d\n", __func__, ret); + return ret; + } + i2c_set_clientdata(client, tps); + + tps->curr_vset_id = (pdata->vsel_def_state & 1); + tps->lru_index[0] = tps->curr_vset_id; + tps->valid_gpios = false; + + if (gpio_is_valid(tps->vsel_gpio)) { + int gpio_flag; + gpio_flag = (tps->curr_vset_id) ? + GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; + ret = gpio_request_one(tps->vsel_gpio, + gpio_flag, "tps6238x0-vsel0"); + if (ret) { + dev_err(&client->dev, + "Err: Could not obtain vsel GPIO %d: %d\n", + tps->vsel_gpio, ret); + return ret; + } + tps->valid_gpios = true; + + /* + * Initialize the lru index with vset_reg id + * The index 0 will be most recently used and + * set with the tps->curr_vset_id */ + for (i = 0; i < TPS6238X0_MAX_VSET; ++i) + tps->lru_index[i] = i; + tps->lru_index[0] = tps->curr_vset_id; + tps->lru_index[tps->curr_vset_id] = 0; + } + + ret = tps6238x0_configure(tps, pdata); + if (ret < 0) { + dev_err(tps->dev, "%s() Err: Init fails with = %d\n", + __func__, ret); + goto err_init; + } + + /* Register the regulators */ + rdev = regulator_register(&tps->desc, &client->dev, + pdata->init_data, tps); + if (IS_ERR(rdev)) { + dev_err(tps->dev, "%s() Err: Failed to register %s\n", + __func__, id->name); + ret = PTR_ERR(rdev); + goto err_init; + } + + tps->rdev = rdev; + return 0; + +err_init: + if (gpio_is_valid(tps->vsel_gpio)) + gpio_free(tps->vsel_gpio); + + return ret; +} + +/** + * tps6238x0_remove - tps62360 driver i2c remove handler + * @client: i2c driver client device structure + * + * Unregister TPS driver as an i2c client device driver + */ +static int __devexit tps6238x0_remove(struct i2c_client *client) +{ + struct tps6238x0_chip *tps = i2c_get_clientdata(client); + + if (gpio_is_valid(tps->vsel_gpio)) + gpio_free(tps->vsel_gpio); + + regulator_unregister(tps->rdev); + return 0; +} + +static void tps6238x0_shutdown(struct i2c_client *client) +{ + struct tps6238x0_chip *tps = i2c_get_clientdata(client); + int st; + + if (!tps->en_discharge) + return; + + /* Configure the output discharge path */ + st = regmap_update_bits(tps->regmap, REG_RAMPCTRL, BIT(2), BIT(2)); + if (st < 0) + dev_err(tps->dev, "%s() fails in updating reg %d\n", + __func__, REG_RAMPCTRL); +} + +static const struct i2c_device_id tps6238x0_id[] = { + {.name = "tps623850", }, + {.name = "tps623860", }, + {.name = "tps623870", }, + {}, +}; + +MODULE_DEVICE_TABLE(i2c, tps6238x0_id); + +static struct i2c_driver tps6238x0_i2c_driver = { + .driver = { + .name = "tps6238x0", + .owner = THIS_MODULE, + }, + .probe = tps6238x0_probe, + .remove = __devexit_p(tps6238x0_remove), + .shutdown = tps6238x0_shutdown, + .id_table = tps6238x0_id, +}; + +static int __init tps6238x0_init(void) +{ + return i2c_add_driver(&tps6238x0_i2c_driver); +} +subsys_initcall(tps6238x0_init); + +static void __exit tps6238x0_cleanup(void) +{ + i2c_del_driver(&tps6238x0_i2c_driver); +} +module_exit(tps6238x0_cleanup); + +MODULE_AUTHOR("Laxman Dewangan "); +MODULE_DESCRIPTION("TPS623850/TPS623860/TPS623870 voltage regulator driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From a9837b0a1bf1dc2d4bf71e26216fb5085a83e75c Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Sun, 13 May 2012 15:42:21 +0530 Subject: regulator: max8973: implement regulator driver for maxim8973 This driver supports ivoltage regulator driver for MAX8973 voltage regulator chip. The MAX8973 high-efficiency, three-phase, DC-DC step-down switching regulator delivers up to 9A of output current. bug 981355 Change-Id: I6e4ff62139face4e47e2be269554a64c2654e74b Signed-off-by: Laxman Dewangan Reviewed-on: http://git-master/r/102148 Reviewed-by: Rohan Somvanshi Tested-by: Rohan Somvanshi --- drivers/regulator/Kconfig | 9 + drivers/regulator/Makefile | 1 + drivers/regulator/max8973-regulator.c | 606 ++++++++++++++++++++++++++++++++++ 3 files changed, 616 insertions(+) create mode 100644 drivers/regulator/max8973-regulator.c (limited to 'drivers/regulator') diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 8d7161b3313f..67093e3f1cd7 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -117,6 +117,15 @@ config REGULATOR_MAX8952 via I2C bus. Maxim 8952 has one voltage output and supports 4 DVS modes ranging from 0.77V to 1.40V by 0.01V steps. +config REGULATOR_MAX8973 + tristate "Maxim MAX8973 Power Regulator" + depends on I2C + select REGMAP_I2C + help + This driver supports MAX8973 voltage regulator chip. + The MAX8973 high-efficiency, three-phase, DC-DC step-down switching + regulator delivers up to 9A of output current. + config REGULATOR_MAX8997 tristate "Maxim 8997/8966 regulator" depends on MFD_MAX8997 diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 7cca6bd64d6c..7642d39fb8d3 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_REGULATOR_MAX8649) += max8649.o obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o obj-$(CONFIG_REGULATOR_MAX8925) += max8925-regulator.o obj-$(CONFIG_REGULATOR_MAX8952) += max8952.o +obj-$(CONFIG_REGULATOR_MAX8973) += max8973-regulator.o obj-$(CONFIG_REGULATOR_MAX8997) += max8997.o obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o obj-$(CONFIG_REGULATOR_MAX8907C) += max8907c-regulator.o diff --git a/drivers/regulator/max8973-regulator.c b/drivers/regulator/max8973-regulator.c new file mode 100644 index 000000000000..8d87970a1b31 --- /dev/null +++ b/drivers/regulator/max8973-regulator.c @@ -0,0 +1,606 @@ +/* + * max8973-regulator.c -- Maxim max8973 + * + * Regulator driver for MAXIM 8973 DC-DC step-down switching regulator. + * + * Copyright (c) 2012, NVIDIA Corporation. + * + * Author: Laxman Dewangan + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Register definitions */ +#define MAX8973_VOUT 0x0 +#define MAX8973_VOUT_DVS 0x1 +#define MAX8973_CONTROL1 0x2 +#define MAX8973_CONTROL2 0x3 +#define MAX8973_CHIPID1 0x4 +#define MAX8973_CHIPID2 0x5 + +#define MAX8973_MAX_VOUT_REG 2 + +/* MAX8973_VOUT */ +#define MAX8973_VOUT_ENABLE BIT(7) +#define MAX8973_VOUT_MASK 0x7F + +/* MAX8973_VOUT_DVS */ +#define MAX8973_DVS_VOUT_MASK 0x7F + +/* MAX8973_CONTROL1 */ +#define MAX8973_SNS_ENABLE BIT(7) +#define MAX8973_FPWM_EN_M BIT(6) +#define MAX8973_NFSR_ENABLE BIT(5) +#define MAX8973_AD_ENABLE BIT(4) +#define MAX8973_BIAS_ENABLE BIT(3) +#define MAX8973_FREQSHIFT_9PER BIT(2) + +#define MAX8973_RAMP_12mV_PER_US 0x0 +#define MAX8973_RAMP_25mV_PER_US 0x1 +#define MAX8973_RAMP_50mV_PER_US 0x2 +#define MAX8973_RAMP_200mV_PER_US 0x3 + +/* MAX8973_CONTROL2 */ +#define MAX8973_WDTMR_ENABLE BIT(6) +#define MAX8973_DISCH_ENBABLE BIT(5) +#define MAX8973_FT_ENABLE BIT(4) + +#define MAX8973_CKKADV_TRIP_DISABLE 0xC +#define MAX8973_CKKADV_TRIP_75mV_PER_US 0x0 +#define MAX8973_CKKADV_TRIP_150mV_PER_US 0x4 +#define MAX8973_CKKADV_TRIP_75mV_PER_US_HIST_DIS 0x8 + +#define MAX8973_INDUCTOR_MIN_30_PER 0x0 +#define MAX8973_INDUCTOR_NOMINAL 0x1 +#define MAX8973_INDUCTOR_PLUS_30_PER 0x2 +#define MAX8973_INDUCTOR_PLUS_60_PER 0x3 + +#define MAX8973_MIN_VOLATGE 606250 +#define MAX8973_MAX_VOLATGE 1400000 +#define MAX8973_VOLATGE_STEP 6250 +#define MAX8973_BUCK_N_VOLTAGE \ + (((MAX8973_MAX_VOLATGE - MAX8973_MIN_VOLATGE) / MAX8973_VOLATGE_STEP) \ + + 1) + +/* Maxim 8973 chip information */ +struct max8973_chip { + struct device *dev; + struct regulator_desc desc; + struct regulator_dev *rdev; + struct regmap *regmap; + bool enable_external_control; + int dvs_gpio; + int lru_index[MAX8973_MAX_VOUT_REG]; + int curr_vout_val[MAX8973_MAX_VOUT_REG]; + int curr_vout_reg; + int curr_gpio_val; + int change_uv_per_us; + bool valid_dvs_gpio; +}; + +/* + * find_voltage_set_register: Find new voltage configuration register (VOUT). + * The finding of the new VOUT register will be based on the LRU mechanism. + * Each VOUT register will have different voltage configured . This + * Function will look if any of the VOUT register have requested voltage set + * or not. + * - If it is already there then it will make that register as most + * recently used and return as found so that caller need not to set + * the VOUT register but need to set the proper gpios to select this + * VOUT register. + * - If requested voltage is not found then it will use the least + * recently mechanism to get new VOUT register for new configuration + * and will return not_found so that caller need to set new VOUT + * register and then gpios (both). + */ +static bool find_voltage_set_register(struct max8973_chip *tps, + int req_vsel, int *vout_reg, int *gpio_val) +{ + int i; + bool found = false; + int new_vout_reg = tps->lru_index[MAX8973_MAX_VOUT_REG - 1]; + int found_index = MAX8973_MAX_VOUT_REG - 1; + + for (i = 0; i < MAX8973_MAX_VOUT_REG; ++i) { + if (tps->curr_vout_val[tps->lru_index[i]] == req_vsel) { + new_vout_reg = tps->lru_index[i]; + found_index = i; + found = true; + goto update_lru_index; + } + } + +update_lru_index: + for (i = found_index; i > 0; i--) + tps->lru_index[i] = tps->lru_index[i - 1]; + + tps->lru_index[0] = new_vout_reg; + *gpio_val = new_vout_reg; + *vout_reg = MAX8973_VOUT + new_vout_reg; + return found; +} + +static int max8973_dcdc_get_voltage_sel(struct regulator_dev *rdev) +{ + struct max8973_chip *max = rdev_get_drvdata(rdev); + unsigned int data; + int ret; + + ret = regmap_read(max->regmap, max->curr_vout_reg, &data); + if (ret < 0) { + dev_err(max->dev, "%s(): register %d read failed with err %d\n", + __func__, max->curr_vout_reg, ret); + return ret; + } + return data & MAX8973_VOUT_MASK; +} + +static int max8973_dcdc_set_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV, unsigned *selector) +{ + struct max8973_chip *max = rdev_get_drvdata(rdev); + int vsel; + int ret; + bool found = false; + int vout_reg = max->curr_vout_reg; + int gpio_val = max->curr_gpio_val; + + if ((max_uV < min_uV) || (max_uV < MAX8973_MIN_VOLATGE) || + (min_uV > MAX8973_MAX_VOLATGE)) + return -EINVAL; + + vsel = DIV_ROUND_UP(min_uV - MAX8973_MIN_VOLATGE, MAX8973_VOLATGE_STEP); + if (selector) + *selector = (vsel & MAX8973_VOUT_MASK); + + /* + * If gpios are available to select the VOUT register then least + * recently used register for new configuration. + */ + if (max->valid_dvs_gpio) + found = find_voltage_set_register(max, vsel, + &vout_reg, &gpio_val); + + if (!found) { + ret = regmap_update_bits(max->regmap, vout_reg, + MAX8973_VOUT_MASK, vsel); + if (ret < 0) { + dev_err(max->dev, + "%s(): register %d update failed with err %d\n", + __func__, vout_reg, ret); + return ret; + } + max->curr_vout_reg = vout_reg; + max->curr_vout_val[gpio_val] = vsel; + } + + /* Select proper VOUT register vio gpios */ + if (max->valid_dvs_gpio) { + gpio_set_value_cansleep(max->dvs_gpio, gpio_val & 0x1); + max->curr_gpio_val = gpio_val; + } + return 0; +} + +static int max8973_dcdc_list_voltage(struct regulator_dev *rdev, + unsigned selector) +{ + if (selector >= MAX8973_BUCK_N_VOLTAGE) + return -EINVAL; + + return MAX8973_MIN_VOLATGE + selector * MAX8973_VOLATGE_STEP; +} + +static int max8973_dcdc_set_voltage_time_sel(struct regulator_dev *rdev, + unsigned int old_selector, unsigned int new_selector) +{ + struct max8973_chip *max = rdev_get_drvdata(rdev); + int old_uV, new_uV; + + old_uV = max8973_dcdc_list_voltage(rdev, old_selector); + if (old_uV < 0) + return old_uV; + + new_uV = max8973_dcdc_list_voltage(rdev, new_selector); + if (new_uV < 0) + return new_uV; + + return DIV_ROUND_UP(abs(old_uV - new_uV), max->change_uv_per_us); +} +static int max8973_dcdc_enable(struct regulator_dev *rdev) +{ + struct max8973_chip *max = rdev_get_drvdata(rdev); + int ret; + + if (max->enable_external_control) + return 0; + + ret = regmap_update_bits(max->regmap, MAX8973_VOUT, + MAX8973_VOUT_ENABLE, MAX8973_VOUT_ENABLE); + if (ret < 0) + dev_err(max->dev, "%s(): register %d update failed with err %d", + __func__, MAX8973_VOUT, ret); + return ret; +} + +static int max8973_dcdc_disable(struct regulator_dev *rdev) +{ + struct max8973_chip *max = rdev_get_drvdata(rdev); + int ret = 0; + + if (max->enable_external_control) + return 0; + + ret = regmap_update_bits(max->regmap, MAX8973_VOUT, + MAX8973_VOUT_ENABLE, 0); + if (ret < 0) + dev_err(max->dev, "%s(): register %d update failed with err %d", + __func__, MAX8973_VOUT, ret); + return ret; +} + +static int max8973_dcdc_is_enabled(struct regulator_dev *rdev) +{ + struct max8973_chip *max = rdev_get_drvdata(rdev); + int ret; + unsigned int data; + + if (max->enable_external_control) + return 1; + + ret = regmap_read(max->regmap, MAX8973_VOUT, &data); + if (ret < 0) { + dev_err(max->dev, "%s(): register %d read failed with err %d", + __func__, max->curr_vout_reg, ret); + return ret; + } + + return !!(data & MAX8973_VOUT_ENABLE); +} + +static int max8973_dcdc_set_mode(struct regulator_dev *rdev, unsigned int mode) +{ + struct max8973_chip *max = rdev_get_drvdata(rdev); + int ret; + int pwm; + + /* Enable force PWM mode in FAST mode only. */ + switch (mode) { + case REGULATOR_MODE_FAST: + pwm = MAX8973_FPWM_EN_M; + break; + + case REGULATOR_MODE_NORMAL: + pwm = 0; + break; + + default: + return -EINVAL; + } + + ret = regmap_update_bits(max->regmap, MAX8973_CONTROL1, + MAX8973_FPWM_EN_M, pwm); + if (ret < 0) + dev_err(max->dev, + "%s(): register %d update failed with err %d\n", + __func__, MAX8973_CONTROL1, ret); + return ret; +} + +static unsigned int max8973_dcdc_get_mode(struct regulator_dev *rdev) +{ + struct max8973_chip *max = rdev_get_drvdata(rdev); + unsigned int data; + int ret; + + ret = regmap_read(max->regmap, MAX8973_CONTROL1, &data); + if (ret < 0) { + dev_err(max->dev, "%s(): register %d read failed with err %d\n", + __func__, MAX8973_CONTROL1, ret); + return ret; + } + return (data & MAX8973_FPWM_EN_M) ? + REGULATOR_MODE_FAST : REGULATOR_MODE_NORMAL; +} + +static struct regulator_ops max8973_dcdc_ops = { + .get_voltage_sel = max8973_dcdc_get_voltage_sel, + .set_voltage = max8973_dcdc_set_voltage, + .list_voltage = max8973_dcdc_list_voltage, + .set_voltage_time_sel = max8973_dcdc_set_voltage_time_sel, + .enable = max8973_dcdc_enable, + .disable = max8973_dcdc_disable, + .is_enabled = max8973_dcdc_is_enabled, + .set_mode = max8973_dcdc_set_mode, + .get_mode = max8973_dcdc_get_mode, +}; + +static int __devinit max8973_init_dcdc(struct max8973_chip *max, + struct max8973_regulator_platform_data *pdata) +{ + int ret; + uint8_t control1 = 0; + uint8_t control2 = 0; + + if (pdata->control_flags & MAX8973_CONTROL_REMOTE_SENSE_ENABLE) + control1 |= MAX8973_SNS_ENABLE; + + if (!(pdata->control_flags & MAX8973_CONTROL_FALLING_SLEW_RATE_ENABLE)) + control1 |= MAX8973_NFSR_ENABLE; + + if (pdata->control_flags & MAX8973_CONTROL_OUTPUT_ACTIVE_DISCH_ENABLE) + control1 |= MAX8973_AD_ENABLE; + + if (pdata->control_flags & MAX8973_CONTROL_BIAS_ENABLE) + control1 |= MAX8973_BIAS_ENABLE; + + if (pdata->control_flags & MAX8973_CONTROL_FREQ_SHIFT_9PER_ENABLE) + control1 |= MAX8973_FREQSHIFT_9PER; + + switch (pdata->control_flags & MAX8973_CONTROL_SLEW_RATE_200MV_PER_US) { + case MAX8973_CONTROL_SLEW_RATE_12_5mV_PER_US: + control1 = MAX8973_RAMP_12mV_PER_US; + max->change_uv_per_us = 12500; + break; + + case MAX8973_CONTROL_SLEW_RATE_25mV_PER_US: + control1 = MAX8973_RAMP_25mV_PER_US; + max->change_uv_per_us = 25000; + break; + + case MAX8973_CONTROL_SLEW_RATE_50mV_PER_US: + control1 = MAX8973_RAMP_50mV_PER_US; + max->change_uv_per_us = 50000; + break; + + case MAX8973_CONTROL_SLEW_RATE_200MV_PER_US: + control1 = MAX8973_RAMP_200mV_PER_US; + max->change_uv_per_us = 200000; + break; + } + + if (!(pdata->control_flags & MAX8973_CONTROL_PULL_DOWN_ENABLE)) + control2 |= MAX8973_DISCH_ENBABLE; + + switch (pdata->control_flags & + MAX8973_CONTROL_CLKADV_TRIP_75mV_PER_US) { + case MAX8973_CONTROL_CLKADV_TRIP_DISABLED: + control2 |= MAX8973_CKKADV_TRIP_DISABLE; + break; + + case MAX8973_CONTROL_CLKADV_TRIP_75mV_PER_US: + control2 |= MAX8973_CKKADV_TRIP_75mV_PER_US; + break; + + case MAX8973_CONTROL_CLKADV_TRIP_150mV_PER_US: + control2 |= MAX8973_CKKADV_TRIP_150mV_PER_US; + break; + + case MAX8973_CONTROL_CLKADV_TRIP_75mV_PER_US_HIST_DIS: + control2 |= MAX8973_CKKADV_TRIP_75mV_PER_US_HIST_DIS; + break; + } + + switch (pdata->control_flags & + MAX8973_CONTROL_INDUCTOR_VALUE_PLUS_60_PER) { + case MAX8973_CONTROL_INDUCTOR_VALUE_NOMINAL: + control2 |= MAX8973_INDUCTOR_NOMINAL; + break; + + case MAX8973_CONTROL_INDUCTOR_VALUE_MINUS_30_PER: + control2 |= MAX8973_INDUCTOR_MIN_30_PER; + break; + + case MAX8973_CONTROL_INDUCTOR_VALUE_PLUS_30_PER: + control2 |= MAX8973_INDUCTOR_PLUS_30_PER; + break; + + case MAX8973_CONTROL_INDUCTOR_VALUE_PLUS_60_PER: + control2 |= MAX8973_INDUCTOR_PLUS_60_PER; + break; + } + + ret = regmap_write(max->regmap, MAX8973_CONTROL1, control1); + if (ret < 0) { + dev_err(max->dev, "%s(): register %d write failed with err %d", + __func__, MAX8973_CONTROL1, ret); + return ret; + } + + ret = regmap_write(max->regmap, MAX8973_CONTROL2, control2); + if (ret < 0) { + dev_err(max->dev, "%s(): register %d write failed with err %d", + __func__, MAX8973_CONTROL2, ret); + return ret; + } + + /* If external control is enabled then disable EN bit */ + if (max->enable_external_control) { + ret = regmap_update_bits(max->regmap, MAX8973_VOUT, + MAX8973_VOUT_ENABLE, 0); + if (ret < 0) + dev_err(max->dev, "%s(): register %d update failed with err %d", + __func__, MAX8973_VOUT, ret); + } + return ret; +} + +static const struct regmap_config max8973_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = MAX8973_CHIPID2, + .cache_type = REGCACHE_RBTREE, +}; + +static int __devinit max8973_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct max8973_regulator_platform_data *pdata; + struct regulator_dev *rdev; + struct max8973_chip *max; + int ret; + + pdata = client->dev.platform_data; + if (!pdata) { + dev_err(&client->dev, "%s(): No Platform data", __func__); + return -EIO; + } + + max = devm_kzalloc(&client->dev, sizeof(*max), GFP_KERNEL); + if (!max) { + dev_err(&client->dev, "%s(): Memory allocation failed\n", + __func__); + return -ENOMEM; + } + + max->dev = &client->dev; + + max->desc.name = id->name; + max->desc.id = 0; + max->desc.ops = &max8973_dcdc_ops; + max->desc.type = REGULATOR_VOLTAGE; + max->desc.owner = THIS_MODULE; + max->regmap = devm_regmap_init_i2c(client, &max8973_regmap_config); + if (IS_ERR(max->regmap)) { + ret = PTR_ERR(max->regmap); + dev_err(&client->dev, + "%s(): regmap allocation failed with err %d\n", + __func__, ret); + return ret; + } + i2c_set_clientdata(client, max); + + max->enable_external_control = pdata->enable_ext_control; + max->dvs_gpio = pdata->dvs_gpio; + max->curr_gpio_val = pdata->dvs_def_state; + max->curr_vout_reg = MAX8973_VOUT + pdata->dvs_def_state; + max->lru_index[0] = max->curr_vout_reg; + max->valid_dvs_gpio = false; + + if (gpio_is_valid(max->dvs_gpio)) { + int gpio_flags; + int i; + + gpio_flags = (pdata->dvs_def_state) ? + GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; + ret = gpio_request_one(max->dvs_gpio, + gpio_flags, "max8973-dvs"); + if (ret) { + dev_err(&client->dev, + "%s(): Could not obtain dvs GPIO %d: %d\n", + __func__, max->dvs_gpio, ret); + return ret; + } + max->valid_dvs_gpio = true; + + /* + * Initialize the lru index with vout_reg id + * The index 0 will be most recently used and + * set with the max->curr_vout_reg */ + for (i = 0; i < MAX8973_MAX_VOUT_REG; ++i) + max->lru_index[i] = i; + max->lru_index[0] = max->curr_vout_reg; + max->lru_index[max->curr_vout_reg] = 0; + } + + ret = max8973_init_dcdc(max, pdata); + if (ret < 0) { + dev_err(max->dev, "%s(): Init failed with err = %d\n", + __func__, ret); + goto err_init; + } + + /* Register the regulators */ + rdev = regulator_register(&max->desc, &client->dev, + pdata->reg_init_data, max); + if (IS_ERR(rdev)) { + dev_err(max->dev, + "%s(): regulator register failed with err %s\n", + __func__, id->name); + ret = PTR_ERR(rdev); + goto err_init; + } + + max->rdev = rdev; + return 0; + +err_init: + if (gpio_is_valid(max->dvs_gpio)) + gpio_free(max->dvs_gpio); + return ret; +} + +/** + * max8973_remove - max8973 driver i2c remove handler + * @client: i2c driver client device structure + * + * Unregister TPS driver as an i2c client device driver + */ +static int __devexit max8973_remove(struct i2c_client *client) +{ + struct max8973_chip *max = i2c_get_clientdata(client); + + if (gpio_is_valid(max->dvs_gpio)) + gpio_free(max->dvs_gpio); + + regulator_unregister(max->rdev); + return 0; +} + +static const struct i2c_device_id max8973_id[] = { + {.name = "max8973",}, + {}, +}; + +MODULE_DEVICE_TABLE(i2c, max8973_id); + +static struct i2c_driver max8973_i2c_driver = { + .driver = { + .name = "max8973", + .owner = THIS_MODULE, + }, + .probe = max8973_probe, + .remove = __devexit_p(max8973_remove), + .id_table = max8973_id, +}; + +static int __init max8973_init(void) +{ + return i2c_add_driver(&max8973_i2c_driver); +} +subsys_initcall(max8973_init); + +static void __exit max8973_cleanup(void) +{ + i2c_del_driver(&max8973_i2c_driver); +} +module_exit(max8973_cleanup); + +MODULE_AUTHOR("Laxman Dewangan "); +MODULE_DESCRIPTION("MAX8973 voltage regulator driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From b0580d28e1d44cf1a501279a08290da803c9f978 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Thu, 17 May 2012 01:49:32 +0530 Subject: regulator: tps6238x0: enable output discharge always Enable output discharge always to have faster ramp-down time. bug 981330 Change-Id: I0a00ab38e9be631a58bc8b11148be5c3c508d119 Signed-off-by: Laxman Dewangan Reviewed-on: http://git-master/r/102882 Reviewed-by: Automatic_Commit_Validation_User Tested-by: Pradeep Goudagunta GVS: Gerrit_Virtual_Submit Reviewed-by: Bitan Biswas --- drivers/regulator/tps6238x0-regulator.c | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/tps6238x0-regulator.c b/drivers/regulator/tps6238x0-regulator.c index 880249627ab6..611b9425a263 100644 --- a/drivers/regulator/tps6238x0-regulator.c +++ b/drivers/regulator/tps6238x0-regulator.c @@ -62,7 +62,6 @@ struct tps6238x0_chip { int vsel_gpio; int change_uv_per_us; bool en_internal_pulldn; - bool en_discharge; bool valid_gpios; int lru_index[TPS6238X0_MAX_VSET]; int curr_vset_vsel[TPS6238X0_MAX_VSET]; @@ -304,8 +303,8 @@ static int __devinit tps6238x0_configure(struct tps6238x0_chip *tps, } } - /* Reset output discharge path to reduce power consumption */ - ret = regmap_update_bits(tps->regmap, REG_RAMPCTRL, BIT(2), 0); + /* Enable output discharge path to have faster discharge */ + ret = regmap_update_bits(tps->regmap, REG_RAMPCTRL, BIT(2), BIT(2)); if (ret < 0) dev_err(tps->dev, "%s() fails in updating reg %d\n", __func__, REG_RAMPCTRL); @@ -344,7 +343,6 @@ static int __devinit tps6238x0_probe(struct i2c_client *client, return -ENOMEM; } - tps->en_discharge = pdata->en_discharge; tps->en_internal_pulldn = pdata->en_internal_pulldn; tps->vsel_gpio = pdata->vsel_gpio; tps->dev = &client->dev; @@ -436,21 +434,6 @@ static int __devexit tps6238x0_remove(struct i2c_client *client) return 0; } -static void tps6238x0_shutdown(struct i2c_client *client) -{ - struct tps6238x0_chip *tps = i2c_get_clientdata(client); - int st; - - if (!tps->en_discharge) - return; - - /* Configure the output discharge path */ - st = regmap_update_bits(tps->regmap, REG_RAMPCTRL, BIT(2), BIT(2)); - if (st < 0) - dev_err(tps->dev, "%s() fails in updating reg %d\n", - __func__, REG_RAMPCTRL); -} - static const struct i2c_device_id tps6238x0_id[] = { {.name = "tps623850", }, {.name = "tps623860", }, @@ -467,7 +450,6 @@ static struct i2c_driver tps6238x0_i2c_driver = { }, .probe = tps6238x0_probe, .remove = __devexit_p(tps6238x0_remove), - .shutdown = tps6238x0_shutdown, .id_table = tps6238x0_id, }; -- cgit v1.2.3 From 461ef9b774c6f079373898a3eed045f183662a8f Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 7 Feb 2012 11:06:20 +0800 Subject: regulator: tps62360: Remove pointless test for unsigned less than zero The variable 'selector' is a 'unsigned int', so it can never be less than zero. Signed-off-by: Axel Lin Acked-by: Laxman Dewangan Signed-off-by: Mark Brown (cherry picked from commit 46783a046e13588f0459271ad6db9785fa8dcb8b) Change-Id: I920b1628016b7d1c0b626497f24210c5c1f549ab Signed-off-by: Laxman Dewangan Reviewed-on: http://git-master/r/105825 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Bitan Biswas GVS: Gerrit_Virtual_Submit --- drivers/regulator/tps62360-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/tps62360-regulator.c b/drivers/regulator/tps62360-regulator.c index 7eaf08275376..2be1dcf00b47 100644 --- a/drivers/regulator/tps62360-regulator.c +++ b/drivers/regulator/tps62360-regulator.c @@ -191,7 +191,7 @@ static int tps62360_dcdc_list_voltage(struct regulator_dev *dev, { struct tps62360_chip *tps = rdev_get_drvdata(dev); - if ((selector < 0) || (selector >= tps->desc.n_voltages)) + if (selector >= tps->desc.n_voltages) return -EINVAL; return (tps->voltage_base + selector * 10) * 1000; } -- cgit v1.2.3 From e4f3c28e6293e1d68a44ca6ad17357b7a9e1d2be Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 28 Mar 2012 10:06:45 +0800 Subject: regulator: Remove unused name and client fields from struct tps62360_chip The client field of struct tps62360_chip is not used after converting to regmap. The name field of struct tps62360_chip is not used in this driver. Signed-off-by: Axel Lin Signed-off-by: Mark Brown (cherry picked from mainline commit c60f1718f508a40964c149f1139b4eaaae825fd3) Change-Id: If7b0606b60bd887bc20ecbdaf5cafa6ccba8ff77 Signed-off-by: Laxman Dewangan Reviewed-on: http://git-master/r/105826 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Bitan Biswas GVS: Gerrit_Virtual_Submit --- drivers/regulator/tps62360-regulator.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/tps62360-regulator.c b/drivers/regulator/tps62360-regulator.c index 2be1dcf00b47..a20a8295f180 100644 --- a/drivers/regulator/tps62360-regulator.c +++ b/drivers/regulator/tps62360-regulator.c @@ -56,10 +56,8 @@ enum chips {TPS62360, TPS62361}; /* tps 62360 chip information */ struct tps62360_chip { - const char *name; struct device *dev; struct regulator_desc desc; - struct i2c_client *client; struct regulator_dev *rdev; struct regmap *regmap; int chip_id; @@ -297,9 +295,7 @@ static int __devinit tps62360_probe(struct i2c_client *client, tps->en_internal_pulldn = pdata->en_internal_pulldn; tps->vsel0_gpio = pdata->vsel0_gpio; tps->vsel1_gpio = pdata->vsel1_gpio; - tps->client = client; tps->dev = &client->dev; - tps->name = id->name; tps->voltage_base = (id->driver_data == TPS62360) ? TPS62360_BASE_VOLTAGE : TPS62361_BASE_VOLTAGE; tps->voltage_reg_mask = (id->driver_data == TPS62360) ? 0x3F : 0x7F; -- cgit v1.2.3 From 502ba325120a4f4beee4c9dfd64455ee5d1953cd Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 2 Apr 2012 18:19:28 +0800 Subject: regulator: Add support for tps62362 and tps62363 in tps62360-regulator driver According to the datasheet[1], tps62360 is register compatible with tps62362. tps62361B is register compatible with tps62363. Thus this patch adds support for tps62362 and tps62363. [1] http://www.ti.com/litv/pdf/slvsau9b Change-Id: I62cdede0755d7decedeb7b1ef08e216a0dad3a12 Signed-off-by: Axel Lin Acked-by: Laxman Dewangan Signed-off-by: Mark Brown (Cherry-picked from mainline commit d1cf4f6) Signed-off-by: Laxman Dewangan Change-Id: Ib9c4a63f06182c0ed2c1f27d9bf63342aa8474bc Reviewed-on: http://git-master/r/105827 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Bitan Biswas GVS: Gerrit_Virtual_Submit --- drivers/regulator/tps62360-regulator.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/tps62360-regulator.c b/drivers/regulator/tps62360-regulator.c index a20a8295f180..e8c883cd3479 100644 --- a/drivers/regulator/tps62360-regulator.c +++ b/drivers/regulator/tps62360-regulator.c @@ -1,7 +1,7 @@ /* * tps62360.c -- TI tps62360 * - * Driver for processor core supply tps62360 and tps62361B + * Driver for processor core supply tps62360, tps62361B, tps62362 and tps62363. * * Copyright (c) 2012, NVIDIA Corporation. * @@ -46,7 +46,7 @@ #define REG_RAMPCTRL 6 #define REG_CHIPID 8 -enum chips {TPS62360, TPS62361}; +enum chips {TPS62360, TPS62361, TPS62362, TPS62363}; #define TPS62360_BASE_VOLTAGE 770 #define TPS62360_N_VOLTAGES 64 @@ -296,14 +296,26 @@ static int __devinit tps62360_probe(struct i2c_client *client, tps->vsel0_gpio = pdata->vsel0_gpio; tps->vsel1_gpio = pdata->vsel1_gpio; tps->dev = &client->dev; - tps->voltage_base = (id->driver_data == TPS62360) ? - TPS62360_BASE_VOLTAGE : TPS62361_BASE_VOLTAGE; - tps->voltage_reg_mask = (id->driver_data == TPS62360) ? 0x3F : 0x7F; + + switch (id->driver_data) { + case TPS62360: + case TPS62362: + tps->voltage_base = TPS62360_BASE_VOLTAGE; + tps->voltage_reg_mask = 0x3F; + tps->desc.n_voltages = TPS62360_N_VOLTAGES; + break; + case TPS62361: + case TPS62363: + tps->voltage_base = TPS62361_BASE_VOLTAGE; + tps->voltage_reg_mask = 0x7F; + tps->desc.n_voltages = TPS62361_N_VOLTAGES; + break; + default: + return -ENODEV; + } tps->desc.name = id->name; tps->desc.id = 0; - tps->desc.n_voltages = (id->driver_data == TPS62360) ? - TPS62360_N_VOLTAGES : TPS62361_N_VOLTAGES; tps->desc.ops = &tps62360_dcdc_ops; tps->desc.type = REGULATOR_VOLTAGE; tps->desc.owner = THIS_MODULE; @@ -435,6 +447,8 @@ static void tps62360_shutdown(struct i2c_client *client) static const struct i2c_device_id tps62360_id[] = { {.name = "tps62360", .driver_data = TPS62360}, {.name = "tps62361", .driver_data = TPS62361}, + {.name = "tps62362", .driver_data = TPS62362}, + {.name = "tps62363", .driver_data = TPS62363}, {}, }; @@ -464,5 +478,5 @@ static void __exit tps62360_cleanup(void) module_exit(tps62360_cleanup); MODULE_AUTHOR("Laxman Dewangan "); -MODULE_DESCRIPTION("TPS62360 voltage regulator driver"); +MODULE_DESCRIPTION("TPS6236x voltage regulator driver"); MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From cf5de026b9578ba54733fbf66666aaa5c00129c6 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 7 Apr 2012 23:29:56 +0800 Subject: regulator: tps62360: Convert to devm_regmap_init_i2c() Signed-off-by: Axel Lin Signed-off-by: Mark Brown (cherry picked from commit 9a4bdd87a29bf297d9046410b011d726d51c3999) Change-Id: Ic7cca64e14b2b2e812140c8d368279b615da074f Signed-off-by: Laxman Dewangan Reviewed-on: http://git-master/r/105828 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Bitan Biswas GVS: Gerrit_Virtual_Submit --- drivers/regulator/tps62360-regulator.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/tps62360-regulator.c b/drivers/regulator/tps62360-regulator.c index e8c883cd3479..73f3117d593b 100644 --- a/drivers/regulator/tps62360-regulator.c +++ b/drivers/regulator/tps62360-regulator.c @@ -319,7 +319,7 @@ static int __devinit tps62360_probe(struct i2c_client *client, tps->desc.ops = &tps62360_dcdc_ops; tps->desc.type = REGULATOR_VOLTAGE; tps->desc.owner = THIS_MODULE; - tps->regmap = regmap_init_i2c(client, &tps62360_regmap_config); + tps->regmap = devm_regmap_init_i2c(client, &tps62360_regmap_config); if (IS_ERR(tps->regmap)) { ret = PTR_ERR(tps->regmap); dev_err(&client->dev, "%s() Err: Failed to allocate register" @@ -404,7 +404,6 @@ err_gpio1: if (gpio_is_valid(tps->vsel0_gpio)) gpio_free(tps->vsel0_gpio); err_gpio0: - regmap_exit(tps->regmap); return ret; } @@ -425,7 +424,6 @@ static int __devexit tps62360_remove(struct i2c_client *client) gpio_free(tps->vsel0_gpio); regulator_unregister(tps->rdev); - regmap_exit(tps->regmap); return 0; } -- cgit v1.2.3 From c6ea134b2623476857bd751c37729873804fb07d Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Mon, 7 May 2012 18:08:25 +0530 Subject: regulator: tps62360: enable register cache Enable cache of device register using regmap cache RBTREE. Signed-off-by: Laxman Dewangan Signed-off-by: Mark Brown (cherry picked from commit 16ea003bd1c95ea55a0b88187ce7cbeaca760fcf) Change-Id: If747dd18a488d500f8295f903c8da92c241c293e Signed-off-by: Laxman Dewangan Reviewed-on: http://git-master/r/105829 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Bitan Biswas GVS: Gerrit_Virtual_Submit --- drivers/regulator/tps62360-regulator.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/tps62360-regulator.c b/drivers/regulator/tps62360-regulator.c index 73f3117d593b..68941ec64445 100644 --- a/drivers/regulator/tps62360-regulator.c +++ b/drivers/regulator/tps62360-regulator.c @@ -263,8 +263,10 @@ static int tps62360_init_dcdc(struct tps62360_chip *tps, } static const struct regmap_config tps62360_regmap_config = { - .reg_bits = 8, - .val_bits = 8, + .reg_bits = 8, + .val_bits = 8, + .max_register = REG_CHIPID, + .cache_type = REGCACHE_RBTREE, }; static int __devinit tps62360_probe(struct i2c_client *client, -- cgit v1.2.3 From 8b0d9edf90c45567b582b1fcd1fa43c11ce39c1e Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Mon, 7 May 2012 18:08:26 +0530 Subject: regulator: tps62360: Provide settling time for voltage change Settling time is require when there is voltage output change. Implement set_voltage_time_sel() callback which returns delay time for voltage change to settle down to new value. Signed-off-by: Laxman Dewangan Signed-off-by: Mark Brown (cherry picked from commit a60cfce051dd5e22329df1018d278bf3e52d82bc) Change-Id: I522df8a72595622fd99cc46043c34610434d932f Signed-off-by: Laxman Dewangan Reviewed-on: http://git-master/r/105830 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Bitan Biswas GVS: Gerrit_Virtual_Submit --- drivers/regulator/tps62360-regulator.c | 46 +++++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 6 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/tps62360-regulator.c b/drivers/regulator/tps62360-regulator.c index 68941ec64445..117c654388a1 100644 --- a/drivers/regulator/tps62360-regulator.c +++ b/drivers/regulator/tps62360-regulator.c @@ -72,6 +72,7 @@ struct tps62360_chip { int lru_index[4]; int curr_vset_vsel[4]; int curr_vset_id; + int change_uv_per_us; }; /* @@ -115,7 +116,7 @@ update_lru_index: return found; } -static int tps62360_dcdc_get_voltage(struct regulator_dev *dev) +static int tps62360_dcdc_get_voltage_sel(struct regulator_dev *dev) { struct tps62360_chip *tps = rdev_get_drvdata(dev); int vsel; @@ -129,7 +130,7 @@ static int tps62360_dcdc_get_voltage(struct regulator_dev *dev) return ret; } vsel = (int)data & tps->voltage_reg_mask; - return (tps->voltage_base + vsel * 10) * 1000; + return vsel; } static int tps62360_dcdc_set_voltage(struct regulator_dev *dev, @@ -194,10 +195,28 @@ static int tps62360_dcdc_list_voltage(struct regulator_dev *dev, return (tps->voltage_base + selector * 10) * 1000; } +static int tps62360_set_voltage_time_sel(struct regulator_dev *rdev, + unsigned int old_selector, unsigned int new_selector) +{ + struct tps62360_chip *tps = rdev_get_drvdata(rdev); + int old_uV, new_uV; + + old_uV = tps62360_dcdc_list_voltage(rdev, old_selector); + if (old_uV < 0) + return old_uV; + + new_uV = tps62360_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 tps62360_dcdc_ops = { - .get_voltage = tps62360_dcdc_get_voltage, - .set_voltage = tps62360_dcdc_set_voltage, - .list_voltage = tps62360_dcdc_list_voltage, + .get_voltage_sel = tps62360_dcdc_get_voltage_sel, + .set_voltage = tps62360_dcdc_set_voltage, + .list_voltage = tps62360_dcdc_list_voltage, + .set_voltage_time_sel = tps62360_set_voltage_time_sel, }; static int tps62360_init_force_pwm(struct tps62360_chip *tps, @@ -229,6 +248,7 @@ static int tps62360_init_dcdc(struct tps62360_chip *tps, { int ret; int i; + unsigned int ramp_ctrl; /* Initailize internal pull up/down control */ if (tps->en_internal_pulldn) @@ -256,9 +276,23 @@ static int tps62360_init_dcdc(struct tps62360_chip *tps, /* Reset output discharge path to reduce power consumption */ ret = regmap_update_bits(tps->regmap, REG_RAMPCTRL, BIT(2), 0); - if (ret < 0) + if (ret < 0) { dev_err(tps->dev, "%s() fails in updating reg %d\n", __func__, REG_RAMPCTRL); + return ret; + } + + /* Get ramp value from ramp control register */ + ret = regmap_read(tps->regmap, REG_RAMPCTRL, &ramp_ctrl); + if (ret < 0) { + dev_err(tps->dev, "%s() fails in reading reg %d\n", + __func__, REG_RAMPCTRL); + return ret; + } + ramp_ctrl = (ramp_ctrl >> 4) & 0x7; + + /* ramp mV/us = 32/(2^ramp_ctrl) */ + tps->change_uv_per_us = DIV_ROUND_UP(32000, BIT(ramp_ctrl)); return ret; } -- cgit v1.2.3 From 15f2303eb2562379e772651494dd55743a5356e0 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Tue, 8 May 2012 17:05:58 +0530 Subject: regulator: tps62360: fix stylistic issue and optimize code Fix multiple stylistic issue like: - The print message should be not break into multiple line. - line gap after variable declaration and statement. - checkpatch error. - some typo. Some enhancement on error message printing to print error value also along with proper text. Avoid voltage_base conversion to microvolts every time. Put init functions in init section. Using efficient function inplace of calling multiple function to reduce the code size. Signed-off-by: Laxman Dewangan Signed-off-by: Mark Brown (cherry picked from commit 2935fb18aa1e75e6afaab3303cdd1a4ac62be63e) Change-Id: I988938f8f8cc6fb5355e32bd6ac25d95db94913c Signed-off-by: Laxman Dewangan Reviewed-on: http://git-master/r/105831 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Bitan Biswas GVS: Gerrit_Virtual_Submit --- drivers/regulator/tps62360-regulator.c | 131 +++++++++++++++------------------ 1 file changed, 60 insertions(+), 71 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/tps62360-regulator.c b/drivers/regulator/tps62360-regulator.c index 117c654388a1..bc58365fa151 100644 --- a/drivers/regulator/tps62360-regulator.c +++ b/drivers/regulator/tps62360-regulator.c @@ -48,10 +48,10 @@ enum chips {TPS62360, TPS62361, TPS62362, TPS62363}; -#define TPS62360_BASE_VOLTAGE 770 +#define TPS62360_BASE_VOLTAGE 770000 #define TPS62360_N_VOLTAGES 64 -#define TPS62361_BASE_VOLTAGE 500 +#define TPS62361_BASE_VOLTAGE 500000 #define TPS62361_N_VOLTAGES 128 /* tps 62360 chip information */ @@ -98,6 +98,7 @@ static bool find_voltage_set_register(struct tps62360_chip *tps, bool found = false; int new_vset_reg = tps->lru_index[3]; int found_index = 3; + for (i = 0; i < 4; ++i) { if (tps->curr_vset_vsel[tps->lru_index[i]] == req_vsel) { new_vset_reg = tps->lru_index[i]; @@ -125,8 +126,8 @@ static int tps62360_dcdc_get_voltage_sel(struct regulator_dev *dev) ret = regmap_read(tps->regmap, REG_VSET0 + tps->curr_vset_id, &data); if (ret < 0) { - dev_err(tps->dev, "%s: Error in reading register %d\n", - __func__, REG_VSET0 + tps->curr_vset_id); + dev_err(tps->dev, "%s(): register %d read failed with err %d\n", + __func__, REG_VSET0 + tps->curr_vset_id, ret); return ret; } vsel = (int)data & tps->voltage_reg_mask; @@ -142,17 +143,13 @@ static int tps62360_dcdc_set_voltage(struct regulator_dev *dev, bool found = false; int new_vset_id = tps->curr_vset_id; - if (max_uV < min_uV) - return -EINVAL; - - if (min_uV > - ((tps->voltage_base + (tps->desc.n_voltages - 1) * 10) * 1000)) + if ((max_uV < min_uV) || (max_uV < tps->voltage_base)) return -EINVAL; - if (max_uV < tps->voltage_base * 1000) + if (min_uV > (tps->voltage_base + (tps->desc.n_voltages - 1) * 10000)) return -EINVAL; - vsel = DIV_ROUND_UP(min_uV - (tps->voltage_base * 1000), 10000); + vsel = DIV_ROUND_UP(min_uV - tps->voltage_base, 10000); if (selector) *selector = (vsel & tps->voltage_reg_mask); @@ -167,8 +164,9 @@ static int tps62360_dcdc_set_voltage(struct regulator_dev *dev, ret = regmap_update_bits(tps->regmap, REG_VSET0 + new_vset_id, tps->voltage_reg_mask, vsel); if (ret < 0) { - dev_err(tps->dev, "%s: Error in updating register %d\n", - __func__, REG_VSET0 + new_vset_id); + dev_err(tps->dev, + "%s(): register %d update failed with err %d\n", + __func__, REG_VSET0 + new_vset_id, ret); return ret; } tps->curr_vset_id = new_vset_id; @@ -177,8 +175,7 @@ static int tps62360_dcdc_set_voltage(struct regulator_dev *dev, /* Select proper VSET register vio gpios */ if (tps->valid_gpios) { - gpio_set_value_cansleep(tps->vsel0_gpio, - new_vset_id & 0x1); + gpio_set_value_cansleep(tps->vsel0_gpio, new_vset_id & 0x1); gpio_set_value_cansleep(tps->vsel1_gpio, (new_vset_id >> 1) & 0x1); } @@ -192,7 +189,8 @@ static int tps62360_dcdc_list_voltage(struct regulator_dev *dev, if (selector >= tps->desc.n_voltages) return -EINVAL; - return (tps->voltage_base + selector * 10) * 1000; + + return tps->voltage_base + selector * 10000; } static int tps62360_set_voltage_time_sel(struct regulator_dev *rdev, @@ -219,49 +217,44 @@ static struct regulator_ops tps62360_dcdc_ops = { .set_voltage_time_sel = tps62360_set_voltage_time_sel, }; -static int tps62360_init_force_pwm(struct tps62360_chip *tps, +static int __devinit tps62360_init_force_pwm(struct tps62360_chip *tps, struct tps62360_regulator_platform_data *pdata, int vset_id) { - unsigned int data; int ret; - ret = regmap_read(tps->regmap, REG_VSET0 + vset_id, &data); - if (ret < 0) { - dev_err(tps->dev, "%s() fails in writing reg %d\n", - __func__, REG_VSET0 + vset_id); - return ret; - } - tps->curr_vset_vsel[vset_id] = data & tps->voltage_reg_mask; + int bit = 0; + if (pdata->en_force_pwm) - data |= BIT(7); - else - data &= ~BIT(7); - ret = regmap_write(tps->regmap, REG_VSET0 + vset_id, data); + bit = BIT(7); + + ret = regmap_update_bits(tps->regmap, REG_VSET0 + vset_id, BIT(7), bit); if (ret < 0) - dev_err(tps->dev, "%s() fails in writing reg %d\n", - __func__, REG_VSET0 + vset_id); + dev_err(tps->dev, + "%s(): register %d update failed with err %d\n", + __func__, REG_VSET0 + vset_id, ret); return ret; } -static int tps62360_init_dcdc(struct tps62360_chip *tps, +static int __devinit tps62360_init_dcdc(struct tps62360_chip *tps, struct tps62360_regulator_platform_data *pdata) { int ret; int i; unsigned int ramp_ctrl; - /* Initailize internal pull up/down control */ + /* Initialize internal pull up/down control */ if (tps->en_internal_pulldn) ret = regmap_write(tps->regmap, REG_CONTROL, 0xE0); else ret = regmap_write(tps->regmap, REG_CONTROL, 0x0); if (ret < 0) { - dev_err(tps->dev, "%s() fails in writing reg %d\n", - __func__, REG_CONTROL); + dev_err(tps->dev, + "%s(): register %d write failed with err %d\n", + __func__, REG_CONTROL, ret); return ret; } - /* Initailize force PWM mode */ + /* Initialize force PWM mode */ if (tps->valid_gpios) { for (i = 0; i < 4; ++i) { ret = tps62360_init_force_pwm(tps, pdata, i); @@ -277,16 +270,18 @@ static int tps62360_init_dcdc(struct tps62360_chip *tps, /* Reset output discharge path to reduce power consumption */ ret = regmap_update_bits(tps->regmap, REG_RAMPCTRL, BIT(2), 0); if (ret < 0) { - dev_err(tps->dev, "%s() fails in updating reg %d\n", - __func__, REG_RAMPCTRL); + dev_err(tps->dev, + "%s(): register %d update failed with err %d\n", + __func__, REG_RAMPCTRL, ret); return ret; } /* Get ramp value from ramp control register */ ret = regmap_read(tps->regmap, REG_RAMPCTRL, &ramp_ctrl); if (ret < 0) { - dev_err(tps->dev, "%s() fails in reading reg %d\n", - __func__, REG_RAMPCTRL); + dev_err(tps->dev, + "%s(): register %d read failed with err %d\n", + __func__, REG_RAMPCTRL, ret); return ret; } ramp_ctrl = (ramp_ctrl >> 4) & 0x7; @@ -314,14 +309,14 @@ static int __devinit tps62360_probe(struct i2c_client *client, pdata = client->dev.platform_data; if (!pdata) { - dev_err(&client->dev, "%s() Err: Platform data not found\n", + dev_err(&client->dev, "%s(): Platform data not found\n", __func__); return -EIO; } tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL); if (!tps) { - dev_err(&client->dev, "%s() Err: Memory allocation fails\n", + dev_err(&client->dev, "%s(): Memory allocation failed\n", __func__); return -ENOMEM; } @@ -358,8 +353,9 @@ static int __devinit tps62360_probe(struct i2c_client *client, tps->regmap = devm_regmap_init_i2c(client, &tps62360_regmap_config); if (IS_ERR(tps->regmap)) { ret = PTR_ERR(tps->regmap); - dev_err(&client->dev, "%s() Err: Failed to allocate register" - "map: %d\n", __func__, ret); + dev_err(&client->dev, + "%s(): regmap allocation failed with err %d\n", + __func__, ret); return ret; } i2c_set_clientdata(client, tps); @@ -370,35 +366,26 @@ static int __devinit tps62360_probe(struct i2c_client *client, tps->valid_gpios = false; if (gpio_is_valid(tps->vsel0_gpio) && gpio_is_valid(tps->vsel1_gpio)) { - ret = gpio_request(tps->vsel0_gpio, "tps62360-vsel0"); + int gpio_flags; + gpio_flags = (pdata->vsel0_def_state) ? + GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; + ret = gpio_request_one(tps->vsel0_gpio, + gpio_flags, "tps62360-vsel0"); if (ret) { dev_err(&client->dev, - "Err: Could not obtain vsel0 GPIO %d: %d\n", - tps->vsel0_gpio, ret); - goto err_gpio0; - } - ret = gpio_direction_output(tps->vsel0_gpio, - pdata->vsel0_def_state); - if (ret) { - dev_err(&client->dev, "Err: Could not set direction of" - "vsel0 GPIO %d: %d\n", tps->vsel0_gpio, ret); - gpio_free(tps->vsel0_gpio); + "%s(): Could not obtain vsel0 GPIO %d: %d\n", + __func__, tps->vsel0_gpio, ret); goto err_gpio0; } - ret = gpio_request(tps->vsel1_gpio, "tps62360-vsel1"); + gpio_flags = (pdata->vsel1_def_state) ? + GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; + ret = gpio_request_one(tps->vsel1_gpio, + gpio_flags, "tps62360-vsel1"); if (ret) { dev_err(&client->dev, - "Err: Could not obtain vsel1 GPIO %d: %d\n", - tps->vsel1_gpio, ret); - goto err_gpio1; - } - ret = gpio_direction_output(tps->vsel1_gpio, - pdata->vsel1_def_state); - if (ret) { - dev_err(&client->dev, "Err: Could not set direction of" - "vsel1 GPIO %d: %d\n", tps->vsel1_gpio, ret); - gpio_free(tps->vsel1_gpio); + "%s(): Could not obtain vsel1 GPIO %d: %d\n", + __func__, tps->vsel1_gpio, ret); goto err_gpio1; } tps->valid_gpios = true; @@ -415,7 +402,7 @@ static int __devinit tps62360_probe(struct i2c_client *client, ret = tps62360_init_dcdc(tps, pdata); if (ret < 0) { - dev_err(tps->dev, "%s() Err: Init fails with = %d\n", + dev_err(tps->dev, "%s(): Init failed with err = %d\n", __func__, ret); goto err_init; } @@ -424,8 +411,9 @@ static int __devinit tps62360_probe(struct i2c_client *client, rdev = regulator_register(&tps->desc, &client->dev, &pdata->reg_init_data, tps); if (IS_ERR(rdev)) { - dev_err(tps->dev, "%s() Err: Failed to register %s\n", - __func__, id->name); + dev_err(tps->dev, + "%s(): regulator register failed with err %s\n", + __func__, id->name); ret = PTR_ERR(rdev); goto err_init; } @@ -474,8 +462,9 @@ static void tps62360_shutdown(struct i2c_client *client) /* Configure the output discharge path */ st = regmap_update_bits(tps->regmap, REG_RAMPCTRL, BIT(2), BIT(2)); if (st < 0) - dev_err(tps->dev, "%s() fails in updating reg %d\n", - __func__, REG_RAMPCTRL); + dev_err(tps->dev, + "%s(): register %d update failed with err %d\n", + __func__, REG_RAMPCTRL, st); } static const struct i2c_device_id tps62360_id[] = { -- cgit v1.2.3 From 63849556b9d43291c7156524333613c69c09d654 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Wed, 4 Apr 2012 12:44:00 +0530 Subject: regulator: Add support for RICOH PMIC RC5T583 regulator The RC5T583 PMIC from RICOH consists of 4 DCDC and 10 LDOs. This driver supports the control of different regulator output through regulator interface. This driver depends on MFD driver of RC5T583 and uses mfd rc5t583 apis to communicate to device for accessing different device's registers. Signed-off-by: Laxman Dewangan Signed-off-by: Mark Brown (Cherry-picked from mainline commit 6ffc3270210efa2bea526953a142ffc908f5bd86) Change-Id: If6bcc9c987fc97ff6f0c61e53de715cd84d0151b Signed-off-by: Laxman Dewangan Reviewed-on: http://git-master/r/105877 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit Reviewed-by: Bitan Biswas --- drivers/regulator/Kconfig | 10 + drivers/regulator/Makefile | 1 + drivers/regulator/rc5t583-regulator.c | 366 ++++++++++++++++++++++++++++++++++ 3 files changed, 377 insertions(+) create mode 100644 drivers/regulator/rc5t583-regulator.c (limited to 'drivers/regulator') diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 67093e3f1cd7..28c58a1c19b1 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -257,6 +257,16 @@ config REGULATOR_AB3100 AB3100 analog baseband dealing with power regulators for the system. +config REGULATOR_RC5T583 + tristate "RICOH RC5T583 Power regulators" + depends on MFD_RC5T583 + help + Select this option to enable the power regulator of RICOH + PMIC RC5T583. + This driver supports the control of different power rails of device + through regulator interface. The device supports multiple DCDC/LDO + outputs which can be controlled by i2c communication. + config REGULATOR_TPS6105X tristate "TI TPS6105X Power regulators" depends on TPS6105X diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 7642d39fb8d3..a25ff34afcbc 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -40,6 +40,7 @@ obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o 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_TPS6105X) += tps6105x-regulator.o obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o obj-$(CONFIG_REGULATOR_TPS6507X) += tps6507x-regulator.o diff --git a/drivers/regulator/rc5t583-regulator.c b/drivers/regulator/rc5t583-regulator.c new file mode 100644 index 000000000000..a665804a31bd --- /dev/null +++ b/drivers/regulator/rc5t583-regulator.c @@ -0,0 +1,366 @@ +/* + * Regulator driver for RICOH RC5T583 power management chip. + * + * Copyright (c) 2011-2012, NVIDIA CORPORATION. All rights reserved. + * Author: Laxman dewangan + * + * based on code + * Copyright (C) 2011 RICOH COMPANY,LTD + * + * + * 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, see . + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct rc5t583_regulator_info { + int deepsleep_id; + + /* Regulator register address.*/ + uint8_t reg_en_reg; + uint8_t en_bit; + uint8_t reg_disc_reg; + uint8_t disc_bit; + uint8_t vout_reg; + uint8_t vout_mask; + uint8_t deepsleep_reg; + + /* Chip constraints on regulator behavior */ + int min_uV; + int max_uV; + int step_uV; + int nsteps; + + /* Regulator specific turn-on delay and voltage settling time*/ + int enable_uv_per_us; + int change_uv_per_us; + + /* Used by regulator core */ + struct regulator_desc desc; +}; + +struct rc5t583_regulator { + struct rc5t583_regulator_info *reg_info; + + /* Devices */ + struct device *dev; + struct rc5t583 *mfd; + struct regulator_dev *rdev; +}; + +static int rc5t583_reg_is_enabled(struct regulator_dev *rdev) +{ + struct rc5t583_regulator *reg = rdev_get_drvdata(rdev); + struct rc5t583_regulator_info *ri = reg->reg_info; + uint8_t control; + int ret; + + ret = rc5t583_read(reg->mfd->dev, ri->reg_en_reg, &control); + if (ret < 0) { + dev_err(&rdev->dev, + "Error in reading the control register 0x%02x\n", + ri->reg_en_reg); + return ret; + } + return !!(control & BIT(ri->en_bit)); +} + +static int rc5t583_reg_enable(struct regulator_dev *rdev) +{ + struct rc5t583_regulator *reg = rdev_get_drvdata(rdev); + struct rc5t583_regulator_info *ri = reg->reg_info; + int ret; + + ret = rc5t583_set_bits(reg->mfd->dev, ri->reg_en_reg, + (1 << ri->en_bit)); + if (ret < 0) { + dev_err(&rdev->dev, + "Error in setting bit of STATE register 0x%02x\n", + ri->reg_en_reg); + return ret; + } + return ret; +} + +static int rc5t583_reg_disable(struct regulator_dev *rdev) +{ + struct rc5t583_regulator *reg = rdev_get_drvdata(rdev); + struct rc5t583_regulator_info *ri = reg->reg_info; + int ret; + + ret = rc5t583_clear_bits(reg->mfd->dev, ri->reg_en_reg, + (1 << ri->en_bit)); + if (ret < 0) + dev_err(&rdev->dev, + "Error in clearing bit of STATE register 0x%02x\n", + ri->reg_en_reg); + + return ret; +} + +static int rc5t583_list_voltage(struct regulator_dev *rdev, unsigned selector) +{ + struct rc5t583_regulator *reg = rdev_get_drvdata(rdev); + struct rc5t583_regulator_info *ri = reg->reg_info; + return ri->min_uV + (ri->step_uV * selector); +} + +static int rc5t583_set_voltage_sel(struct regulator_dev *rdev, + unsigned int selector) +{ + struct rc5t583_regulator *reg = rdev_get_drvdata(rdev); + struct rc5t583_regulator_info *ri = reg->reg_info; + int ret; + if (selector > ri->nsteps) { + dev_err(&rdev->dev, "Invalid selector 0x%02x\n", selector); + return -EINVAL; + } + + ret = rc5t583_update(reg->mfd->dev, ri->vout_reg, + selector, ri->vout_mask); + if (ret < 0) + dev_err(&rdev->dev, + "Error in update voltage register 0x%02x\n", ri->vout_reg); + return ret; +} + +static int rc5t583_get_voltage_sel(struct regulator_dev *rdev) +{ + struct rc5t583_regulator *reg = rdev_get_drvdata(rdev); + struct rc5t583_regulator_info *ri = reg->reg_info; + uint8_t vsel; + int ret; + ret = rc5t583_read(reg->mfd->dev, ri->vout_reg, &vsel); + if (ret < 0) { + dev_err(&rdev->dev, + "Error in reading voltage register 0x%02x\n", ri->vout_reg); + return ret; + } + return vsel & ri->vout_mask; +} + +static int rc5t583_regulator_enable_time(struct regulator_dev *rdev) +{ + struct rc5t583_regulator *reg = rdev_get_drvdata(rdev); + int vsel = rc5t583_get_voltage_sel(rdev); + int curr_uV = rc5t583_list_voltage(rdev, vsel); + return DIV_ROUND_UP(curr_uV, reg->reg_info->enable_uv_per_us); +} + +static int rc5t583_set_voltage_time_sel(struct regulator_dev *rdev, + unsigned int old_selector, unsigned int new_selector) +{ + struct rc5t583_regulator *reg = rdev_get_drvdata(rdev); + int old_uV, new_uV; + old_uV = rc5t583_list_voltage(rdev, old_selector); + + if (old_uV < 0) + return old_uV; + + new_uV = rc5t583_list_voltage(rdev, new_selector); + if (new_uV < 0) + return new_uV; + + return DIV_ROUND_UP(abs(old_uV - new_uV), + reg->reg_info->change_uv_per_us); +} + + +static struct regulator_ops rc5t583_ops = { + .is_enabled = rc5t583_reg_is_enabled, + .enable = rc5t583_reg_enable, + .disable = rc5t583_reg_disable, + .enable_time = rc5t583_regulator_enable_time, + .get_voltage_sel = rc5t583_get_voltage_sel, + .set_voltage_sel = rc5t583_set_voltage_sel, + .list_voltage = rc5t583_list_voltage, + .set_voltage_time_sel = rc5t583_set_voltage_time_sel, +}; + +#define RC5T583_REG(_id, _en_reg, _en_bit, _disc_reg, _disc_bit, _vout_reg, \ + _vout_mask, _ds_reg, _min_mv, _max_mv, _step_uV, _nsteps, \ + _enable_mv) \ +{ \ + .reg_en_reg = RC5T583_REG_##_en_reg, \ + .en_bit = _en_bit, \ + .reg_disc_reg = RC5T583_REG_##_disc_reg, \ + .disc_bit = _disc_bit, \ + .vout_reg = RC5T583_REG_##_vout_reg, \ + .vout_mask = _vout_mask, \ + .deepsleep_reg = RC5T583_REG_##_ds_reg, \ + .min_uV = _min_mv * 1000, \ + .max_uV = _max_mv * 1000, \ + .step_uV = _step_uV, \ + .nsteps = _nsteps, \ + .enable_uv_per_us = _enable_mv * 1000, \ + .change_uv_per_us = 40 * 1000, \ + .deepsleep_id = RC5T583_DS_##_id, \ + .desc = { \ + .name = "rc5t583-regulator-"#_id, \ + .id = RC5T583_REGULATOR_##_id, \ + .n_voltages = _nsteps, \ + .ops = &rc5t583_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + }, \ +} + +static struct rc5t583_regulator_info rc5t583_reg_info[RC5T583_REGULATOR_MAX] = { + RC5T583_REG(DC0, DC0CTL, 0, DC0CTL, 1, DC0DAC, 0x7F, DC0DAC_DS, + 700, 1500, 12500, 0x41, 4), + RC5T583_REG(DC1, DC1CTL, 0, DC1CTL, 1, DC1DAC, 0x7F, DC1DAC_DS, + 700, 1500, 12500, 0x41, 14), + RC5T583_REG(DC2, DC2CTL, 0, DC2CTL, 1, DC2DAC, 0x7F, DC2DAC_DS, + 900, 2400, 12500, 0x79, 14), + RC5T583_REG(DC3, DC3CTL, 0, DC3CTL, 1, DC3DAC, 0x7F, DC3DAC_DS, + 900, 2400, 12500, 0x79, 14), + RC5T583_REG(LDO0, LDOEN2, 0, LDODIS2, 0, LDO0DAC, 0x7F, LDO0DAC_DS, + 900, 3400, 25000, 0x65, 160), + RC5T583_REG(LDO1, LDOEN2, 1, LDODIS2, 1, LDO1DAC, 0x7F, LDO1DAC_DS, + 900, 3400, 25000, 0x65, 160), + RC5T583_REG(LDO2, LDOEN2, 2, LDODIS2, 2, LDO2DAC, 0x7F, LDO2DAC_DS, + 900, 3400, 25000, 0x65, 160), + RC5T583_REG(LDO3, LDOEN2, 3, LDODIS2, 3, LDO3DAC, 0x7F, LDO3DAC_DS, + 900, 3400, 25000, 0x65, 160), + RC5T583_REG(LDO4, LDOEN2, 4, LDODIS2, 4, LDO4DAC, 0x3F, LDO4DAC_DS, + 750, 1500, 12500, 0x3D, 133), + RC5T583_REG(LDO5, LDOEN2, 5, LDODIS2, 5, LDO5DAC, 0x7F, LDO5DAC_DS, + 900, 3400, 25000, 0x65, 267), + RC5T583_REG(LDO6, LDOEN2, 6, LDODIS2, 6, LDO6DAC, 0x7F, LDO6DAC_DS, + 900, 3400, 25000, 0x65, 133), + RC5T583_REG(LDO7, LDOEN2, 7, LDODIS2, 7, LDO7DAC, 0x7F, LDO7DAC_DS, + 900, 3400, 25000, 0x65, 233), + RC5T583_REG(LDO8, LDOEN1, 0, LDODIS1, 0, LDO8DAC, 0x7F, LDO8DAC_DS, + 900, 3400, 25000, 0x65, 233), + RC5T583_REG(LDO9, LDOEN1, 1, LDODIS1, 1, LDO9DAC, 0x7F, LDO9DAC_DS, + 900, 3400, 25000, 0x65, 133), +}; + +static int __devinit rc5t583_regulator_probe(struct platform_device *pdev) +{ + struct rc5t583 *rc5t583 = dev_get_drvdata(pdev->dev.parent); + struct rc5t583_platform_data *pdata = dev_get_platdata(rc5t583->dev); + struct regulator_init_data *reg_data; + struct rc5t583_regulator *reg = NULL; + struct rc5t583_regulator *regs; + struct regulator_dev *rdev; + struct rc5t583_regulator_info *ri; + int ret; + int id; + + if (!pdata) { + dev_err(&pdev->dev, "No platform data, exiting...\n"); + return -ENODEV; + } + + regs = devm_kzalloc(&pdev->dev, RC5T583_REGULATOR_MAX * + sizeof(struct rc5t583_regulator), GFP_KERNEL); + if (!regs) { + dev_err(&pdev->dev, "Memory allocation failed exiting..\n"); + return -ENOMEM; + } + + + for (id = 0; id < RC5T583_REGULATOR_MAX; ++id) { + reg_data = pdata->reg_init_data[id]; + + /* No need to register if there is no regulator data */ + if (!reg_data) + continue; + + reg = ®s[id]; + ri = &rc5t583_reg_info[id]; + reg->reg_info = ri; + reg->mfd = rc5t583; + reg->dev = &pdev->dev; + + if (ri->deepsleep_id == RC5T583_DS_NONE) + goto skip_ext_pwr_config; + + ret = rc5t583_ext_power_req_config(rc5t583->dev, + ri->deepsleep_id, + pdata->regulator_ext_pwr_control[id], + pdata->regulator_deepsleep_slot[id]); + /* + * Configuring external control is not a major issue, + * just give warning. + */ + if (ret < 0) + dev_warn(&pdev->dev, + "Failed to configure ext control %d\n", id); + +skip_ext_pwr_config: + rdev = regulator_register(&ri->desc, &pdev->dev, reg_data, reg); + if (IS_ERR_OR_NULL(rdev)) { + dev_err(&pdev->dev, "Failed to register regulator %s\n", + ri->desc.name); + ret = PTR_ERR(rdev); + goto clean_exit; + } + reg->rdev = rdev; + } + platform_set_drvdata(pdev, regs); + return 0; + +clean_exit: + while (--id > 0) + regulator_unregister(regs[id].rdev); + + return ret; +} + +static int __devexit rc5t583_regulator_remove(struct platform_device *pdev) +{ + struct rc5t583_regulator *regs = platform_get_drvdata(pdev); + int id; + + for (id = 0; id < RC5T583_REGULATOR_MAX; ++id) + regulator_unregister(regs[id].rdev); + return 0; +} + +static struct platform_driver rc5t583_regulator_driver = { + .driver = { + .name = "rc5t583-regulator", + .owner = THIS_MODULE, + }, + .probe = rc5t583_regulator_probe, + .remove = __devexit_p(rc5t583_regulator_remove), +}; + +static int __init rc5t583_regulator_init(void) +{ + return platform_driver_register(&rc5t583_regulator_driver); +} +subsys_initcall(rc5t583_regulator_init); + +static void __exit rc5t583_regulator_exit(void) +{ + platform_driver_unregister(&rc5t583_regulator_driver); +} +module_exit(rc5t583_regulator_exit); + +MODULE_AUTHOR("Laxman Dewangan "); +MODULE_DESCRIPTION("RC5T583 regulator driver"); +MODULE_ALIAS("platform:rc5t583-regulator"); +MODULE_LICENSE("GPL V2"); -- cgit v1.2.3 From 7380f01e1d2d665f8ffc7656320cb53475d84a24 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 4 Apr 2012 19:52:35 +0800 Subject: regulator: Fix rc5t583_regulator_probe error handling 1. regulator_register returns ERR_PTR on error, thus use IS_ERR to check the return value. 2. Fix off-by-one for unregistering the registered regulator. Current code does not unregister regs[0].rdev in clean_exit. Signed-off-by: Axel Lin Acked-by: Laxman Dewangan Signed-off-by: Mark Brown (cherry picked from commit a69df8a14ae7b891ee22f0e4c081f3ff65c0640f) Change-Id: Ib5e00e655020e313c73e5b838e62dbdea54c28d0 Signed-off-by: Laxman Dewangan Reviewed-on: http://git-master/r/105881 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit Reviewed-by: Bitan Biswas --- drivers/regulator/rc5t583-regulator.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/rc5t583-regulator.c b/drivers/regulator/rc5t583-regulator.c index a665804a31bd..c2c543c3a278 100644 --- a/drivers/regulator/rc5t583-regulator.c +++ b/drivers/regulator/rc5t583-regulator.c @@ -311,7 +311,7 @@ static int __devinit rc5t583_regulator_probe(struct platform_device *pdev) skip_ext_pwr_config: rdev = regulator_register(&ri->desc, &pdev->dev, reg_data, reg); - if (IS_ERR_OR_NULL(rdev)) { + if (IS_ERR(rdev)) { dev_err(&pdev->dev, "Failed to register regulator %s\n", ri->desc.name); ret = PTR_ERR(rdev); @@ -323,7 +323,7 @@ skip_ext_pwr_config: return 0; clean_exit: - while (--id > 0) + while (--id >= 0) regulator_unregister(regs[id].rdev); return ret; -- cgit v1.2.3 From 37942f91eae17ea97ce20de7c3f74aac35a1120c Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 4 Apr 2012 22:38:09 +0800 Subject: regulator: rc5t583: Fix off-by-one valid range checking for selector The valid selector should be 0 ... nsteps-1. Signed-off-by: Axel Lin Signed-off-by: Mark Brown (cherry picked from commit 9cc7a453b637d8c1f628f9873204ff55d7aa664c) Change-Id: Ie1a39883036de3b2945d35854e0a16c46d2a9db2 Signed-off-by: Laxman Dewangan Reviewed-on: http://git-master/r/105882 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit Reviewed-by: Bitan Biswas --- drivers/regulator/rc5t583-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/rc5t583-regulator.c b/drivers/regulator/rc5t583-regulator.c index c2c543c3a278..48437ff853ca 100644 --- a/drivers/regulator/rc5t583-regulator.c +++ b/drivers/regulator/rc5t583-regulator.c @@ -131,7 +131,7 @@ static int rc5t583_set_voltage_sel(struct regulator_dev *rdev, struct rc5t583_regulator *reg = rdev_get_drvdata(rdev); struct rc5t583_regulator_info *ri = reg->reg_info; int ret; - if (selector > ri->nsteps) { + if (selector >= ri->nsteps) { dev_err(&rdev->dev, "Invalid selector 0x%02x\n", selector); return -EINVAL; } -- cgit v1.2.3 From a1dc7dab57c4425e23b78f35ce630f68a21313b4 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 5 Apr 2012 14:04:48 +0800 Subject: regulator: rc5t583: Remove nsteps from struct rc5t583_regulator_info The nsteps can be calculated by (_max_mv - _min_mv) * 1000 / _step_uV + 1, thus we can remove _nsteps from RC5T583_REG macro, and then remove nsteps from struct rc5t583_regulator_info. Signed-off-by: Axel Lin Acked-by: Laxman Dewangan Signed-off-by: Mark Brown (cherry picked from commit e3a7384c3e98c48b5f122e449e22cc8a1a6c7e0d) Change-Id: If6db39255b2f7f8be38b848f2ca2619301b19b38 Signed-off-by: Laxman Dewangan Reviewed-on: http://git-master/r/105883 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit Reviewed-by: Bitan Biswas --- drivers/regulator/rc5t583-regulator.c | 37 ++++++++++++++++------------------- 1 file changed, 17 insertions(+), 20 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/rc5t583-regulator.c b/drivers/regulator/rc5t583-regulator.c index 48437ff853ca..33ab12afb0f3 100644 --- a/drivers/regulator/rc5t583-regulator.c +++ b/drivers/regulator/rc5t583-regulator.c @@ -49,7 +49,6 @@ struct rc5t583_regulator_info { int min_uV; int max_uV; int step_uV; - int nsteps; /* Regulator specific turn-on delay and voltage settling time*/ int enable_uv_per_us; @@ -131,7 +130,7 @@ static int rc5t583_set_voltage_sel(struct regulator_dev *rdev, struct rc5t583_regulator *reg = rdev_get_drvdata(rdev); struct rc5t583_regulator_info *ri = reg->reg_info; int ret; - if (selector >= ri->nsteps) { + if (selector >= rdev->desc->n_voltages) { dev_err(&rdev->dev, "Invalid selector 0x%02x\n", selector); return -EINVAL; } @@ -198,8 +197,7 @@ static struct regulator_ops rc5t583_ops = { }; #define RC5T583_REG(_id, _en_reg, _en_bit, _disc_reg, _disc_bit, _vout_reg, \ - _vout_mask, _ds_reg, _min_mv, _max_mv, _step_uV, _nsteps, \ - _enable_mv) \ + _vout_mask, _ds_reg, _min_mv, _max_mv, _step_uV, _enable_mv) \ { \ .reg_en_reg = RC5T583_REG_##_en_reg, \ .en_bit = _en_bit, \ @@ -211,14 +209,13 @@ static struct regulator_ops rc5t583_ops = { .min_uV = _min_mv * 1000, \ .max_uV = _max_mv * 1000, \ .step_uV = _step_uV, \ - .nsteps = _nsteps, \ .enable_uv_per_us = _enable_mv * 1000, \ .change_uv_per_us = 40 * 1000, \ .deepsleep_id = RC5T583_DS_##_id, \ .desc = { \ .name = "rc5t583-regulator-"#_id, \ .id = RC5T583_REGULATOR_##_id, \ - .n_voltages = _nsteps, \ + .n_voltages = (_max_mv - _min_mv) * 1000 / _step_uV + 1, \ .ops = &rc5t583_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ @@ -227,33 +224,33 @@ static struct regulator_ops rc5t583_ops = { static struct rc5t583_regulator_info rc5t583_reg_info[RC5T583_REGULATOR_MAX] = { RC5T583_REG(DC0, DC0CTL, 0, DC0CTL, 1, DC0DAC, 0x7F, DC0DAC_DS, - 700, 1500, 12500, 0x41, 4), + 700, 1500, 12500, 4), RC5T583_REG(DC1, DC1CTL, 0, DC1CTL, 1, DC1DAC, 0x7F, DC1DAC_DS, - 700, 1500, 12500, 0x41, 14), + 700, 1500, 12500, 14), RC5T583_REG(DC2, DC2CTL, 0, DC2CTL, 1, DC2DAC, 0x7F, DC2DAC_DS, - 900, 2400, 12500, 0x79, 14), + 900, 2400, 12500, 14), RC5T583_REG(DC3, DC3CTL, 0, DC3CTL, 1, DC3DAC, 0x7F, DC3DAC_DS, - 900, 2400, 12500, 0x79, 14), + 900, 2400, 12500, 14), RC5T583_REG(LDO0, LDOEN2, 0, LDODIS2, 0, LDO0DAC, 0x7F, LDO0DAC_DS, - 900, 3400, 25000, 0x65, 160), + 900, 3400, 25000, 160), RC5T583_REG(LDO1, LDOEN2, 1, LDODIS2, 1, LDO1DAC, 0x7F, LDO1DAC_DS, - 900, 3400, 25000, 0x65, 160), + 900, 3400, 25000, 160), RC5T583_REG(LDO2, LDOEN2, 2, LDODIS2, 2, LDO2DAC, 0x7F, LDO2DAC_DS, - 900, 3400, 25000, 0x65, 160), + 900, 3400, 25000, 160), RC5T583_REG(LDO3, LDOEN2, 3, LDODIS2, 3, LDO3DAC, 0x7F, LDO3DAC_DS, - 900, 3400, 25000, 0x65, 160), + 900, 3400, 25000, 160), RC5T583_REG(LDO4, LDOEN2, 4, LDODIS2, 4, LDO4DAC, 0x3F, LDO4DAC_DS, - 750, 1500, 12500, 0x3D, 133), + 750, 1500, 12500, 133), RC5T583_REG(LDO5, LDOEN2, 5, LDODIS2, 5, LDO5DAC, 0x7F, LDO5DAC_DS, - 900, 3400, 25000, 0x65, 267), + 900, 3400, 25000, 267), RC5T583_REG(LDO6, LDOEN2, 6, LDODIS2, 6, LDO6DAC, 0x7F, LDO6DAC_DS, - 900, 3400, 25000, 0x65, 133), + 900, 3400, 25000, 133), RC5T583_REG(LDO7, LDOEN2, 7, LDODIS2, 7, LDO7DAC, 0x7F, LDO7DAC_DS, - 900, 3400, 25000, 0x65, 233), + 900, 3400, 25000, 233), RC5T583_REG(LDO8, LDOEN1, 0, LDODIS1, 0, LDO8DAC, 0x7F, LDO8DAC_DS, - 900, 3400, 25000, 0x65, 233), + 900, 3400, 25000, 233), RC5T583_REG(LDO9, LDOEN1, 1, LDODIS1, 1, LDO9DAC, 0x7F, LDO9DAC_DS, - 900, 3400, 25000, 0x65, 133), + 900, 3400, 25000, 133), }; static int __devinit rc5t583_regulator_probe(struct platform_device *pdev) -- cgit v1.2.3 From c7afbb56d4be5f18a9e02ff07d18bfb6ea10b2b6 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Fri, 6 Apr 2012 10:58:33 +0530 Subject: regulator: rc5t583: Correct MODULE LICENSE to GPL v2 Fixing build issue reported by Paul Gortmaker: It appears this breaks linux-next allmodconfig build, because it uses an uppercase V in the v2 of its MODULE_LICENSE. FATAL: modpost: GPL-incompatible module rc5t583-regulator.ko uses GPL-only symbol 'platform_driver_unregister' make[2]: *** [__modpost] Error 1 Signed-off-by: Laxman Dewangan Signed-off-by: Mark Brown (cherry picked from commit 4eb06453648bb0d1eca3669f26798a19b6f40eb8) Change-Id: I8c715cf5a8e72555721a954d6db6879aed2eb423 Signed-off-by: Laxman Dewangan Reviewed-on: http://git-master/r/105884 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit Reviewed-by: Bitan Biswas --- drivers/regulator/rc5t583-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/rc5t583-regulator.c b/drivers/regulator/rc5t583-regulator.c index 33ab12afb0f3..81a03b281fa0 100644 --- a/drivers/regulator/rc5t583-regulator.c +++ b/drivers/regulator/rc5t583-regulator.c @@ -360,4 +360,4 @@ module_exit(rc5t583_regulator_exit); MODULE_AUTHOR("Laxman Dewangan "); MODULE_DESCRIPTION("RC5T583 regulator driver"); MODULE_ALIAS("platform:rc5t583-regulator"); -MODULE_LICENSE("GPL V2"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 4f569435116d03ae59e3acbfed7bdcc75ca88945 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Mon, 14 May 2012 17:46:51 +0530 Subject: regulator: tps62360: support force PWM mode via regulator mode Change the mechanism of enabling the force PWM mode through regulator set mode. This can be dynamically configured now. In the REGULATOR_MODE_FAST the force PWM is enabled and in REGULATOR_MODE_NORMAL the force PWM is disabled. Signed-off-by: Laxman Dewangan Signed-off-by: Mark Brown Cherry-picked from mainline commit 9a00630 Change-Id: I39a77dbe5d0c4c2a5b81dbfe51163a65894bc98c Signed-off-by: Laxman Dewangan Reviewed-on: http://git-master/r/105832 Reviewed-by: Automatic_Commit_Validation_User --- drivers/regulator/tps62360-regulator.c | 99 ++++++++++++++++++++++------------ 1 file changed, 65 insertions(+), 34 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/tps62360-regulator.c b/drivers/regulator/tps62360-regulator.c index bc58365fa151..7db148202436 100644 --- a/drivers/regulator/tps62360-regulator.c +++ b/drivers/regulator/tps62360-regulator.c @@ -46,6 +46,8 @@ #define REG_RAMPCTRL 6 #define REG_CHIPID 8 +#define FORCE_PWM_ENABLE BIT(7) + enum chips {TPS62360, TPS62361, TPS62362, TPS62363}; #define TPS62360_BASE_VOLTAGE 770000 @@ -66,7 +68,6 @@ struct tps62360_chip { int voltage_base; u8 voltage_reg_mask; bool en_internal_pulldn; - bool en_force_pwm; bool en_discharge; bool valid_gpios; int lru_index[4]; @@ -210,36 +211,80 @@ static int tps62360_set_voltage_time_sel(struct regulator_dev *rdev, return DIV_ROUND_UP(abs(old_uV - new_uV), tps->change_uv_per_us); } -static struct regulator_ops tps62360_dcdc_ops = { - .get_voltage_sel = tps62360_dcdc_get_voltage_sel, - .set_voltage = tps62360_dcdc_set_voltage, - .list_voltage = tps62360_dcdc_list_voltage, - .set_voltage_time_sel = tps62360_set_voltage_time_sel, -}; - -static int __devinit tps62360_init_force_pwm(struct tps62360_chip *tps, - struct tps62360_regulator_platform_data *pdata, - int vset_id) +static int tps62360_set_mode(struct regulator_dev *rdev, unsigned int mode) { + struct tps62360_chip *tps = rdev_get_drvdata(rdev); + int i; + int val; int ret; - int bit = 0; - if (pdata->en_force_pwm) - bit = BIT(7); + /* Enable force PWM mode in FAST mode only. */ + switch (mode) { + case REGULATOR_MODE_FAST: + val = FORCE_PWM_ENABLE; + break; - ret = regmap_update_bits(tps->regmap, REG_VSET0 + vset_id, BIT(7), bit); - if (ret < 0) - dev_err(tps->dev, - "%s(): register %d update failed with err %d\n", - __func__, REG_VSET0 + vset_id, ret); + case REGULATOR_MODE_NORMAL: + val = 0; + break; + + default: + return -EINVAL; + } + + if (!tps->valid_gpios) { + ret = regmap_update_bits(tps->regmap, + REG_VSET0 + tps->curr_vset_id, FORCE_PWM_ENABLE, val); + if (ret < 0) + dev_err(tps->dev, + "%s(): register %d update failed with err %d\n", + __func__, REG_VSET0 + tps->curr_vset_id, ret); + return ret; + } + + /* If gpios are valid then all register set need to be control */ + for (i = 0; i < 4; ++i) { + ret = regmap_update_bits(tps->regmap, + REG_VSET0 + i, FORCE_PWM_ENABLE, val); + if (ret < 0) { + dev_err(tps->dev, + "%s(): register %d update failed with err %d\n", + __func__, REG_VSET0 + i, ret); + return ret; + } + } return ret; } +static unsigned int tps62360_get_mode(struct regulator_dev *rdev) +{ + struct tps62360_chip *tps = rdev_get_drvdata(rdev); + unsigned int data; + int ret; + + ret = regmap_read(tps->regmap, REG_VSET0 + tps->curr_vset_id, &data); + if (ret < 0) { + dev_err(tps->dev, "%s(): register %d read failed with err %d\n", + __func__, REG_VSET0 + tps->curr_vset_id, ret); + return ret; + } + return (data & FORCE_PWM_ENABLE) ? + REGULATOR_MODE_FAST : REGULATOR_MODE_NORMAL; +} + +static struct regulator_ops tps62360_dcdc_ops = { + .get_voltage_sel = tps62360_dcdc_get_voltage_sel, + .set_voltage = tps62360_dcdc_set_voltage, + .list_voltage = tps62360_dcdc_list_voltage, + .set_voltage_time_sel = tps62360_set_voltage_time_sel, + .set_mode = tps62360_set_mode, + .get_mode = tps62360_get_mode, +}; + static int __devinit tps62360_init_dcdc(struct tps62360_chip *tps, struct tps62360_regulator_platform_data *pdata) { int ret; - int i; unsigned int ramp_ctrl; /* Initialize internal pull up/down control */ @@ -254,19 +299,6 @@ static int __devinit tps62360_init_dcdc(struct tps62360_chip *tps, return ret; } - /* Initialize force PWM mode */ - if (tps->valid_gpios) { - for (i = 0; i < 4; ++i) { - ret = tps62360_init_force_pwm(tps, pdata, i); - if (ret < 0) - return ret; - } - } else { - ret = tps62360_init_force_pwm(tps, pdata, tps->curr_vset_id); - if (ret < 0) - return ret; - } - /* Reset output discharge path to reduce power consumption */ ret = regmap_update_bits(tps->regmap, REG_RAMPCTRL, BIT(2), 0); if (ret < 0) { @@ -321,7 +353,6 @@ static int __devinit tps62360_probe(struct i2c_client *client, return -ENOMEM; } - tps->en_force_pwm = pdata->en_force_pwm; tps->en_discharge = pdata->en_discharge; tps->en_internal_pulldn = pdata->en_internal_pulldn; tps->vsel0_gpio = pdata->vsel0_gpio; -- cgit v1.2.3 From d167de5fef02520c5dfd924eeeb5fb9fae671729 Mon Sep 17 00:00:00 2001 From: Rhyland Klein Date: Tue, 8 May 2012 11:42:38 -0700 Subject: mfd: Commonize tps65910 regmap access through header This change removes the read/write callback functions in favor of common regmap accessors inside the header file. This change also makes use of regmap_read/write for single register access which maps better onto what this driver actually needs. Signed-off-by: Rhyland Klein Signed-off-by: Samuel Ortiz (Cherry-pick from mainline 3f7e82759c692df473675ed06fb90b20f1f225c3) Change-Id: Ida79b196acf65ed14ff9fd2cc1f7c0048f99ba2b Signed-off-by: Laxman Dewangan Reviewed-on: http://git-master/r/105922 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Rhyland Klein GVS: Gerrit_Virtual_Submit --- drivers/regulator/tps65910-regulator.c | 88 ++++++++++++++++------------------ 1 file changed, 42 insertions(+), 46 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/tps65910-regulator.c b/drivers/regulator/tps65910-regulator.c index fe2f1a8412b7..a2fef3880065 100644 --- a/drivers/regulator/tps65910-regulator.c +++ b/drivers/regulator/tps65910-regulator.c @@ -331,21 +331,16 @@ struct tps65910_reg { static inline int tps65910_read(struct tps65910_reg *pmic, u8 reg) { - u8 val; + unsigned int val; int err; - err = pmic->mfd->read(pmic->mfd, reg, 1, &val); + err = tps65910_reg_read(pmic->mfd, reg, &val); if (err) return err; return val; } -static inline int tps65910_write(struct tps65910_reg *pmic, u8 reg, u8 val) -{ - return pmic->mfd->write(pmic->mfd, reg, 1, &val); -} - static int tps65910_modify_bits(struct tps65910_reg *pmic, u8 reg, u8 set_mask, u8 clear_mask) { @@ -362,7 +357,7 @@ static int tps65910_modify_bits(struct tps65910_reg *pmic, u8 reg, data &= ~clear_mask; data |= set_mask; - err = tps65910_write(pmic, reg, data); + err = tps65910_reg_write(pmic->mfd, reg, data); if (err) dev_err(pmic->mfd->dev, "Write for reg 0x%x failed\n", reg); @@ -371,7 +366,7 @@ out: return err; } -static int tps65910_reg_read(struct tps65910_reg *pmic, u8 reg) +static int tps65910_reg_read_locked(struct tps65910_reg *pmic, u8 reg) { int data; @@ -385,13 +380,13 @@ static int tps65910_reg_read(struct tps65910_reg *pmic, u8 reg) return data; } -static int tps65910_reg_write(struct tps65910_reg *pmic, u8 reg, u8 val) +static int tps65910_reg_write_locked(struct tps65910_reg *pmic, u8 reg, u8 val) { int err; mutex_lock(&pmic->mutex); - err = tps65910_write(pmic, reg, val); + err = tps65910_reg_write(pmic->mfd, reg, val); if (err < 0) dev_err(pmic->mfd->dev, "Write for reg 0x%x failed\n", reg); @@ -476,7 +471,7 @@ static int tps65910_is_enabled(struct regulator_dev *dev) if (reg < 0) return reg; - value = tps65910_reg_read(pmic, reg); + value = tps65910_reg_read_locked(pmic, reg); if (value < 0) return value; @@ -493,7 +488,7 @@ static int tps65910_enable(struct regulator_dev *dev) if (reg < 0) return reg; - return tps65910_set_bits(mfd, reg, TPS65910_SUPPLY_STATE_ENABLED); + return tps65910_reg_set_bits(mfd, reg, TPS65910_SUPPLY_STATE_ENABLED); } static int tps65910_disable(struct regulator_dev *dev) @@ -506,7 +501,7 @@ static int tps65910_disable(struct regulator_dev *dev) if (reg < 0) return reg; - return tps65910_clear_bits(mfd, reg, TPS65910_SUPPLY_STATE_ENABLED); + return tps65910_reg_clear_bits(mfd, reg, TPS65910_SUPPLY_STATE_ENABLED); } static int tps65910_enable_time(struct regulator_dev *dev) @@ -532,9 +527,9 @@ static int tps65910_set_mode(struct regulator_dev *dev, unsigned int mode) LDO_ST_MODE_BIT); case REGULATOR_MODE_IDLE: value = LDO_ST_ON_BIT | LDO_ST_MODE_BIT; - return tps65910_set_bits(mfd, reg, value); + return tps65910_reg_set_bits(mfd, reg, value); case REGULATOR_MODE_STANDBY: - return tps65910_clear_bits(mfd, reg, LDO_ST_ON_BIT); + return tps65910_reg_clear_bits(mfd, reg, LDO_ST_ON_BIT); } return -EINVAL; @@ -549,7 +544,7 @@ static unsigned int tps65910_get_mode(struct regulator_dev *dev) if (reg < 0) return reg; - value = tps65910_reg_read(pmic, reg); + value = tps65910_reg_read_locked(pmic, reg); if (value < 0) return value; @@ -569,28 +564,28 @@ static int tps65910_get_voltage_dcdc_sel(struct regulator_dev *dev) switch (id) { case TPS65910_REG_VDD1: - opvsel = tps65910_reg_read(pmic, TPS65910_VDD1_OP); - mult = tps65910_reg_read(pmic, TPS65910_VDD1); + opvsel = tps65910_reg_read_locked(pmic, TPS65910_VDD1_OP); + mult = tps65910_reg_read_locked(pmic, TPS65910_VDD1); mult = (mult & VDD1_VGAIN_SEL_MASK) >> VDD1_VGAIN_SEL_SHIFT; - srvsel = tps65910_reg_read(pmic, TPS65910_VDD1_SR); + srvsel = tps65910_reg_read_locked(pmic, TPS65910_VDD1_SR); sr = opvsel & VDD1_OP_CMD_MASK; opvsel &= VDD1_OP_SEL_MASK; srvsel &= VDD1_SR_SEL_MASK; vselmax = 75; break; case TPS65910_REG_VDD2: - opvsel = tps65910_reg_read(pmic, TPS65910_VDD2_OP); - mult = tps65910_reg_read(pmic, TPS65910_VDD2); + opvsel = tps65910_reg_read_locked(pmic, TPS65910_VDD2_OP); + mult = tps65910_reg_read_locked(pmic, TPS65910_VDD2); mult = (mult & VDD2_VGAIN_SEL_MASK) >> VDD2_VGAIN_SEL_SHIFT; - srvsel = tps65910_reg_read(pmic, TPS65910_VDD2_SR); + srvsel = tps65910_reg_read_locked(pmic, TPS65910_VDD2_SR); sr = opvsel & VDD2_OP_CMD_MASK; opvsel &= VDD2_OP_SEL_MASK; srvsel &= VDD2_SR_SEL_MASK; vselmax = 75; break; case TPS65911_REG_VDDCTRL: - opvsel = tps65910_reg_read(pmic, TPS65911_VDDCTRL_OP); - srvsel = tps65910_reg_read(pmic, TPS65911_VDDCTRL_SR); + opvsel = tps65910_reg_read_locked(pmic, TPS65911_VDDCTRL_OP); + srvsel = tps65910_reg_read_locked(pmic, TPS65911_VDDCTRL_SR); sr = opvsel & VDDCTRL_OP_CMD_MASK; opvsel &= VDDCTRL_OP_SEL_MASK; srvsel &= VDDCTRL_SR_SEL_MASK; @@ -630,7 +625,7 @@ static int tps65910_get_voltage(struct regulator_dev *dev) if (reg < 0) return reg; - value = tps65910_reg_read(pmic, reg); + value = tps65910_reg_read_locked(pmic, reg); if (value < 0) return value; @@ -669,7 +664,7 @@ static int tps65911_get_voltage(struct regulator_dev *dev) reg = pmic->get_ctrl_reg(id); - value = tps65910_reg_read(pmic, reg); + value = tps65910_reg_read_locked(pmic, reg); switch (id) { case TPS65911_REG_LDO1: @@ -728,7 +723,7 @@ static int tps65910_set_voltage_dcdc_sel(struct regulator_dev *dev, tps65910_modify_bits(pmic, TPS65910_VDD1, (dcdc_mult << VDD1_VGAIN_SEL_SHIFT), VDD1_VGAIN_SEL_MASK); - tps65910_reg_write(pmic, TPS65910_VDD1_OP, vsel); + tps65910_reg_write_locked(pmic, TPS65910_VDD1_OP, vsel); break; case TPS65910_REG_VDD2: dcdc_mult = (selector / VDD1_2_NUM_VOLT_FINE) + 1; @@ -739,11 +734,11 @@ static int tps65910_set_voltage_dcdc_sel(struct regulator_dev *dev, tps65910_modify_bits(pmic, TPS65910_VDD2, (dcdc_mult << VDD2_VGAIN_SEL_SHIFT), VDD1_VGAIN_SEL_MASK); - tps65910_reg_write(pmic, TPS65910_VDD2_OP, vsel); + tps65910_reg_write_locked(pmic, TPS65910_VDD2_OP, vsel); break; case TPS65911_REG_VDDCTRL: vsel = selector + 3; - tps65910_reg_write(pmic, TPS65911_VDDCTRL_OP, vsel); + tps65910_reg_write_locked(pmic, TPS65911_VDDCTRL_OP, vsel); } return 0; @@ -994,10 +989,10 @@ static int tps65910_set_ext_sleep_config(struct tps65910_reg *pmic, /* External EN1 control */ if (ext_sleep_config & TPS65910_SLEEP_CONTROL_EXT_INPUT_EN1) - ret = tps65910_set_bits(mfd, + ret = tps65910_reg_set_bits(mfd, TPS65910_EN1_LDO_ASS + regoffs, bit_pos); else - ret = tps65910_clear_bits(mfd, + ret = tps65910_reg_clear_bits(mfd, TPS65910_EN1_LDO_ASS + regoffs, bit_pos); if (ret < 0) { dev_err(mfd->dev, @@ -1007,10 +1002,10 @@ static int tps65910_set_ext_sleep_config(struct tps65910_reg *pmic, /* External EN2 control */ if (ext_sleep_config & TPS65910_SLEEP_CONTROL_EXT_INPUT_EN2) - ret = tps65910_set_bits(mfd, + ret = tps65910_reg_set_bits(mfd, TPS65910_EN2_LDO_ASS + regoffs, bit_pos); else - ret = tps65910_clear_bits(mfd, + ret = tps65910_reg_clear_bits(mfd, TPS65910_EN2_LDO_ASS + regoffs, bit_pos); if (ret < 0) { dev_err(mfd->dev, @@ -1022,10 +1017,10 @@ static int tps65910_set_ext_sleep_config(struct tps65910_reg *pmic, if ((tps65910_chip_id(mfd) == TPS65910) && (id >= TPS65910_REG_VDIG1)) { if (ext_sleep_config & TPS65910_SLEEP_CONTROL_EXT_INPUT_EN3) - ret = tps65910_set_bits(mfd, + ret = tps65910_reg_set_bits(mfd, TPS65910_EN3_LDO_ASS + regoffs, bit_pos); else - ret = tps65910_clear_bits(mfd, + ret = tps65910_reg_clear_bits(mfd, TPS65910_EN3_LDO_ASS + regoffs, bit_pos); if (ret < 0) { dev_err(mfd->dev, @@ -1037,10 +1032,10 @@ static int tps65910_set_ext_sleep_config(struct tps65910_reg *pmic, /* Return if no external control is selected */ if (!(ext_sleep_config & EXT_SLEEP_CONTROL)) { /* Clear all sleep controls */ - ret = tps65910_clear_bits(mfd, + ret = tps65910_reg_clear_bits(mfd, TPS65910_SLEEP_KEEP_LDO_ON + regoffs, bit_pos); if (!ret) - ret = tps65910_clear_bits(mfd, + ret = tps65910_reg_clear_bits(mfd, TPS65910_SLEEP_SET_LDO_OFF + regoffs, bit_pos); if (ret < 0) dev_err(mfd->dev, @@ -1059,32 +1054,33 @@ static int tps65910_set_ext_sleep_config(struct tps65910_reg *pmic, (tps65910_chip_id(mfd) == TPS65911))) { int op_reg_add = pmic->get_ctrl_reg(id) + 1; int sr_reg_add = pmic->get_ctrl_reg(id) + 2; - int opvsel = tps65910_reg_read(pmic, op_reg_add); - int srvsel = tps65910_reg_read(pmic, sr_reg_add); + int opvsel = tps65910_reg_read_locked(pmic, op_reg_add); + int srvsel = tps65910_reg_read_locked(pmic, sr_reg_add); if (opvsel & VDD1_OP_CMD_MASK) { u8 reg_val = srvsel & VDD1_OP_SEL_MASK; - ret = tps65910_reg_write(pmic, op_reg_add, reg_val); + ret = tps65910_reg_write_locked(pmic, op_reg_add, + reg_val); if (ret < 0) { dev_err(mfd->dev, "Error in configuring op register\n"); return ret; } } - ret = tps65910_reg_write(pmic, sr_reg_add, 0); + ret = tps65910_reg_write_locked(pmic, sr_reg_add, 0); if (ret < 0) { dev_err(mfd->dev, "Error in settting sr register\n"); return ret; } } - ret = tps65910_clear_bits(mfd, + ret = tps65910_reg_clear_bits(mfd, TPS65910_SLEEP_KEEP_LDO_ON + regoffs, bit_pos); if (!ret) { if (ext_sleep_config & TPS65911_SLEEP_CONTROL_EXT_INPUT_SLEEP) - ret = tps65910_set_bits(mfd, + ret = tps65910_reg_set_bits(mfd, TPS65910_SLEEP_SET_LDO_OFF + regoffs, bit_pos); else - ret = tps65910_clear_bits(mfd, + ret = tps65910_reg_clear_bits(mfd, TPS65910_SLEEP_SET_LDO_OFF + regoffs, bit_pos); } if (ret < 0) @@ -1117,7 +1113,7 @@ static __devinit int tps65910_probe(struct platform_device *pdev) platform_set_drvdata(pdev, pmic); /* Give control of all register to control port */ - tps65910_set_bits(pmic->mfd, TPS65910_DEVCTRL, + tps65910_reg_set_bits(pmic->mfd, TPS65910_DEVCTRL, DEVCTRL_SR_CTL_I2C_SEL_MASK); switch(tps65910_chip_id(tps65910)) { -- cgit v1.2.3 From 4d2a8be9772cc2e236bb57b1c734828f1229e632 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Mon, 25 Jun 2012 18:59:27 +0530 Subject: regulator: tps80031: Allow to configure in OFF mode in sleep state Allow to configure the rail into sleep-off mode even if the external req is not supported for a regulator. bug 979143 Change-Id: I3c1bd789410b557a2ffc3133ca15ec3753ed2004 Signed-off-by: Laxman Dewangan Reviewed-on: http://git-master/r/110881 Reviewed-by: Automatic_Commit_Validation_User --- drivers/regulator/tps80031-regulator.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/regulator') diff --git a/drivers/regulator/tps80031-regulator.c b/drivers/regulator/tps80031-regulator.c index 411b839f1a74..4b1df3613f56 100644 --- a/drivers/regulator/tps80031-regulator.c +++ b/drivers/regulator/tps80031-regulator.c @@ -801,11 +801,11 @@ static int tps80031_power_req_config(struct device *parent, struct tps80031_regulator *ri, struct tps80031_regulator_platform_data *tps80031_pdata) { - int ret; + int ret = 0; uint8_t reg_val; if (ri->preq_bit < 0) - return 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); @@ -821,6 +821,7 @@ static int tps80031_power_req_config(struct device *parent, return ret; } +skip_pwr_req_config: if (tps80031_pdata->ext_ctrl_flag & (PWR_OFF_ON_SLEEP | PWR_ON_ON_SLEEP)) { reg_val = (ri->trans_reg_cache & ~0xC); -- cgit v1.2.3 From 33b50b0bf4e501a81605c4351ff163d82c87e0d1 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Fri, 22 Jun 2012 12:12:38 +0530 Subject: regulator: tps80031: support for min voltage tolerance Sometimes the system allow to run in less than requested minimum voltage and if this tolerance allow the regulator to set voltage in lower side range than this saves the power. For the example, if client request vmin = 975mV for regulator voltage then it sets the voltage to 987.5mv as the nearest to this desired value. The next lower side for the voltage is 974.8mv. So if system runs on tolerance of 1mv and if it request for 975mv then driver can look for minimum voltage as 975 - tolerance(1) = 974mv and possible configure 974.8mv rather than 987.5mV and so it can save the power equivalent to 12.5mV higher voltage. Support the configuration of tolerance value. Change-Id: Ic8312bb397c2615a3ee0f84072ec394e513525ea Signed-off-by: Laxman Dewangan Reviewed-on: http://git-master/r/110523 Reviewed-by: Rohan Somvanshi Tested-by: Rohan Somvanshi --- drivers/regulator/tps80031-regulator.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/regulator') diff --git a/drivers/regulator/tps80031-regulator.c b/drivers/regulator/tps80031-regulator.c index 4b1df3613f56..efc608c936ea 100644 --- a/drivers/regulator/tps80031-regulator.c +++ b/drivers/regulator/tps80031-regulator.c @@ -100,6 +100,7 @@ struct tps80031_regulator { /* chip constraints on regulator behavior */ u16 min_mV; u16 max_mV; + unsigned int tolerance_uv; /* regulator specific turn-on delay */ int delay; @@ -296,6 +297,8 @@ 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 == 0) @@ -1025,6 +1028,7 @@ static int __devinit tps80031_regulator_probe(struct platform_device *pdev) 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; -- cgit v1.2.3