2 * TI LP8788 MFD - buck regulator driver
4 * Copyright 2012 Texas Instruments
6 * Author: Milo(Woogyom) Kim <milo.kim@ti.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
14 #include <linux/module.h>
15 #include <linux/slab.h>
16 #include <linux/err.h>
17 #include <linux/platform_device.h>
18 #include <linux/regulator/driver.h>
19 #include <linux/mfd/lp8788.h>
20 #include <linux/gpio.h>
22 /* register address */
23 #define LP8788_EN_BUCK 0x0C
24 #define LP8788_BUCK_DVS_SEL 0x1D
25 #define LP8788_BUCK1_VOUT0 0x1E
26 #define LP8788_BUCK1_VOUT1 0x1F
27 #define LP8788_BUCK1_VOUT2 0x20
28 #define LP8788_BUCK1_VOUT3 0x21
29 #define LP8788_BUCK2_VOUT0 0x22
30 #define LP8788_BUCK2_VOUT1 0x23
31 #define LP8788_BUCK2_VOUT2 0x24
32 #define LP8788_BUCK2_VOUT3 0x25
33 #define LP8788_BUCK3_VOUT 0x26
34 #define LP8788_BUCK4_VOUT 0x27
35 #define LP8788_BUCK1_TIMESTEP 0x28
36 #define LP8788_BUCK_PWM 0x2D
39 #define LP8788_EN_BUCK1_M BIT(0) /* Addr 0Ch */
40 #define LP8788_EN_BUCK2_M BIT(1)
41 #define LP8788_EN_BUCK3_M BIT(2)
42 #define LP8788_EN_BUCK4_M BIT(3)
43 #define LP8788_BUCK1_DVS_SEL_M 0x04 /* Addr 1Dh */
44 #define LP8788_BUCK1_DVS_M 0x03
45 #define LP8788_BUCK1_DVS_S 0
46 #define LP8788_BUCK2_DVS_SEL_M 0x40
47 #define LP8788_BUCK2_DVS_M 0x30
48 #define LP8788_BUCK2_DVS_S 4
49 #define LP8788_BUCK1_DVS_I2C BIT(2)
50 #define LP8788_BUCK2_DVS_I2C BIT(6)
51 #define LP8788_BUCK1_DVS_PIN (0 << 2)
52 #define LP8788_BUCK2_DVS_PIN (0 << 6)
53 #define LP8788_VOUT_M 0x1F /* Addr 1Eh ~ 27h */
54 #define LP8788_STARTUP_TIME_M 0xF8 /* Addr 28h ~ 2Bh */
55 #define LP8788_STARTUP_TIME_S 3
56 #define LP8788_FPWM_BUCK1_M BIT(0) /* Addr 2Dh */
57 #define LP8788_FPWM_BUCK1_S 0
58 #define LP8788_FPWM_BUCK2_M BIT(1)
59 #define LP8788_FPWM_BUCK2_S 1
60 #define LP8788_FPWM_BUCK3_M BIT(2)
61 #define LP8788_FPWM_BUCK3_S 2
62 #define LP8788_FPWM_BUCK4_M BIT(3)
63 #define LP8788_FPWM_BUCK4_S 3
65 #define INVALID_ADDR 0xFF
66 #define LP8788_FORCE_PWM 1
67 #define LP8788_AUTO_PWM 0
70 #define ENABLE_TIME_USEC 32
72 #define BUCK_FPWM_MASK(x) (1 << (x))
73 #define BUCK_FPWM_SHIFT(x) (x)
75 enum lp8788_dvs_state
{
76 DVS_LOW
= GPIOF_OUT_INIT_LOW
,
77 DVS_HIGH
= GPIOF_OUT_INIT_HIGH
,
80 enum lp8788_dvs_mode
{
94 struct regulator_dev
*regulator
;
98 /* BUCK 1 ~ 4 voltage table */
99 static const int lp8788_buck_vtbl
[] = {
100 500000, 800000, 850000, 900000, 950000, 1000000, 1050000, 1100000,
101 1150000, 1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000,
102 1550000, 1600000, 1650000, 1700000, 1750000, 1800000, 1850000, 1900000,
106 static void lp8788_buck1_set_dvs(struct lp8788_buck
*buck
)
108 struct lp8788_buck1_dvs
*dvs
= (struct lp8788_buck1_dvs
*)buck
->dvs
;
109 enum lp8788_dvs_state pinstate
;
114 pinstate
= dvs
->vsel
== DVS_SEL_V0
? DVS_LOW
: DVS_HIGH
;
115 if (gpio_is_valid(dvs
->gpio
))
116 gpio_set_value(dvs
->gpio
, pinstate
);
119 static void lp8788_buck2_set_dvs(struct lp8788_buck
*buck
)
121 struct lp8788_buck2_dvs
*dvs
= (struct lp8788_buck2_dvs
*)buck
->dvs
;
122 enum lp8788_dvs_state pin1
, pin2
;
148 if (gpio_is_valid(dvs
->gpio
[0]))
149 gpio_set_value(dvs
->gpio
[0], pin1
);
151 if (gpio_is_valid(dvs
->gpio
[1]))
152 gpio_set_value(dvs
->gpio
[1], pin2
);
155 static void lp8788_set_dvs(struct lp8788_buck
*buck
, enum lp8788_buck_id id
)
159 lp8788_buck1_set_dvs(buck
);
162 lp8788_buck2_set_dvs(buck
);
169 static enum lp8788_dvs_mode
170 lp8788_get_buck_dvs_ctrl_mode(struct lp8788_buck
*buck
, enum lp8788_buck_id id
)
176 mask
= LP8788_BUCK1_DVS_SEL_M
;
179 mask
= LP8788_BUCK2_DVS_SEL_M
;
185 lp8788_read_byte(buck
->lp
, LP8788_BUCK_DVS_SEL
, &val
);
187 return val
& mask
? REGISTER
: EXTPIN
;
190 static bool lp8788_is_valid_buck_addr(u8 addr
)
193 case LP8788_BUCK1_VOUT0
:
194 case LP8788_BUCK1_VOUT1
:
195 case LP8788_BUCK1_VOUT2
:
196 case LP8788_BUCK1_VOUT3
:
197 case LP8788_BUCK2_VOUT0
:
198 case LP8788_BUCK2_VOUT1
:
199 case LP8788_BUCK2_VOUT2
:
200 case LP8788_BUCK2_VOUT3
:
207 static u8
lp8788_select_buck_vout_addr(struct lp8788_buck
*buck
,
208 enum lp8788_buck_id id
)
210 enum lp8788_dvs_mode mode
= lp8788_get_buck_dvs_ctrl_mode(buck
, id
);
211 struct lp8788_buck1_dvs
*b1_dvs
;
212 struct lp8788_buck2_dvs
*b2_dvs
;
218 if (mode
== EXTPIN
) {
219 b1_dvs
= (struct lp8788_buck1_dvs
*)buck
->dvs
;
223 idx
= gpio_get_value(b1_dvs
->gpio
) ? 1 : 0;
225 lp8788_read_byte(buck
->lp
, LP8788_BUCK_DVS_SEL
, &val
);
226 idx
= (val
& LP8788_BUCK1_DVS_M
) >> LP8788_BUCK1_DVS_S
;
228 addr
= LP8788_BUCK1_VOUT0
+ idx
;
231 if (mode
== EXTPIN
) {
232 b2_dvs
= (struct lp8788_buck2_dvs
*)buck
->dvs
;
236 pin1
= gpio_get_value(b2_dvs
->gpio
[0]);
237 pin2
= gpio_get_value(b2_dvs
->gpio
[1]);
239 if (pin1
== PIN_LOW
&& pin2
== PIN_LOW
)
241 else if (pin1
== PIN_LOW
&& pin2
== PIN_HIGH
)
243 else if (pin1
== PIN_HIGH
&& pin2
== PIN_LOW
)
248 lp8788_read_byte(buck
->lp
, LP8788_BUCK_DVS_SEL
, &val
);
249 idx
= (val
& LP8788_BUCK2_DVS_M
) >> LP8788_BUCK2_DVS_S
;
251 addr
= LP8788_BUCK2_VOUT0
+ idx
;
262 static int lp8788_buck12_set_voltage_sel(struct regulator_dev
*rdev
,
265 struct lp8788_buck
*buck
= rdev_get_drvdata(rdev
);
266 enum lp8788_buck_id id
= rdev_get_id(rdev
);
270 lp8788_set_dvs(buck
, id
);
272 addr
= lp8788_select_buck_vout_addr(buck
, id
);
273 if (!lp8788_is_valid_buck_addr(addr
))
276 return lp8788_update_bits(buck
->lp
, addr
, LP8788_VOUT_M
, selector
);
279 static int lp8788_buck12_get_voltage_sel(struct regulator_dev
*rdev
)
281 struct lp8788_buck
*buck
= rdev_get_drvdata(rdev
);
282 enum lp8788_buck_id id
= rdev_get_id(rdev
);
286 addr
= lp8788_select_buck_vout_addr(buck
, id
);
287 if (!lp8788_is_valid_buck_addr(addr
))
290 ret
= lp8788_read_byte(buck
->lp
, addr
, &val
);
294 return val
& LP8788_VOUT_M
;
297 static int lp8788_buck_enable_time(struct regulator_dev
*rdev
)
299 struct lp8788_buck
*buck
= rdev_get_drvdata(rdev
);
300 enum lp8788_buck_id id
= rdev_get_id(rdev
);
301 u8 val
, addr
= LP8788_BUCK1_TIMESTEP
+ id
;
303 if (lp8788_read_byte(buck
->lp
, addr
, &val
))
306 val
= (val
& LP8788_STARTUP_TIME_M
) >> LP8788_STARTUP_TIME_S
;
308 return ENABLE_TIME_USEC
* val
;
311 static int lp8788_buck_set_mode(struct regulator_dev
*rdev
, unsigned int mode
)
313 struct lp8788_buck
*buck
= rdev_get_drvdata(rdev
);
314 enum lp8788_buck_id id
= rdev_get_id(rdev
);
317 mask
= BUCK_FPWM_MASK(id
);
319 case REGULATOR_MODE_FAST
:
320 val
= LP8788_FORCE_PWM
<< BUCK_FPWM_SHIFT(id
);
322 case REGULATOR_MODE_NORMAL
:
323 val
= LP8788_AUTO_PWM
<< BUCK_FPWM_SHIFT(id
);
329 return lp8788_update_bits(buck
->lp
, LP8788_BUCK_PWM
, mask
, val
);
332 static unsigned int lp8788_buck_get_mode(struct regulator_dev
*rdev
)
334 struct lp8788_buck
*buck
= rdev_get_drvdata(rdev
);
335 enum lp8788_buck_id id
= rdev_get_id(rdev
);
339 ret
= lp8788_read_byte(buck
->lp
, LP8788_BUCK_PWM
, &val
);
343 return val
& BUCK_FPWM_MASK(id
) ?
344 REGULATOR_MODE_FAST
: REGULATOR_MODE_NORMAL
;
347 static struct regulator_ops lp8788_buck12_ops
= {
348 .list_voltage
= regulator_list_voltage_table
,
349 .map_voltage
= regulator_map_voltage_ascend
,
350 .set_voltage_sel
= lp8788_buck12_set_voltage_sel
,
351 .get_voltage_sel
= lp8788_buck12_get_voltage_sel
,
352 .enable
= regulator_enable_regmap
,
353 .disable
= regulator_disable_regmap
,
354 .is_enabled
= regulator_is_enabled_regmap
,
355 .enable_time
= lp8788_buck_enable_time
,
356 .set_mode
= lp8788_buck_set_mode
,
357 .get_mode
= lp8788_buck_get_mode
,
360 static struct regulator_ops lp8788_buck34_ops
= {
361 .list_voltage
= regulator_list_voltage_table
,
362 .map_voltage
= regulator_map_voltage_ascend
,
363 .set_voltage_sel
= regulator_set_voltage_sel_regmap
,
364 .get_voltage_sel
= regulator_get_voltage_sel_regmap
,
365 .enable
= regulator_enable_regmap
,
366 .disable
= regulator_disable_regmap
,
367 .is_enabled
= regulator_is_enabled_regmap
,
368 .enable_time
= lp8788_buck_enable_time
,
369 .set_mode
= lp8788_buck_set_mode
,
370 .get_mode
= lp8788_buck_get_mode
,
373 static struct regulator_desc lp8788_buck_desc
[] = {
377 .ops
= &lp8788_buck12_ops
,
378 .n_voltages
= ARRAY_SIZE(lp8788_buck_vtbl
),
379 .volt_table
= lp8788_buck_vtbl
,
380 .type
= REGULATOR_VOLTAGE
,
381 .owner
= THIS_MODULE
,
382 .enable_reg
= LP8788_EN_BUCK
,
383 .enable_mask
= LP8788_EN_BUCK1_M
,
388 .ops
= &lp8788_buck12_ops
,
389 .n_voltages
= ARRAY_SIZE(lp8788_buck_vtbl
),
390 .volt_table
= lp8788_buck_vtbl
,
391 .type
= REGULATOR_VOLTAGE
,
392 .owner
= THIS_MODULE
,
393 .enable_reg
= LP8788_EN_BUCK
,
394 .enable_mask
= LP8788_EN_BUCK2_M
,
399 .ops
= &lp8788_buck34_ops
,
400 .n_voltages
= ARRAY_SIZE(lp8788_buck_vtbl
),
401 .volt_table
= lp8788_buck_vtbl
,
402 .type
= REGULATOR_VOLTAGE
,
403 .owner
= THIS_MODULE
,
404 .vsel_reg
= LP8788_BUCK3_VOUT
,
405 .vsel_mask
= LP8788_VOUT_M
,
406 .enable_reg
= LP8788_EN_BUCK
,
407 .enable_mask
= LP8788_EN_BUCK3_M
,
412 .ops
= &lp8788_buck34_ops
,
413 .n_voltages
= ARRAY_SIZE(lp8788_buck_vtbl
),
414 .volt_table
= lp8788_buck_vtbl
,
415 .type
= REGULATOR_VOLTAGE
,
416 .owner
= THIS_MODULE
,
417 .vsel_reg
= LP8788_BUCK4_VOUT
,
418 .vsel_mask
= LP8788_VOUT_M
,
419 .enable_reg
= LP8788_EN_BUCK
,
420 .enable_mask
= LP8788_EN_BUCK4_M
,
424 static int lp8788_dvs_gpio_request(struct platform_device
*pdev
,
425 struct lp8788_buck
*buck
,
426 enum lp8788_buck_id id
)
428 struct lp8788_platform_data
*pdata
= buck
->lp
->pdata
;
429 char *b1_name
= "LP8788_B1_DVS";
430 char *b2_name
[] = { "LP8788_B2_DVS1", "LP8788_B2_DVS2" };
435 gpio
= pdata
->buck1_dvs
->gpio
;
436 ret
= devm_gpio_request_one(&pdev
->dev
, gpio
, DVS_LOW
,
441 buck
->dvs
= pdata
->buck1_dvs
;
444 for (i
= 0; i
< LP8788_NUM_BUCK2_DVS
; i
++) {
445 gpio
= pdata
->buck2_dvs
->gpio
[i
];
446 ret
= devm_gpio_request_one(&pdev
->dev
, gpio
,
447 DVS_LOW
, b2_name
[i
]);
451 buck
->dvs
= pdata
->buck2_dvs
;
460 static int lp8788_init_dvs(struct platform_device
*pdev
,
461 struct lp8788_buck
*buck
, enum lp8788_buck_id id
)
463 struct lp8788_platform_data
*pdata
= buck
->lp
->pdata
;
464 u8 mask
[] = { LP8788_BUCK1_DVS_SEL_M
, LP8788_BUCK2_DVS_SEL_M
};
465 u8 val
[] = { LP8788_BUCK1_DVS_PIN
, LP8788_BUCK2_DVS_PIN
};
466 u8 default_dvs_mode
[] = { LP8788_BUCK1_DVS_I2C
, LP8788_BUCK2_DVS_I2C
};
468 /* no dvs for buck3, 4 */
472 /* no dvs platform data, then dvs will be selected by I2C registers */
474 goto set_default_dvs_mode
;
476 if ((id
== BUCK1
&& !pdata
->buck1_dvs
) ||
477 (id
== BUCK2
&& !pdata
->buck2_dvs
))
478 goto set_default_dvs_mode
;
480 if (lp8788_dvs_gpio_request(pdev
, buck
, id
))
481 goto set_default_dvs_mode
;
483 return lp8788_update_bits(buck
->lp
, LP8788_BUCK_DVS_SEL
, mask
[id
],
486 set_default_dvs_mode
:
487 return lp8788_update_bits(buck
->lp
, LP8788_BUCK_DVS_SEL
, mask
[id
],
488 default_dvs_mode
[id
]);
491 static int lp8788_buck_probe(struct platform_device
*pdev
)
493 struct lp8788
*lp
= dev_get_drvdata(pdev
->dev
.parent
);
495 struct lp8788_buck
*buck
;
496 struct regulator_config cfg
= { };
497 struct regulator_dev
*rdev
;
500 if (id
>= LP8788_NUM_BUCKS
)
503 buck
= devm_kzalloc(&pdev
->dev
, sizeof(struct lp8788_buck
), GFP_KERNEL
);
509 ret
= lp8788_init_dvs(pdev
, buck
, id
);
513 cfg
.dev
= pdev
->dev
.parent
;
514 cfg
.init_data
= lp
->pdata
? lp
->pdata
->buck_data
[id
] : NULL
;
515 cfg
.driver_data
= buck
;
516 cfg
.regmap
= lp
->regmap
;
518 rdev
= regulator_register(&lp8788_buck_desc
[id
], &cfg
);
521 dev_err(&pdev
->dev
, "BUCK%d regulator register err = %d\n",
526 buck
->regulator
= rdev
;
527 platform_set_drvdata(pdev
, buck
);
532 static int lp8788_buck_remove(struct platform_device
*pdev
)
534 struct lp8788_buck
*buck
= platform_get_drvdata(pdev
);
536 regulator_unregister(buck
->regulator
);
541 static struct platform_driver lp8788_buck_driver
= {
542 .probe
= lp8788_buck_probe
,
543 .remove
= lp8788_buck_remove
,
545 .name
= LP8788_DEV_BUCK
,
546 .owner
= THIS_MODULE
,
550 static int __init
lp8788_buck_init(void)
552 return platform_driver_register(&lp8788_buck_driver
);
554 subsys_initcall(lp8788_buck_init
);
556 static void __exit
lp8788_buck_exit(void)
558 platform_driver_unregister(&lp8788_buck_driver
);
560 module_exit(lp8788_buck_exit
);
562 MODULE_DESCRIPTION("TI LP8788 BUCK Driver");
563 MODULE_AUTHOR("Milo Kim");
564 MODULE_LICENSE("GPL");
565 MODULE_ALIAS("platform:lp8788-buck");