diff options
author | Icenowy Zheng <icenowy@aosc.io> | 2017-05-18 03:16:49 -0400 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2017-05-19 12:57:59 -0400 |
commit | 1dbe0ccb0631c4ed399261934fe16f07407b078d (patch) | |
tree | 3b0709acd9a113dcedacc4209475fc2991301625 /drivers/regulator | |
parent | 2ea659a9ef488125eb46da6eb571de5eae5c43f6 (diff) |
regulator: axp20x-regulator: add support for AXP803
AXP803 PMIC also have a series of regulators (DCDCs and LDOs)
controllable via I2C/RSB bus.
Add support for them.
Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
Acked-by: Chen-Yu Tsai <wens@csie.org>
Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'drivers/regulator')
-rw-r--r-- | drivers/regulator/axp20x-regulator.c | 153 |
1 files changed, 131 insertions, 22 deletions
diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c index 0b9d4e3e52c7..e2608fe770b9 100644 --- a/drivers/regulator/axp20x-regulator.c +++ b/drivers/regulator/axp20x-regulator.c | |||
@@ -244,6 +244,82 @@ static const struct regulator_desc axp22x_drivevbus_regulator = { | |||
244 | .ops = &axp20x_ops_sw, | 244 | .ops = &axp20x_ops_sw, |
245 | }; | 245 | }; |
246 | 246 | ||
247 | static const struct regulator_linear_range axp803_dcdc234_ranges[] = { | ||
248 | REGULATOR_LINEAR_RANGE(500000, 0x0, 0x46, 10000), | ||
249 | REGULATOR_LINEAR_RANGE(1220000, 0x47, 0x4b, 20000), | ||
250 | }; | ||
251 | |||
252 | static const struct regulator_linear_range axp803_dcdc5_ranges[] = { | ||
253 | REGULATOR_LINEAR_RANGE(800000, 0x0, 0x20, 10000), | ||
254 | REGULATOR_LINEAR_RANGE(1140000, 0x21, 0x44, 20000), | ||
255 | }; | ||
256 | |||
257 | static const struct regulator_linear_range axp803_dcdc6_ranges[] = { | ||
258 | REGULATOR_LINEAR_RANGE(600000, 0x0, 0x32, 10000), | ||
259 | REGULATOR_LINEAR_RANGE(1120000, 0x33, 0x47, 20000), | ||
260 | }; | ||
261 | |||
262 | /* AXP806's CLDO2 and AXP809's DLDO1 shares the same range */ | ||
263 | static const struct regulator_linear_range axp803_dldo2_ranges[] = { | ||
264 | REGULATOR_LINEAR_RANGE(700000, 0x0, 0x1a, 100000), | ||
265 | REGULATOR_LINEAR_RANGE(3400000, 0x1b, 0x1f, 200000), | ||
266 | }; | ||
267 | |||
268 | static const struct regulator_desc axp803_regulators[] = { | ||
269 | AXP_DESC(AXP803, DCDC1, "dcdc1", "vin1", 1600, 3400, 100, | ||
270 | AXP803_DCDC1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(0)), | ||
271 | AXP_DESC_RANGES(AXP803, DCDC2, "dcdc2", "vin2", axp803_dcdc234_ranges, | ||
272 | 76, AXP803_DCDC2_V_OUT, 0x7f, AXP22X_PWR_OUT_CTRL1, | ||
273 | BIT(1)), | ||
274 | AXP_DESC_RANGES(AXP803, DCDC3, "dcdc3", "vin3", axp803_dcdc234_ranges, | ||
275 | 76, AXP803_DCDC3_V_OUT, 0x7f, AXP22X_PWR_OUT_CTRL1, | ||
276 | BIT(2)), | ||
277 | AXP_DESC_RANGES(AXP803, DCDC4, "dcdc4", "vin4", axp803_dcdc234_ranges, | ||
278 | 76, AXP803_DCDC4_V_OUT, 0x7f, AXP22X_PWR_OUT_CTRL1, | ||
279 | BIT(3)), | ||
280 | AXP_DESC_RANGES(AXP803, DCDC5, "dcdc5", "vin5", axp803_dcdc5_ranges, | ||
281 | 68, AXP803_DCDC5_V_OUT, 0x7f, AXP22X_PWR_OUT_CTRL1, | ||
282 | BIT(4)), | ||
283 | AXP_DESC_RANGES(AXP803, DCDC6, "dcdc6", "vin6", axp803_dcdc6_ranges, | ||
284 | 72, AXP803_DCDC6_V_OUT, 0x7f, AXP22X_PWR_OUT_CTRL1, | ||
285 | BIT(5)), | ||
286 | /* secondary switchable output of DCDC1 */ | ||
287 | AXP_DESC_SW(AXP803, DC1SW, "dc1sw", NULL, AXP22X_PWR_OUT_CTRL2, | ||
288 | BIT(7)), | ||
289 | AXP_DESC(AXP803, ALDO1, "aldo1", "aldoin", 700, 3300, 100, | ||
290 | AXP22X_ALDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL3, BIT(5)), | ||
291 | AXP_DESC(AXP803, ALDO2, "aldo2", "aldoin", 700, 3300, 100, | ||
292 | AXP22X_ALDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL3, BIT(6)), | ||
293 | AXP_DESC(AXP803, ALDO3, "aldo3", "aldoin", 700, 3300, 100, | ||
294 | AXP22X_ALDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL3, BIT(7)), | ||
295 | AXP_DESC(AXP803, DLDO1, "dldo1", "dldoin", 700, 3300, 100, | ||
296 | AXP22X_DLDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(3)), | ||
297 | AXP_DESC_RANGES(AXP803, DLDO2, "dldo2", "dldoin", axp803_dldo2_ranges, | ||
298 | 32, AXP22X_DLDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, | ||
299 | BIT(4)), | ||
300 | AXP_DESC(AXP803, DLDO3, "dldo3", "dldoin", 700, 3300, 100, | ||
301 | AXP22X_DLDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(5)), | ||
302 | AXP_DESC(AXP803, DLDO4, "dldo4", "dldoin", 700, 3300, 100, | ||
303 | AXP22X_DLDO4_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(6)), | ||
304 | AXP_DESC(AXP803, ELDO1, "eldo1", "eldoin", 700, 1900, 50, | ||
305 | AXP22X_ELDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(0)), | ||
306 | AXP_DESC(AXP803, ELDO2, "eldo2", "eldoin", 700, 1900, 50, | ||
307 | AXP22X_ELDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(1)), | ||
308 | AXP_DESC(AXP803, ELDO3, "eldo3", "eldoin", 700, 1900, 50, | ||
309 | AXP22X_ELDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(2)), | ||
310 | AXP_DESC(AXP803, FLDO1, "fldo1", "fldoin", 700, 1450, 50, | ||
311 | AXP803_FLDO1_V_OUT, 0x0f, AXP22X_PWR_OUT_CTRL3, BIT(2)), | ||
312 | AXP_DESC(AXP803, FLDO2, "fldo2", "fldoin", 700, 1450, 50, | ||
313 | AXP803_FLDO2_V_OUT, 0x0f, AXP22X_PWR_OUT_CTRL3, BIT(3)), | ||
314 | AXP_DESC_IO(AXP803, LDO_IO0, "ldo-io0", "ips", 700, 3300, 100, | ||
315 | AXP22X_LDO_IO0_V_OUT, 0x1f, AXP20X_GPIO0_CTRL, 0x07, | ||
316 | AXP22X_IO_ENABLED, AXP22X_IO_DISABLED), | ||
317 | AXP_DESC_IO(AXP803, LDO_IO1, "ldo-io1", "ips", 700, 3300, 100, | ||
318 | AXP22X_LDO_IO1_V_OUT, 0x1f, AXP20X_GPIO1_CTRL, 0x07, | ||
319 | AXP22X_IO_ENABLED, AXP22X_IO_DISABLED), | ||
320 | AXP_DESC_FIXED(AXP803, RTC_LDO, "rtc-ldo", "ips", 3000), | ||
321 | }; | ||
322 | |||
247 | static const struct regulator_linear_range axp806_dcdca_ranges[] = { | 323 | static const struct regulator_linear_range axp806_dcdca_ranges[] = { |
248 | REGULATOR_LINEAR_RANGE(600000, 0x0, 0x32, 10000), | 324 | REGULATOR_LINEAR_RANGE(600000, 0x0, 0x32, 10000), |
249 | REGULATOR_LINEAR_RANGE(1120000, 0x33, 0x47, 20000), | 325 | REGULATOR_LINEAR_RANGE(1120000, 0x33, 0x47, 20000), |
@@ -254,11 +330,6 @@ static const struct regulator_linear_range axp806_dcdcd_ranges[] = { | |||
254 | REGULATOR_LINEAR_RANGE(1600000, 0x2e, 0x3f, 100000), | 330 | REGULATOR_LINEAR_RANGE(1600000, 0x2e, 0x3f, 100000), |
255 | }; | 331 | }; |
256 | 332 | ||
257 | static const struct regulator_linear_range axp806_cldo2_ranges[] = { | ||
258 | REGULATOR_LINEAR_RANGE(700000, 0x0, 0x1a, 100000), | ||
259 | REGULATOR_LINEAR_RANGE(3400000, 0x1b, 0x1f, 200000), | ||
260 | }; | ||
261 | |||
262 | static const struct regulator_desc axp806_regulators[] = { | 333 | static const struct regulator_desc axp806_regulators[] = { |
263 | AXP_DESC_RANGES(AXP806, DCDCA, "dcdca", "vina", axp806_dcdca_ranges, | 334 | AXP_DESC_RANGES(AXP806, DCDCA, "dcdca", "vina", axp806_dcdca_ranges, |
264 | 72, AXP806_DCDCA_V_CTRL, 0x7f, AXP806_PWR_OUT_CTRL1, | 335 | 72, AXP806_DCDCA_V_CTRL, 0x7f, AXP806_PWR_OUT_CTRL1, |
@@ -289,7 +360,7 @@ static const struct regulator_desc axp806_regulators[] = { | |||
289 | AXP806_BLDO4_V_CTRL, 0x0f, AXP806_PWR_OUT_CTRL2, BIT(3)), | 360 | AXP806_BLDO4_V_CTRL, 0x0f, AXP806_PWR_OUT_CTRL2, BIT(3)), |
290 | AXP_DESC(AXP806, CLDO1, "cldo1", "cldoin", 700, 3300, 100, | 361 | AXP_DESC(AXP806, CLDO1, "cldo1", "cldoin", 700, 3300, 100, |
291 | AXP806_CLDO1_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL2, BIT(4)), | 362 | AXP806_CLDO1_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL2, BIT(4)), |
292 | AXP_DESC_RANGES(AXP806, CLDO2, "cldo2", "cldoin", axp806_cldo2_ranges, | 363 | AXP_DESC_RANGES(AXP806, CLDO2, "cldo2", "cldoin", axp803_dldo2_ranges, |
293 | 32, AXP806_CLDO2_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL2, | 364 | 32, AXP806_CLDO2_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL2, |
294 | BIT(5)), | 365 | BIT(5)), |
295 | AXP_DESC(AXP806, CLDO3, "cldo3", "cldoin", 700, 3300, 100, | 366 | AXP_DESC(AXP806, CLDO3, "cldo3", "cldoin", 700, 3300, 100, |
@@ -326,7 +397,7 @@ static const struct regulator_desc axp809_regulators[] = { | |||
326 | AXP22X_ALDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(7)), | 397 | AXP22X_ALDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(7)), |
327 | AXP_DESC(AXP809, ALDO3, "aldo3", "aldoin", 700, 3300, 100, | 398 | AXP_DESC(AXP809, ALDO3, "aldo3", "aldoin", 700, 3300, 100, |
328 | AXP22X_ALDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(5)), | 399 | AXP22X_ALDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(5)), |
329 | AXP_DESC_RANGES(AXP809, DLDO1, "dldo1", "dldoin", axp806_cldo2_ranges, | 400 | AXP_DESC_RANGES(AXP809, DLDO1, "dldo1", "dldoin", axp803_dldo2_ranges, |
330 | 32, AXP22X_DLDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, | 401 | 32, AXP22X_DLDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, |
331 | BIT(3)), | 402 | BIT(3)), |
332 | AXP_DESC(AXP809, DLDO2, "dldo2", "dldoin", 700, 3300, 100, | 403 | AXP_DESC(AXP809, DLDO2, "dldo2", "dldoin", 700, 3300, 100, |
@@ -369,14 +440,21 @@ static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq) | |||
369 | def = 1500; | 440 | def = 1500; |
370 | step = 75; | 441 | step = 75; |
371 | break; | 442 | break; |
372 | case AXP806_ID: | 443 | case AXP803_ID: |
373 | /* | 444 | /* |
374 | * AXP806 DCDC work frequency setting has the same range and | 445 | * AXP803 DCDC work frequency setting has the same range and |
375 | * step as AXP22X, but at a different register. | 446 | * step as AXP22X, but at a different register. |
376 | * Fall through to the check below. | 447 | * Fall through to the check below. |
377 | * (See include/linux/mfd/axp20x.h) | 448 | * (See include/linux/mfd/axp20x.h) |
378 | */ | 449 | */ |
379 | reg = AXP806_DCDC_FREQ_CTRL; | 450 | reg = AXP803_DCDC_FREQ_CTRL; |
451 | case AXP806_ID: | ||
452 | /* | ||
453 | * AXP806 also have DCDC work frequency setting register at a | ||
454 | * different position. | ||
455 | */ | ||
456 | if (axp20x->variant == AXP806_ID) | ||
457 | reg = AXP806_DCDC_FREQ_CTRL; | ||
380 | case AXP221_ID: | 458 | case AXP221_ID: |
381 | case AXP223_ID: | 459 | case AXP223_ID: |
382 | case AXP809_ID: | 460 | case AXP809_ID: |
@@ -475,6 +553,14 @@ static int axp20x_set_dcdc_workmode(struct regulator_dev *rdev, int id, u32 work | |||
475 | workmode <<= id - AXP22X_DCDC1; | 553 | workmode <<= id - AXP22X_DCDC1; |
476 | break; | 554 | break; |
477 | 555 | ||
556 | case AXP803_ID: | ||
557 | if (id < AXP803_DCDC1 || id > AXP803_DCDC6) | ||
558 | return -EINVAL; | ||
559 | |||
560 | mask = AXP22X_WORKMODE_DCDCX_MASK(id - AXP803_DCDC1); | ||
561 | workmode <<= id - AXP803_DCDC1; | ||
562 | break; | ||
563 | |||
478 | default: | 564 | default: |
479 | /* should not happen */ | 565 | /* should not happen */ |
480 | WARN_ON(1); | 566 | WARN_ON(1); |
@@ -492,20 +578,38 @@ static bool axp20x_is_polyphase_slave(struct axp20x_dev *axp20x, int id) | |||
492 | { | 578 | { |
493 | u32 reg = 0; | 579 | u32 reg = 0; |
494 | 580 | ||
495 | /* Only AXP806 has poly-phase outputs */ | 581 | /* |
496 | if (axp20x->variant != AXP806_ID) | 582 | * Currently in our supported AXP variants, only AXP803 and AXP806 |
497 | return false; | 583 | * have polyphase regulators. |
584 | */ | ||
585 | switch (axp20x->variant) { | ||
586 | case AXP803_ID: | ||
587 | regmap_read(axp20x->regmap, AXP803_POLYPHASE_CTRL, ®); | ||
588 | |||
589 | switch (id) { | ||
590 | case AXP803_DCDC3: | ||
591 | return !!(reg & BIT(6)); | ||
592 | case AXP803_DCDC6: | ||
593 | return !!(reg & BIT(7)); | ||
594 | } | ||
595 | break; | ||
498 | 596 | ||
499 | regmap_read(axp20x->regmap, AXP806_DCDC_MODE_CTRL2, ®); | 597 | case AXP806_ID: |
598 | regmap_read(axp20x->regmap, AXP806_DCDC_MODE_CTRL2, ®); | ||
599 | |||
600 | switch (id) { | ||
601 | case AXP806_DCDCB: | ||
602 | return (((reg & GENMASK(7, 6)) == BIT(6)) || | ||
603 | ((reg & GENMASK(7, 6)) == BIT(7))); | ||
604 | case AXP806_DCDCC: | ||
605 | return ((reg & GENMASK(7, 6)) == BIT(7)); | ||
606 | case AXP806_DCDCE: | ||
607 | return !!(reg & BIT(5)); | ||
608 | } | ||
609 | break; | ||
500 | 610 | ||
501 | switch (id) { | 611 | default: |
502 | case AXP806_DCDCB: | 612 | return false; |
503 | return (((reg & GENMASK(7, 6)) == BIT(6)) || | ||
504 | ((reg & GENMASK(7, 6)) == BIT(7))); | ||
505 | case AXP806_DCDCC: | ||
506 | return ((reg & GENMASK(7, 6)) == BIT(7)); | ||
507 | case AXP806_DCDCE: | ||
508 | return !!(reg & BIT(5)); | ||
509 | } | 613 | } |
510 | 614 | ||
511 | return false; | 615 | return false; |
@@ -540,6 +644,10 @@ static int axp20x_regulator_probe(struct platform_device *pdev) | |||
540 | drivevbus = of_property_read_bool(pdev->dev.parent->of_node, | 644 | drivevbus = of_property_read_bool(pdev->dev.parent->of_node, |
541 | "x-powers,drive-vbus-en"); | 645 | "x-powers,drive-vbus-en"); |
542 | break; | 646 | break; |
647 | case AXP803_ID: | ||
648 | regulators = axp803_regulators; | ||
649 | nregulators = AXP803_REG_ID_MAX; | ||
650 | break; | ||
543 | case AXP806_ID: | 651 | case AXP806_ID: |
544 | regulators = axp806_regulators; | 652 | regulators = axp806_regulators; |
545 | nregulators = AXP806_REG_ID_MAX; | 653 | nregulators = AXP806_REG_ID_MAX; |
@@ -579,6 +687,7 @@ static int axp20x_regulator_probe(struct platform_device *pdev) | |||
579 | * name. | 687 | * name. |
580 | */ | 688 | */ |
581 | if ((regulators == axp22x_regulators && i == AXP22X_DC1SW) || | 689 | if ((regulators == axp22x_regulators && i == AXP22X_DC1SW) || |
690 | (regulators == axp803_regulators && i == AXP803_DC1SW) || | ||
582 | (regulators == axp809_regulators && i == AXP809_DC1SW)) { | 691 | (regulators == axp809_regulators && i == AXP809_DC1SW)) { |
583 | new_desc = devm_kzalloc(&pdev->dev, sizeof(*desc), | 692 | new_desc = devm_kzalloc(&pdev->dev, sizeof(*desc), |
584 | GFP_KERNEL); | 693 | GFP_KERNEL); |