diff options
| author | Graeme Gregory <gg@slimlogic.co.uk> | 2011-05-02 17:20:08 -0400 |
|---|---|---|
| committer | Liam Girdwood <lrg@slimlogic.co.uk> | 2011-05-27 05:49:08 -0400 |
| commit | 518fb721de3685c8326e72746151b534a241feda (patch) | |
| tree | 9791db510544af58eadd2f5f2754724df292be9a /drivers/regulator | |
| parent | e3471bdc2784ee20a0d636c5904200c2d1148ef9 (diff) | |
TPS65910: Add tps65910 regulator driver
The regulator module consists of 3 DCDCs and 8 LDOs. The output
voltages are configurable and are meant to supply power to the
main processor and other components
Signed-off-by: Graeme Gregory <gg@slimlogic.co.uk>
Signed-off-by: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>
Acked-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Signed-off-by: Liam Girdwood <lrg@slimlogic.co.uk>
Diffstat (limited to 'drivers/regulator')
| -rw-r--r-- | drivers/regulator/Kconfig | 6 | ||||
| -rw-r--r-- | drivers/regulator/Makefile | 1 | ||||
| -rw-r--r-- | drivers/regulator/tps65910-regulator.c | 705 |
3 files changed, 712 insertions, 0 deletions
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index f0b13a0d185..d7ed20f293d 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig | |||
| @@ -297,5 +297,11 @@ config REGULATOR_TPS6524X | |||
| 297 | serial interface currently supported on the sequencer serial | 297 | serial interface currently supported on the sequencer serial |
| 298 | port controller. | 298 | port controller. |
| 299 | 299 | ||
| 300 | config REGULATOR_TPS65910 | ||
| 301 | tristate "TI TPS65910 Power Regulator" | ||
| 302 | depends on MFD_TPS65910 | ||
| 303 | help | ||
| 304 | This driver supports TPS65910 voltage regulator chips. | ||
| 305 | |||
| 300 | endif | 306 | endif |
| 301 | 307 | ||
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 165ff5371e9..3932d2ec38f 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile | |||
| @@ -42,5 +42,6 @@ obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o | |||
| 42 | obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o | 42 | obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o |
| 43 | obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o | 43 | obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o |
| 44 | obj-$(CONFIG_REGULATOR_DB8500_PRCMU) += db8500-prcmu.o | 44 | obj-$(CONFIG_REGULATOR_DB8500_PRCMU) += db8500-prcmu.o |
| 45 | obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o | ||
| 45 | 46 | ||
| 46 | ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG | 47 | ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG |
diff --git a/drivers/regulator/tps65910-regulator.c b/drivers/regulator/tps65910-regulator.c new file mode 100644 index 00000000000..d461fa7906b --- /dev/null +++ b/drivers/regulator/tps65910-regulator.c | |||
| @@ -0,0 +1,705 @@ | |||
| 1 | /* | ||
| 2 | * tps65910.c -- TI tps65910 | ||
| 3 | * | ||
| 4 | * Copyright 2010 Texas Instruments Inc. | ||
| 5 | * | ||
| 6 | * Author: Graeme Gregory <gg@slimlogic.co.uk> | ||
| 7 | * Author: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk> | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify it | ||
| 10 | * under the terms of the GNU General Public License as published by the | ||
| 11 | * Free Software Foundation; either version 2 of the License, or (at your | ||
| 12 | * option) any later version. | ||
| 13 | * | ||
| 14 | */ | ||
| 15 | |||
| 16 | #include <linux/kernel.h> | ||
| 17 | #include <linux/module.h> | ||
| 18 | #include <linux/init.h> | ||
| 19 | #include <linux/err.h> | ||
| 20 | #include <linux/platform_device.h> | ||
| 21 | #include <linux/regulator/driver.h> | ||
| 22 | #include <linux/regulator/machine.h> | ||
| 23 | #include <linux/delay.h> | ||
| 24 | #include <linux/slab.h> | ||
| 25 | #include <linux/gpio.h> | ||
| 26 | #include <linux/mfd/tps65910.h> | ||
| 27 | |||
| 28 | #define TPS65910_REG_VRTC 0 | ||
| 29 | #define TPS65910_REG_VIO 1 | ||
| 30 | #define TPS65910_REG_VDD1 2 | ||
| 31 | #define TPS65910_REG_VDD2 3 | ||
| 32 | #define TPS65910_REG_VDD3 4 | ||
| 33 | #define TPS65910_REG_VDIG1 5 | ||
| 34 | #define TPS65910_REG_VDIG2 6 | ||
| 35 | #define TPS65910_REG_VPLL 7 | ||
| 36 | #define TPS65910_REG_VDAC 8 | ||
| 37 | #define TPS65910_REG_VAUX1 9 | ||
| 38 | #define TPS65910_REG_VAUX2 10 | ||
| 39 | #define TPS65910_REG_VAUX33 11 | ||
| 40 | #define TPS65910_REG_VMMC 12 | ||
| 41 | |||
| 42 | #define TPS65910_NUM_REGULATOR 13 | ||
| 43 | |||
| 44 | #define TPS65910_SUPPLY_STATE_ENABLED 0x1 | ||
| 45 | |||
| 46 | /* supported VIO voltages in milivolts */ | ||
| 47 | static const u16 VIO_VSEL_table[] = { | ||
| 48 | 1500, 1800, 2500, 3300, | ||
| 49 | }; | ||
| 50 | |||
| 51 | /* supported VIO voltages in milivolts */ | ||
| 52 | static const u16 VDD3_VSEL_table[] = { | ||
| 53 | 5000, | ||
| 54 | }; | ||
| 55 | |||
| 56 | /* supported VDIG1 voltages in milivolts */ | ||
| 57 | static const u16 VDIG1_VSEL_table[] = { | ||
| 58 | 1200, 1500, 1800, 2700, | ||
| 59 | }; | ||
| 60 | |||
| 61 | /* supported VDIG2 voltages in milivolts */ | ||
| 62 | static const u16 VDIG2_VSEL_table[] = { | ||
| 63 | 1000, 1100, 1200, 1800, | ||
| 64 | }; | ||
| 65 | |||
| 66 | /* supported VPLL voltages in milivolts */ | ||
| 67 | static const u16 VPLL_VSEL_table[] = { | ||
| 68 | 1000, 1100, 1800, 2500, | ||
| 69 | }; | ||
| 70 | |||
| 71 | /* supported VDAC voltages in milivolts */ | ||
| 72 | static const u16 VDAC_VSEL_table[] = { | ||
| 73 | 1800, 2600, 2800, 2850, | ||
| 74 | }; | ||
| 75 | |||
| 76 | /* supported VAUX1 voltages in milivolts */ | ||
| 77 | static const u16 VAUX1_VSEL_table[] = { | ||
| 78 | 1800, 2500, 2800, 2850, | ||
| 79 | }; | ||
| 80 | |||
| 81 | /* supported VAUX2 voltages in milivolts */ | ||
| 82 | static const u16 VAUX2_VSEL_table[] = { | ||
| 83 | 1800, 2800, 2900, 3300, | ||
| 84 | }; | ||
| 85 | |||
| 86 | /* supported VAUX33 voltages in milivolts */ | ||
| 87 | static const u16 VAUX33_VSEL_table[] = { | ||
| 88 | 1800, 2000, 2800, 3300, | ||
| 89 | }; | ||
| 90 | |||
| 91 | /* supported VMMC voltages in milivolts */ | ||
| 92 | static const u16 VMMC_VSEL_table[] = { | ||
| 93 | 1800, 2800, 3000, 3300, | ||
| 94 | }; | ||
| 95 | |||
| 96 | struct tps_info { | ||
| 97 | const char *name; | ||
| 98 | unsigned min_uV; | ||
| 99 | unsigned max_uV; | ||
| 100 | u8 table_len; | ||
| 101 | const u16 *table; | ||
| 102 | }; | ||
| 103 | |||
| 104 | static struct tps_info tps65910_regs[] = { | ||
| 105 | { | ||
| 106 | .name = "VRTC", | ||
| 107 | }, | ||
| 108 | { | ||
| 109 | .name = "VIO", | ||
| 110 | .min_uV = 1500000, | ||
| 111 | .max_uV = 3300000, | ||
| 112 | .table_len = ARRAY_SIZE(VIO_VSEL_table), | ||
| 113 | .table = VIO_VSEL_table, | ||
| 114 | }, | ||
| 115 | { | ||
| 116 | .name = "VDD1", | ||
| 117 | .min_uV = 600000, | ||
| 118 | .max_uV = 4500000, | ||
| 119 | }, | ||
| 120 | { | ||
| 121 | .name = "VDD2", | ||
| 122 | .min_uV = 600000, | ||
| 123 | .max_uV = 4500000, | ||
| 124 | }, | ||
| 125 | { | ||
| 126 | .name = "VDD3", | ||
| 127 | .min_uV = 5000000, | ||
| 128 | .max_uV = 5000000, | ||
| 129 | .table_len = ARRAY_SIZE(VDD3_VSEL_table), | ||
| 130 | .table = VDD3_VSEL_table, | ||
| 131 | }, | ||
| 132 | { | ||
| 133 | .name = "VDIG1", | ||
| 134 | .min_uV = 1200000, | ||
| 135 | .max_uV = 2700000, | ||
| 136 | .table_len = ARRAY_SIZE(VDIG1_VSEL_table), | ||
| 137 | .table = VDIG1_VSEL_table, | ||
| 138 | }, | ||
| 139 | { | ||
| 140 | .name = "VDIG2", | ||
| 141 | .min_uV = 1000000, | ||
| 142 | .max_uV = 1800000, | ||
| 143 | .table_len = ARRAY_SIZE(VDIG2_VSEL_table), | ||
| 144 | .table = VDIG2_VSEL_table, | ||
| 145 | }, | ||
| 146 | { | ||
| 147 | .name = "VPLL", | ||
| 148 | .min_uV = 1000000, | ||
| 149 | .max_uV = 2500000, | ||
| 150 | .table_len = ARRAY_SIZE(VPLL_VSEL_table), | ||
| 151 | .table = VPLL_VSEL_table, | ||
| 152 | }, | ||
| 153 | { | ||
| 154 | .name = "VDAC", | ||
| 155 | .min_uV = 1800000, | ||
| 156 | .max_uV = 2850000, | ||
| 157 | .table_len = ARRAY_SIZE(VDAC_VSEL_table), | ||
| 158 | .table = VDAC_VSEL_table, | ||
| 159 | }, | ||
| 160 | { | ||
| 161 | .name = "VAUX1", | ||
| 162 | .min_uV = 1800000, | ||
| 163 | .max_uV = 2850000, | ||
| 164 | .table_len = ARRAY_SIZE(VAUX1_VSEL_table), | ||
| 165 | .table = VAUX1_VSEL_table, | ||
| 166 | }, | ||
| 167 | { | ||
| 168 | .name = "VAUX2", | ||
| 169 | .min_uV = 1800000, | ||
| 170 | .max_uV = 3300000, | ||
| 171 | .table_len = ARRAY_SIZE(VAUX2_VSEL_table), | ||
| 172 | .table = VAUX2_VSEL_table, | ||
| 173 | }, | ||
| 174 | { | ||
| 175 | .name = "VAUX33", | ||
| 176 | .min_uV = 1800000, | ||
| 177 | .max_uV = 3300000, | ||
| 178 | .table_len = ARRAY_SIZE(VAUX33_VSEL_table), | ||
| 179 | .table = VAUX33_VSEL_table, | ||
| 180 | }, | ||
| 181 | { | ||
| 182 | .name = "VMMC", | ||
| 183 | .min_uV = 1800000, | ||
| 184 | .max_uV = 3300000, | ||
| 185 | .table_len = ARRAY_SIZE(VMMC_VSEL_table), | ||
| 186 | .table = VMMC_VSEL_table, | ||
| 187 | }, | ||
| 188 | }; | ||
| 189 | |||
| 190 | struct tps65910_reg { | ||
| 191 | struct regulator_desc desc[TPS65910_NUM_REGULATOR]; | ||
| 192 | struct tps65910 *mfd; | ||
| 193 | struct regulator_dev *rdev[TPS65910_NUM_REGULATOR]; | ||
| 194 | struct tps_info *info[TPS65910_NUM_REGULATOR]; | ||
| 195 | struct mutex mutex; | ||
| 196 | int mode; | ||
| 197 | }; | ||
| 198 | |||
| 199 | static inline int tps65910_read(struct tps65910_reg *pmic, u8 reg) | ||
| 200 | { | ||
| 201 | u8 val; | ||
| 202 | int err; | ||
| 203 | |||
| 204 | err = pmic->mfd->read(pmic->mfd, reg, 1, &val); | ||
| 205 | if (err) | ||
| 206 | return err; | ||
| 207 | |||
| 208 | return val; | ||
| 209 | } | ||
| 210 | |||
| 211 | static inline int tps65910_write(struct tps65910_reg *pmic, u8 reg, u8 val) | ||
| 212 | { | ||
| 213 | return pmic->mfd->write(pmic->mfd, reg, 1, &val); | ||
| 214 | } | ||
| 215 | |||
| 216 | static int tps65910_modify_bits(struct tps65910_reg *pmic, u8 reg, | ||
| 217 | u8 set_mask, u8 clear_mask) | ||
| 218 | { | ||
| 219 | int err, data; | ||
| 220 | |||
| 221 | mutex_lock(&pmic->mutex); | ||
| 222 | |||
| 223 | data = tps65910_read(pmic, reg); | ||
| 224 | if (data < 0) { | ||
| 225 | dev_err(pmic->mfd->dev, "Read from reg 0x%x failed\n", reg); | ||
| 226 | err = data; | ||
| 227 | goto out; | ||
| 228 | } | ||
| 229 | |||
| 230 | data &= ~clear_mask; | ||
| 231 | data |= set_mask; | ||
| 232 | err = tps65910_write(pmic, reg, data); | ||
| 233 | if (err) | ||
| 234 | dev_err(pmic->mfd->dev, "Write for reg 0x%x failed\n", reg); | ||
| 235 | |||
| 236 | out: | ||
| 237 | mutex_unlock(&pmic->mutex); | ||
| 238 | return err; | ||
| 239 | } | ||
| 240 | |||
| 241 | static int tps65910_reg_read(struct tps65910_reg *pmic, u8 reg) | ||
| 242 | { | ||
| 243 | int data; | ||
| 244 | |||
| 245 | mutex_lock(&pmic->mutex); | ||
| 246 | |||
| 247 | data = tps65910_read(pmic, reg); | ||
| 248 | if (data < 0) | ||
| 249 | dev_err(pmic->mfd->dev, "Read from reg 0x%x failed\n", reg); | ||
| 250 | |||
| 251 | mutex_unlock(&pmic->mutex); | ||
| 252 | return data; | ||
| 253 | } | ||
| 254 | |||
| 255 | static int tps65910_reg_write(struct tps65910_reg *pmic, u8 reg, u8 val) | ||
| 256 | { | ||
| 257 | int err; | ||
| 258 | |||
| 259 | mutex_lock(&pmic->mutex); | ||
| 260 | |||
| 261 | err = tps65910_write(pmic, reg, val); | ||
| 262 | if (err < 0) | ||
| 263 | dev_err(pmic->mfd->dev, "Write for reg 0x%x failed\n", reg); | ||
| 264 | |||
| 265 | mutex_unlock(&pmic->mutex); | ||
| 266 | return err; | ||
| 267 | } | ||
| 268 | |||
| 269 | static int tps65910_get_ctrl_register(int id) | ||
| 270 | { | ||
| 271 | switch (id) { | ||
| 272 | case TPS65910_REG_VRTC: | ||
| 273 | return TPS65910_VRTC; | ||
| 274 | case TPS65910_REG_VIO: | ||
| 275 | return TPS65910_VIO; | ||
| 276 | case TPS65910_REG_VDD1: | ||
| 277 | return TPS65910_VDD1; | ||
| 278 | case TPS65910_REG_VDD2: | ||
| 279 | return TPS65910_VDD2; | ||
| 280 | case TPS65910_REG_VDD3: | ||
| 281 | return TPS65910_VDD3; | ||
| 282 | case TPS65910_REG_VDIG1: | ||
| 283 | return TPS65910_VDIG1; | ||
| 284 | case TPS65910_REG_VDIG2: | ||
| 285 | return TPS65910_VDIG2; | ||
| 286 | case TPS65910_REG_VPLL: | ||
| 287 | return TPS65910_VPLL; | ||
| 288 | case TPS65910_REG_VDAC: | ||
| 289 | return TPS65910_VDAC; | ||
| 290 | case TPS65910_REG_VAUX1: | ||
| 291 | return TPS65910_VAUX1; | ||
| 292 | case TPS65910_REG_VAUX2: | ||
| 293 | return TPS65910_VAUX2; | ||
| 294 | case TPS65910_REG_VAUX33: | ||
| 295 | return TPS65910_VAUX33; | ||
| 296 | case TPS65910_REG_VMMC: | ||
| 297 | return TPS65910_VMMC; | ||
| 298 | default: | ||
| 299 | return -EINVAL; | ||
| 300 | } | ||
| 301 | } | ||
| 302 | |||
| 303 | static int tps65910_is_enabled(struct regulator_dev *dev) | ||
| 304 | { | ||
| 305 | struct tps65910_reg *pmic = rdev_get_drvdata(dev); | ||
| 306 | int reg, value, id = rdev_get_id(dev); | ||
| 307 | |||
| 308 | reg = tps65910_get_ctrl_register(id); | ||
| 309 | if (reg < 0) | ||
| 310 | return reg; | ||
| 311 | |||
| 312 | value = tps65910_reg_read(pmic, reg); | ||
| 313 | if (value < 0) | ||
| 314 | return value; | ||
| 315 | |||
| 316 | return value & TPS65910_SUPPLY_STATE_ENABLED; | ||
| 317 | } | ||
| 318 | |||
| 319 | static int tps65910_enable(struct regulator_dev *dev) | ||
| 320 | { | ||
| 321 | struct tps65910_reg *pmic = rdev_get_drvdata(dev); | ||
| 322 | struct tps65910 *mfd = pmic->mfd; | ||
| 323 | int reg, id = rdev_get_id(dev); | ||
| 324 | |||
| 325 | reg = tps65910_get_ctrl_register(id); | ||
| 326 | if (reg < 0) | ||
| 327 | return reg; | ||
| 328 | |||
| 329 | return tps65910_set_bits(mfd, reg, TPS65910_SUPPLY_STATE_ENABLED); | ||
| 330 | } | ||
| 331 | |||
| 332 | static int tps65910_disable(struct regulator_dev *dev) | ||
| 333 | { | ||
| 334 | struct tps65910_reg *pmic = rdev_get_drvdata(dev); | ||
| 335 | struct tps65910 *mfd = pmic->mfd; | ||
| 336 | int reg, id = rdev_get_id(dev); | ||
| 337 | |||
| 338 | reg = tps65910_get_ctrl_register(id); | ||
| 339 | if (reg < 0) | ||
| 340 | return reg; | ||
| 341 | |||
| 342 | return tps65910_clear_bits(mfd, reg, TPS65910_SUPPLY_STATE_ENABLED); | ||
| 343 | } | ||
| 344 | |||
| 345 | |||
| 346 | static int tps65910_set_mode(struct regulator_dev *dev, unsigned int mode) | ||
| 347 | { | ||
| 348 | struct tps65910_reg *pmic = rdev_get_drvdata(dev); | ||
| 349 | struct tps65910 *mfd = pmic->mfd; | ||
| 350 | int reg, value, id = rdev_get_id(dev); | ||
| 351 | reg = tps65910_get_ctrl_register(id); | ||
| 352 | if (reg < 0) | ||
| 353 | return reg; | ||
| 354 | |||
| 355 | switch (mode) { | ||
| 356 | case REGULATOR_MODE_NORMAL: | ||
| 357 | return tps65910_modify_bits(pmic, reg, LDO_ST_ON_BIT, | ||
| 358 | LDO_ST_MODE_BIT); | ||
| 359 | case REGULATOR_MODE_IDLE: | ||
| 360 | value = LDO_ST_ON_BIT | LDO_ST_MODE_BIT; | ||
| 361 | return tps65910_set_bits(mfd, reg, value); | ||
| 362 | case REGULATOR_MODE_STANDBY: | ||
| 363 | return tps65910_clear_bits(mfd, reg, LDO_ST_ON_BIT); | ||
| 364 | } | ||
| 365 | |||
| 366 | return -EINVAL; | ||
| 367 | } | ||
| 368 | |||
| 369 | static unsigned int tps65910_get_mode(struct regulator_dev *dev) | ||
| 370 | { | ||
| 371 | struct tps65910_reg *pmic = rdev_get_drvdata(dev); | ||
| 372 | int reg, value, id = rdev_get_id(dev); | ||
| 373 | |||
| 374 | reg = tps65910_get_ctrl_register(id); | ||
| 375 | if (reg < 0) | ||
| 376 | return reg; | ||
| 377 | |||
| 378 | value = tps65910_reg_read(pmic, reg); | ||
| 379 | if (value < 0) | ||
| 380 | return value; | ||
| 381 | |||
| 382 | if (value & LDO_ST_ON_BIT) | ||
| 383 | return REGULATOR_MODE_STANDBY; | ||
| 384 | else if (value & LDO_ST_MODE_BIT) | ||
| 385 | return REGULATOR_MODE_IDLE; | ||
| 386 | else | ||
| 387 | return REGULATOR_MODE_NORMAL; | ||
| 388 | } | ||
| 389 | |||
| 390 | static int tps65910_get_voltage_dcdc(struct regulator_dev *dev) | ||
| 391 | { | ||
| 392 | struct tps65910_reg *pmic = rdev_get_drvdata(dev); | ||
| 393 | int id = rdev_get_id(dev), voltage = 0; | ||
| 394 | int opvsel = 0, srvsel = 0, mult = 0, sr = 0; | ||
| 395 | |||
| 396 | switch (id) { | ||
| 397 | case TPS65910_REG_VDD1: | ||
| 398 | opvsel = tps65910_reg_read(pmic, TPS65910_VDD1_OP); | ||
| 399 | mult = tps65910_reg_read(pmic, TPS65910_VDD1); | ||
| 400 | mult = (mult & VDD1_VGAIN_SEL_MASK) >> VDD1_VGAIN_SEL_SHIFT; | ||
| 401 | srvsel = tps65910_reg_read(pmic, TPS65910_VDD1_SR); | ||
| 402 | sr = opvsel & VDD1_OP_CMD_MASK; | ||
| 403 | opvsel &= VDD1_OP_SEL_MASK; | ||
| 404 | srvsel &= VDD1_SR_SEL_MASK; | ||
| 405 | break; | ||
| 406 | case TPS65910_REG_VDD2: | ||
| 407 | opvsel = tps65910_reg_read(pmic, TPS65910_VDD2_OP); | ||
| 408 | mult = tps65910_reg_read(pmic, TPS65910_VDD2); | ||
| 409 | mult = (mult & VDD2_VGAIN_SEL_MASK) >> VDD2_VGAIN_SEL_SHIFT; | ||
| 410 | srvsel = tps65910_reg_read(pmic, TPS65910_VDD2_SR); | ||
| 411 | sr = opvsel & VDD2_OP_CMD_MASK; | ||
| 412 | opvsel &= VDD2_OP_SEL_MASK; | ||
| 413 | srvsel &= VDD2_SR_SEL_MASK; | ||
| 414 | break; | ||
| 415 | } | ||
| 416 | |||
| 417 | /* multiplier 0 == 1 but 2,3 normal */ | ||
| 418 | if (!mult) | ||
| 419 | mult=1; | ||
| 420 | |||
| 421 | if (sr) { | ||
| 422 | /* Valid range is 3-75 so normalise */ | ||
| 423 | if (srvsel < 3) srvsel = 3; | ||
| 424 | if (srvsel > 75) srvsel = 75; | ||
| 425 | srvsel -= 3; | ||
| 426 | |||
| 427 | voltage = (srvsel * VDD1_2_OFFSET + VDD1_2_MIN_VOLT) * 100; | ||
| 428 | } else { | ||
| 429 | |||
| 430 | /* Valid range is 3-75 so normalise */ | ||
| 431 | if (opvsel < 3) opvsel = 3; | ||
| 432 | if (opvsel > 75) opvsel = 75; | ||
| 433 | opvsel -= 3; | ||
| 434 | |||
| 435 | voltage = (opvsel * VDD1_2_OFFSET + VDD1_2_MIN_VOLT) * 100; | ||
| 436 | } | ||
| 437 | |||
| 438 | voltage *= mult; | ||
| 439 | |||
| 440 | return voltage; | ||
| 441 | } | ||
| 442 | |||
| 443 | static int tps65910_get_voltage(struct regulator_dev *dev) | ||
| 444 | { | ||
| 445 | struct tps65910_reg *pmic = rdev_get_drvdata(dev); | ||
| 446 | int reg, value, id = rdev_get_id(dev), voltage = 0; | ||
| 447 | |||
| 448 | reg = tps65910_get_ctrl_register(id); | ||
| 449 | if (reg < 0) | ||
| 450 | return reg; | ||
| 451 | |||
| 452 | value = tps65910_reg_read(pmic, reg); | ||
| 453 | if (value < 0) | ||
| 454 | return value; | ||
| 455 | |||
| 456 | switch (id) { | ||
| 457 | case TPS65910_REG_VIO: | ||
| 458 | case TPS65910_REG_VDIG1: | ||
| 459 | case TPS65910_REG_VDIG2: | ||
| 460 | case TPS65910_REG_VPLL: | ||
| 461 | case TPS65910_REG_VDAC: | ||
| 462 | case TPS65910_REG_VAUX1: | ||
| 463 | case TPS65910_REG_VAUX2: | ||
| 464 | case TPS65910_REG_VAUX33: | ||
| 465 | case TPS65910_REG_VMMC: | ||
| 466 | value &= LDO_SEL_MASK; | ||
| 467 | value >>= LDO_SEL_SHIFT; | ||
| 468 | break; | ||
| 469 | default: | ||
| 470 | return -EINVAL; | ||
| 471 | } | ||
| 472 | |||
| 473 | voltage = pmic->info[id]->table[value] * 1000; | ||
| 474 | |||
| 475 | return voltage; | ||
| 476 | } | ||
| 477 | |||
| 478 | static int tps65910_get_voltage_vdd3(struct regulator_dev *dev) | ||
| 479 | { | ||
| 480 | return 5 * 1000 * 1000; | ||
| 481 | } | ||
| 482 | |||
| 483 | static int tps65910_set_voltage_dcdc(struct regulator_dev *dev, | ||
| 484 | unsigned selector) | ||
| 485 | { | ||
| 486 | struct tps65910_reg *pmic = rdev_get_drvdata(dev); | ||
| 487 | int id = rdev_get_id(dev), vsel; | ||
| 488 | int dcdc_mult; | ||
| 489 | |||
| 490 | /* Split vsel into appropriate registers */ | ||
| 491 | dcdc_mult = (selector / VDD1_2_NUM_VOLTS) + 1; | ||
| 492 | if (dcdc_mult == 1) dcdc_mult--; | ||
| 493 | |||
| 494 | vsel = (selector % VDD1_2_NUM_VOLTS) + 3; | ||
| 495 | |||
| 496 | if (id == TPS65910_REG_VDD1) { | ||
| 497 | tps65910_modify_bits(pmic, TPS65910_VDD1, | ||
| 498 | (dcdc_mult << VDD1_VGAIN_SEL_SHIFT), | ||
| 499 | VDD1_VGAIN_SEL_MASK); | ||
| 500 | tps65910_reg_write(pmic, TPS65910_VDD1_OP, vsel); | ||
| 501 | } else { | ||
| 502 | tps65910_modify_bits(pmic, TPS65910_VDD2, | ||
| 503 | (dcdc_mult << VDD2_VGAIN_SEL_SHIFT), | ||
| 504 | VDD1_VGAIN_SEL_MASK); | ||
| 505 | tps65910_reg_write(pmic, TPS65910_VDD2_OP, vsel); | ||
| 506 | } | ||
| 507 | |||
| 508 | return 0; | ||
| 509 | } | ||
| 510 | |||
| 511 | static int tps65910_set_voltage(struct regulator_dev *dev, unsigned selector) | ||
| 512 | { | ||
| 513 | struct tps65910_reg *pmic = rdev_get_drvdata(dev); | ||
| 514 | int reg, id = rdev_get_id(dev); | ||
| 515 | |||
| 516 | reg = tps65910_get_ctrl_register(id); | ||
| 517 | if (reg < 0) | ||
| 518 | return reg; | ||
| 519 | |||
| 520 | switch (id) { | ||
| 521 | case TPS65910_REG_VIO: | ||
| 522 | case TPS65910_REG_VDIG1: | ||
| 523 | case TPS65910_REG_VDIG2: | ||
| 524 | case TPS65910_REG_VPLL: | ||
| 525 | case TPS65910_REG_VDAC: | ||
| 526 | case TPS65910_REG_VAUX1: | ||
| 527 | case TPS65910_REG_VAUX2: | ||
| 528 | case TPS65910_REG_VAUX33: | ||
| 529 | case TPS65910_REG_VMMC: | ||
| 530 | return tps65910_modify_bits(pmic, reg, | ||
| 531 | (selector << LDO_SEL_SHIFT), LDO_SEL_MASK); | ||
| 532 | } | ||
| 533 | |||
| 534 | return -EINVAL; | ||
| 535 | } | ||
| 536 | |||
| 537 | static int tps65910_list_voltage_dcdc(struct regulator_dev *dev, | ||
| 538 | unsigned selector) | ||
| 539 | { | ||
| 540 | int mult, volt; | ||
| 541 | |||
| 542 | mult = (selector / VDD1_2_NUM_VOLTS) + 1; | ||
| 543 | |||
| 544 | volt = VDD1_2_MIN_VOLT + (selector % VDD1_2_NUM_VOLTS) * VDD1_2_OFFSET; | ||
| 545 | |||
| 546 | return volt * 100 * mult; | ||
| 547 | } | ||
| 548 | |||
| 549 | static int tps65910_list_voltage(struct regulator_dev *dev, | ||
| 550 | unsigned selector) | ||
| 551 | { | ||
| 552 | struct tps65910_reg *pmic = rdev_get_drvdata(dev); | ||
| 553 | int id = rdev_get_id(dev), voltage; | ||
| 554 | |||
| 555 | if (id < TPS65910_REG_VIO || id > TPS65910_REG_VMMC) | ||
| 556 | return -EINVAL; | ||
| 557 | |||
| 558 | if (selector >= pmic->info[id]->table_len) | ||
| 559 | return -EINVAL; | ||
| 560 | else | ||
| 561 | voltage = pmic->info[id]->table[selector] * 1000; | ||
| 562 | |||
| 563 | return voltage; | ||
| 564 | } | ||
| 565 | |||
| 566 | /* Regulator ops (except VRTC) */ | ||
| 567 | static struct regulator_ops tps65910_ops_dcdc = { | ||
| 568 | .is_enabled = tps65910_is_enabled, | ||
| 569 | .enable = tps65910_enable, | ||
| 570 | .disable = tps65910_disable, | ||
| 571 | .set_mode = tps65910_set_mode, | ||
| 572 | .get_mode = tps65910_get_mode, | ||
| 573 | .get_voltage = tps65910_get_voltage_dcdc, | ||
| 574 | .set_voltage_sel = tps65910_set_voltage_dcdc, | ||
| 575 | .list_voltage = tps65910_list_voltage_dcdc, | ||
| 576 | }; | ||
| 577 | |||
| 578 | static struct regulator_ops tps65910_ops_vdd3 = { | ||
| 579 | .is_enabled = tps65910_is_enabled, | ||
| 580 | .enable = tps65910_enable, | ||
| 581 | .disable = tps65910_disable, | ||
| 582 | .set_mode = tps65910_set_mode, | ||
| 583 | .get_mode = tps65910_get_mode, | ||
| 584 | .get_voltage = tps65910_get_voltage_vdd3, | ||
| 585 | .list_voltage = tps65910_list_voltage, | ||
| 586 | }; | ||
| 587 | |||
| 588 | static struct regulator_ops tps65910_ops = { | ||
| 589 | .is_enabled = tps65910_is_enabled, | ||
| 590 | .enable = tps65910_enable, | ||
| 591 | .disable = tps65910_disable, | ||
| 592 | .set_mode = tps65910_set_mode, | ||
| 593 | .get_mode = tps65910_get_mode, | ||
| 594 | .get_voltage = tps65910_get_voltage, | ||
| 595 | .set_voltage_sel = tps65910_set_voltage, | ||
| 596 | .list_voltage = tps65910_list_voltage, | ||
| 597 | }; | ||
| 598 | |||
| 599 | static __devinit int tps65910_probe(struct platform_device *pdev) | ||
| 600 | { | ||
| 601 | struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent); | ||
| 602 | struct tps_info *info = tps65910_regs; | ||
| 603 | struct regulator_init_data *reg_data; | ||
| 604 | struct regulator_dev *rdev; | ||
| 605 | struct tps65910_reg *pmic; | ||
| 606 | struct tps65910_board *pmic_plat_data; | ||
| 607 | static int desc_id; | ||
| 608 | int i, err; | ||
| 609 | |||
| 610 | pmic_plat_data = dev_get_platdata(tps65910->dev); | ||
| 611 | if (!pmic_plat_data) | ||
| 612 | return -EINVAL; | ||
| 613 | |||
| 614 | reg_data = pmic_plat_data->tps65910_pmic_init_data; | ||
| 615 | |||
| 616 | pmic = kzalloc(sizeof(*pmic), GFP_KERNEL); | ||
| 617 | if (!pmic) | ||
| 618 | return -ENOMEM; | ||
| 619 | |||
| 620 | mutex_init(&pmic->mutex); | ||
| 621 | pmic->mfd = tps65910; | ||
| 622 | platform_set_drvdata(pdev, pmic); | ||
| 623 | |||
| 624 | /* Give control of all register to control port */ | ||
| 625 | tps65910_set_bits(pmic->mfd, TPS65910_DEVCTRL, | ||
| 626 | DEVCTRL_SR_CTL_I2C_SEL_MASK); | ||
| 627 | |||
| 628 | for (i = 0; i < TPS65910_NUM_REGULATOR; i++, info++, reg_data++) { | ||
| 629 | /* Register the regulators */ | ||
| 630 | pmic->info[i] = info; | ||
| 631 | |||
| 632 | pmic->desc[i].name = info->name; | ||
| 633 | pmic->desc[i].id = desc_id++; | ||
| 634 | pmic->desc[i].n_voltages = info->table_len; | ||
| 635 | |||
| 636 | if ((i == TPS65910_REG_VDD1) || (i == TPS65910_REG_VDD2)) | ||
| 637 | pmic->desc[i].ops = &tps65910_ops_dcdc; | ||
| 638 | else if (i == TPS65910_REG_VDD3) | ||
| 639 | pmic->desc[i].ops = &tps65910_ops_vdd3; | ||
| 640 | else | ||
| 641 | pmic->desc[i].ops = &tps65910_ops; | ||
| 642 | |||
| 643 | pmic->desc[i].type = REGULATOR_VOLTAGE; | ||
| 644 | pmic->desc[i].owner = THIS_MODULE; | ||
| 645 | |||
| 646 | rdev = regulator_register(&pmic->desc[i], | ||
| 647 | tps65910->dev, reg_data, pmic); | ||
| 648 | if (IS_ERR(rdev)) { | ||
| 649 | dev_err(tps65910->dev, | ||
| 650 | "failed to register %s regulator\n", | ||
| 651 | pdev->name); | ||
| 652 | err = PTR_ERR(rdev); | ||
| 653 | goto err; | ||
| 654 | } | ||
| 655 | |||
| 656 | /* Save regulator for cleanup */ | ||
| 657 | pmic->rdev[i] = rdev; | ||
| 658 | } | ||
| 659 | return 0; | ||
| 660 | |||
| 661 | err: | ||
| 662 | while (--i >= 0) | ||
| 663 | regulator_unregister(pmic->rdev[i]); | ||
| 664 | |||
| 665 | kfree(pmic); | ||
| 666 | return err; | ||
| 667 | } | ||
| 668 | |||
| 669 | static int __devexit tps65910_remove(struct platform_device *pdev) | ||
| 670 | { | ||
| 671 | struct tps65910_reg *tps65910_reg = platform_get_drvdata(pdev); | ||
| 672 | int i; | ||
| 673 | |||
| 674 | for (i = 0; i < TPS65910_NUM_REGULATOR; i++) | ||
| 675 | regulator_unregister(tps65910_reg->rdev[i]); | ||
| 676 | |||
| 677 | kfree(tps65910_reg); | ||
| 678 | return 0; | ||
| 679 | } | ||
| 680 | |||
| 681 | static struct platform_driver tps65910_driver = { | ||
| 682 | .driver = { | ||
| 683 | .name = "tps65910-pmic", | ||
| 684 | .owner = THIS_MODULE, | ||
| 685 | }, | ||
| 686 | .probe = tps65910_probe, | ||
| 687 | .remove = __devexit_p(tps65910_remove), | ||
| 688 | }; | ||
| 689 | |||
| 690 | static int __init tps65910_init(void) | ||
| 691 | { | ||
| 692 | return platform_driver_register(&tps65910_driver); | ||
| 693 | } | ||
| 694 | subsys_initcall(tps65910_init); | ||
| 695 | |||
| 696 | static void __exit tps65910_cleanup(void) | ||
| 697 | { | ||
| 698 | platform_driver_unregister(&tps65910_driver); | ||
| 699 | } | ||
| 700 | module_exit(tps65910_cleanup); | ||
| 701 | |||
| 702 | MODULE_AUTHOR("Graeme Gregory <gg@slimlogic.co.uk>"); | ||
| 703 | MODULE_DESCRIPTION("TPS6507x voltage regulator driver"); | ||
| 704 | MODULE_LICENSE("GPL v2"); | ||
| 705 | MODULE_ALIAS("platform:tps65910-pmic"); | ||
