blob: 7385b273a10fe6dae293970cf33b003c5de82e73 [file] [log] [blame]
David Brownellfa16a5c2009-02-08 10:37:06 -08001/*
Rajendra Nayakc4aa6f32009-12-13 21:36:49 +01002 * twl-regulator.c -- support regulators in twl4030/twl6030 family chips
David Brownellfa16a5c2009-02-08 10:37:06 -08003 *
4 * Copyright (C) 2008 David Brownell
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11
12#include <linux/module.h>
13#include <linux/init.h>
14#include <linux/err.h>
Juha Keski-Saari53b8a9d2009-12-16 14:55:26 +020015#include <linux/delay.h>
David Brownellfa16a5c2009-02-08 10:37:06 -080016#include <linux/platform_device.h>
Rajendra Nayak2098e952012-02-28 15:09:11 +053017#include <linux/of.h>
18#include <linux/of_device.h>
David Brownellfa16a5c2009-02-08 10:37:06 -080019#include <linux/regulator/driver.h>
20#include <linux/regulator/machine.h>
Rajendra Nayak2098e952012-02-28 15:09:11 +053021#include <linux/regulator/of_regulator.h>
Santosh Shilimkarb07682b2009-12-13 20:05:51 +010022#include <linux/i2c/twl.h>
David Brownellfa16a5c2009-02-08 10:37:06 -080023
24
25/*
Rajendra Nayakc4aa6f32009-12-13 21:36:49 +010026 * The TWL4030/TW5030/TPS659x0/TWL6030 family chips include power management, a
David Brownellfa16a5c2009-02-08 10:37:06 -080027 * USB OTG transceiver, an RTC, ADC, PWM, and lots more. Some versions
28 * include an audio codec, battery charger, and more voltage regulators.
29 * These chips are often used in OMAP-based systems.
30 *
31 * This driver implements software-based resource control for various
32 * voltage regulators. This is usually augmented with state machine
33 * based control.
34 */
35
36struct twlreg_info {
37 /* start of regulator's PM_RECEIVER control register bank */
38 u8 base;
39
Rajendra Nayakc4aa6f32009-12-13 21:36:49 +010040 /* twl resource ID, for resource control state machine */
David Brownellfa16a5c2009-02-08 10:37:06 -080041 u8 id;
42
43 /* voltage in mV = table[VSEL]; table_len must be a power-of-two */
44 u8 table_len;
45 const u16 *table;
46
Juha Keski-Saari045f9722009-12-16 14:49:52 +020047 /* regulator specific turn-on delay */
48 u16 delay;
49
50 /* State REMAP default configuration */
51 u8 remap;
52
David Brownellfa16a5c2009-02-08 10:37:06 -080053 /* chip constraints on regulator behavior */
54 u16 min_mV;
Rajendra Nayak3e3d3be2010-04-22 14:18:32 +053055 u16 max_mV;
David Brownellfa16a5c2009-02-08 10:37:06 -080056
Graeme Gregory4d94aee2011-05-22 21:21:23 +010057 u8 flags;
58
David Brownellfa16a5c2009-02-08 10:37:06 -080059 /* used by regulator core */
60 struct regulator_desc desc;
Graeme Gregory4d94aee2011-05-22 21:21:23 +010061
62 /* chip specific features */
63 unsigned long features;
Tero Kristo63bfff42012-02-16 12:27:52 +020064
65 /*
66 * optional override functions for voltage set/get
67 * these are currently only used for SMPS regulators
68 */
69 int (*get_voltage)(void *data);
70 int (*set_voltage)(void *data, int target_uV);
71
72 /* data passed from board for external get/set voltage */
73 void *data;
David Brownellfa16a5c2009-02-08 10:37:06 -080074};
75
76
77/* LDO control registers ... offset is from the base of its register bank.
78 * The first three registers of all power resource banks help hardware to
79 * manage the various resource groups.
80 */
Rajendra Nayak441a4502009-12-13 22:19:23 +010081/* Common offset in TWL4030/6030 */
David Brownellfa16a5c2009-02-08 10:37:06 -080082#define VREG_GRP 0
Rajendra Nayak441a4502009-12-13 22:19:23 +010083/* TWL4030 register offsets */
David Brownellfa16a5c2009-02-08 10:37:06 -080084#define VREG_TYPE 1
85#define VREG_REMAP 2
86#define VREG_DEDICATED 3 /* LDO control */
Tero Kristoba305e32011-11-28 16:53:19 +020087#define VREG_VOLTAGE_SMPS_4030 9
Rajendra Nayak441a4502009-12-13 22:19:23 +010088/* TWL6030 register offsets */
89#define VREG_TRANS 1
90#define VREG_STATE 2
91#define VREG_VOLTAGE 3
Graeme Gregory4d94aee2011-05-22 21:21:23 +010092#define VREG_VOLTAGE_SMPS 4
Rajendra Nayak441a4502009-12-13 22:19:23 +010093/* TWL6030 Misc register offsets */
94#define VREG_BC_ALL 1
95#define VREG_BC_REF 2
96#define VREG_BC_PROC 3
97#define VREG_BC_CLK_RST 4
David Brownellfa16a5c2009-02-08 10:37:06 -080098
Saquib Herman21657ebf2011-04-01 10:22:42 +053099/* TWL6030 LDO register values for CFG_STATE */
100#define TWL6030_CFG_STATE_OFF 0x00
101#define TWL6030_CFG_STATE_ON 0x01
Saquib Herman9a0244a2011-04-01 10:22:45 +0530102#define TWL6030_CFG_STATE_OFF2 0x02
103#define TWL6030_CFG_STATE_SLEEP 0x03
Saquib Herman21657ebf2011-04-01 10:22:42 +0530104#define TWL6030_CFG_STATE_GRP_SHIFT 5
Saquib Hermanb2456772011-04-01 10:22:44 +0530105#define TWL6030_CFG_STATE_APP_SHIFT 2
106#define TWL6030_CFG_STATE_APP_MASK (0x03 << TWL6030_CFG_STATE_APP_SHIFT)
107#define TWL6030_CFG_STATE_APP(v) (((v) & TWL6030_CFG_STATE_APP_MASK) >>\
108 TWL6030_CFG_STATE_APP_SHIFT)
Saquib Herman21657ebf2011-04-01 10:22:42 +0530109
Graeme Gregory4d94aee2011-05-22 21:21:23 +0100110/* Flags for SMPS Voltage reading */
111#define SMPS_OFFSET_EN BIT(0)
112#define SMPS_EXTENDED_EN BIT(1)
113
114/* twl6025 SMPS EPROM values */
115#define TWL6030_SMPS_OFFSET 0xB0
116#define TWL6030_SMPS_MULT 0xB3
117#define SMPS_MULTOFFSET_SMPS4 BIT(0)
118#define SMPS_MULTOFFSET_VIO BIT(1)
119#define SMPS_MULTOFFSET_SMPS3 BIT(6)
120
David Brownellfa16a5c2009-02-08 10:37:06 -0800121static inline int
Rajendra Nayak441a4502009-12-13 22:19:23 +0100122twlreg_read(struct twlreg_info *info, unsigned slave_subgp, unsigned offset)
David Brownellfa16a5c2009-02-08 10:37:06 -0800123{
124 u8 value;
125 int status;
126
Rajendra Nayak441a4502009-12-13 22:19:23 +0100127 status = twl_i2c_read_u8(slave_subgp,
David Brownellfa16a5c2009-02-08 10:37:06 -0800128 &value, info->base + offset);
129 return (status < 0) ? status : value;
130}
131
132static inline int
Rajendra Nayak441a4502009-12-13 22:19:23 +0100133twlreg_write(struct twlreg_info *info, unsigned slave_subgp, unsigned offset,
134 u8 value)
David Brownellfa16a5c2009-02-08 10:37:06 -0800135{
Rajendra Nayak441a4502009-12-13 22:19:23 +0100136 return twl_i2c_write_u8(slave_subgp,
David Brownellfa16a5c2009-02-08 10:37:06 -0800137 value, info->base + offset);
138}
139
140/*----------------------------------------------------------------------*/
141
142/* generic power resource operations, which work on all regulators */
143
Rajendra Nayakc4aa6f32009-12-13 21:36:49 +0100144static int twlreg_grp(struct regulator_dev *rdev)
David Brownellfa16a5c2009-02-08 10:37:06 -0800145{
Rajendra Nayak441a4502009-12-13 22:19:23 +0100146 return twlreg_read(rdev_get_drvdata(rdev), TWL_MODULE_PM_RECEIVER,
147 VREG_GRP);
David Brownellfa16a5c2009-02-08 10:37:06 -0800148}
149
150/*
151 * Enable/disable regulators by joining/leaving the P1 (processor) group.
152 * We assume nobody else is updating the DEV_GRP registers.
153 */
Rajendra Nayak441a4502009-12-13 22:19:23 +0100154/* definition for 4030 family */
155#define P3_GRP_4030 BIT(7) /* "peripherals" */
156#define P2_GRP_4030 BIT(6) /* secondary processor, modem, etc */
157#define P1_GRP_4030 BIT(5) /* CPU/Linux */
158/* definition for 6030 family */
159#define P3_GRP_6030 BIT(2) /* secondary processor, modem, etc */
160#define P2_GRP_6030 BIT(1) /* "peripherals" */
161#define P1_GRP_6030 BIT(0) /* CPU/Linux */
David Brownellfa16a5c2009-02-08 10:37:06 -0800162
Saquib Hermanb2456772011-04-01 10:22:44 +0530163static int twl4030reg_is_enabled(struct regulator_dev *rdev)
David Brownellfa16a5c2009-02-08 10:37:06 -0800164{
Rajendra Nayakc4aa6f32009-12-13 21:36:49 +0100165 int state = twlreg_grp(rdev);
David Brownellfa16a5c2009-02-08 10:37:06 -0800166
167 if (state < 0)
168 return state;
169
Saquib Hermanb2456772011-04-01 10:22:44 +0530170 return state & P1_GRP_4030;
171}
172
173static int twl6030reg_is_enabled(struct regulator_dev *rdev)
174{
175 struct twlreg_info *info = rdev_get_drvdata(rdev);
Graeme Gregory4d94aee2011-05-22 21:21:23 +0100176 int grp = 0, val;
Saquib Hermanb2456772011-04-01 10:22:44 +0530177
Axel Linb6f476c2012-04-11 11:07:17 +0800178 if (!(twl_class_is_6030() && (info->features & TWL6025_SUBCLASS))) {
179 grp = twlreg_grp(rdev);
180 if (grp < 0)
181 return grp;
Graeme Gregory4d94aee2011-05-22 21:21:23 +0100182 grp &= P1_GRP_6030;
Axel Linb6f476c2012-04-11 11:07:17 +0800183 } else {
Graeme Gregory4d94aee2011-05-22 21:21:23 +0100184 grp = 1;
Axel Linb6f476c2012-04-11 11:07:17 +0800185 }
Saquib Hermanb2456772011-04-01 10:22:44 +0530186
187 val = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_STATE);
188 val = TWL6030_CFG_STATE_APP(val);
189
190 return grp && (val == TWL6030_CFG_STATE_ON);
David Brownellfa16a5c2009-02-08 10:37:06 -0800191}
192
Balaji T Kf8c29402011-05-20 19:03:51 +0530193static int twl4030reg_enable(struct regulator_dev *rdev)
David Brownellfa16a5c2009-02-08 10:37:06 -0800194{
195 struct twlreg_info *info = rdev_get_drvdata(rdev);
196 int grp;
Juha Keski-Saari53b8a9d2009-12-16 14:55:26 +0200197 int ret;
David Brownellfa16a5c2009-02-08 10:37:06 -0800198
Axel Linb6f476c2012-04-11 11:07:17 +0800199 grp = twlreg_grp(rdev);
David Brownellfa16a5c2009-02-08 10:37:06 -0800200 if (grp < 0)
201 return grp;
202
Balaji T Kf8c29402011-05-20 19:03:51 +0530203 grp |= P1_GRP_4030;
Rajendra Nayak441a4502009-12-13 22:19:23 +0100204
Juha Keski-Saari53b8a9d2009-12-16 14:55:26 +0200205 ret = twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_GRP, grp);
206
Balaji T Kf8c29402011-05-20 19:03:51 +0530207 return ret;
208}
209
210static int twl6030reg_enable(struct regulator_dev *rdev)
211{
212 struct twlreg_info *info = rdev_get_drvdata(rdev);
Graeme Gregory4d94aee2011-05-22 21:21:23 +0100213 int grp = 0;
Balaji T Kf8c29402011-05-20 19:03:51 +0530214 int ret;
215
Graeme Gregory4d94aee2011-05-22 21:21:23 +0100216 if (!(twl_class_is_6030() && (info->features & TWL6025_SUBCLASS)))
Axel Linb6f476c2012-04-11 11:07:17 +0800217 grp = twlreg_grp(rdev);
Balaji T Kf8c29402011-05-20 19:03:51 +0530218 if (grp < 0)
219 return grp;
220
221 ret = twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_STATE,
222 grp << TWL6030_CFG_STATE_GRP_SHIFT |
223 TWL6030_CFG_STATE_ON);
Juha Keski-Saari53b8a9d2009-12-16 14:55:26 +0200224 return ret;
David Brownellfa16a5c2009-02-08 10:37:06 -0800225}
226
Axel Lin48c936d2012-04-11 11:05:57 +0800227static int twl4030reg_enable_time(struct regulator_dev *rdev)
228{
229 struct twlreg_info *info = rdev_get_drvdata(rdev);
230
231 return info->delay;
232}
233
234static int twl6030reg_enable_time(struct regulator_dev *rdev)
235{
236 struct twlreg_info *info = rdev_get_drvdata(rdev);
237
238 return info->delay;
239}
240
Balaji T K0ff38972011-05-20 19:03:52 +0530241static int twl4030reg_disable(struct regulator_dev *rdev)
David Brownellfa16a5c2009-02-08 10:37:06 -0800242{
243 struct twlreg_info *info = rdev_get_drvdata(rdev);
244 int grp;
Saquib Herman21657ebf2011-04-01 10:22:42 +0530245 int ret;
David Brownellfa16a5c2009-02-08 10:37:06 -0800246
Axel Linb6f476c2012-04-11 11:07:17 +0800247 grp = twlreg_grp(rdev);
David Brownellfa16a5c2009-02-08 10:37:06 -0800248 if (grp < 0)
249 return grp;
250
Balaji T K0ff38972011-05-20 19:03:52 +0530251 grp &= ~(P1_GRP_4030 | P2_GRP_4030 | P3_GRP_4030);
Rajendra Nayak441a4502009-12-13 22:19:23 +0100252
Saquib Herman21657ebf2011-04-01 10:22:42 +0530253 ret = twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_GRP, grp);
254
Balaji T K0ff38972011-05-20 19:03:52 +0530255 return ret;
256}
257
258static int twl6030reg_disable(struct regulator_dev *rdev)
259{
260 struct twlreg_info *info = rdev_get_drvdata(rdev);
261 int grp = 0;
262 int ret;
263
Graeme Gregory4d94aee2011-05-22 21:21:23 +0100264 if (!(twl_class_is_6030() && (info->features & TWL6025_SUBCLASS)))
265 grp = P1_GRP_6030 | P2_GRP_6030 | P3_GRP_6030;
Balaji T K0ff38972011-05-20 19:03:52 +0530266
267 /* For 6030, set the off state for all grps enabled */
268 ret = twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_STATE,
269 (grp) << TWL6030_CFG_STATE_GRP_SHIFT |
270 TWL6030_CFG_STATE_OFF);
Saquib Herman21657ebf2011-04-01 10:22:42 +0530271
272 return ret;
David Brownellfa16a5c2009-02-08 10:37:06 -0800273}
274
Saquib Herman9a0244a2011-04-01 10:22:45 +0530275static int twl4030reg_get_status(struct regulator_dev *rdev)
David Brownellfa16a5c2009-02-08 10:37:06 -0800276{
Rajendra Nayakc4aa6f32009-12-13 21:36:49 +0100277 int state = twlreg_grp(rdev);
David Brownellfa16a5c2009-02-08 10:37:06 -0800278
279 if (state < 0)
280 return state;
281 state &= 0x0f;
282
283 /* assume state != WARM_RESET; we'd not be running... */
284 if (!state)
285 return REGULATOR_STATUS_OFF;
286 return (state & BIT(3))
287 ? REGULATOR_STATUS_NORMAL
288 : REGULATOR_STATUS_STANDBY;
289}
290
Saquib Herman9a0244a2011-04-01 10:22:45 +0530291static int twl6030reg_get_status(struct regulator_dev *rdev)
292{
293 struct twlreg_info *info = rdev_get_drvdata(rdev);
294 int val;
295
296 val = twlreg_grp(rdev);
297 if (val < 0)
298 return val;
299
300 val = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_STATE);
301
302 switch (TWL6030_CFG_STATE_APP(val)) {
303 case TWL6030_CFG_STATE_ON:
304 return REGULATOR_STATUS_NORMAL;
305
306 case TWL6030_CFG_STATE_SLEEP:
307 return REGULATOR_STATUS_STANDBY;
308
309 case TWL6030_CFG_STATE_OFF:
310 case TWL6030_CFG_STATE_OFF2:
311 default:
312 break;
313 }
314
315 return REGULATOR_STATUS_OFF;
316}
317
Saquib Herman1a399622011-04-01 10:22:46 +0530318static int twl4030reg_set_mode(struct regulator_dev *rdev, unsigned mode)
David Brownellfa16a5c2009-02-08 10:37:06 -0800319{
320 struct twlreg_info *info = rdev_get_drvdata(rdev);
321 unsigned message;
322 int status;
323
324 /* We can only set the mode through state machine commands... */
325 switch (mode) {
326 case REGULATOR_MODE_NORMAL:
327 message = MSG_SINGULAR(DEV_GRP_P1, info->id, RES_STATE_ACTIVE);
328 break;
329 case REGULATOR_MODE_STANDBY:
330 message = MSG_SINGULAR(DEV_GRP_P1, info->id, RES_STATE_SLEEP);
331 break;
332 default:
333 return -EINVAL;
334 }
335
336 /* Ensure the resource is associated with some group */
Rajendra Nayakc4aa6f32009-12-13 21:36:49 +0100337 status = twlreg_grp(rdev);
David Brownellfa16a5c2009-02-08 10:37:06 -0800338 if (status < 0)
339 return status;
Rajendra Nayak441a4502009-12-13 22:19:23 +0100340 if (!(status & (P3_GRP_4030 | P2_GRP_4030 | P1_GRP_4030)))
David Brownellfa16a5c2009-02-08 10:37:06 -0800341 return -EACCES;
342
Rajendra Nayakc4aa6f32009-12-13 21:36:49 +0100343 status = twl_i2c_write_u8(TWL_MODULE_PM_MASTER,
Axel Linb9e26bc2010-10-22 16:38:22 +0800344 message >> 8, TWL4030_PM_MASTER_PB_WORD_MSB);
345 if (status < 0)
David Brownellfa16a5c2009-02-08 10:37:06 -0800346 return status;
347
Rajendra Nayakc4aa6f32009-12-13 21:36:49 +0100348 return twl_i2c_write_u8(TWL_MODULE_PM_MASTER,
Axel Linb9e26bc2010-10-22 16:38:22 +0800349 message & 0xff, TWL4030_PM_MASTER_PB_WORD_LSB);
David Brownellfa16a5c2009-02-08 10:37:06 -0800350}
351
Saquib Herman1a399622011-04-01 10:22:46 +0530352static int twl6030reg_set_mode(struct regulator_dev *rdev, unsigned mode)
353{
354 struct twlreg_info *info = rdev_get_drvdata(rdev);
Graeme Gregory4d94aee2011-05-22 21:21:23 +0100355 int grp = 0;
Saquib Herman1a399622011-04-01 10:22:46 +0530356 int val;
357
Graeme Gregory4d94aee2011-05-22 21:21:23 +0100358 if (!(twl_class_is_6030() && (info->features & TWL6025_SUBCLASS)))
Axel Linb6f476c2012-04-11 11:07:17 +0800359 grp = twlreg_grp(rdev);
Saquib Herman1a399622011-04-01 10:22:46 +0530360
361 if (grp < 0)
362 return grp;
363
364 /* Compose the state register settings */
365 val = grp << TWL6030_CFG_STATE_GRP_SHIFT;
366 /* We can only set the mode through state machine commands... */
367 switch (mode) {
368 case REGULATOR_MODE_NORMAL:
369 val |= TWL6030_CFG_STATE_ON;
370 break;
371 case REGULATOR_MODE_STANDBY:
372 val |= TWL6030_CFG_STATE_SLEEP;
373 break;
374
375 default:
376 return -EINVAL;
377 }
378
379 return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_STATE, val);
380}
381
David Brownellfa16a5c2009-02-08 10:37:06 -0800382/*----------------------------------------------------------------------*/
383
384/*
385 * Support for adjustable-voltage LDOs uses a four bit (or less) voltage
386 * select field in its control register. We use tables indexed by VSEL
387 * to record voltages in milliVolts. (Accuracy is about three percent.)
388 *
389 * Note that VSEL values for VAUX2 changed in twl5030 and newer silicon;
390 * currently handled by listing two slightly different VAUX2 regulators,
391 * only one of which will be configured.
392 *
393 * VSEL values documented as "TI cannot support these values" are flagged
394 * in these tables as UNSUP() values; we normally won't assign them.
Adrian Hunterd6bb69c2009-03-06 14:51:30 +0200395 *
396 * VAUX3 at 3V is incorrectly listed in some TI manuals as unsupported.
397 * TI are revising the twl5030/tps659x0 specs to support that 3.0V setting.
David Brownellfa16a5c2009-02-08 10:37:06 -0800398 */
399#ifdef CONFIG_TWL4030_ALLOW_UNSUPPORTED
400#define UNSUP_MASK 0x0000
401#else
402#define UNSUP_MASK 0x8000
403#endif
404
405#define UNSUP(x) (UNSUP_MASK | (x))
406#define IS_UNSUP(x) (UNSUP_MASK & (x))
407#define LDO_MV(x) (~UNSUP_MASK & (x))
408
409
410static const u16 VAUX1_VSEL_table[] = {
411 UNSUP(1500), UNSUP(1800), 2500, 2800,
412 3000, 3000, 3000, 3000,
413};
414static const u16 VAUX2_4030_VSEL_table[] = {
415 UNSUP(1000), UNSUP(1000), UNSUP(1200), 1300,
416 1500, 1800, UNSUP(1850), 2500,
417 UNSUP(2600), 2800, UNSUP(2850), UNSUP(3000),
418 UNSUP(3150), UNSUP(3150), UNSUP(3150), UNSUP(3150),
419};
420static const u16 VAUX2_VSEL_table[] = {
421 1700, 1700, 1900, 1300,
422 1500, 1800, 2000, 2500,
423 2100, 2800, 2200, 2300,
424 2400, 2400, 2400, 2400,
425};
426static const u16 VAUX3_VSEL_table[] = {
427 1500, 1800, 2500, 2800,
Adrian Hunterd6bb69c2009-03-06 14:51:30 +0200428 3000, 3000, 3000, 3000,
David Brownellfa16a5c2009-02-08 10:37:06 -0800429};
430static const u16 VAUX4_VSEL_table[] = {
431 700, 1000, 1200, UNSUP(1300),
432 1500, 1800, UNSUP(1850), 2500,
David Brownell1897e742009-03-10 11:51:15 -0800433 UNSUP(2600), 2800, UNSUP(2850), UNSUP(3000),
434 UNSUP(3150), UNSUP(3150), UNSUP(3150), UNSUP(3150),
David Brownellfa16a5c2009-02-08 10:37:06 -0800435};
436static const u16 VMMC1_VSEL_table[] = {
437 1850, 2850, 3000, 3150,
438};
439static const u16 VMMC2_VSEL_table[] = {
440 UNSUP(1000), UNSUP(1000), UNSUP(1200), UNSUP(1300),
441 UNSUP(1500), UNSUP(1800), 1850, UNSUP(2500),
442 2600, 2800, 2850, 3000,
443 3150, 3150, 3150, 3150,
444};
445static const u16 VPLL1_VSEL_table[] = {
446 1000, 1200, 1300, 1800,
447 UNSUP(2800), UNSUP(3000), UNSUP(3000), UNSUP(3000),
448};
449static const u16 VPLL2_VSEL_table[] = {
450 700, 1000, 1200, 1300,
451 UNSUP(1500), 1800, UNSUP(1850), UNSUP(2500),
452 UNSUP(2600), UNSUP(2800), UNSUP(2850), UNSUP(3000),
453 UNSUP(3150), UNSUP(3150), UNSUP(3150), UNSUP(3150),
454};
455static const u16 VSIM_VSEL_table[] = {
456 UNSUP(1000), UNSUP(1200), UNSUP(1300), 1800,
457 2800, 3000, 3000, 3000,
458};
459static const u16 VDAC_VSEL_table[] = {
460 1200, 1300, 1800, 1800,
461};
Juha Keski-Saari07fc4932009-12-16 15:27:55 +0200462static const u16 VDD1_VSEL_table[] = {
463 800, 1450,
464};
465static const u16 VDD2_VSEL_table[] = {
466 800, 1450, 1500,
467};
468static const u16 VIO_VSEL_table[] = {
469 1800, 1850,
470};
471static const u16 VINTANA2_VSEL_table[] = {
472 2500, 2750,
473};
David Brownellfa16a5c2009-02-08 10:37:06 -0800474
Rajendra Nayak3e3d3be2010-04-22 14:18:32 +0530475static int twl4030ldo_list_voltage(struct regulator_dev *rdev, unsigned index)
David Brownell66b659e2009-02-26 11:50:14 -0800476{
477 struct twlreg_info *info = rdev_get_drvdata(rdev);
478 int mV = info->table[index];
479
480 return IS_UNSUP(mV) ? 0 : (LDO_MV(mV) * 1000);
481}
482
David Brownellfa16a5c2009-02-08 10:37:06 -0800483static int
Axel Lindd16b1f2012-03-26 09:30:06 +0800484twl4030ldo_set_voltage_sel(struct regulator_dev *rdev, unsigned selector)
David Brownellfa16a5c2009-02-08 10:37:06 -0800485{
486 struct twlreg_info *info = rdev_get_drvdata(rdev);
David Brownellfa16a5c2009-02-08 10:37:06 -0800487
Axel Lindd16b1f2012-03-26 09:30:06 +0800488 return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE,
489 selector);
David Brownellfa16a5c2009-02-08 10:37:06 -0800490}
491
Rajendra Nayak3e3d3be2010-04-22 14:18:32 +0530492static int twl4030ldo_get_voltage(struct regulator_dev *rdev)
David Brownellfa16a5c2009-02-08 10:37:06 -0800493{
494 struct twlreg_info *info = rdev_get_drvdata(rdev);
Rajendra Nayak441a4502009-12-13 22:19:23 +0100495 int vsel = twlreg_read(info, TWL_MODULE_PM_RECEIVER,
496 VREG_VOLTAGE);
David Brownellfa16a5c2009-02-08 10:37:06 -0800497
498 if (vsel < 0)
499 return vsel;
500
501 vsel &= info->table_len - 1;
502 return LDO_MV(info->table[vsel]) * 1000;
503}
504
Rajendra Nayak3e3d3be2010-04-22 14:18:32 +0530505static struct regulator_ops twl4030ldo_ops = {
506 .list_voltage = twl4030ldo_list_voltage,
David Brownell66b659e2009-02-26 11:50:14 -0800507
Axel Lindd16b1f2012-03-26 09:30:06 +0800508 .set_voltage_sel = twl4030ldo_set_voltage_sel,
Rajendra Nayak3e3d3be2010-04-22 14:18:32 +0530509 .get_voltage = twl4030ldo_get_voltage,
510
Balaji T Kf8c29402011-05-20 19:03:51 +0530511 .enable = twl4030reg_enable,
Balaji T K0ff38972011-05-20 19:03:52 +0530512 .disable = twl4030reg_disable,
Saquib Hermanb2456772011-04-01 10:22:44 +0530513 .is_enabled = twl4030reg_is_enabled,
Axel Lin48c936d2012-04-11 11:05:57 +0800514 .enable_time = twl4030reg_enable_time,
Rajendra Nayak3e3d3be2010-04-22 14:18:32 +0530515
Saquib Herman1a399622011-04-01 10:22:46 +0530516 .set_mode = twl4030reg_set_mode,
Rajendra Nayak3e3d3be2010-04-22 14:18:32 +0530517
Saquib Herman9a0244a2011-04-01 10:22:45 +0530518 .get_status = twl4030reg_get_status,
Rajendra Nayak3e3d3be2010-04-22 14:18:32 +0530519};
520
Tero Kristoba305e32011-11-28 16:53:19 +0200521static int
522twl4030smps_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV,
523 unsigned *selector)
524{
525 struct twlreg_info *info = rdev_get_drvdata(rdev);
526 int vsel = DIV_ROUND_UP(min_uV - 600000, 12500);
527
Tero Kristo63bfff42012-02-16 12:27:52 +0200528 if (info->set_voltage) {
529 return info->set_voltage(info->data, min_uV);
530 } else {
531 twlreg_write(info, TWL_MODULE_PM_RECEIVER,
532 VREG_VOLTAGE_SMPS_4030, vsel);
533 }
534
Tero Kristoba305e32011-11-28 16:53:19 +0200535 return 0;
536}
537
538static int twl4030smps_get_voltage(struct regulator_dev *rdev)
539{
540 struct twlreg_info *info = rdev_get_drvdata(rdev);
Tero Kristo63bfff42012-02-16 12:27:52 +0200541 int vsel;
542
543 if (info->get_voltage)
544 return info->get_voltage(info->data);
545
546 vsel = twlreg_read(info, TWL_MODULE_PM_RECEIVER,
Tero Kristoba305e32011-11-28 16:53:19 +0200547 VREG_VOLTAGE_SMPS_4030);
548
549 return vsel * 12500 + 600000;
550}
551
552static struct regulator_ops twl4030smps_ops = {
553 .set_voltage = twl4030smps_set_voltage,
554 .get_voltage = twl4030smps_get_voltage,
555};
556
Tero Kristo34a38442012-02-28 15:09:10 +0530557static int twl6030coresmps_set_voltage(struct regulator_dev *rdev, int min_uV,
558 int max_uV, unsigned *selector)
559{
560 struct twlreg_info *info = rdev_get_drvdata(rdev);
561
562 if (info->set_voltage)
563 return info->set_voltage(info->data, min_uV);
564
565 return -ENODEV;
566}
567
568static int twl6030coresmps_get_voltage(struct regulator_dev *rdev)
569{
570 struct twlreg_info *info = rdev_get_drvdata(rdev);
571
572 if (info->get_voltage)
573 return info->get_voltage(info->data);
574
575 return -ENODEV;
576}
577
578static struct regulator_ops twl6030coresmps_ops = {
579 .set_voltage = twl6030coresmps_set_voltage,
580 .get_voltage = twl6030coresmps_get_voltage,
581};
582
Rajendra Nayak3e3d3be2010-04-22 14:18:32 +0530583static int twl6030ldo_list_voltage(struct regulator_dev *rdev, unsigned index)
584{
585 struct twlreg_info *info = rdev_get_drvdata(rdev);
586
587 return ((info->min_mV + (index * 100)) * 1000);
588}
589
590static int
Mark Brown3a93f2a2010-11-10 14:38:29 +0000591twl6030ldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV,
592 unsigned *selector)
Rajendra Nayak3e3d3be2010-04-22 14:18:32 +0530593{
594 struct twlreg_info *info = rdev_get_drvdata(rdev);
595 int vsel;
596
597 if ((min_uV/1000 < info->min_mV) || (max_uV/1000 > info->max_mV))
598 return -EDOM;
599
600 /*
601 * Use the below formula to calculate vsel
602 * mV = 1000mv + 100mv * (vsel - 1)
603 */
604 vsel = (min_uV/1000 - 1000)/100 + 1;
Mark Brown3a93f2a2010-11-10 14:38:29 +0000605 *selector = vsel;
Rajendra Nayak3e3d3be2010-04-22 14:18:32 +0530606 return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE, vsel);
607
608}
609
610static int twl6030ldo_get_voltage(struct regulator_dev *rdev)
611{
612 struct twlreg_info *info = rdev_get_drvdata(rdev);
613 int vsel = twlreg_read(info, TWL_MODULE_PM_RECEIVER,
614 VREG_VOLTAGE);
615
616 if (vsel < 0)
617 return vsel;
618
619 /*
620 * Use the below formula to calculate vsel
621 * mV = 1000mv + 100mv * (vsel - 1)
622 */
623 return (1000 + (100 * (vsel - 1))) * 1000;
624}
625
626static struct regulator_ops twl6030ldo_ops = {
627 .list_voltage = twl6030ldo_list_voltage,
628
629 .set_voltage = twl6030ldo_set_voltage,
630 .get_voltage = twl6030ldo_get_voltage,
David Brownellfa16a5c2009-02-08 10:37:06 -0800631
Balaji T Kf8c29402011-05-20 19:03:51 +0530632 .enable = twl6030reg_enable,
Balaji T K0ff38972011-05-20 19:03:52 +0530633 .disable = twl6030reg_disable,
Saquib Hermanb2456772011-04-01 10:22:44 +0530634 .is_enabled = twl6030reg_is_enabled,
Axel Lin48c936d2012-04-11 11:05:57 +0800635 .enable_time = twl6030reg_enable_time,
David Brownellfa16a5c2009-02-08 10:37:06 -0800636
Saquib Herman1a399622011-04-01 10:22:46 +0530637 .set_mode = twl6030reg_set_mode,
David Brownellfa16a5c2009-02-08 10:37:06 -0800638
Saquib Herman9a0244a2011-04-01 10:22:45 +0530639 .get_status = twl6030reg_get_status,
David Brownellfa16a5c2009-02-08 10:37:06 -0800640};
641
642/*----------------------------------------------------------------------*/
643
644/*
645 * Fixed voltage LDOs don't have a VSEL field to update.
646 */
Rajendra Nayakc4aa6f32009-12-13 21:36:49 +0100647static int twlfixed_list_voltage(struct regulator_dev *rdev, unsigned index)
David Brownell66b659e2009-02-26 11:50:14 -0800648{
649 struct twlreg_info *info = rdev_get_drvdata(rdev);
650
651 return info->min_mV * 1000;
652}
653
Rajendra Nayakc4aa6f32009-12-13 21:36:49 +0100654static int twlfixed_get_voltage(struct regulator_dev *rdev)
David Brownellfa16a5c2009-02-08 10:37:06 -0800655{
656 struct twlreg_info *info = rdev_get_drvdata(rdev);
657
658 return info->min_mV * 1000;
659}
660
Saquib Hermanb2456772011-04-01 10:22:44 +0530661static struct regulator_ops twl4030fixed_ops = {
Rajendra Nayakc4aa6f32009-12-13 21:36:49 +0100662 .list_voltage = twlfixed_list_voltage,
David Brownell66b659e2009-02-26 11:50:14 -0800663
Rajendra Nayakc4aa6f32009-12-13 21:36:49 +0100664 .get_voltage = twlfixed_get_voltage,
David Brownellfa16a5c2009-02-08 10:37:06 -0800665
Balaji T Kf8c29402011-05-20 19:03:51 +0530666 .enable = twl4030reg_enable,
Balaji T K0ff38972011-05-20 19:03:52 +0530667 .disable = twl4030reg_disable,
Saquib Hermanb2456772011-04-01 10:22:44 +0530668 .is_enabled = twl4030reg_is_enabled,
Axel Lin48c936d2012-04-11 11:05:57 +0800669 .enable_time = twl4030reg_enable_time,
Saquib Hermanb2456772011-04-01 10:22:44 +0530670
Saquib Herman1a399622011-04-01 10:22:46 +0530671 .set_mode = twl4030reg_set_mode,
Saquib Hermanb2456772011-04-01 10:22:44 +0530672
Saquib Herman9a0244a2011-04-01 10:22:45 +0530673 .get_status = twl4030reg_get_status,
Saquib Hermanb2456772011-04-01 10:22:44 +0530674};
675
676static struct regulator_ops twl6030fixed_ops = {
677 .list_voltage = twlfixed_list_voltage,
678
679 .get_voltage = twlfixed_get_voltage,
680
Balaji T Kf8c29402011-05-20 19:03:51 +0530681 .enable = twl6030reg_enable,
Balaji T K0ff38972011-05-20 19:03:52 +0530682 .disable = twl6030reg_disable,
Saquib Hermanb2456772011-04-01 10:22:44 +0530683 .is_enabled = twl6030reg_is_enabled,
Axel Lin48c936d2012-04-11 11:05:57 +0800684 .enable_time = twl6030reg_enable_time,
David Brownellfa16a5c2009-02-08 10:37:06 -0800685
Saquib Herman1a399622011-04-01 10:22:46 +0530686 .set_mode = twl6030reg_set_mode,
David Brownellfa16a5c2009-02-08 10:37:06 -0800687
Saquib Herman9a0244a2011-04-01 10:22:45 +0530688 .get_status = twl6030reg_get_status,
David Brownellfa16a5c2009-02-08 10:37:06 -0800689};
690
Balaji T K8e6de4a2011-02-10 18:44:50 +0530691static struct regulator_ops twl6030_fixed_resource = {
Balaji T Kf8c29402011-05-20 19:03:51 +0530692 .enable = twl6030reg_enable,
Balaji T K0ff38972011-05-20 19:03:52 +0530693 .disable = twl6030reg_disable,
Saquib Hermanb2456772011-04-01 10:22:44 +0530694 .is_enabled = twl6030reg_is_enabled,
Axel Lin48c936d2012-04-11 11:05:57 +0800695 .enable_time = twl6030reg_enable_time,
Saquib Herman9a0244a2011-04-01 10:22:45 +0530696 .get_status = twl6030reg_get_status,
Balaji T K8e6de4a2011-02-10 18:44:50 +0530697};
698
Graeme Gregory4d94aee2011-05-22 21:21:23 +0100699/*
700 * SMPS status and control
701 */
702
703static int twl6030smps_list_voltage(struct regulator_dev *rdev, unsigned index)
704{
705 struct twlreg_info *info = rdev_get_drvdata(rdev);
706
707 int voltage = 0;
708
709 switch (info->flags) {
710 case SMPS_OFFSET_EN:
711 voltage = 100000;
712 /* fall through */
713 case 0:
714 switch (index) {
715 case 0:
716 voltage = 0;
717 break;
718 case 58:
719 voltage = 1350 * 1000;
720 break;
721 case 59:
722 voltage = 1500 * 1000;
723 break;
724 case 60:
725 voltage = 1800 * 1000;
726 break;
727 case 61:
728 voltage = 1900 * 1000;
729 break;
730 case 62:
731 voltage = 2100 * 1000;
732 break;
733 default:
734 voltage += (600000 + (12500 * (index - 1)));
735 }
736 break;
737 case SMPS_EXTENDED_EN:
738 switch (index) {
739 case 0:
740 voltage = 0;
741 break;
742 case 58:
743 voltage = 2084 * 1000;
744 break;
745 case 59:
746 voltage = 2315 * 1000;
747 break;
748 case 60:
749 voltage = 2778 * 1000;
750 break;
751 case 61:
752 voltage = 2932 * 1000;
753 break;
754 case 62:
755 voltage = 3241 * 1000;
756 break;
757 default:
758 voltage = (1852000 + (38600 * (index - 1)));
759 }
760 break;
761 case SMPS_OFFSET_EN | SMPS_EXTENDED_EN:
762 switch (index) {
763 case 0:
764 voltage = 0;
765 break;
766 case 58:
767 voltage = 4167 * 1000;
768 break;
769 case 59:
770 voltage = 2315 * 1000;
771 break;
772 case 60:
773 voltage = 2778 * 1000;
774 break;
775 case 61:
776 voltage = 2932 * 1000;
777 break;
778 case 62:
779 voltage = 3241 * 1000;
780 break;
781 default:
782 voltage = (2161000 + (38600 * (index - 1)));
783 }
784 break;
785 }
786
787 return voltage;
788}
789
790static int
791twl6030smps_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV,
792 unsigned int *selector)
793{
794 struct twlreg_info *info = rdev_get_drvdata(rdev);
795 int vsel = 0;
796
797 switch (info->flags) {
798 case 0:
799 if (min_uV == 0)
800 vsel = 0;
Laxman Dewangana33b6e52012-02-03 12:54:38 +0530801 else if ((min_uV >= 600000) && (min_uV <= 1300000)) {
802 int calc_uV;
Axel Lin268a1642012-04-09 23:35:10 +0800803 vsel = DIV_ROUND_UP(min_uV - 600000, 12500);
Axel Lin0cb2f122012-04-10 23:07:52 +0800804 vsel++;
Laxman Dewangana33b6e52012-02-03 12:54:38 +0530805 calc_uV = twl6030smps_list_voltage(rdev, vsel);
806 if (calc_uV > max_uV)
807 return -EINVAL;
Graeme Gregory4d94aee2011-05-22 21:21:23 +0100808 }
809 /* Values 1..57 for vsel are linear and can be calculated
810 * values 58..62 are non linear.
811 */
812 else if ((min_uV > 1900000) && (max_uV >= 2100000))
813 vsel = 62;
814 else if ((min_uV > 1800000) && (max_uV >= 1900000))
815 vsel = 61;
816 else if ((min_uV > 1500000) && (max_uV >= 1800000))
817 vsel = 60;
818 else if ((min_uV > 1350000) && (max_uV >= 1500000))
819 vsel = 59;
820 else if ((min_uV > 1300000) && (max_uV >= 1350000))
821 vsel = 58;
822 else
823 return -EINVAL;
824 break;
825 case SMPS_OFFSET_EN:
826 if (min_uV == 0)
827 vsel = 0;
Laxman Dewangana33b6e52012-02-03 12:54:38 +0530828 else if ((min_uV >= 700000) && (min_uV <= 1420000)) {
829 int calc_uV;
Axel Lin268a1642012-04-09 23:35:10 +0800830 vsel = DIV_ROUND_UP(min_uV - 700000, 12500);
Axel Lin0cb2f122012-04-10 23:07:52 +0800831 vsel++;
Laxman Dewangana33b6e52012-02-03 12:54:38 +0530832 calc_uV = twl6030smps_list_voltage(rdev, vsel);
833 if (calc_uV > max_uV)
834 return -EINVAL;
Graeme Gregory4d94aee2011-05-22 21:21:23 +0100835 }
836 /* Values 1..57 for vsel are linear and can be calculated
837 * values 58..62 are non linear.
838 */
839 else if ((min_uV > 1900000) && (max_uV >= 2100000))
840 vsel = 62;
841 else if ((min_uV > 1800000) && (max_uV >= 1900000))
842 vsel = 61;
843 else if ((min_uV > 1350000) && (max_uV >= 1800000))
844 vsel = 60;
845 else if ((min_uV > 1350000) && (max_uV >= 1500000))
846 vsel = 59;
847 else if ((min_uV > 1300000) && (max_uV >= 1350000))
848 vsel = 58;
849 else
850 return -EINVAL;
851 break;
852 case SMPS_EXTENDED_EN:
Axel Lin0cb2f122012-04-10 23:07:52 +0800853 if (min_uV == 0) {
Graeme Gregory4d94aee2011-05-22 21:21:23 +0100854 vsel = 0;
Axel Lin0cb2f122012-04-10 23:07:52 +0800855 } else if ((min_uV >= 1852000) && (max_uV <= 4013600)) {
Axel Lin268a1642012-04-09 23:35:10 +0800856 vsel = DIV_ROUND_UP(min_uV - 1852000, 38600);
Axel Lin0cb2f122012-04-10 23:07:52 +0800857 vsel++;
858 }
Graeme Gregory4d94aee2011-05-22 21:21:23 +0100859 break;
860 case SMPS_OFFSET_EN|SMPS_EXTENDED_EN:
Axel Lin0cb2f122012-04-10 23:07:52 +0800861 if (min_uV == 0) {
Graeme Gregory4d94aee2011-05-22 21:21:23 +0100862 vsel = 0;
Axel Lin0cb2f122012-04-10 23:07:52 +0800863 } else if ((min_uV >= 2161000) && (max_uV <= 4321000)) {
Axel Lin268a1642012-04-09 23:35:10 +0800864 vsel = DIV_ROUND_UP(min_uV - 2161000, 38600);
Axel Lin0cb2f122012-04-10 23:07:52 +0800865 vsel++;
866 }
Graeme Gregory4d94aee2011-05-22 21:21:23 +0100867 break;
868 }
869
870 *selector = vsel;
871
872 return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE_SMPS,
873 vsel);
874}
875
876static int twl6030smps_get_voltage_sel(struct regulator_dev *rdev)
877{
878 struct twlreg_info *info = rdev_get_drvdata(rdev);
879
880 return twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE_SMPS);
881}
882
883static struct regulator_ops twlsmps_ops = {
884 .list_voltage = twl6030smps_list_voltage,
885
886 .set_voltage = twl6030smps_set_voltage,
887 .get_voltage_sel = twl6030smps_get_voltage_sel,
888
889 .enable = twl6030reg_enable,
890 .disable = twl6030reg_disable,
891 .is_enabled = twl6030reg_is_enabled,
Axel Lin48c936d2012-04-11 11:05:57 +0800892 .enable_time = twl6030reg_enable_time,
Graeme Gregory4d94aee2011-05-22 21:21:23 +0100893
894 .set_mode = twl6030reg_set_mode,
895
896 .get_status = twl6030reg_get_status,
897};
898
David Brownellfa16a5c2009-02-08 10:37:06 -0800899/*----------------------------------------------------------------------*/
900
Juha Keski-Saari045f9722009-12-16 14:49:52 +0200901#define TWL4030_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \
902 remap_conf) \
903 TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \
Saquib Hermanb2456772011-04-01 10:22:44 +0530904 remap_conf, TWL4030, twl4030fixed_ops)
Ambresh Kaf8b2442011-07-09 19:02:21 -0700905#define TWL6030_FIXED_LDO(label, offset, mVolts, turnon_delay) \
906 TWL_FIXED_LDO(label, offset, mVolts, 0x0, turnon_delay, \
Saquib Hermanb2456772011-04-01 10:22:44 +0530907 0x0, TWL6030, twl6030fixed_ops)
Rajendra Nayakc4aa6f32009-12-13 21:36:49 +0100908
Rajendra Nayak2098e952012-02-28 15:09:11 +0530909#define TWL4030_ADJUSTABLE_LDO(label, offset, num, turnon_delay, remap_conf) \
910static struct twlreg_info TWL4030_INFO_##label = { \
David Brownellfa16a5c2009-02-08 10:37:06 -0800911 .base = offset, \
912 .id = num, \
913 .table_len = ARRAY_SIZE(label##_VSEL_table), \
914 .table = label##_VSEL_table, \
Juha Keski-Saari045f9722009-12-16 14:49:52 +0200915 .delay = turnon_delay, \
916 .remap = remap_conf, \
David Brownellfa16a5c2009-02-08 10:37:06 -0800917 .desc = { \
918 .name = #label, \
Rajendra Nayak3e3d3be2010-04-22 14:18:32 +0530919 .id = TWL4030_REG_##label, \
David Brownell66b659e2009-02-26 11:50:14 -0800920 .n_voltages = ARRAY_SIZE(label##_VSEL_table), \
Rajendra Nayak3e3d3be2010-04-22 14:18:32 +0530921 .ops = &twl4030ldo_ops, \
David Brownellfa16a5c2009-02-08 10:37:06 -0800922 .type = REGULATOR_VOLTAGE, \
923 .owner = THIS_MODULE, \
924 }, \
925 }
926
Tero Kristoba305e32011-11-28 16:53:19 +0200927#define TWL4030_ADJUSTABLE_SMPS(label, offset, num, turnon_delay, remap_conf) \
Rajendra Nayak2098e952012-02-28 15:09:11 +0530928static struct twlreg_info TWL4030_INFO_##label = { \
Tero Kristoba305e32011-11-28 16:53:19 +0200929 .base = offset, \
930 .id = num, \
931 .delay = turnon_delay, \
932 .remap = remap_conf, \
933 .desc = { \
934 .name = #label, \
935 .id = TWL4030_REG_##label, \
936 .ops = &twl4030smps_ops, \
937 .type = REGULATOR_VOLTAGE, \
938 .owner = THIS_MODULE, \
939 }, \
940 }
941
Rajendra Nayak2098e952012-02-28 15:09:11 +0530942#define TWL6030_ADJUSTABLE_SMPS(label) \
943static struct twlreg_info TWL6030_INFO_##label = { \
Tero Kristo34a38442012-02-28 15:09:10 +0530944 .desc = { \
945 .name = #label, \
946 .id = TWL6030_REG_##label, \
947 .ops = &twl6030coresmps_ops, \
948 .type = REGULATOR_VOLTAGE, \
949 .owner = THIS_MODULE, \
950 }, \
951 }
952
Rajendra Nayak2098e952012-02-28 15:09:11 +0530953#define TWL6030_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts) \
954static struct twlreg_info TWL6030_INFO_##label = { \
Rajendra Nayak3e3d3be2010-04-22 14:18:32 +0530955 .base = offset, \
Rajendra Nayak3e3d3be2010-04-22 14:18:32 +0530956 .min_mV = min_mVolts, \
957 .max_mV = max_mVolts, \
Rajendra Nayak3e3d3be2010-04-22 14:18:32 +0530958 .desc = { \
959 .name = #label, \
960 .id = TWL6030_REG_##label, \
Colin Cross7736f112011-05-27 12:25:27 -0700961 .n_voltages = (max_mVolts - min_mVolts)/100 + 1, \
Rajendra Nayak3e3d3be2010-04-22 14:18:32 +0530962 .ops = &twl6030ldo_ops, \
963 .type = REGULATOR_VOLTAGE, \
964 .owner = THIS_MODULE, \
965 }, \
966 }
967
Rajendra Nayak2098e952012-02-28 15:09:11 +0530968#define TWL6025_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts) \
969static struct twlreg_info TWL6025_INFO_##label = { \
Graeme Gregory4d94aee2011-05-22 21:21:23 +0100970 .base = offset, \
Graeme Gregory4d94aee2011-05-22 21:21:23 +0100971 .min_mV = min_mVolts, \
972 .max_mV = max_mVolts, \
973 .desc = { \
974 .name = #label, \
975 .id = TWL6025_REG_##label, \
976 .n_voltages = ((max_mVolts - min_mVolts)/100) + 1, \
977 .ops = &twl6030ldo_ops, \
978 .type = REGULATOR_VOLTAGE, \
979 .owner = THIS_MODULE, \
980 }, \
981 }
Rajendra Nayak3e3d3be2010-04-22 14:18:32 +0530982
Juha Keski-Saari045f9722009-12-16 14:49:52 +0200983#define TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, remap_conf, \
Rajendra Nayak2098e952012-02-28 15:09:11 +0530984 family, operations) \
985static struct twlreg_info TWLFIXED_INFO_##label = { \
David Brownellfa16a5c2009-02-08 10:37:06 -0800986 .base = offset, \
987 .id = num, \
988 .min_mV = mVolts, \
Juha Keski-Saari045f9722009-12-16 14:49:52 +0200989 .delay = turnon_delay, \
990 .remap = remap_conf, \
David Brownellfa16a5c2009-02-08 10:37:06 -0800991 .desc = { \
992 .name = #label, \
Rajendra Nayakc4aa6f32009-12-13 21:36:49 +0100993 .id = family##_REG_##label, \
David Brownell66b659e2009-02-26 11:50:14 -0800994 .n_voltages = 1, \
Saquib Hermanb2456772011-04-01 10:22:44 +0530995 .ops = &operations, \
David Brownellfa16a5c2009-02-08 10:37:06 -0800996 .type = REGULATOR_VOLTAGE, \
997 .owner = THIS_MODULE, \
998 }, \
999 }
1000
Rajendra Nayak2098e952012-02-28 15:09:11 +05301001#define TWL6030_FIXED_RESOURCE(label, offset, turnon_delay) \
1002static struct twlreg_info TWLRES_INFO_##label = { \
Balaji T K8e6de4a2011-02-10 18:44:50 +05301003 .base = offset, \
Balaji T K8e6de4a2011-02-10 18:44:50 +05301004 .delay = turnon_delay, \
Balaji T K8e6de4a2011-02-10 18:44:50 +05301005 .desc = { \
1006 .name = #label, \
1007 .id = TWL6030_REG_##label, \
1008 .ops = &twl6030_fixed_resource, \
1009 .type = REGULATOR_VOLTAGE, \
1010 .owner = THIS_MODULE, \
1011 }, \
1012 }
1013
Rajendra Nayak2098e952012-02-28 15:09:11 +05301014#define TWL6025_ADJUSTABLE_SMPS(label, offset) \
1015static struct twlreg_info TWLSMPS_INFO_##label = { \
Graeme Gregory4d94aee2011-05-22 21:21:23 +01001016 .base = offset, \
Graeme Gregory4d94aee2011-05-22 21:21:23 +01001017 .min_mV = 600, \
1018 .max_mV = 2100, \
1019 .desc = { \
1020 .name = #label, \
1021 .id = TWL6025_REG_##label, \
1022 .n_voltages = 63, \
1023 .ops = &twlsmps_ops, \
1024 .type = REGULATOR_VOLTAGE, \
1025 .owner = THIS_MODULE, \
1026 }, \
1027 }
1028
David Brownellfa16a5c2009-02-08 10:37:06 -08001029/*
1030 * We list regulators here if systems need some level of
1031 * software control over them after boot.
1032 */
Rajendra Nayak2098e952012-02-28 15:09:11 +05301033TWL4030_ADJUSTABLE_LDO(VAUX1, 0x17, 1, 100, 0x08);
1034TWL4030_ADJUSTABLE_LDO(VAUX2_4030, 0x1b, 2, 100, 0x08);
1035TWL4030_ADJUSTABLE_LDO(VAUX2, 0x1b, 2, 100, 0x08);
1036TWL4030_ADJUSTABLE_LDO(VAUX3, 0x1f, 3, 100, 0x08);
1037TWL4030_ADJUSTABLE_LDO(VAUX4, 0x23, 4, 100, 0x08);
1038TWL4030_ADJUSTABLE_LDO(VMMC1, 0x27, 5, 100, 0x08);
1039TWL4030_ADJUSTABLE_LDO(VMMC2, 0x2b, 6, 100, 0x08);
1040TWL4030_ADJUSTABLE_LDO(VPLL1, 0x2f, 7, 100, 0x00);
1041TWL4030_ADJUSTABLE_LDO(VPLL2, 0x33, 8, 100, 0x08);
1042TWL4030_ADJUSTABLE_LDO(VSIM, 0x37, 9, 100, 0x00);
1043TWL4030_ADJUSTABLE_LDO(VDAC, 0x3b, 10, 100, 0x08);
1044TWL4030_ADJUSTABLE_LDO(VINTANA2, 0x43, 12, 100, 0x08);
1045TWL4030_ADJUSTABLE_LDO(VIO, 0x4b, 14, 1000, 0x08);
1046TWL4030_ADJUSTABLE_SMPS(VDD1, 0x55, 15, 1000, 0x08);
1047TWL4030_ADJUSTABLE_SMPS(VDD2, 0x63, 16, 1000, 0x08);
1048/* VUSBCP is managed *only* by the USB subchip */
1049/* 6030 REG with base as PMC Slave Misc : 0x0030 */
1050/* Turnon-delay and remap configuration values for 6030 are not
1051 verified since the specification is not public */
1052TWL6030_ADJUSTABLE_SMPS(VDD1);
1053TWL6030_ADJUSTABLE_SMPS(VDD2);
1054TWL6030_ADJUSTABLE_SMPS(VDD3);
1055TWL6030_ADJUSTABLE_LDO(VAUX1_6030, 0x54, 1000, 3300);
1056TWL6030_ADJUSTABLE_LDO(VAUX2_6030, 0x58, 1000, 3300);
1057TWL6030_ADJUSTABLE_LDO(VAUX3_6030, 0x5c, 1000, 3300);
1058TWL6030_ADJUSTABLE_LDO(VMMC, 0x68, 1000, 3300);
1059TWL6030_ADJUSTABLE_LDO(VPP, 0x6c, 1000, 3300);
1060TWL6030_ADJUSTABLE_LDO(VUSIM, 0x74, 1000, 3300);
1061/* 6025 are renamed compared to 6030 versions */
1062TWL6025_ADJUSTABLE_LDO(LDO2, 0x54, 1000, 3300);
1063TWL6025_ADJUSTABLE_LDO(LDO4, 0x58, 1000, 3300);
1064TWL6025_ADJUSTABLE_LDO(LDO3, 0x5c, 1000, 3300);
1065TWL6025_ADJUSTABLE_LDO(LDO5, 0x68, 1000, 3300);
1066TWL6025_ADJUSTABLE_LDO(LDO1, 0x6c, 1000, 3300);
1067TWL6025_ADJUSTABLE_LDO(LDO7, 0x74, 1000, 3300);
1068TWL6025_ADJUSTABLE_LDO(LDO6, 0x60, 1000, 3300);
1069TWL6025_ADJUSTABLE_LDO(LDOLN, 0x64, 1000, 3300);
1070TWL6025_ADJUSTABLE_LDO(LDOUSB, 0x70, 1000, 3300);
1071TWL4030_FIXED_LDO(VINTANA2, 0x3f, 1500, 11, 100, 0x08);
1072TWL4030_FIXED_LDO(VINTDIG, 0x47, 1500, 13, 100, 0x08);
1073TWL4030_FIXED_LDO(VUSB1V5, 0x71, 1500, 17, 100, 0x08);
1074TWL4030_FIXED_LDO(VUSB1V8, 0x74, 1800, 18, 100, 0x08);
1075TWL4030_FIXED_LDO(VUSB3V1, 0x77, 3100, 19, 150, 0x08);
1076TWL6030_FIXED_LDO(VANA, 0x50, 2100, 0);
1077TWL6030_FIXED_LDO(VCXIO, 0x60, 1800, 0);
1078TWL6030_FIXED_LDO(VDAC, 0x64, 1800, 0);
1079TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 0);
Peter Ujfalusie9d47fa2012-02-28 15:09:12 +05301080TWL6030_FIXED_LDO(V1V8, 0x16, 1800, 0);
1081TWL6030_FIXED_LDO(V2V1, 0x1c, 2100, 0);
Rajendra Nayak2098e952012-02-28 15:09:11 +05301082TWL6030_FIXED_RESOURCE(CLK32KG, 0x8C, 0);
1083TWL6025_ADJUSTABLE_SMPS(SMPS3, 0x34);
1084TWL6025_ADJUSTABLE_SMPS(SMPS4, 0x10);
1085TWL6025_ADJUSTABLE_SMPS(VIO, 0x16);
David Brownellfa16a5c2009-02-08 10:37:06 -08001086
Graeme Gregory4d94aee2011-05-22 21:21:23 +01001087static u8 twl_get_smps_offset(void)
1088{
1089 u8 value;
1090
1091 twl_i2c_read_u8(TWL_MODULE_PM_RECEIVER, &value,
1092 TWL6030_SMPS_OFFSET);
1093 return value;
1094}
1095
1096static u8 twl_get_smps_mult(void)
1097{
1098 u8 value;
1099
1100 twl_i2c_read_u8(TWL_MODULE_PM_RECEIVER, &value,
1101 TWL6030_SMPS_MULT);
1102 return value;
1103}
1104
Rajendra Nayak2098e952012-02-28 15:09:11 +05301105#define TWL_OF_MATCH(comp, family, label) \
1106 { \
1107 .compatible = comp, \
1108 .data = &family##_INFO_##label, \
1109 }
1110
1111#define TWL4030_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWL4030, label)
1112#define TWL6030_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWL6030, label)
1113#define TWL6025_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWL6025, label)
1114#define TWLFIXED_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWLFIXED, label)
1115#define TWLRES_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWLRES, label)
1116#define TWLSMPS_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWLSMPS, label)
1117
1118static const struct of_device_id twl_of_match[] __devinitconst = {
1119 TWL4030_OF_MATCH("ti,twl4030-vaux1", VAUX1),
1120 TWL4030_OF_MATCH("ti,twl4030-vaux2", VAUX2_4030),
1121 TWL4030_OF_MATCH("ti,twl5030-vaux2", VAUX2),
1122 TWL4030_OF_MATCH("ti,twl4030-vaux3", VAUX3),
1123 TWL4030_OF_MATCH("ti,twl4030-vaux4", VAUX4),
1124 TWL4030_OF_MATCH("ti,twl4030-vmmc1", VMMC1),
1125 TWL4030_OF_MATCH("ti,twl4030-vmmc2", VMMC2),
1126 TWL4030_OF_MATCH("ti,twl4030-vpll1", VPLL1),
1127 TWL4030_OF_MATCH("ti,twl4030-vpll2", VPLL2),
1128 TWL4030_OF_MATCH("ti,twl4030-vsim", VSIM),
1129 TWL4030_OF_MATCH("ti,twl4030-vdac", VDAC),
1130 TWL4030_OF_MATCH("ti,twl4030-vintana2", VINTANA2),
1131 TWL4030_OF_MATCH("ti,twl4030-vio", VIO),
1132 TWL4030_OF_MATCH("ti,twl4030-vdd1", VDD1),
1133 TWL4030_OF_MATCH("ti,twl4030-vdd2", VDD2),
1134 TWL6030_OF_MATCH("ti,twl6030-vdd1", VDD1),
1135 TWL6030_OF_MATCH("ti,twl6030-vdd2", VDD2),
1136 TWL6030_OF_MATCH("ti,twl6030-vdd3", VDD3),
1137 TWL6030_OF_MATCH("ti,twl6030-vaux1", VAUX1_6030),
1138 TWL6030_OF_MATCH("ti,twl6030-vaux2", VAUX2_6030),
1139 TWL6030_OF_MATCH("ti,twl6030-vaux3", VAUX3_6030),
1140 TWL6030_OF_MATCH("ti,twl6030-vmmc", VMMC),
1141 TWL6030_OF_MATCH("ti,twl6030-vpp", VPP),
1142 TWL6030_OF_MATCH("ti,twl6030-vusim", VUSIM),
1143 TWL6025_OF_MATCH("ti,twl6025-ldo2", LDO2),
1144 TWL6025_OF_MATCH("ti,twl6025-ldo4", LDO4),
1145 TWL6025_OF_MATCH("ti,twl6025-ldo3", LDO3),
1146 TWL6025_OF_MATCH("ti,twl6025-ldo5", LDO5),
1147 TWL6025_OF_MATCH("ti,twl6025-ldo1", LDO1),
1148 TWL6025_OF_MATCH("ti,twl6025-ldo7", LDO7),
1149 TWL6025_OF_MATCH("ti,twl6025-ldo6", LDO6),
1150 TWL6025_OF_MATCH("ti,twl6025-ldoln", LDOLN),
1151 TWL6025_OF_MATCH("ti,twl6025-ldousb", LDOUSB),
1152 TWLFIXED_OF_MATCH("ti,twl4030-vintana2", VINTANA2),
1153 TWLFIXED_OF_MATCH("ti,twl4030-vintdig", VINTDIG),
1154 TWLFIXED_OF_MATCH("ti,twl4030-vusb1v5", VUSB1V5),
1155 TWLFIXED_OF_MATCH("ti,twl4030-vusb1v8", VUSB1V8),
1156 TWLFIXED_OF_MATCH("ti,twl4030-vusb3v1", VUSB3V1),
1157 TWLFIXED_OF_MATCH("ti,twl6030-vana", VANA),
1158 TWLFIXED_OF_MATCH("ti,twl6030-vcxio", VCXIO),
1159 TWLFIXED_OF_MATCH("ti,twl6030-vdac", VDAC),
1160 TWLFIXED_OF_MATCH("ti,twl6030-vusb", VUSB),
Peter Ujfalusie9d47fa2012-02-28 15:09:12 +05301161 TWLFIXED_OF_MATCH("ti,twl6030-v1v8", V1V8),
1162 TWLFIXED_OF_MATCH("ti,twl6030-v2v1", V2V1),
Rajendra Nayak2098e952012-02-28 15:09:11 +05301163 TWLRES_OF_MATCH("ti,twl6030-clk32kg", CLK32KG),
1164 TWLSMPS_OF_MATCH("ti,twl6025-smps3", SMPS3),
1165 TWLSMPS_OF_MATCH("ti,twl6025-smps4", SMPS4),
1166 TWLSMPS_OF_MATCH("ti,twl6025-vio", VIO),
1167 {},
1168};
1169MODULE_DEVICE_TABLE(of, twl_of_match);
1170
Dmitry Torokhov24c29022010-02-23 23:38:01 -08001171static int __devinit twlreg_probe(struct platform_device *pdev)
David Brownellfa16a5c2009-02-08 10:37:06 -08001172{
Rajendra Nayak2098e952012-02-28 15:09:11 +05301173 int i, id;
David Brownellfa16a5c2009-02-08 10:37:06 -08001174 struct twlreg_info *info;
1175 struct regulator_init_data *initdata;
1176 struct regulation_constraints *c;
1177 struct regulator_dev *rdev;
Tero Kristo63bfff42012-02-16 12:27:52 +02001178 struct twl_regulator_driver_data *drvdata;
Rajendra Nayak2098e952012-02-28 15:09:11 +05301179 const struct of_device_id *match;
Mark Brownc1727082012-04-04 00:50:22 +01001180 struct regulator_config config = { };
David Brownellfa16a5c2009-02-08 10:37:06 -08001181
Rajendra Nayak2098e952012-02-28 15:09:11 +05301182 match = of_match_device(twl_of_match, &pdev->dev);
1183 if (match) {
1184 info = match->data;
1185 id = info->desc.id;
1186 initdata = of_get_regulator_init_data(&pdev->dev,
1187 pdev->dev.of_node);
1188 drvdata = NULL;
1189 } else {
1190 id = pdev->id;
1191 initdata = pdev->dev.platform_data;
1192 for (i = 0, info = NULL; i < ARRAY_SIZE(twl_of_match); i++) {
1193 info = twl_of_match[i].data;
Axel Lin5ade3932012-04-09 22:32:49 +08001194 if (info && info->desc.id == id)
1195 break;
Rajendra Nayak2098e952012-02-28 15:09:11 +05301196 }
Axel Lin5ade3932012-04-09 22:32:49 +08001197 if (i == ARRAY_SIZE(twl_of_match))
1198 return -ENODEV;
1199
Rajendra Nayak2098e952012-02-28 15:09:11 +05301200 drvdata = initdata->driver_data;
1201 if (!drvdata)
1202 return -EINVAL;
David Brownellfa16a5c2009-02-08 10:37:06 -08001203 }
Rajendra Nayak2098e952012-02-28 15:09:11 +05301204
David Brownellfa16a5c2009-02-08 10:37:06 -08001205 if (!info)
1206 return -ENODEV;
1207
David Brownellfa16a5c2009-02-08 10:37:06 -08001208 if (!initdata)
1209 return -EINVAL;
1210
Rajendra Nayak2098e952012-02-28 15:09:11 +05301211 if (drvdata) {
1212 /* copy the driver data into regulator data */
1213 info->features = drvdata->features;
1214 info->data = drvdata->data;
1215 info->set_voltage = drvdata->set_voltage;
1216 info->get_voltage = drvdata->get_voltage;
1217 }
Graeme Gregory4d94aee2011-05-22 21:21:23 +01001218
David Brownellfa16a5c2009-02-08 10:37:06 -08001219 /* Constrain board-specific capabilities according to what
1220 * this driver and the chip itself can actually do.
1221 */
1222 c = &initdata->constraints;
David Brownellfa16a5c2009-02-08 10:37:06 -08001223 c->valid_modes_mask &= REGULATOR_MODE_NORMAL | REGULATOR_MODE_STANDBY;
1224 c->valid_ops_mask &= REGULATOR_CHANGE_VOLTAGE
1225 | REGULATOR_CHANGE_MODE
1226 | REGULATOR_CHANGE_STATUS;
Rajendra Nayak2098e952012-02-28 15:09:11 +05301227 switch (id) {
Juha Keski-Saari205e5cd2009-12-16 15:27:56 +02001228 case TWL4030_REG_VIO:
1229 case TWL4030_REG_VDD1:
1230 case TWL4030_REG_VDD2:
1231 case TWL4030_REG_VPLL1:
1232 case TWL4030_REG_VINTANA1:
1233 case TWL4030_REG_VINTANA2:
1234 case TWL4030_REG_VINTDIG:
1235 c->always_on = true;
1236 break;
1237 default:
1238 break;
1239 }
David Brownellfa16a5c2009-02-08 10:37:06 -08001240
Rajendra Nayak2098e952012-02-28 15:09:11 +05301241 switch (id) {
Graeme Gregory4d94aee2011-05-22 21:21:23 +01001242 case TWL6025_REG_SMPS3:
1243 if (twl_get_smps_mult() & SMPS_MULTOFFSET_SMPS3)
1244 info->flags |= SMPS_EXTENDED_EN;
1245 if (twl_get_smps_offset() & SMPS_MULTOFFSET_SMPS3)
1246 info->flags |= SMPS_OFFSET_EN;
1247 break;
1248 case TWL6025_REG_SMPS4:
1249 if (twl_get_smps_mult() & SMPS_MULTOFFSET_SMPS4)
1250 info->flags |= SMPS_EXTENDED_EN;
1251 if (twl_get_smps_offset() & SMPS_MULTOFFSET_SMPS4)
1252 info->flags |= SMPS_OFFSET_EN;
1253 break;
1254 case TWL6025_REG_VIO:
1255 if (twl_get_smps_mult() & SMPS_MULTOFFSET_VIO)
1256 info->flags |= SMPS_EXTENDED_EN;
1257 if (twl_get_smps_offset() & SMPS_MULTOFFSET_VIO)
1258 info->flags |= SMPS_OFFSET_EN;
1259 break;
1260 }
1261
Mark Brownc1727082012-04-04 00:50:22 +01001262 config.dev = &pdev->dev;
1263 config.init_data = initdata;
1264 config.driver_data = info;
1265 config.of_node = pdev->dev.of_node;
1266
1267 rdev = regulator_register(&info->desc, &config);
David Brownellfa16a5c2009-02-08 10:37:06 -08001268 if (IS_ERR(rdev)) {
1269 dev_err(&pdev->dev, "can't register %s, %ld\n",
1270 info->desc.name, PTR_ERR(rdev));
1271 return PTR_ERR(rdev);
1272 }
1273 platform_set_drvdata(pdev, rdev);
1274
Saquib Herman776dc922011-04-01 10:22:43 +05301275 if (twl_class_is_4030())
1276 twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_REMAP,
Juha Keski-Saari30010fa2009-12-16 15:27:58 +02001277 info->remap);
1278
David Brownellfa16a5c2009-02-08 10:37:06 -08001279 /* NOTE: many regulators support short-circuit IRQs (presentable
1280 * as REGULATOR_OVER_CURRENT notifications?) configured via:
1281 * - SC_CONFIG
1282 * - SC_DETECT1 (vintana2, vmmc1/2, vaux1/2/3/4)
1283 * - SC_DETECT2 (vusb, vdac, vio, vdd1/2, vpll2)
1284 * - IT_CONFIG
1285 */
1286
1287 return 0;
1288}
1289
Rajendra Nayakc4aa6f32009-12-13 21:36:49 +01001290static int __devexit twlreg_remove(struct platform_device *pdev)
David Brownellfa16a5c2009-02-08 10:37:06 -08001291{
1292 regulator_unregister(platform_get_drvdata(pdev));
1293 return 0;
1294}
1295
Rajendra Nayakc4aa6f32009-12-13 21:36:49 +01001296MODULE_ALIAS("platform:twl_reg");
David Brownellfa16a5c2009-02-08 10:37:06 -08001297
Rajendra Nayakc4aa6f32009-12-13 21:36:49 +01001298static struct platform_driver twlreg_driver = {
1299 .probe = twlreg_probe,
1300 .remove = __devexit_p(twlreg_remove),
David Brownellfa16a5c2009-02-08 10:37:06 -08001301 /* NOTE: short name, to work around driver model truncation of
Rajendra Nayakc4aa6f32009-12-13 21:36:49 +01001302 * "twl_regulator.12" (and friends) to "twl_regulator.1".
David Brownellfa16a5c2009-02-08 10:37:06 -08001303 */
Rajendra Nayak2098e952012-02-28 15:09:11 +05301304 .driver = {
1305 .name = "twl_reg",
1306 .owner = THIS_MODULE,
1307 .of_match_table = of_match_ptr(twl_of_match),
1308 },
David Brownellfa16a5c2009-02-08 10:37:06 -08001309};
1310
Rajendra Nayakc4aa6f32009-12-13 21:36:49 +01001311static int __init twlreg_init(void)
David Brownellfa16a5c2009-02-08 10:37:06 -08001312{
Rajendra Nayakc4aa6f32009-12-13 21:36:49 +01001313 return platform_driver_register(&twlreg_driver);
David Brownellfa16a5c2009-02-08 10:37:06 -08001314}
Rajendra Nayakc4aa6f32009-12-13 21:36:49 +01001315subsys_initcall(twlreg_init);
David Brownellfa16a5c2009-02-08 10:37:06 -08001316
Rajendra Nayakc4aa6f32009-12-13 21:36:49 +01001317static void __exit twlreg_exit(void)
David Brownellfa16a5c2009-02-08 10:37:06 -08001318{
Rajendra Nayakc4aa6f32009-12-13 21:36:49 +01001319 platform_driver_unregister(&twlreg_driver);
David Brownellfa16a5c2009-02-08 10:37:06 -08001320}
Rajendra Nayakc4aa6f32009-12-13 21:36:49 +01001321module_exit(twlreg_exit)
David Brownellfa16a5c2009-02-08 10:37:06 -08001322
Rajendra Nayakc4aa6f32009-12-13 21:36:49 +01001323MODULE_DESCRIPTION("TWL regulator driver");
David Brownellfa16a5c2009-02-08 10:37:06 -08001324MODULE_LICENSE("GPL");