Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

regulator: tps51632: Add tps51632 regulator driver

The TPS51632 is a driverless step down controller with
serial control. Advanced features such as D-Cap+
architecture with overlapping pulse support and OSR
overshoot reduction provide fast transient response,
lowest output capacitance and high efficiency.
The TPS51632 supports both I2C and DVFS interfaces
(through PWM) for dynamic control of the output voltage
and current monitor telemetry.
Add regulator driver for TPS51632.

Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>

authored by

Laxman Dewangan and committed by
Mark Brown
0c570674 ddffeb8c

+391
+11
drivers/regulator/Kconfig
··· 335 335 on the muxing. This is handled automatically in the driver by 336 336 reading the mux info from OTP. 337 337 338 + config REGULATOR_TPS51632 339 + tristate "TI TPS51632 Power Regulator" 340 + depends on I2C 341 + select REGMAP_I2C 342 + help 343 + This driver supports TPS51632 voltage regulator chip. 344 + The TPS52632 is 3-2-1 Phase D-Cap+ Step Down Driverless Controller 345 + with Serial VID control and DVFS. 346 + The voltage output can be configure through I2C interface or PWM 347 + interface. 348 + 338 349 config REGULATOR_TPS6105X 339 350 tristate "TI TPS6105X Power regulators" 340 351 depends on TPS6105X
+1
drivers/regulator/Makefile
··· 41 41 obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o 42 42 obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o 43 43 obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o 44 + obj-$(CONFIG_REGULATOR_TPS51632) += tps51632-regulator.o 44 45 obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o 45 46 obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o 46 47 obj-$(CONFIG_REGULATOR_RC5T583) += rc5t583-regulator.o
+332
drivers/regulator/tps51632-regulator.c
··· 1 + /* 2 + * tps51632-regulator.c -- TI TPS51632 3 + * 4 + * Regulator driver for TPS51632 3-2-1 Phase D-Cap Step Down Driverless 5 + * Controller with serial VID control and DVFS. 6 + * 7 + * Copyright (c) 2012, NVIDIA Corporation. 8 + * 9 + * Author: Laxman Dewangan <ldewangan@nvidia.com> 10 + * 11 + * This program is free software; you can redistribute it and/or 12 + * modify it under the terms of the GNU General Public License as 13 + * published by the Free Software Foundation version 2. 14 + * 15 + * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, 16 + * whether express or implied; without even the implied warranty of 17 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 + * General Public License for more details. 19 + * 20 + * You should have received a copy of the GNU General Public License 21 + * along with this program; if not, write to the Free Software 22 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 23 + * 02111-1307, USA 24 + */ 25 + 26 + #include <linux/err.h> 27 + #include <linux/i2c.h> 28 + #include <linux/init.h> 29 + #include <linux/kernel.h> 30 + #include <linux/module.h> 31 + #include <linux/platform_device.h> 32 + #include <linux/regmap.h> 33 + #include <linux/regulator/driver.h> 34 + #include <linux/regulator/machine.h> 35 + #include <linux/regulator/tps51632-regulator.h> 36 + #include <linux/slab.h> 37 + 38 + /* Register definitions */ 39 + #define TPS51632_VOLTAGE_SELECT_REG 0x0 40 + #define TPS51632_VOLTAGE_BASE_REG 0x1 41 + #define TPS51632_OFFSET_REG 0x2 42 + #define TPS51632_IMON_REG 0x3 43 + #define TPS51632_VMAX_REG 0x4 44 + #define TPS51632_DVFS_CONTROL_REG 0x5 45 + #define TPS51632_POWER_STATE_REG 0x6 46 + #define TPS51632_SLEW_REGS 0x7 47 + #define TPS51632_FAULT_REG 0x14 48 + 49 + #define TPS51632_MAX_REG 0x15 50 + 51 + #define TPS51632_VOUT_MASK 0x7F 52 + #define TPS51632_VOUT_OFFSET_MASK 0x1F 53 + #define TPS51632_VMAX_MASK 0x7F 54 + #define TPS51632_VMAX_LOCK 0x80 55 + 56 + /* TPS51632_DVFS_CONTROL_REG */ 57 + #define TPS51632_DVFS_PWMEN 0x1 58 + #define TPS51632_DVFS_STEP_20 0x2 59 + #define TPS51632_DVFS_VMAX_PG 0x4 60 + #define TPS51632_DVFS_PWMRST 0x8 61 + #define TPS51632_DVFS_OCA_EN 0x10 62 + #define TPS51632_DVFS_FCCM 0x20 63 + 64 + /* TPS51632_POWER_STATE_REG */ 65 + #define TPS51632_POWER_STATE_MASK 0x03 66 + #define TPS51632_POWER_STATE_MULTI_PHASE_CCM 0x0 67 + #define TPS51632_POWER_STATE_SINGLE_PHASE_CCM 0x1 68 + #define TPS51632_POWER_STATE_SINGLE_PHASE_DCM 0x2 69 + 70 + #define TPS51632_MIN_VOLATGE 500000 71 + #define TPS51632_MAX_VOLATGE 1520000 72 + #define TPS51632_VOLATGE_STEP_10mV 10000 73 + #define TPS51632_VOLATGE_STEP_20mV 20000 74 + #define TPS51632_MAX_VSEL 0x7F 75 + #define TPS51632_MIN_VSEL 0x19 76 + #define TPS51632_DEFAULT_RAMP_DELAY 6000 77 + #define TPS51632_VOLT_VSEL(uV) \ 78 + (DIV_ROUND_UP(uV - TPS51632_MIN_VOLATGE, \ 79 + TPS51632_VOLATGE_STEP_10mV) + \ 80 + TPS51632_MIN_VSEL) 81 + 82 + /* TPS51632 chip information */ 83 + struct tps51632_chip { 84 + struct device *dev; 85 + struct regulator_desc desc; 86 + struct regulator_dev *rdev; 87 + struct regmap *regmap; 88 + bool enable_pwm_dvfs; 89 + }; 90 + 91 + static int tps51632_dcdc_get_voltage_sel(struct regulator_dev *rdev) 92 + { 93 + struct tps51632_chip *tps = rdev_get_drvdata(rdev); 94 + unsigned int data; 95 + int ret; 96 + unsigned int reg = TPS51632_VOLTAGE_SELECT_REG; 97 + int vsel; 98 + 99 + if (tps->enable_pwm_dvfs) 100 + reg = TPS51632_VOLTAGE_BASE_REG; 101 + 102 + ret = regmap_read(tps->regmap, reg, &data); 103 + if (ret < 0) { 104 + dev_err(tps->dev, "reg read failed, err %d\n", ret); 105 + return ret; 106 + } 107 + 108 + vsel = data & TPS51632_VOUT_MASK; 109 + 110 + if (vsel < TPS51632_MIN_VSEL) 111 + return 0; 112 + else 113 + return vsel - TPS51632_MIN_VSEL; 114 + } 115 + 116 + static int tps51632_dcdc_set_voltage_sel(struct regulator_dev *rdev, 117 + unsigned selector) 118 + { 119 + struct tps51632_chip *tps = rdev_get_drvdata(rdev); 120 + int vsel; 121 + int ret; 122 + unsigned int reg = TPS51632_VOLTAGE_SELECT_REG; 123 + 124 + if (tps->enable_pwm_dvfs) 125 + reg = TPS51632_VOLTAGE_BASE_REG; 126 + 127 + vsel = selector + TPS51632_MIN_VSEL; 128 + if (vsel > TPS51632_MAX_VSEL) 129 + return -EINVAL; 130 + 131 + ret = regmap_write(tps->regmap, TPS51632_VOLTAGE_SELECT_REG, vsel); 132 + if (ret < 0) 133 + dev_err(tps->dev, "reg write failed, err %d\n", ret); 134 + return ret; 135 + } 136 + 137 + static int tps51632_dcdc_set_ramp_delay(struct regulator_dev *rdev, 138 + int ramp_delay) 139 + { 140 + struct tps51632_chip *tps = rdev_get_drvdata(rdev); 141 + int bit = ramp_delay/6000; 142 + int ret; 143 + 144 + if (bit) 145 + bit--; 146 + ret = regmap_write(tps->regmap, TPS51632_SLEW_REGS, BIT(bit)); 147 + if (ret < 0) 148 + dev_err(tps->dev, "SLEW reg write failed, err %d\n", ret); 149 + return ret; 150 + } 151 + 152 + static struct regulator_ops tps51632_dcdc_ops = { 153 + .get_voltage_sel = tps51632_dcdc_get_voltage_sel, 154 + .set_voltage_sel = tps51632_dcdc_set_voltage_sel, 155 + .list_voltage = regulator_list_voltage_linear, 156 + .set_voltage_time_sel = regulator_set_voltage_time_sel, 157 + .set_ramp_delay = tps51632_dcdc_set_ramp_delay, 158 + }; 159 + 160 + static int __devinit tps51632_init_dcdc(struct tps51632_chip *tps, 161 + struct tps51632_regulator_platform_data *pdata) 162 + { 163 + int ret; 164 + uint8_t control = 0; 165 + int vsel; 166 + 167 + if (!pdata->enable_pwm_dvfs) 168 + goto skip_pwm_config; 169 + 170 + control |= TPS51632_DVFS_PWMEN; 171 + tps->enable_pwm_dvfs = pdata->enable_pwm_dvfs; 172 + vsel = TPS51632_VOLT_VSEL(pdata->base_voltage_uV); 173 + ret = regmap_write(tps->regmap, TPS51632_VOLTAGE_BASE_REG, vsel); 174 + if (ret < 0) { 175 + dev_err(tps->dev, "BASE reg write failed, err %d\n", ret); 176 + return ret; 177 + } 178 + 179 + if (pdata->dvfs_step_20mV) 180 + control |= TPS51632_DVFS_STEP_20; 181 + 182 + if (pdata->max_voltage_uV) { 183 + unsigned int vmax; 184 + /** 185 + * TPS51632 hw behavior: VMAX register can be write only 186 + * once as it get locked after first write. The lock get 187 + * reset only when device is power-reset. 188 + * Write register only when lock bit is not enabled. 189 + */ 190 + ret = regmap_read(tps->regmap, TPS51632_VMAX_REG, &vmax); 191 + if (ret < 0) { 192 + dev_err(tps->dev, "VMAX read failed, err %d\n", ret); 193 + return ret; 194 + } 195 + if (!(vmax & TPS51632_VMAX_LOCK)) { 196 + vsel = TPS51632_VOLT_VSEL(pdata->max_voltage_uV); 197 + ret = regmap_write(tps->regmap, TPS51632_VMAX_REG, 198 + vsel); 199 + if (ret < 0) { 200 + dev_err(tps->dev, 201 + "VMAX write failed, err %d\n", ret); 202 + return ret; 203 + } 204 + } 205 + } 206 + 207 + skip_pwm_config: 208 + ret = regmap_write(tps->regmap, TPS51632_DVFS_CONTROL_REG, control); 209 + if (ret < 0) 210 + dev_err(tps->dev, "DVFS reg write failed, err %d\n", ret); 211 + return ret; 212 + } 213 + 214 + static bool rd_wr_reg(struct device *dev, unsigned int reg) 215 + { 216 + if ((reg >= 0x8) && (reg <= 0x10)) 217 + return false; 218 + return true; 219 + } 220 + 221 + static const struct regmap_config tps51632_regmap_config = { 222 + .reg_bits = 8, 223 + .val_bits = 8, 224 + .writeable_reg = rd_wr_reg, 225 + .readable_reg = rd_wr_reg, 226 + .max_register = TPS51632_MAX_REG - 1, 227 + .cache_type = REGCACHE_RBTREE, 228 + }; 229 + 230 + static int __devinit tps51632_probe(struct i2c_client *client, 231 + const struct i2c_device_id *id) 232 + { 233 + struct tps51632_regulator_platform_data *pdata; 234 + struct regulator_dev *rdev; 235 + struct tps51632_chip *tps; 236 + int ret; 237 + struct regulator_config config = { }; 238 + 239 + pdata = client->dev.platform_data; 240 + if (!pdata) { 241 + dev_err(&client->dev, "No Platform data\n"); 242 + return -EINVAL; 243 + } 244 + 245 + tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL); 246 + if (!tps) { 247 + dev_err(&client->dev, "Memory allocation failed\n"); 248 + return -ENOMEM; 249 + } 250 + 251 + tps->dev = &client->dev; 252 + tps->desc.name = id->name; 253 + tps->desc.id = 0; 254 + tps->desc.ramp_delay = TPS51632_DEFAULT_RAMP_DELAY; 255 + tps->desc.min_uV = TPS51632_MIN_VOLATGE; 256 + tps->desc.uV_step = TPS51632_VOLATGE_STEP_10mV; 257 + tps->desc.n_voltages = (TPS51632_MAX_VSEL - TPS51632_MIN_VSEL) + 1; 258 + tps->desc.ops = &tps51632_dcdc_ops; 259 + tps->desc.type = REGULATOR_VOLTAGE; 260 + tps->desc.owner = THIS_MODULE; 261 + 262 + tps->regmap = devm_regmap_init_i2c(client, &tps51632_regmap_config); 263 + if (IS_ERR(tps->regmap)) { 264 + ret = PTR_ERR(tps->regmap); 265 + dev_err(&client->dev, "regmap init failed, err %d\n", ret); 266 + return ret; 267 + } 268 + i2c_set_clientdata(client, tps); 269 + 270 + ret = tps51632_init_dcdc(tps, pdata); 271 + if (ret < 0) { 272 + dev_err(tps->dev, "Init failed, err = %d\n", ret); 273 + return ret; 274 + } 275 + 276 + /* Register the regulators */ 277 + config.dev = &client->dev; 278 + config.init_data = pdata->reg_init_data; 279 + config.driver_data = tps; 280 + config.regmap = tps->regmap; 281 + config.of_node = client->dev.of_node; 282 + 283 + rdev = regulator_register(&tps->desc, &config); 284 + if (IS_ERR(rdev)) { 285 + dev_err(tps->dev, "regulator register failed\n"); 286 + return PTR_ERR(rdev); 287 + } 288 + 289 + tps->rdev = rdev; 290 + return 0; 291 + } 292 + 293 + static int __devexit tps51632_remove(struct i2c_client *client) 294 + { 295 + struct tps51632_chip *tps = i2c_get_clientdata(client); 296 + 297 + regulator_unregister(tps->rdev); 298 + return 0; 299 + } 300 + 301 + static const struct i2c_device_id tps51632_id[] = { 302 + {.name = "tps51632",}, 303 + {}, 304 + }; 305 + 306 + MODULE_DEVICE_TABLE(i2c, tps51632_id); 307 + 308 + static struct i2c_driver tps51632_i2c_driver = { 309 + .driver = { 310 + .name = "tps51632", 311 + .owner = THIS_MODULE, 312 + }, 313 + .probe = tps51632_probe, 314 + .remove = __devexit_p(tps51632_remove), 315 + .id_table = tps51632_id, 316 + }; 317 + 318 + static int __init tps51632_init(void) 319 + { 320 + return i2c_add_driver(&tps51632_i2c_driver); 321 + } 322 + subsys_initcall(tps51632_init); 323 + 324 + static void __exit tps51632_cleanup(void) 325 + { 326 + i2c_del_driver(&tps51632_i2c_driver); 327 + } 328 + module_exit(tps51632_cleanup); 329 + 330 + MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); 331 + MODULE_DESCRIPTION("TPS51632 voltage regulator driver"); 332 + MODULE_LICENSE("GPL v2");
+47
include/linux/regulator/tps51632-regulator.h
··· 1 + /* 2 + * tps51632-regulator.h -- TPS51632 regulator 3 + * 4 + * Interface for regulator driver for TPS51632 3-2-1 Phase D-Cap Step Down 5 + * Driverless Controller with serial VID control and DVFS. 6 + * 7 + * Copyright (C) 2012 NVIDIA Corporation 8 + 9 + * Author: Laxman Dewangan <ldewangan@nvidia.com> 10 + * 11 + * This program is free software; you can redistribute it and/or modify 12 + * it under the terms of the GNU General Public License as published by 13 + * the Free Software Foundation; either version 2 of the License, or 14 + * (at your option) any later version. 15 + * 16 + * This program is distributed in the hope that it will be useful, but WITHOUT 17 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 18 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 19 + * more details. 20 + * 21 + * You should have received a copy of the GNU General Public License along 22 + * with this program; if not, write to the Free Software Foundation, Inc., 23 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 24 + * 25 + */ 26 + 27 + #ifndef __LINUX_REGULATOR_TPS51632_H 28 + #define __LINUX_REGULATOR_TPS51632_H 29 + 30 + /* 31 + * struct tps51632_regulator_platform_data - tps51632 regulator platform data. 32 + * 33 + * @reg_init_data: The regulator init data. 34 + * @enable_pwm_dvfs: Enable PWM DVFS or not. 35 + * @dvfs_step_20mV: Step for DVFS is 20mV or 10mV. 36 + * @max_voltage_uV: Maximum possible voltage in PWM-DVFS mode. 37 + * @base_voltage_uV: Base voltage when PWM-DVFS enabled. 38 + */ 39 + struct tps51632_regulator_platform_data { 40 + struct regulator_init_data *reg_init_data; 41 + bool enable_pwm_dvfs; 42 + bool dvfs_step_20mV; 43 + int max_voltage_uV; 44 + int base_voltage_uV; 45 + }; 46 + 47 + #endif /* __LINUX_REGULATOR_TPS51632_H */