blob: 2db71497b741dcac5ee30f663bc5a9f963a47fab [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];
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530142 struct regulator_dev *rdev[TPS65023_NUM_REGULATOR];
143 const struct tps_info *info[TPS65023_NUM_REGULATOR];
Mark Brown90923352011-06-18 01:18:51 +0100144 struct regmap *regmap;
Marcus Folkesson1c3ede02011-08-08 20:29:34 +0200145 u8 core_regulator;
146};
147
148/* Struct passed as driver data */
149struct tps_driver_data {
150 const struct tps_info *info;
151 u8 core_regulator;
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530152};
153
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530154static int tps65023_dcdc_is_enabled(struct regulator_dev *dev)
155{
156 struct tps_pmic *tps = rdev_get_drvdata(dev);
157 int data, dcdc = rdev_get_id(dev);
Jonghwan Choi43530b62011-11-07 08:16:04 +0900158 int ret;
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530159 u8 shift;
160
161 if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3)
162 return -EINVAL;
163
164 shift = TPS65023_NUM_REGULATOR - dcdc;
Jonghwan Choi43530b62011-11-07 08:16:04 +0900165 ret = regmap_read(tps->regmap, TPS65023_REG_REG_CTRL, &data);
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530166
Jonghwan Choi43530b62011-11-07 08:16:04 +0900167 if (ret != 0)
168 return ret;
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530169 else
170 return (data & 1<<shift) ? 1 : 0;
171}
172
173static int tps65023_ldo_is_enabled(struct regulator_dev *dev)
174{
175 struct tps_pmic *tps = rdev_get_drvdata(dev);
176 int data, ldo = rdev_get_id(dev);
Jonghwan Choi43530b62011-11-07 08:16:04 +0900177 int ret;
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530178 u8 shift;
179
180 if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2)
181 return -EINVAL;
182
183 shift = (ldo == TPS65023_LDO_1 ? 1 : 2);
Jonghwan Choi43530b62011-11-07 08:16:04 +0900184 ret = regmap_read(tps->regmap, TPS65023_REG_REG_CTRL, &data);
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530185
Jonghwan Choi43530b62011-11-07 08:16:04 +0900186 if (ret != 0)
187 return ret;
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530188 else
189 return (data & 1<<shift) ? 1 : 0;
190}
191
192static int tps65023_dcdc_enable(struct regulator_dev *dev)
193{
194 struct tps_pmic *tps = rdev_get_drvdata(dev);
195 int dcdc = rdev_get_id(dev);
196 u8 shift;
197
198 if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3)
199 return -EINVAL;
200
201 shift = TPS65023_NUM_REGULATOR - dcdc;
Jonghwan Choi43530b62011-11-07 08:16:04 +0900202 return regmap_update_bits(tps->regmap, TPS65023_REG_REG_CTRL, 1 << shift, 1 << shift);
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530203}
204
205static int tps65023_dcdc_disable(struct regulator_dev *dev)
206{
207 struct tps_pmic *tps = rdev_get_drvdata(dev);
208 int dcdc = rdev_get_id(dev);
209 u8 shift;
210
211 if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3)
212 return -EINVAL;
213
214 shift = TPS65023_NUM_REGULATOR - dcdc;
Jonghwan Choi43530b62011-11-07 08:16:04 +0900215 return regmap_update_bits(tps->regmap, TPS65023_REG_REG_CTRL, 1 << shift, 0);
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530216}
217
218static int tps65023_ldo_enable(struct regulator_dev *dev)
219{
220 struct tps_pmic *tps = rdev_get_drvdata(dev);
221 int ldo = rdev_get_id(dev);
222 u8 shift;
223
224 if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2)
225 return -EINVAL;
226
227 shift = (ldo == TPS65023_LDO_1 ? 1 : 2);
Jonghwan Choi43530b62011-11-07 08:16:04 +0900228 return regmap_update_bits(tps->regmap, TPS65023_REG_REG_CTRL, 1 << shift, 1 << shift);
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530229}
230
231static int tps65023_ldo_disable(struct regulator_dev *dev)
232{
233 struct tps_pmic *tps = rdev_get_drvdata(dev);
234 int ldo = rdev_get_id(dev);
235 u8 shift;
236
237 if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2)
238 return -EINVAL;
239
240 shift = (ldo == TPS65023_LDO_1 ? 1 : 2);
Jonghwan Choi43530b62011-11-07 08:16:04 +0900241 return regmap_update_bits(tps->regmap, TPS65023_REG_REG_CTRL, 1 << shift, 0);
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530242}
243
244static int tps65023_dcdc_get_voltage(struct regulator_dev *dev)
245{
246 struct tps_pmic *tps = rdev_get_drvdata(dev);
Jonghwan Choi43530b62011-11-07 08:16:04 +0900247 int ret;
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530248 int data, dcdc = rdev_get_id(dev);
249
250 if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3)
251 return -EINVAL;
252
Marcus Folkesson1c3ede02011-08-08 20:29:34 +0200253 if (dcdc == tps->core_regulator) {
Jonghwan Choi43530b62011-11-07 08:16:04 +0900254 ret = regmap_read(tps->regmap, TPS65023_REG_DEF_CORE, &data);
255 if (ret != 0)
256 return ret;
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530257 data &= (tps->info[dcdc]->table_len - 1);
258 return tps->info[dcdc]->table[data] * 1000;
259 } else
260 return tps->info[dcdc]->min_uV;
261}
262
Axel Lin70618732012-03-26 13:46:44 +0800263static int tps65023_dcdc_set_voltage_sel(struct regulator_dev *dev,
264 unsigned selector)
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530265{
266 struct tps_pmic *tps = rdev_get_drvdata(dev);
267 int dcdc = rdev_get_id(dev);
Marcus Folkessoncc17ef32011-08-08 20:29:33 +0200268 int ret;
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530269
Marcus Folkesson1c3ede02011-08-08 20:29:34 +0200270 if (dcdc != tps->core_regulator)
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530271 return -EINVAL;
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530272
Axel Lin70618732012-03-26 13:46:44 +0800273 ret = regmap_write(tps->regmap, TPS65023_REG_DEF_CORE, selector);
274 if (ret)
275 goto out;
Marcus Folkessoncc17ef32011-08-08 20:29:33 +0200276
277 /* Tell the chip that we have changed the value in DEFCORE
278 * and its time to update the core voltage
279 */
Axel Lin70618732012-03-26 13:46:44 +0800280 ret = regmap_update_bits(tps->regmap, TPS65023_REG_CON_CTRL2,
281 TPS65023_REG_CTRL2_GO, TPS65023_REG_CTRL2_GO);
Marcus Folkessoncc17ef32011-08-08 20:29:33 +0200282
Axel Lin70618732012-03-26 13:46:44 +0800283out:
Marcus Folkessoncc17ef32011-08-08 20:29:33 +0200284 return ret;
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530285}
286
287static int tps65023_ldo_get_voltage(struct regulator_dev *dev)
288{
289 struct tps_pmic *tps = rdev_get_drvdata(dev);
290 int data, ldo = rdev_get_id(dev);
Jonghwan Choi43530b62011-11-07 08:16:04 +0900291 int ret;
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530292
293 if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2)
294 return -EINVAL;
295
Jonghwan Choi43530b62011-11-07 08:16:04 +0900296 ret = regmap_read(tps->regmap, TPS65023_REG_LDO_CTRL, &data);
297 if (ret != 0)
298 return ret;
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530299
300 data >>= (TPS65023_LDO_CTRL_LDOx_SHIFT(ldo - TPS65023_LDO_1));
301 data &= (tps->info[ldo]->table_len - 1);
302 return tps->info[ldo]->table[data] * 1000;
303}
304
Axel Lin70618732012-03-26 13:46:44 +0800305static int tps65023_ldo_set_voltage_sel(struct regulator_dev *dev,
306 unsigned selector)
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530307{
308 struct tps_pmic *tps = rdev_get_drvdata(dev);
Axel Lin70618732012-03-26 13:46:44 +0800309 int ldo_index = rdev_get_id(dev) - TPS65023_LDO_1;
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530310
Axel Lin70618732012-03-26 13:46:44 +0800311 return regmap_update_bits(tps->regmap, TPS65023_REG_LDO_CTRL,
312 TPS65023_LDO_CTRL_LDOx_MASK(ldo_index),
313 selector << TPS65023_LDO_CTRL_LDOx_SHIFT(ldo_index));
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530314}
315
316static int tps65023_dcdc_list_voltage(struct regulator_dev *dev,
317 unsigned selector)
318{
319 struct tps_pmic *tps = rdev_get_drvdata(dev);
320 int dcdc = rdev_get_id(dev);
321
322 if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3)
323 return -EINVAL;
324
Marcus Folkesson1c3ede02011-08-08 20:29:34 +0200325 if (dcdc == tps->core_regulator) {
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530326 if (selector >= tps->info[dcdc]->table_len)
327 return -EINVAL;
328 else
329 return tps->info[dcdc]->table[selector] * 1000;
330 } else
331 return tps->info[dcdc]->min_uV;
332}
333
334static int tps65023_ldo_list_voltage(struct regulator_dev *dev,
335 unsigned selector)
336{
337 struct tps_pmic *tps = rdev_get_drvdata(dev);
338 int ldo = rdev_get_id(dev);
339
340 if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2)
341 return -EINVAL;
342
343 if (selector >= tps->info[ldo]->table_len)
344 return -EINVAL;
345 else
346 return tps->info[ldo]->table[selector] * 1000;
347}
348
349/* Operations permitted on VDCDCx */
350static struct regulator_ops tps65023_dcdc_ops = {
351 .is_enabled = tps65023_dcdc_is_enabled,
352 .enable = tps65023_dcdc_enable,
353 .disable = tps65023_dcdc_disable,
354 .get_voltage = tps65023_dcdc_get_voltage,
Axel Lin70618732012-03-26 13:46:44 +0800355 .set_voltage_sel = tps65023_dcdc_set_voltage_sel,
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530356 .list_voltage = tps65023_dcdc_list_voltage,
357};
358
359/* Operations permitted on LDOx */
360static struct regulator_ops tps65023_ldo_ops = {
361 .is_enabled = tps65023_ldo_is_enabled,
362 .enable = tps65023_ldo_enable,
363 .disable = tps65023_ldo_disable,
364 .get_voltage = tps65023_ldo_get_voltage,
Axel Lin70618732012-03-26 13:46:44 +0800365 .set_voltage_sel = tps65023_ldo_set_voltage_sel,
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530366 .list_voltage = tps65023_ldo_list_voltage,
367};
368
Mark Brown90923352011-06-18 01:18:51 +0100369static struct regmap_config tps65023_regmap_config = {
370 .reg_bits = 8,
371 .val_bits = 8,
372};
373
Dmitry Torokhov54d13ab2010-02-23 23:38:06 -0800374static int __devinit tps_65023_probe(struct i2c_client *client,
375 const struct i2c_device_id *id)
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530376{
Marcus Folkesson1c3ede02011-08-08 20:29:34 +0200377 const struct tps_driver_data *drv_data = (void *)id->driver_data;
378 const struct tps_info *info = drv_data->info;
Mark Brownc1727082012-04-04 00:50:22 +0100379 struct regulator_config config = { };
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
Axel Lin19a8da22012-04-07 23:31:44 +0800397 tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530398 if (!tps)
399 return -ENOMEM;
400
Axel Lin19a8da22012-04-07 23:31:44 +0800401 tps->regmap = devm_regmap_init_i2c(client, &tps65023_regmap_config);
Mark Brown90923352011-06-18 01:18:51 +0100402 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);
Axel Lin19a8da22012-04-07 23:31:44 +0800406 return error;
Mark Brown90923352011-06-18 01:18:51 +0100407 }
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530408
409 /* common for all regulators */
Marcus Folkesson1c3ede02011-08-08 20:29:34 +0200410 tps->core_regulator = drv_data->core_regulator;
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530411
412 for (i = 0; i < TPS65023_NUM_REGULATOR; i++, info++, init_data++) {
413 /* Store regulator specific information */
414 tps->info[i] = info;
415
416 tps->desc[i].name = info->name;
Axel Lin77fa44d2011-05-12 13:47:50 +0800417 tps->desc[i].id = i;
Marcus Folkesson1c3ede02011-08-08 20:29:34 +0200418 tps->desc[i].n_voltages = info->table_len;
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530419 tps->desc[i].ops = (i > TPS65023_DCDC_3 ?
420 &tps65023_ldo_ops : &tps65023_dcdc_ops);
421 tps->desc[i].type = REGULATOR_VOLTAGE;
422 tps->desc[i].owner = THIS_MODULE;
423
Mark Brownc1727082012-04-04 00:50:22 +0100424 config.dev = &client->dev;
425 config.init_data = init_data;
426 config.driver_data = tps;
427
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530428 /* Register the regulators */
Mark Brownc1727082012-04-04 00:50:22 +0100429 rdev = regulator_register(&tps->desc[i], &config);
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530430 if (IS_ERR(rdev)) {
431 dev_err(&client->dev, "failed to register %s\n",
432 id->name);
Dmitry Torokhov54d13ab2010-02-23 23:38:06 -0800433 error = PTR_ERR(rdev);
434 goto fail;
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530435 }
436
437 /* Save regulator for cleanup */
438 tps->rdev[i] = rdev;
439 }
440
441 i2c_set_clientdata(client, tps);
442
Marcus Folkessonfc999b82011-08-04 13:33:49 +0200443 /* Enable setting output voltage by I2C */
Jonghwan Choi43530b62011-11-07 08:16:04 +0900444 regmap_update_bits(tps->regmap, TPS65023_REG_CON_CTRL2,
445 TPS65023_REG_CTRL2_CORE_ADJ, TPS65023_REG_CTRL2_CORE_ADJ);
Marcus Folkessonfc999b82011-08-04 13:33:49 +0200446
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530447 return 0;
Dmitry Torokhov54d13ab2010-02-23 23:38:06 -0800448
449 fail:
450 while (--i >= 0)
451 regulator_unregister(tps->rdev[i]);
Dmitry Torokhov54d13ab2010-02-23 23:38:06 -0800452 return error;
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530453}
454
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530455static int __devexit tps_65023_remove(struct i2c_client *client)
456{
457 struct tps_pmic *tps = i2c_get_clientdata(client);
458 int i;
459
460 for (i = 0; i < TPS65023_NUM_REGULATOR; i++)
461 regulator_unregister(tps->rdev[i]);
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530462 return 0;
463}
464
Marcus Folkesson437afd22011-08-08 20:29:35 +0200465static const struct tps_info tps65020_regs[] = {
466 {
467 .name = "VDCDC1",
468 .min_uV = 3300000,
469 .max_uV = 3300000,
470 .fixed = 1,
471 },
472 {
473 .name = "VDCDC2",
474 .min_uV = 1800000,
475 .max_uV = 1800000,
476 .fixed = 1,
477 },
478 {
479 .name = "VDCDC3",
480 .min_uV = 800000,
481 .max_uV = 1600000,
482 .table_len = ARRAY_SIZE(VCORE_VSEL_table),
483 .table = VCORE_VSEL_table,
484 },
485
486 {
487 .name = "LDO1",
488 .min_uV = 1000000,
489 .max_uV = 3150000,
490 .table_len = ARRAY_SIZE(TPS65020_LDO1_VSEL_table),
491 .table = TPS65020_LDO1_VSEL_table,
492 },
493 {
494 .name = "LDO2",
495 .min_uV = 1050000,
496 .max_uV = 3300000,
497 .table_len = ARRAY_SIZE(TPS65020_LDO2_VSEL_table),
498 .table = TPS65020_LDO2_VSEL_table,
499 },
500};
501
Marcus Folkesson1c3ede02011-08-08 20:29:34 +0200502static const struct tps_info tps65021_regs[] = {
503 {
504 .name = "VDCDC1",
505 .min_uV = 3300000,
506 .max_uV = 3300000,
507 .fixed = 1,
508 },
509 {
510 .name = "VDCDC2",
511 .min_uV = 1800000,
512 .max_uV = 1800000,
513 .fixed = 1,
514 },
515 {
516 .name = "VDCDC3",
517 .min_uV = 800000,
518 .max_uV = 1600000,
519 .table_len = ARRAY_SIZE(VCORE_VSEL_table),
520 .table = VCORE_VSEL_table,
521 },
522 {
523 .name = "LDO1",
524 .min_uV = 1000000,
525 .max_uV = 3150000,
526 .table_len = ARRAY_SIZE(TPS65023_LDO1_VSEL_table),
527 .table = TPS65023_LDO1_VSEL_table,
528 },
529 {
530 .name = "LDO2",
531 .min_uV = 1050000,
532 .max_uV = 3300000,
533 .table_len = ARRAY_SIZE(TPS65023_LDO2_VSEL_table),
534 .table = TPS65023_LDO2_VSEL_table,
535 },
536};
537
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530538static const struct tps_info tps65023_regs[] = {
539 {
540 .name = "VDCDC1",
541 .min_uV = 800000,
542 .max_uV = 1600000,
Marcus Folkesson1c3ede02011-08-08 20:29:34 +0200543 .table_len = ARRAY_SIZE(VCORE_VSEL_table),
544 .table = VCORE_VSEL_table,
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530545 },
546 {
547 .name = "VDCDC2",
548 .min_uV = 3300000,
549 .max_uV = 3300000,
550 .fixed = 1,
551 },
552 {
553 .name = "VDCDC3",
554 .min_uV = 1800000,
555 .max_uV = 1800000,
556 .fixed = 1,
557 },
558 {
559 .name = "LDO1",
560 .min_uV = 1000000,
561 .max_uV = 3150000,
Marcus Folkesson1c3ede02011-08-08 20:29:34 +0200562 .table_len = ARRAY_SIZE(TPS65023_LDO1_VSEL_table),
563 .table = TPS65023_LDO1_VSEL_table,
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530564 },
565 {
566 .name = "LDO2",
567 .min_uV = 1050000,
568 .max_uV = 3300000,
Marcus Folkesson1c3ede02011-08-08 20:29:34 +0200569 .table_len = ARRAY_SIZE(TPS65023_LDO2_VSEL_table),
570 .table = TPS65023_LDO2_VSEL_table,
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530571 },
572};
573
Marcus Folkesson437afd22011-08-08 20:29:35 +0200574static struct tps_driver_data tps65020_drv_data = {
575 .info = tps65020_regs,
576 .core_regulator = TPS65023_DCDC_3,
577};
578
Marcus Folkesson1c3ede02011-08-08 20:29:34 +0200579static struct tps_driver_data tps65021_drv_data = {
Axel Lin70618732012-03-26 13:46:44 +0800580 .info = tps65021_regs,
581 .core_regulator = TPS65023_DCDC_3,
Marcus Folkesson1c3ede02011-08-08 20:29:34 +0200582};
583
584static struct tps_driver_data tps65023_drv_data = {
Axel Lin70618732012-03-26 13:46:44 +0800585 .info = tps65023_regs,
586 .core_regulator = TPS65023_DCDC_1,
Marcus Folkesson1c3ede02011-08-08 20:29:34 +0200587};
588
Liam Girdwood9e108d32009-08-24 10:31:34 +0100589static const struct i2c_device_id tps_65023_id[] = {
590 {.name = "tps65023",
Marcus Folkesson1c3ede02011-08-08 20:29:34 +0200591 .driver_data = (unsigned long) &tps65023_drv_data},
Marek Vasut1880a2f2010-06-24 15:49:49 +0200592 {.name = "tps65021",
Marcus Folkesson1c3ede02011-08-08 20:29:34 +0200593 .driver_data = (unsigned long) &tps65021_drv_data,},
Marcus Folkesson437afd22011-08-08 20:29:35 +0200594 {.name = "tps65020",
595 .driver_data = (unsigned long) &tps65020_drv_data},
Liam Girdwood9e108d32009-08-24 10:31:34 +0100596 { },
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530597};
598
599MODULE_DEVICE_TABLE(i2c, tps_65023_id);
600
601static struct i2c_driver tps_65023_i2c_driver = {
602 .driver = {
603 .name = "tps65023",
604 .owner = THIS_MODULE,
605 },
606 .probe = tps_65023_probe,
607 .remove = __devexit_p(tps_65023_remove),
Liam Girdwood9e108d32009-08-24 10:31:34 +0100608 .id_table = tps_65023_id,
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530609};
610
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530611static int __init tps_65023_init(void)
612{
613 return i2c_add_driver(&tps_65023_i2c_driver);
614}
615subsys_initcall(tps_65023_init);
616
Anuj Aggarwal30e65992009-08-21 00:39:31 +0530617static void __exit tps_65023_cleanup(void)
618{
619 i2c_del_driver(&tps_65023_i2c_driver);
620}
621module_exit(tps_65023_cleanup);
622
623MODULE_AUTHOR("Texas Instruments");
624MODULE_DESCRIPTION("TPS65023 voltage regulator driver");
Liam Girdwood9e108d32009-08-24 10:31:34 +0100625MODULE_LICENSE("GPL v2");