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

regulator: Fairchild fan53555 support

This driver supports Fairchild FAN53555 Digitally Programmable
TinyBuck Regulator. The FAN53555 is a step-down switching voltage
regulator that delivers a digitally programmable output from an
input voltage supply of 2.5V to 5.5V. The output voltage is
programmed through an I2C interface.

Signed-off-by: Yunfan Zhang <yfzhang@marvell.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>

authored by

Yunfan Zhang and committed by
Mark Brown
49d8c599 029dd3ce

+397
+11
drivers/regulator/Kconfig
··· 110 110 This driver supports the voltage regulators of DA9052-BC and 111 111 DA9053-AA/Bx PMIC. 112 112 113 + config REGULATOR_FAN53555 114 + tristate "Fairchild FAN53555 Regulator" 115 + depends on I2C 116 + select REGMAP_I2C 117 + help 118 + This driver supports Fairchild FAN53555 Digitally Programmable 119 + TinyBuck Regulator. The FAN53555 is a step-down switching voltage 120 + regulator that delivers a digitally programmable output from an 121 + input voltage supply of 2.5V to 5.5V. The output voltage is 122 + programmed through an I2C interface. 123 + 113 124 config REGULATOR_ANATOP 114 125 tristate "Freescale i.MX on-chip ANATOP LDO regulators" 115 126 depends on MFD_ANATOP
+1
drivers/regulator/Makefile
··· 20 20 obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o 21 21 obj-$(CONFIG_REGULATOR_DBX500_PRCMU) += dbx500-prcmu.o 22 22 obj-$(CONFIG_REGULATOR_DB8500_PRCMU) += db8500-prcmu.o 23 + obj-$(CONFIG_REGULATOR_FAN53555) += fan53555.o 23 24 obj-$(CONFIG_REGULATOR_GPIO) += gpio-regulator.o 24 25 obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o 25 26 obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o
+325
drivers/regulator/fan53555.c
··· 1 + /* 2 + * FAN53555 Fairchild Digitally Programmable TinyBuck Regulator Driver. 3 + * 4 + * Supported Part Numbers: 5 + * FAN53555UC00X/01X/03X/04X/05X 6 + * 7 + * Copyright (c) 2012 Marvell Technology Ltd. 8 + * Yunfan Zhang <yfzhang@marvell.com> 9 + * 10 + * This package is free software; you can redistribute it and/or modify 11 + * it under the terms of the GNU General Public License version 2 as 12 + * published by the Free Software Foundation. 13 + * 14 + */ 15 + #include <linux/module.h> 16 + #include <linux/param.h> 17 + #include <linux/err.h> 18 + #include <linux/platform_device.h> 19 + #include <linux/regulator/driver.h> 20 + #include <linux/regulator/machine.h> 21 + #include <linux/i2c.h> 22 + #include <linux/slab.h> 23 + #include <linux/regmap.h> 24 + #include <linux/regulator/fan53555.h> 25 + 26 + /* Voltage setting */ 27 + #define FAN53555_VSEL0 0x00 28 + #define FAN53555_VSEL1 0x01 29 + /* Control register */ 30 + #define FAN53555_CONTROL 0x02 31 + /* IC Type */ 32 + #define FAN53555_ID1 0x03 33 + /* IC mask version */ 34 + #define FAN53555_ID2 0x04 35 + /* Monitor register */ 36 + #define FAN53555_MONITOR 0x05 37 + 38 + /* VSEL bit definitions */ 39 + #define VSEL_BUCK_EN (1 << 7) 40 + #define VSEL_MODE (1 << 6) 41 + #define VSEL_NSEL_MASK 0x3F 42 + /* Chip ID and Verison */ 43 + #define DIE_ID 0x0F /* ID1 */ 44 + #define DIE_REV 0x0F /* ID2 */ 45 + /* Control bit definitions */ 46 + #define CTL_OUTPUT_DISCHG (1 << 7) 47 + #define CTL_SLEW_MASK (0x7 << 4) 48 + #define CTL_SLEW_SHIFT 4 49 + #define CTL_RESET (1 << 2) 50 + 51 + #define FAN53555_NVOLTAGES 64 /* Numbers of voltages */ 52 + 53 + /* IC Type */ 54 + enum { 55 + FAN53555_CHIP_ID_00 = 0, 56 + FAN53555_CHIP_ID_01, 57 + FAN53555_CHIP_ID_02, 58 + FAN53555_CHIP_ID_03, 59 + FAN53555_CHIP_ID_04, 60 + FAN53555_CHIP_ID_05, 61 + }; 62 + 63 + struct fan53555_device_info { 64 + struct regmap *regmap; 65 + struct device *dev; 66 + struct regulator_desc desc; 67 + struct regulator_dev *rdev; 68 + struct regulator_init_data *regulator; 69 + /* IC Type and Rev */ 70 + int chip_id; 71 + int chip_rev; 72 + /* Voltage setting register */ 73 + unsigned int vol_reg; 74 + unsigned int sleep_reg; 75 + /* Voltage range and step(linear) */ 76 + unsigned int vsel_min; 77 + unsigned int vsel_max; 78 + unsigned int vsel_step; 79 + /* Voltage slew rate limiting */ 80 + unsigned int slew_rate; 81 + /* Sleep voltage cache */ 82 + unsigned int sleep_vol_cache; 83 + }; 84 + 85 + static int fan53555_set_suspend_voltage(struct regulator_dev *rdev, int uV) 86 + { 87 + struct fan53555_device_info *di = rdev_get_drvdata(rdev); 88 + int ret; 89 + 90 + if (di->sleep_vol_cache == uV) 91 + return 0; 92 + ret = regulator_map_voltage_linear(rdev, uV, uV); 93 + if (ret < 0) 94 + return -EINVAL; 95 + ret = regmap_update_bits(di->regmap, di->sleep_reg, 96 + VSEL_NSEL_MASK, ret); 97 + if (ret < 0) 98 + return -EINVAL; 99 + /* Cache the sleep voltage setting. 100 + * Might not be the real voltage which is rounded */ 101 + di->sleep_vol_cache = uV; 102 + 103 + return 0; 104 + } 105 + 106 + static int fan53555_set_mode(struct regulator_dev *rdev, unsigned int mode) 107 + { 108 + struct fan53555_device_info *di = rdev_get_drvdata(rdev); 109 + 110 + switch (mode) { 111 + case REGULATOR_MODE_FAST: 112 + regmap_update_bits(di->regmap, di->vol_reg, 113 + VSEL_MODE, VSEL_MODE); 114 + break; 115 + case REGULATOR_MODE_NORMAL: 116 + regmap_update_bits(di->regmap, di->vol_reg, VSEL_MODE, 0); 117 + break; 118 + default: 119 + return -EINVAL; 120 + } 121 + return 0; 122 + } 123 + 124 + static unsigned int fan53555_get_mode(struct regulator_dev *rdev) 125 + { 126 + struct fan53555_device_info *di = rdev_get_drvdata(rdev); 127 + unsigned int val; 128 + int ret = 0; 129 + 130 + ret = regmap_read(di->regmap, di->vol_reg, &val); 131 + if (ret < 0) 132 + return ret; 133 + if (val & VSEL_MODE) 134 + return REGULATOR_MODE_FAST; 135 + else 136 + return REGULATOR_MODE_NORMAL; 137 + } 138 + 139 + static struct regulator_ops fan53555_regulator_ops = { 140 + .set_voltage_sel = regulator_set_voltage_sel_regmap, 141 + .get_voltage_sel = regulator_get_voltage_sel_regmap, 142 + .map_voltage = regulator_map_voltage_linear, 143 + .list_voltage = regulator_list_voltage_linear, 144 + .set_suspend_voltage = fan53555_set_suspend_voltage, 145 + .enable = regulator_enable_regmap, 146 + .disable = regulator_disable_regmap, 147 + .is_enabled = regulator_is_enabled_regmap, 148 + .set_mode = fan53555_set_mode, 149 + .get_mode = fan53555_get_mode, 150 + }; 151 + 152 + /* For 00,01,03,05 options: 153 + * VOUT = 0.60V + NSELx * 10mV, from 0.60 to 1.23V. 154 + * For 04 option: 155 + * VOUT = 0.603V + NSELx * 12.826mV, from 0.603 to 1.411V. 156 + * */ 157 + static int fan53555_device_setup(struct fan53555_device_info *di, 158 + struct fan53555_platform_data *pdata) 159 + { 160 + unsigned int reg, data, mask; 161 + 162 + /* Setup voltage control register */ 163 + switch (pdata->sleep_vsel_id) { 164 + case FAN53555_VSEL_ID_0: 165 + di->sleep_reg = FAN53555_VSEL0; 166 + di->vol_reg = FAN53555_VSEL1; 167 + break; 168 + case FAN53555_VSEL_ID_1: 169 + di->sleep_reg = FAN53555_VSEL1; 170 + di->vol_reg = FAN53555_VSEL0; 171 + break; 172 + default: 173 + dev_err(di->dev, "Invalid VSEL ID!\n"); 174 + return -EINVAL; 175 + } 176 + /* Init voltage range and step */ 177 + switch (di->chip_id) { 178 + case FAN53555_CHIP_ID_00: 179 + case FAN53555_CHIP_ID_01: 180 + case FAN53555_CHIP_ID_03: 181 + case FAN53555_CHIP_ID_05: 182 + di->vsel_min = 600000; 183 + di->vsel_max = 1230000; 184 + di->vsel_step = 10000; 185 + break; 186 + case FAN53555_CHIP_ID_04: 187 + di->vsel_min = 603000; 188 + di->vsel_max = 1411000; 189 + di->vsel_step = 12826; 190 + break; 191 + default: 192 + dev_err(di->dev, 193 + "Chip ID[%d]\n not supported!\n", di->chip_id); 194 + return -EINVAL; 195 + } 196 + /* Init slew rate */ 197 + if (pdata->slew_rate & 0x7) 198 + di->slew_rate = pdata->slew_rate; 199 + else 200 + di->slew_rate = FAN53555_SLEW_RATE_64MV; 201 + reg = FAN53555_CONTROL; 202 + data = di->slew_rate << CTL_SLEW_SHIFT; 203 + mask = CTL_SLEW_MASK; 204 + return regmap_update_bits(di->regmap, reg, mask, data); 205 + } 206 + 207 + static int fan53555_regulator_register(struct fan53555_device_info *di, 208 + struct regulator_config *config) 209 + { 210 + struct regulator_desc *rdesc = &di->desc; 211 + 212 + rdesc->name = "fan53555-reg"; 213 + rdesc->ops = &fan53555_regulator_ops; 214 + rdesc->type = REGULATOR_VOLTAGE; 215 + rdesc->n_voltages = FAN53555_NVOLTAGES; 216 + rdesc->enable_reg = di->vol_reg; 217 + rdesc->enable_mask = VSEL_BUCK_EN; 218 + rdesc->min_uV = di->vsel_min; 219 + rdesc->uV_step = di->vsel_step; 220 + rdesc->vsel_reg = di->vol_reg; 221 + rdesc->vsel_mask = VSEL_NSEL_MASK; 222 + rdesc->owner = THIS_MODULE; 223 + 224 + di->rdev = regulator_register(&di->desc, config); 225 + if (IS_ERR(di->rdev)) 226 + return PTR_ERR(di->rdev); 227 + return 0; 228 + 229 + } 230 + 231 + static struct regmap_config fan53555_regmap_config = { 232 + .reg_bits = 8, 233 + .val_bits = 8, 234 + }; 235 + 236 + static int __devinit fan53555_regulator_probe(struct i2c_client *client, 237 + const struct i2c_device_id *id) 238 + { 239 + struct fan53555_device_info *di; 240 + struct fan53555_platform_data *pdata; 241 + struct regulator_config config = { }; 242 + unsigned int val; 243 + int ret; 244 + 245 + pdata = client->dev.platform_data; 246 + if (!pdata || !pdata->regulator) { 247 + dev_err(&client->dev, "Platform data not found!\n"); 248 + return -ENODEV; 249 + } 250 + 251 + di = devm_kzalloc(&client->dev, sizeof(struct fan53555_device_info), 252 + GFP_KERNEL); 253 + if (!di) { 254 + dev_err(&client->dev, "Failed to allocate device info data!\n"); 255 + return -ENOMEM; 256 + } 257 + di->regmap = devm_regmap_init_i2c(client, &fan53555_regmap_config); 258 + if (IS_ERR(di->regmap)) { 259 + dev_err(&client->dev, "Failed to allocate regmap!\n"); 260 + return PTR_ERR(di->regmap); 261 + } 262 + di->dev = &client->dev; 263 + di->regulator = pdata->regulator; 264 + i2c_set_clientdata(client, di); 265 + /* Get chip ID */ 266 + ret = regmap_read(di->regmap, FAN53555_ID1, &val); 267 + if (ret < 0) { 268 + dev_err(&client->dev, "Failed to get chip ID!\n"); 269 + return -ENODEV; 270 + } 271 + di->chip_id = val & DIE_ID; 272 + /* Get chip revision */ 273 + ret = regmap_read(di->regmap, FAN53555_ID2, &val); 274 + if (ret < 0) { 275 + dev_err(&client->dev, "Failed to get chip Rev!\n"); 276 + return -ENODEV; 277 + } 278 + di->chip_rev = val & DIE_REV; 279 + dev_info(&client->dev, "FAN53555 Option[%d] Rev[%d] Detected!\n", 280 + di->chip_id, di->chip_rev); 281 + /* Device init */ 282 + ret = fan53555_device_setup(di, pdata); 283 + if (ret < 0) { 284 + dev_err(&client->dev, "Failed to setup device!\n"); 285 + return ret; 286 + } 287 + /* Register regulator */ 288 + config.dev = di->dev; 289 + config.init_data = di->regulator; 290 + config.regmap = di->regmap; 291 + config.driver_data = di; 292 + ret = fan53555_regulator_register(di, &config); 293 + if (ret < 0) 294 + dev_err(&client->dev, "Failed to register regulator!\n"); 295 + return ret; 296 + 297 + } 298 + 299 + static int __devexit fan53555_regulator_remove(struct i2c_client *client) 300 + { 301 + struct fan53555_device_info *di = i2c_get_clientdata(client); 302 + 303 + regulator_unregister(di->rdev); 304 + return 0; 305 + } 306 + 307 + static const struct i2c_device_id fan53555_id[] = { 308 + {"fan53555", -1}, 309 + { }, 310 + }; 311 + 312 + static struct i2c_driver fan53555_regulator_driver = { 313 + .driver = { 314 + .name = "fan53555-regulator", 315 + }, 316 + .probe = fan53555_regulator_probe, 317 + .remove = __devexit_p(fan53555_regulator_remove), 318 + .id_table = fan53555_id, 319 + }; 320 + 321 + module_i2c_driver(fan53555_regulator_driver); 322 + 323 + MODULE_AUTHOR("Yunfan Zhang <yfzhang@marvell.com>"); 324 + MODULE_DESCRIPTION("FAN53555 regulator driver"); 325 + MODULE_LICENSE("GPL v2");
+60
include/linux/regulator/fan53555.h
··· 1 + /* 2 + * fan53555.h - Fairchild Regulator FAN53555 Driver 3 + * 4 + * Copyright (C) 2012 Marvell Technology Ltd. 5 + * Yunfan Zhang <yfzhang@marvell.com> 6 + * 7 + * This package is free software; you can redistribute it and/or modify 8 + * it under the terms of the GNU General Public License version 2 as 9 + * published by the Free Software Foundation. 10 + * 11 + */ 12 + 13 + #ifndef __FAN53555_H__ 14 + 15 + /* VSEL ID */ 16 + enum { 17 + FAN53555_VSEL_ID_0 = 0, 18 + FAN53555_VSEL_ID_1, 19 + }; 20 + 21 + /* Transition slew rate limiting from a low to high voltage. 22 + * ----------------------- 23 + * Bin |Slew Rate(mV/uS) 24 + * ------|---------------- 25 + * 000 | 64.00 26 + * ------|---------------- 27 + * 001 | 32.00 28 + * ------|---------------- 29 + * 010 | 16.00 30 + * ------|---------------- 31 + * 011 | 8.00 32 + * ------|---------------- 33 + * 100 | 4.00 34 + * ------|---------------- 35 + * 101 | 2.00 36 + * ------|---------------- 37 + * 110 | 1.00 38 + * ------|---------------- 39 + * 111 | 0.50 40 + * ----------------------- 41 + */ 42 + enum { 43 + FAN53555_SLEW_RATE_64MV = 0, 44 + FAN53555_SLEW_RATE_32MV, 45 + FAN53555_SLEW_RATE_16MV, 46 + FAN53555_SLEW_RATE_8MV, 47 + FAN53555_SLEW_RATE_4MV, 48 + FAN53555_SLEW_RATE_2MV, 49 + FAN53555_SLEW_RATE_1MV, 50 + FAN53555_SLEW_RATE_0_5MV, 51 + }; 52 + 53 + struct fan53555_platform_data { 54 + struct regulator_init_data *regulator; 55 + unsigned int slew_rate; 56 + /* Sleep VSEL ID */ 57 + unsigned int sleep_vsel_id; 58 + }; 59 + 60 + #endif /* __FAN53555_H__ */