blob: 08b3b41270a8189a813149531dc544652dc20a60 [file] [log] [blame]
Anuj Aggarwal30e65992009-08-21 00:39:31 +05301/*
2 * tps65023-regulator.c
3 *
4 * Supports TPS65023 Regulator
5 *
6 * Copyright (C) 2009 Texas Instrument Incorporated - http://www.ti.com/
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation version 2.
11 *
12 * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
13 * whether express or implied; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 */
17
18#include <linux/kernel.h>
19#include <linux/module.h>
20#include <linux/init.h>
21#include <linux/err.h>
22#include <linux/platform_device.h>
23#include <linux/regulator/driver.h>
24#include <linux/regulator/machine.h>
25#include <linux/i2c.h>
26#include <linux/delay.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090027#include <linux/slab.h>
Mark Brown90923352011-06-18 01:18:51 +010028#include <linux/regmap.h>
Anuj Aggarwal30e65992009-08-21 00:39:31 +053029
30/* Register definitions */
31#define TPS65023_REG_VERSION 0
32#define TPS65023_REG_PGOODZ 1
33#define TPS65023_REG_MASK 2
34#define TPS65023_REG_REG_CTRL 3
35#define TPS65023_REG_CON_CTRL 4
36#define TPS65023_REG_CON_CTRL2 5
37#define TPS65023_REG_DEF_CORE 6
38#define TPS65023_REG_DEFSLEW 7
39#define TPS65023_REG_LDO_CTRL 8
40
41/* PGOODZ bitfields */
42#define TPS65023_PGOODZ_PWRFAILZ BIT(7)
43#define TPS65023_PGOODZ_LOWBATTZ BIT(6)
44#define TPS65023_PGOODZ_VDCDC1 BIT(5)
45#define TPS65023_PGOODZ_VDCDC2 BIT(4)
46#define TPS65023_PGOODZ_VDCDC3 BIT(3)
47#define TPS65023_PGOODZ_LDO2 BIT(2)
48#define TPS65023_PGOODZ_LDO1 BIT(1)
49
50/* MASK bitfields */
51#define TPS65023_MASK_PWRFAILZ BIT(7)
52#define TPS65023_MASK_LOWBATTZ BIT(6)
53#define TPS65023_MASK_VDCDC1 BIT(5)
54#define TPS65023_MASK_VDCDC2 BIT(4)
55#define TPS65023_MASK_VDCDC3 BIT(3)
56#define TPS65023_MASK_LDO2 BIT(2)
57#define TPS65023_MASK_LDO1 BIT(1)
58
59/* REG_CTRL bitfields */
60#define TPS65023_REG_CTRL_VDCDC1_EN BIT(5)
61#define TPS65023_REG_CTRL_VDCDC2_EN BIT(4)
62#define TPS65023_REG_CTRL_VDCDC3_EN BIT(3)
63#define TPS65023_REG_CTRL_LDO2_EN BIT(2)
64#define TPS65023_REG_CTRL_LDO1_EN BIT(1)
65
Marcus Folkessonfc999b82011-08-04 13:33:49 +020066/* REG_CTRL2 bitfields */
67#define TPS65023_REG_CTRL2_GO BIT(7)
68#define TPS65023_REG_CTRL2_CORE_ADJ BIT(6)
69#define TPS65023_REG_CTRL2_DCDC2 BIT(2)
Marcus Folkessonf068ad82011-08-08 20:29:32 +020070#define TPS65023_REG_CTRL2_DCDC1 BIT(1)
71#define TPS65023_REG_CTRL2_DCDC3 BIT(0)
72
Anuj Aggarwal30e65992009-08-21 00:39:31 +053073/* LDO_CTRL bitfields */
74#define TPS65023_LDO_CTRL_LDOx_SHIFT(ldo_id) ((ldo_id)*4)
Axel Lin70618732012-03-26 13:46:44 +080075#define TPS65023_LDO_CTRL_LDOx_MASK(ldo_id) (0x0F << ((ldo_id)*4))
Anuj Aggarwal30e65992009-08-21 00:39:31 +053076
77/* Number of step-down converters available */
78#define TPS65023_NUM_DCDC 3
79/* Number of LDO voltage regulators available */
80#define TPS65023_NUM_LDO 2
81/* Number of total regulators available */
82#define TPS65023_NUM_REGULATOR (TPS65023_NUM_DCDC + TPS65023_NUM_LDO)
83
84/* DCDCs */
85#define TPS65023_DCDC_1 0
86#define TPS65023_DCDC_2 1
87#define TPS65023_DCDC_3 2
88/* LDOs */
89#define TPS65023_LDO_1 3
90#define TPS65023_LDO_2 4
91
92#define TPS65023_MAX_REG_ID TPS65023_LDO_2
93
94/* Supported voltage values for regulators */
Marcus Folkesson1c3ede02011-08-08 20:29:34 +020095static const u16 VCORE_VSEL_table[] = {
Anuj Aggarwal30e65992009-08-21 00:39:31 +053096 800, 825, 850, 875,
97 900, 925, 950, 975,
98 1000, 1025, 1050, 1075,
99 1100, 1125, 1150, 1175,
100 1200, 1225, 1250, 1275,
101 1300, 1325, 1350, 1375,
102 1400, 1425, 1450, 1475,
103 1500, 1525, 1550, 1600,
104};
105
Marcus Folkesson437afd22011-08-08 20:29:35 +0200106/* Supported voltage values for LDO regulators for tps65020 */
107static const u16 TPS65020_LDO1_VSEL_table[] = {
108 1000, 1050, 1100, 1300,
109 1800, 2500, 3000, 3300,
110};
Marcus Folkesson1c3ede02011-08-08 20:29:34 +0200111
Marcus Folkesson437afd22011-08-08 20:29:35 +0200112static const u16 TPS65020_LDO2_VSEL_table[] = {
113 1000, 1050, 1100, 1300,
114 1800, 2500, 3000, 3300,
115};
Marcus Folkesson1c3ede02011-08-08 20:29:34 +0200116
117/* Supported voltage values for LDO regulators
118 * for tps65021 and tps65023 */
119static const u16 TPS65023_LDO1_VSEL_table[] = {
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530120 1000, 1100, 1300, 1800,
121 2200, 2600, 2800, 3150,
122};
123
Marcus Folkesson1c3ede02011-08-08 20:29:34 +0200124static const u16 TPS65023_LDO2_VSEL_table[] = {
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530125 1050, 1200, 1300, 1800,
126 2500, 2800, 3000, 3300,
127};
128
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530129/* Regulator specific details */
130struct tps_info {
131 const char *name;
132 unsigned min_uV;
133 unsigned max_uV;
134 bool fixed;
135 u8 table_len;
136 const u16 *table;
137};
138
139/* PMIC details */
140struct tps_pmic {
141 struct regulator_desc desc[TPS65023_NUM_REGULATOR];
142 struct i2c_client *client;
143 struct regulator_dev *rdev[TPS65023_NUM_REGULATOR];
144 const struct tps_info *info[TPS65023_NUM_REGULATOR];
Mark Brown90923352011-06-18 01:18:51 +0100145 struct regmap *regmap;
Marcus Folkesson1c3ede02011-08-08 20:29:34 +0200146 u8 core_regulator;
147};
148
149/* Struct passed as driver data */
150struct tps_driver_data {
151 const struct tps_info *info;
152 u8 core_regulator;
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530153};
154
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530155static int tps65023_dcdc_is_enabled(struct regulator_dev *dev)
156{
157 struct tps_pmic *tps = rdev_get_drvdata(dev);
158 int data, dcdc = rdev_get_id(dev);
Jonghwan Choi43530b62011-11-07 08:16:04 +0900159 int ret;
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530160 u8 shift;
161
162 if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3)
163 return -EINVAL;
164
165 shift = TPS65023_NUM_REGULATOR - dcdc;
Jonghwan Choi43530b62011-11-07 08:16:04 +0900166 ret = regmap_read(tps->regmap, TPS65023_REG_REG_CTRL, &data);
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530167
Jonghwan Choi43530b62011-11-07 08:16:04 +0900168 if (ret != 0)
169 return ret;
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530170 else
171 return (data & 1<<shift) ? 1 : 0;
172}
173
174static int tps65023_ldo_is_enabled(struct regulator_dev *dev)
175{
176 struct tps_pmic *tps = rdev_get_drvdata(dev);
177 int data, ldo = rdev_get_id(dev);
Jonghwan Choi43530b62011-11-07 08:16:04 +0900178 int ret;
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530179 u8 shift;
180
181 if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2)
182 return -EINVAL;
183
184 shift = (ldo == TPS65023_LDO_1 ? 1 : 2);
Jonghwan Choi43530b62011-11-07 08:16:04 +0900185 ret = regmap_read(tps->regmap, TPS65023_REG_REG_CTRL, &data);
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530186
Jonghwan Choi43530b62011-11-07 08:16:04 +0900187 if (ret != 0)
188 return ret;
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530189 else
190 return (data & 1<<shift) ? 1 : 0;
191}
192
193static int tps65023_dcdc_enable(struct regulator_dev *dev)
194{
195 struct tps_pmic *tps = rdev_get_drvdata(dev);
196 int dcdc = rdev_get_id(dev);
197 u8 shift;
198
199 if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3)
200 return -EINVAL;
201
202 shift = TPS65023_NUM_REGULATOR - dcdc;
Jonghwan Choi43530b62011-11-07 08:16:04 +0900203 return regmap_update_bits(tps->regmap, TPS65023_REG_REG_CTRL, 1 << shift, 1 << shift);
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530204}
205
206static int tps65023_dcdc_disable(struct regulator_dev *dev)
207{
208 struct tps_pmic *tps = rdev_get_drvdata(dev);
209 int dcdc = rdev_get_id(dev);
210 u8 shift;
211
212 if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3)
213 return -EINVAL;
214
215 shift = TPS65023_NUM_REGULATOR - dcdc;
Jonghwan Choi43530b62011-11-07 08:16:04 +0900216 return regmap_update_bits(tps->regmap, TPS65023_REG_REG_CTRL, 1 << shift, 0);
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530217}
218
219static int tps65023_ldo_enable(struct regulator_dev *dev)
220{
221 struct tps_pmic *tps = rdev_get_drvdata(dev);
222 int ldo = rdev_get_id(dev);
223 u8 shift;
224
225 if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2)
226 return -EINVAL;
227
228 shift = (ldo == TPS65023_LDO_1 ? 1 : 2);
Jonghwan Choi43530b62011-11-07 08:16:04 +0900229 return regmap_update_bits(tps->regmap, TPS65023_REG_REG_CTRL, 1 << shift, 1 << shift);
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530230}
231
232static int tps65023_ldo_disable(struct regulator_dev *dev)
233{
234 struct tps_pmic *tps = rdev_get_drvdata(dev);
235 int ldo = rdev_get_id(dev);
236 u8 shift;
237
238 if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2)
239 return -EINVAL;
240
241 shift = (ldo == TPS65023_LDO_1 ? 1 : 2);
Jonghwan Choi43530b62011-11-07 08:16:04 +0900242 return regmap_update_bits(tps->regmap, TPS65023_REG_REG_CTRL, 1 << shift, 0);
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530243}
244
245static int tps65023_dcdc_get_voltage(struct regulator_dev *dev)
246{
247 struct tps_pmic *tps = rdev_get_drvdata(dev);
Jonghwan Choi43530b62011-11-07 08:16:04 +0900248 int ret;
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530249 int data, dcdc = rdev_get_id(dev);
250
251 if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3)
252 return -EINVAL;
253
Marcus Folkesson1c3ede02011-08-08 20:29:34 +0200254 if (dcdc == tps->core_regulator) {
Jonghwan Choi43530b62011-11-07 08:16:04 +0900255 ret = regmap_read(tps->regmap, TPS65023_REG_DEF_CORE, &data);
256 if (ret != 0)
257 return ret;
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530258 data &= (tps->info[dcdc]->table_len - 1);
259 return tps->info[dcdc]->table[data] * 1000;
260 } else
261 return tps->info[dcdc]->min_uV;
262}
263
Axel Lin70618732012-03-26 13:46:44 +0800264static int tps65023_dcdc_set_voltage_sel(struct regulator_dev *dev,
265 unsigned selector)
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530266{
267 struct tps_pmic *tps = rdev_get_drvdata(dev);
268 int dcdc = rdev_get_id(dev);
Marcus Folkessoncc17ef32011-08-08 20:29:33 +0200269 int ret;
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530270
Marcus Folkesson1c3ede02011-08-08 20:29:34 +0200271 if (dcdc != tps->core_regulator)
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530272 return -EINVAL;
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530273
Axel Lin70618732012-03-26 13:46:44 +0800274 ret = regmap_write(tps->regmap, TPS65023_REG_DEF_CORE, selector);
275 if (ret)
276 goto out;
Marcus Folkessoncc17ef32011-08-08 20:29:33 +0200277
278 /* Tell the chip that we have changed the value in DEFCORE
279 * and its time to update the core voltage
280 */
Axel Lin70618732012-03-26 13:46:44 +0800281 ret = regmap_update_bits(tps->regmap, TPS65023_REG_CON_CTRL2,
282 TPS65023_REG_CTRL2_GO, TPS65023_REG_CTRL2_GO);
Marcus Folkessoncc17ef32011-08-08 20:29:33 +0200283
Axel Lin70618732012-03-26 13:46:44 +0800284out:
Marcus Folkessoncc17ef32011-08-08 20:29:33 +0200285 return ret;
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530286}
287
288static int tps65023_ldo_get_voltage(struct regulator_dev *dev)
289{
290 struct tps_pmic *tps = rdev_get_drvdata(dev);
291 int data, ldo = rdev_get_id(dev);
Jonghwan Choi43530b62011-11-07 08:16:04 +0900292 int ret;
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530293
294 if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2)
295 return -EINVAL;
296
Jonghwan Choi43530b62011-11-07 08:16:04 +0900297 ret = regmap_read(tps->regmap, TPS65023_REG_LDO_CTRL, &data);
298 if (ret != 0)
299 return ret;
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530300
301 data >>= (TPS65023_LDO_CTRL_LDOx_SHIFT(ldo - TPS65023_LDO_1));
302 data &= (tps->info[ldo]->table_len - 1);
303 return tps->info[ldo]->table[data] * 1000;
304}
305
Axel Lin70618732012-03-26 13:46:44 +0800306static int tps65023_ldo_set_voltage_sel(struct regulator_dev *dev,
307 unsigned selector)
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530308{
309 struct tps_pmic *tps = rdev_get_drvdata(dev);
Axel Lin70618732012-03-26 13:46:44 +0800310 int ldo_index = rdev_get_id(dev) - TPS65023_LDO_1;
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530311
Axel Lin70618732012-03-26 13:46:44 +0800312 return regmap_update_bits(tps->regmap, TPS65023_REG_LDO_CTRL,
313 TPS65023_LDO_CTRL_LDOx_MASK(ldo_index),
314 selector << TPS65023_LDO_CTRL_LDOx_SHIFT(ldo_index));
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530315}
316
317static int tps65023_dcdc_list_voltage(struct regulator_dev *dev,
318 unsigned selector)
319{
320 struct tps_pmic *tps = rdev_get_drvdata(dev);
321 int dcdc = rdev_get_id(dev);
322
323 if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3)
324 return -EINVAL;
325
Marcus Folkesson1c3ede02011-08-08 20:29:34 +0200326 if (dcdc == tps->core_regulator) {
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530327 if (selector >= tps->info[dcdc]->table_len)
328 return -EINVAL;
329 else
330 return tps->info[dcdc]->table[selector] * 1000;
331 } else
332 return tps->info[dcdc]->min_uV;
333}
334
335static int tps65023_ldo_list_voltage(struct regulator_dev *dev,
336 unsigned selector)
337{
338 struct tps_pmic *tps = rdev_get_drvdata(dev);
339 int ldo = rdev_get_id(dev);
340
341 if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2)
342 return -EINVAL;
343
344 if (selector >= tps->info[ldo]->table_len)
345 return -EINVAL;
346 else
347 return tps->info[ldo]->table[selector] * 1000;
348}
349
350/* Operations permitted on VDCDCx */
351static struct regulator_ops tps65023_dcdc_ops = {
352 .is_enabled = tps65023_dcdc_is_enabled,
353 .enable = tps65023_dcdc_enable,
354 .disable = tps65023_dcdc_disable,
355 .get_voltage = tps65023_dcdc_get_voltage,
Axel Lin70618732012-03-26 13:46:44 +0800356 .set_voltage_sel = tps65023_dcdc_set_voltage_sel,
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530357 .list_voltage = tps65023_dcdc_list_voltage,
358};
359
360/* Operations permitted on LDOx */
361static struct regulator_ops tps65023_ldo_ops = {
362 .is_enabled = tps65023_ldo_is_enabled,
363 .enable = tps65023_ldo_enable,
364 .disable = tps65023_ldo_disable,
365 .get_voltage = tps65023_ldo_get_voltage,
Axel Lin70618732012-03-26 13:46:44 +0800366 .set_voltage_sel = tps65023_ldo_set_voltage_sel,
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530367 .list_voltage = tps65023_ldo_list_voltage,
368};
369
Mark Brown90923352011-06-18 01:18:51 +0100370static struct regmap_config tps65023_regmap_config = {
371 .reg_bits = 8,
372 .val_bits = 8,
373};
374
Dmitry Torokhov54d13ab2010-02-23 23:38:06 -0800375static int __devinit tps_65023_probe(struct i2c_client *client,
376 const struct i2c_device_id *id)
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530377{
Marcus Folkesson1c3ede02011-08-08 20:29:34 +0200378 const struct tps_driver_data *drv_data = (void *)id->driver_data;
379 const struct tps_info *info = drv_data->info;
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530380 struct regulator_init_data *init_data;
381 struct regulator_dev *rdev;
382 struct tps_pmic *tps;
383 int i;
Dmitry Torokhov54d13ab2010-02-23 23:38:06 -0800384 int error;
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530385
386 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
387 return -EIO;
388
389 /**
390 * init_data points to array of regulator_init structures
391 * coming from the board-evm file.
392 */
393 init_data = client->dev.platform_data;
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530394 if (!init_data)
395 return -EIO;
396
397 tps = kzalloc(sizeof(*tps), GFP_KERNEL);
398 if (!tps)
399 return -ENOMEM;
400
Mark Brown90923352011-06-18 01:18:51 +0100401 tps->regmap = regmap_init_i2c(client, &tps65023_regmap_config);
402 if (IS_ERR(tps->regmap)) {
403 error = PTR_ERR(tps->regmap);
404 dev_err(&client->dev, "Failed to allocate register map: %d\n",
405 error);
406 goto fail_alloc;
407 }
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530408
409 /* common for all regulators */
410 tps->client = client;
Marcus Folkesson1c3ede02011-08-08 20:29:34 +0200411 tps->core_regulator = drv_data->core_regulator;
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530412
413 for (i = 0; i < TPS65023_NUM_REGULATOR; i++, info++, init_data++) {
414 /* Store regulator specific information */
415 tps->info[i] = info;
416
417 tps->desc[i].name = info->name;
Axel Lin77fa44d2011-05-12 13:47:50 +0800418 tps->desc[i].id = i;
Marcus Folkesson1c3ede02011-08-08 20:29:34 +0200419 tps->desc[i].n_voltages = info->table_len;
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530420 tps->desc[i].ops = (i > TPS65023_DCDC_3 ?
421 &tps65023_ldo_ops : &tps65023_dcdc_ops);
422 tps->desc[i].type = REGULATOR_VOLTAGE;
423 tps->desc[i].owner = THIS_MODULE;
424
425 /* Register the regulators */
426 rdev = regulator_register(&tps->desc[i], &client->dev,
Rajendra Nayak2c043bc2011-11-18 16:47:19 +0530427 init_data, tps, NULL);
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530428 if (IS_ERR(rdev)) {
429 dev_err(&client->dev, "failed to register %s\n",
430 id->name);
Dmitry Torokhov54d13ab2010-02-23 23:38:06 -0800431 error = PTR_ERR(rdev);
432 goto fail;
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530433 }
434
435 /* Save regulator for cleanup */
436 tps->rdev[i] = rdev;
437 }
438
439 i2c_set_clientdata(client, tps);
440
Marcus Folkessonfc999b82011-08-04 13:33:49 +0200441 /* Enable setting output voltage by I2C */
Jonghwan Choi43530b62011-11-07 08:16:04 +0900442 regmap_update_bits(tps->regmap, TPS65023_REG_CON_CTRL2,
443 TPS65023_REG_CTRL2_CORE_ADJ, TPS65023_REG_CTRL2_CORE_ADJ);
Marcus Folkessonfc999b82011-08-04 13:33:49 +0200444
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530445 return 0;
Dmitry Torokhov54d13ab2010-02-23 23:38:06 -0800446
447 fail:
448 while (--i >= 0)
449 regulator_unregister(tps->rdev[i]);
450
Mark Brown90923352011-06-18 01:18:51 +0100451 regmap_exit(tps->regmap);
452 fail_alloc:
Dmitry Torokhov54d13ab2010-02-23 23:38:06 -0800453 kfree(tps);
454 return error;
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530455}
456
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530457static int __devexit tps_65023_remove(struct i2c_client *client)
458{
459 struct tps_pmic *tps = i2c_get_clientdata(client);
460 int i;
461
462 for (i = 0; i < TPS65023_NUM_REGULATOR; i++)
463 regulator_unregister(tps->rdev[i]);
464
Mark Brown90923352011-06-18 01:18:51 +0100465 regmap_exit(tps->regmap);
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530466 kfree(tps);
467
468 return 0;
469}
470
Marcus Folkesson437afd22011-08-08 20:29:35 +0200471static const struct tps_info tps65020_regs[] = {
472 {
473 .name = "VDCDC1",
474 .min_uV = 3300000,
475 .max_uV = 3300000,
476 .fixed = 1,
477 },
478 {
479 .name = "VDCDC2",
480 .min_uV = 1800000,
481 .max_uV = 1800000,
482 .fixed = 1,
483 },
484 {
485 .name = "VDCDC3",
486 .min_uV = 800000,
487 .max_uV = 1600000,
488 .table_len = ARRAY_SIZE(VCORE_VSEL_table),
489 .table = VCORE_VSEL_table,
490 },
491
492 {
493 .name = "LDO1",
494 .min_uV = 1000000,
495 .max_uV = 3150000,
496 .table_len = ARRAY_SIZE(TPS65020_LDO1_VSEL_table),
497 .table = TPS65020_LDO1_VSEL_table,
498 },
499 {
500 .name = "LDO2",
501 .min_uV = 1050000,
502 .max_uV = 3300000,
503 .table_len = ARRAY_SIZE(TPS65020_LDO2_VSEL_table),
504 .table = TPS65020_LDO2_VSEL_table,
505 },
506};
507
Marcus Folkesson1c3ede02011-08-08 20:29:34 +0200508static const struct tps_info tps65021_regs[] = {
509 {
510 .name = "VDCDC1",
511 .min_uV = 3300000,
512 .max_uV = 3300000,
513 .fixed = 1,
514 },
515 {
516 .name = "VDCDC2",
517 .min_uV = 1800000,
518 .max_uV = 1800000,
519 .fixed = 1,
520 },
521 {
522 .name = "VDCDC3",
523 .min_uV = 800000,
524 .max_uV = 1600000,
525 .table_len = ARRAY_SIZE(VCORE_VSEL_table),
526 .table = VCORE_VSEL_table,
527 },
528 {
529 .name = "LDO1",
530 .min_uV = 1000000,
531 .max_uV = 3150000,
532 .table_len = ARRAY_SIZE(TPS65023_LDO1_VSEL_table),
533 .table = TPS65023_LDO1_VSEL_table,
534 },
535 {
536 .name = "LDO2",
537 .min_uV = 1050000,
538 .max_uV = 3300000,
539 .table_len = ARRAY_SIZE(TPS65023_LDO2_VSEL_table),
540 .table = TPS65023_LDO2_VSEL_table,
541 },
542};
543
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530544static const struct tps_info tps65023_regs[] = {
545 {
546 .name = "VDCDC1",
547 .min_uV = 800000,
548 .max_uV = 1600000,
Marcus Folkesson1c3ede02011-08-08 20:29:34 +0200549 .table_len = ARRAY_SIZE(VCORE_VSEL_table),
550 .table = VCORE_VSEL_table,
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530551 },
552 {
553 .name = "VDCDC2",
554 .min_uV = 3300000,
555 .max_uV = 3300000,
556 .fixed = 1,
557 },
558 {
559 .name = "VDCDC3",
560 .min_uV = 1800000,
561 .max_uV = 1800000,
562 .fixed = 1,
563 },
564 {
565 .name = "LDO1",
566 .min_uV = 1000000,
567 .max_uV = 3150000,
Marcus Folkesson1c3ede02011-08-08 20:29:34 +0200568 .table_len = ARRAY_SIZE(TPS65023_LDO1_VSEL_table),
569 .table = TPS65023_LDO1_VSEL_table,
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530570 },
571 {
572 .name = "LDO2",
573 .min_uV = 1050000,
574 .max_uV = 3300000,
Marcus Folkesson1c3ede02011-08-08 20:29:34 +0200575 .table_len = ARRAY_SIZE(TPS65023_LDO2_VSEL_table),
576 .table = TPS65023_LDO2_VSEL_table,
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530577 },
578};
579
Marcus Folkesson437afd22011-08-08 20:29:35 +0200580static struct tps_driver_data tps65020_drv_data = {
581 .info = tps65020_regs,
582 .core_regulator = TPS65023_DCDC_3,
583};
584
Marcus Folkesson1c3ede02011-08-08 20:29:34 +0200585static struct tps_driver_data tps65021_drv_data = {
Axel Lin70618732012-03-26 13:46:44 +0800586 .info = tps65021_regs,
587 .core_regulator = TPS65023_DCDC_3,
Marcus Folkesson1c3ede02011-08-08 20:29:34 +0200588};
589
590static struct tps_driver_data tps65023_drv_data = {
Axel Lin70618732012-03-26 13:46:44 +0800591 .info = tps65023_regs,
592 .core_regulator = TPS65023_DCDC_1,
Marcus Folkesson1c3ede02011-08-08 20:29:34 +0200593};
594
Liam Girdwood9e108d32009-08-24 10:31:34 +0100595static const struct i2c_device_id tps_65023_id[] = {
596 {.name = "tps65023",
Marcus Folkesson1c3ede02011-08-08 20:29:34 +0200597 .driver_data = (unsigned long) &tps65023_drv_data},
Marek Vasut1880a2f2010-06-24 15:49:49 +0200598 {.name = "tps65021",
Marcus Folkesson1c3ede02011-08-08 20:29:34 +0200599 .driver_data = (unsigned long) &tps65021_drv_data,},
Marcus Folkesson437afd22011-08-08 20:29:35 +0200600 {.name = "tps65020",
601 .driver_data = (unsigned long) &tps65020_drv_data},
Liam Girdwood9e108d32009-08-24 10:31:34 +0100602 { },
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530603};
604
605MODULE_DEVICE_TABLE(i2c, tps_65023_id);
606
607static struct i2c_driver tps_65023_i2c_driver = {
608 .driver = {
609 .name = "tps65023",
610 .owner = THIS_MODULE,
611 },
612 .probe = tps_65023_probe,
613 .remove = __devexit_p(tps_65023_remove),
Liam Girdwood9e108d32009-08-24 10:31:34 +0100614 .id_table = tps_65023_id,
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530615};
616
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530617static int __init tps_65023_init(void)
618{
619 return i2c_add_driver(&tps_65023_i2c_driver);
620}
621subsys_initcall(tps_65023_init);
622
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530623static void __exit tps_65023_cleanup(void)
624{
625 i2c_del_driver(&tps_65023_i2c_driver);
626}
627module_exit(tps_65023_cleanup);
628
629MODULE_AUTHOR("Texas Instruments");
630MODULE_DESCRIPTION("TPS65023 voltage regulator driver");
Liam Girdwood9e108d32009-08-24 10:31:34 +0100631MODULE_LICENSE("GPL v2");