2 * Copyright (C) ST-Ericsson SA 2010
4 * License Terms: GNU General Public License v2
6 * Authors: Bengt Jonsson <bengt.g.jonsson@stericsson.com>
8 * This file is based on drivers/regulator/ab8500.c
10 * AB8500 external regulators
12 * ab8500-ext supports the following regulators:
15 #include <linux/init.h>
16 #include <linux/kernel.h>
17 #include <linux/err.h>
18 #include <linux/module.h>
19 #include <linux/platform_device.h>
20 #include <linux/regulator/driver.h>
21 #include <linux/regulator/machine.h>
22 #include <linux/mfd/abx500.h>
23 #include <linux/mfd/abx500/ab8500.h>
24 #include <linux/regulator/ab8500.h>
27 * struct ab8500_ext_regulator_info - ab8500 regulator information
28 * @dev: device pointer
29 * @desc: regulator description
30 * @rdev: regulator device
31 * @cfg: regulator configuration (extension of regulator FW configuration)
32 * @is_enabled: status of regulator (on/off)
33 * @update_bank: bank to control on/off
34 * @update_reg: register to control on/off
35 * @update_mask: mask to enable/disable and set mode of regulator
36 * @update_val: bits holding the regulator current mode
37 * @update_val_hp: bits to set EN pin active (LPn pin deactive)
38 * normally this means high power mode
39 * @update_val_lp: bits to set EN pin active and LPn pin active
40 * normally this means low power mode
41 * @update_val_hw: bits to set regulator pins in HW control
42 * SysClkReq pins and logic will choose mode
44 struct ab8500_ext_regulator_info
{
46 struct regulator_desc desc
;
47 struct regulator_dev
*rdev
;
48 struct ab8500_ext_regulator_cfg
*cfg
;
59 static int enable(struct ab8500_ext_regulator_info
*info
, u8
*regval
)
63 *regval
= info
->update_val
;
66 * To satisfy both HW high power request and SW request, the regulator
67 * must be on in high power.
69 if (info
->cfg
&& info
->cfg
->hwreq
)
70 *regval
= info
->update_val_hp
;
72 ret
= abx500_mask_and_set_register_interruptible(info
->dev
,
73 info
->update_bank
, info
->update_reg
,
74 info
->update_mask
, *regval
);
76 dev_err(rdev_get_dev(info
->rdev
),
77 "couldn't set enable bits for regulator\n");
79 info
->is_enabled
= true;
84 static int ab8500_ext_regulator_enable(struct regulator_dev
*rdev
)
87 struct ab8500_ext_regulator_info
*info
= rdev_get_drvdata(rdev
);
91 dev_err(rdev_get_dev(rdev
), "regulator info null pointer\n");
95 ret
= enable(info
, ®val
);
97 dev_dbg(rdev_get_dev(rdev
), "%s-enable (bank, reg, mask, value):"
98 " 0x%02x, 0x%02x, 0x%02x, 0x%02x\n",
99 info
->desc
.name
, info
->update_bank
, info
->update_reg
,
100 info
->update_mask
, regval
);
105 static int disable(struct ab8500_ext_regulator_info
*info
, u8
*regval
)
112 * Set the regulator in HW request mode if configured
114 if (info
->cfg
&& info
->cfg
->hwreq
)
115 *regval
= info
->update_val_hw
;
117 ret
= abx500_mask_and_set_register_interruptible(info
->dev
,
118 info
->update_bank
, info
->update_reg
,
119 info
->update_mask
, *regval
);
121 dev_err(rdev_get_dev(info
->rdev
),
122 "couldn't set disable bits for regulator\n");
124 info
->is_enabled
= false;
129 static int ab8500_ext_regulator_disable(struct regulator_dev
*rdev
)
132 struct ab8500_ext_regulator_info
*info
= rdev_get_drvdata(rdev
);
136 dev_err(rdev_get_dev(rdev
), "regulator info null pointer\n");
140 ret
= disable(info
, ®val
);
142 dev_dbg(rdev_get_dev(rdev
), "%s-disable (bank, reg, mask, value):"
143 " 0x%02x, 0x%02x, 0x%02x, 0x%02x\n",
144 info
->desc
.name
, info
->update_bank
, info
->update_reg
,
145 info
->update_mask
, regval
);
150 static int ab8500_ext_regulator_is_enabled(struct regulator_dev
*rdev
)
153 struct ab8500_ext_regulator_info
*info
= rdev_get_drvdata(rdev
);
157 dev_err(rdev_get_dev(rdev
), "regulator info null pointer\n");
161 ret
= abx500_get_register_interruptible(info
->dev
,
162 info
->update_bank
, info
->update_reg
, ®val
);
164 dev_err(rdev_get_dev(rdev
),
165 "couldn't read 0x%x register\n", info
->update_reg
);
169 dev_dbg(rdev_get_dev(rdev
), "%s-is_enabled (bank, reg, mask, value):"
170 " 0x%02x, 0x%02x, 0x%02x, 0x%02x\n",
171 info
->desc
.name
, info
->update_bank
, info
->update_reg
,
172 info
->update_mask
, regval
);
174 if (((regval
& info
->update_mask
) == info
->update_val_lp
) ||
175 ((regval
& info
->update_mask
) == info
->update_val_hp
))
176 info
->is_enabled
= true;
178 info
->is_enabled
= false;
180 return info
->is_enabled
;
183 static int ab8500_ext_regulator_set_mode(struct regulator_dev
*rdev
,
187 struct ab8500_ext_regulator_info
*info
= rdev_get_drvdata(rdev
);
190 dev_err(rdev_get_dev(rdev
), "regulator info null pointer\n");
195 case REGULATOR_MODE_NORMAL
:
196 info
->update_val
= info
->update_val_hp
;
198 case REGULATOR_MODE_IDLE
:
199 info
->update_val
= info
->update_val_lp
;
206 if (info
->is_enabled
) {
209 ret
= enable(info
, ®val
);
211 dev_err(rdev_get_dev(rdev
),
212 "Could not set regulator mode.\n");
214 dev_dbg(rdev_get_dev(rdev
),
215 "%s-set_mode (bank, reg, mask, value): "
216 "0x%x, 0x%x, 0x%x, 0x%x\n",
217 info
->desc
.name
, info
->update_bank
, info
->update_reg
,
218 info
->update_mask
, regval
);
224 static unsigned int ab8500_ext_regulator_get_mode(struct regulator_dev
*rdev
)
226 struct ab8500_ext_regulator_info
*info
= rdev_get_drvdata(rdev
);
230 dev_err(rdev_get_dev(rdev
), "regulator info null pointer\n");
234 if (info
->update_val
== info
->update_val_hp
)
235 ret
= REGULATOR_MODE_NORMAL
;
236 else if (info
->update_val
== info
->update_val_lp
)
237 ret
= REGULATOR_MODE_IDLE
;
244 static int ab8500_ext_fixed_get_voltage(struct regulator_dev
*rdev
)
246 struct regulation_constraints
*regu_constraints
= rdev
->constraints
;
248 if (regu_constraints
== NULL
) {
249 dev_err(rdev_get_dev(rdev
), "regulator constraints null pointer\n");
252 if (regu_constraints
->min_uV
&& regu_constraints
->max_uV
) {
253 if (regu_constraints
->min_uV
== regu_constraints
->max_uV
)
254 return regu_constraints
->min_uV
;
259 static int ab8500_ext_list_voltage(struct regulator_dev
*rdev
,
262 struct regulation_constraints
*regu_constraints
= rdev
->constraints
;
264 if (regu_constraints
== NULL
) {
265 dev_err(rdev_get_dev(rdev
), "regulator constraints null pointer\n");
268 /* return the uV for the fixed regulators */
269 if (regu_constraints
->min_uV
&& regu_constraints
->max_uV
) {
270 if (regu_constraints
->min_uV
== regu_constraints
->max_uV
)
271 return regu_constraints
->min_uV
;
276 static struct regulator_ops ab8500_ext_regulator_ops
= {
277 .enable
= ab8500_ext_regulator_enable
,
278 .disable
= ab8500_ext_regulator_disable
,
279 .is_enabled
= ab8500_ext_regulator_is_enabled
,
280 .set_mode
= ab8500_ext_regulator_set_mode
,
281 .get_mode
= ab8500_ext_regulator_get_mode
,
282 .get_voltage
= ab8500_ext_fixed_get_voltage
,
283 .list_voltage
= ab8500_ext_list_voltage
,
286 static struct ab8500_ext_regulator_info
287 ab8500_ext_regulator_info
[AB8500_NUM_EXT_REGULATORS
] = {
288 [AB8500_EXT_SUPPLY1
] = {
290 .name
= "VEXTSUPPLY1",
291 .ops
= &ab8500_ext_regulator_ops
,
292 .type
= REGULATOR_VOLTAGE
,
293 .id
= AB8500_EXT_SUPPLY1
,
294 .owner
= THIS_MODULE
,
301 .update_val_hp
= 0x01,
302 .update_val_lp
= 0x03,
303 .update_val_hw
= 0x02,
305 [AB8500_EXT_SUPPLY2
] = {
307 .name
= "VEXTSUPPLY2",
308 .ops
= &ab8500_ext_regulator_ops
,
309 .type
= REGULATOR_VOLTAGE
,
310 .id
= AB8500_EXT_SUPPLY2
,
311 .owner
= THIS_MODULE
,
318 .update_val_hp
= 0x04,
319 .update_val_lp
= 0x0c,
320 .update_val_hw
= 0x08,
322 [AB8500_EXT_SUPPLY3
] = {
324 .name
= "VEXTSUPPLY3",
325 .ops
= &ab8500_ext_regulator_ops
,
326 .type
= REGULATOR_VOLTAGE
,
327 .id
= AB8500_EXT_SUPPLY3
,
328 .owner
= THIS_MODULE
,
335 .update_val_hp
= 0x10,
336 .update_val_lp
= 0x30,
337 .update_val_hw
= 0x20,
341 int ab8500_ext_regulator_init(struct platform_device
*pdev
)
343 struct ab8500
*ab8500
= dev_get_drvdata(pdev
->dev
.parent
);
344 struct ab8500_platform_data
*ppdata
;
345 struct ab8500_regulator_platform_data
*pdata
;
346 struct regulator_config config
= { };
350 dev_err(&pdev
->dev
, "null mfd parent\n");
353 ppdata
= dev_get_platdata(ab8500
->dev
);
355 dev_err(&pdev
->dev
, "null parent pdata\n");
359 pdata
= ppdata
->regulator
;
361 dev_err(&pdev
->dev
, "null pdata\n");
365 /* make sure the platform data has the correct size */
366 if (pdata
->num_ext_regulator
!= ARRAY_SIZE(ab8500_ext_regulator_info
)) {
367 dev_err(&pdev
->dev
, "Configuration error: size mismatch.\n");
371 /* check for AB8500 2.x */
372 if (is_ab8500_2p0_or_earlier(ab8500
)) {
373 struct ab8500_ext_regulator_info
*info
;
375 /* VextSupply3LPn is inverted on AB8500 2.x */
376 info
= &ab8500_ext_regulator_info
[AB8500_EXT_SUPPLY3
];
377 info
->update_val
= 0x30;
378 info
->update_val_hp
= 0x30;
379 info
->update_val_lp
= 0x10;
382 /* register all regulators */
383 for (i
= 0; i
< ARRAY_SIZE(ab8500_ext_regulator_info
); i
++) {
384 struct ab8500_ext_regulator_info
*info
= NULL
;
386 /* assign per-regulator data */
387 info
= &ab8500_ext_regulator_info
[i
];
388 info
->dev
= &pdev
->dev
;
389 info
->cfg
= (struct ab8500_ext_regulator_cfg
*)
390 pdata
->ext_regulator
[i
].driver_data
;
392 config
.dev
= &pdev
->dev
;
393 config
.init_data
= &pdata
->ext_regulator
[i
];
394 config
.driver_data
= info
;
396 if (is_ab9540(ab8500
) &&
397 ((info
->desc
.id
== AB8500_EXT_SUPPLY1
) ||
398 (info
->desc
.id
== AB8500_EXT_SUPPLY2
) ||
399 (info
->desc
.id
== AB8500_EXT_SUPPLY3
)))
400 info
->desc
.ops
= &ab8500_ext_regulator_ops
;
402 /* register regulator with framework */
403 info
->rdev
= regulator_register(&info
->desc
, &config
);
405 if (IS_ERR(info
->rdev
)) {
406 err
= PTR_ERR(info
->rdev
);
407 dev_err(&pdev
->dev
, "failed to register regulator %s\n",
409 /* when we fail, un-register all earlier regulators */
411 info
= &ab8500_ext_regulator_info
[i
];
412 regulator_unregister(info
->rdev
);
417 dev_dbg(rdev_get_dev(info
->rdev
),
418 "%s-probed\n", info
->desc
.name
);
424 int ab8500_ext_regulator_exit(struct platform_device
*pdev
)
428 for (i
= 0; i
< ARRAY_SIZE(ab8500_ext_regulator_info
); i
++) {
429 struct ab8500_ext_regulator_info
*info
= NULL
;
430 info
= &ab8500_ext_regulator_info
[i
];
432 dev_vdbg(rdev_get_dev(info
->rdev
),
433 "%s-remove\n", info
->desc
.name
);
435 regulator_unregister(info
->rdev
);
441 MODULE_LICENSE("GPL v2");
442 MODULE_AUTHOR("Bengt Jonsson <bengt.g.jonsson@stericsson.com>");
443 MODULE_DESCRIPTION("AB8500 external regulator driver");
444 MODULE_ALIAS("platform:ab8500-ext-regulator");