aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/regulator
diff options
context:
space:
mode:
authorChen-Yu Tsai <wens@csie.org>2016-08-27 03:55:39 -0400
committerLee Jones <lee.jones@linaro.org>2016-09-13 07:49:45 -0400
commit2ca342d391e3d8b56ed64626db8cfba8101b7c1d (patch)
treebcaf1b7dfd41dfe3e1357e4a9127ce4791e260cd /drivers/regulator
parent29b4817d4018df78086157ea3a55c1d9424a7cfc (diff)
regulator: axp20x: Support AXP806 variant
The X-Powers AXP806 PMIC has a new set of buck and LDO regulators, and also a switch. The buck regulators support teaming into multi-phase groups, with A+B, A+B+C, D+E groupings. Some registers controlling DCDC converter work settings are at different offsets. Deal with them as well. Add support for this new variant. Signed-off-by: Chen-Yu Tsai <wens@csie.org> Acked-by: Mark Brown <broonie@kernel.org> Signed-off-by: Lee Jones <lee.jones@linaro.org>
Diffstat (limited to 'drivers/regulator')
-rw-r--r--drivers/regulator/axp20x-regulator.c118
1 files changed, 111 insertions, 7 deletions
diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c
index 6d9ac76a772f..54382ef902c6 100644
--- a/drivers/regulator/axp20x-regulator.c
+++ b/drivers/regulator/axp20x-regulator.c
@@ -244,16 +244,64 @@ static const struct regulator_desc axp22x_drivevbus_regulator = {
244 .ops = &axp20x_ops_sw, 244 .ops = &axp20x_ops_sw,
245}; 245};
246 246
247static const struct regulator_linear_range axp809_dcdc4_ranges[] = { 247static const struct regulator_linear_range axp806_dcdca_ranges[] = {
248 REGULATOR_LINEAR_RANGE(600000, 0x0, 0x2f, 20000), 248 REGULATOR_LINEAR_RANGE(600000, 0x0, 0x32, 10000),
249 REGULATOR_LINEAR_RANGE(1800000, 0x30, 0x38, 100000), 249 REGULATOR_LINEAR_RANGE(1120000, 0x33, 0x47, 20000),
250}; 250};
251 251
252static const struct regulator_linear_range axp809_dldo1_ranges[] = { 252static const struct regulator_linear_range axp806_dcdcd_ranges[] = {
253 REGULATOR_LINEAR_RANGE(600000, 0x0, 0x2d, 20000),
254 REGULATOR_LINEAR_RANGE(1600000, 0x2e, 0x3f, 100000),
255};
256
257static const struct regulator_linear_range axp806_cldo2_ranges[] = {
253 REGULATOR_LINEAR_RANGE(700000, 0x0, 0x1a, 100000), 258 REGULATOR_LINEAR_RANGE(700000, 0x0, 0x1a, 100000),
254 REGULATOR_LINEAR_RANGE(3400000, 0x1b, 0x1f, 200000), 259 REGULATOR_LINEAR_RANGE(3400000, 0x1b, 0x1f, 200000),
255}; 260};
256 261
262static const struct regulator_desc axp806_regulators[] = {
263 AXP_DESC_RANGES(AXP806, DCDCA, "dcdca", "vina", axp806_dcdca_ranges,
264 72, AXP806_DCDCA_V_CTRL, 0x7f, AXP806_PWR_OUT_CTRL1,
265 BIT(0)),
266 AXP_DESC(AXP806, DCDCB, "dcdcb", "vinb", 1000, 2550, 50,
267 AXP806_DCDCB_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL1, BIT(1)),
268 AXP_DESC_RANGES(AXP806, DCDCC, "dcdcc", "vinc", axp806_dcdca_ranges,
269 72, AXP806_DCDCC_V_CTRL, 0x7f, AXP806_PWR_OUT_CTRL1,
270 BIT(2)),
271 AXP_DESC_RANGES(AXP806, DCDCD, "dcdcd", "vind", axp806_dcdcd_ranges,
272 64, AXP806_DCDCD_V_CTRL, 0x3f, AXP806_PWR_OUT_CTRL1,
273 BIT(3)),
274 AXP_DESC(AXP806, DCDCE, "dcdce", "vine", 1100, 3400, 100,
275 AXP806_DCDCB_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL1, BIT(4)),
276 AXP_DESC(AXP806, ALDO1, "aldo1", "aldoin", 700, 3300, 100,
277 AXP806_ALDO1_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL1, BIT(5)),
278 AXP_DESC(AXP806, ALDO2, "aldo2", "aldoin", 700, 3400, 100,
279 AXP806_ALDO2_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL1, BIT(6)),
280 AXP_DESC(AXP806, ALDO3, "aldo3", "aldoin", 700, 3300, 100,
281 AXP806_ALDO3_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL1, BIT(7)),
282 AXP_DESC(AXP806, BLDO1, "bldo1", "bldoin", 700, 1900, 100,
283 AXP806_BLDO1_V_CTRL, 0x0f, AXP806_PWR_OUT_CTRL2, BIT(0)),
284 AXP_DESC(AXP806, BLDO2, "bldo2", "bldoin", 700, 1900, 100,
285 AXP806_BLDO2_V_CTRL, 0x0f, AXP806_PWR_OUT_CTRL2, BIT(1)),
286 AXP_DESC(AXP806, BLDO3, "bldo3", "bldoin", 700, 1900, 100,
287 AXP806_BLDO3_V_CTRL, 0x0f, AXP806_PWR_OUT_CTRL2, BIT(2)),
288 AXP_DESC(AXP806, BLDO4, "bldo4", "bldoin", 700, 1900, 100,
289 AXP806_BLDO4_V_CTRL, 0x0f, AXP806_PWR_OUT_CTRL2, BIT(3)),
290 AXP_DESC(AXP806, CLDO1, "cldo1", "cldoin", 700, 3300, 100,
291 AXP806_CLDO1_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL2, BIT(4)),
292 AXP_DESC_RANGES(AXP806, CLDO2, "cldo2", "cldoin", axp806_cldo2_ranges,
293 32, AXP806_CLDO2_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL2,
294 BIT(5)),
295 AXP_DESC(AXP806, CLDO3, "cldo3", "cldoin", 700, 3300, 100,
296 AXP806_CLDO3_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL2, BIT(6)),
297 AXP_DESC_SW(AXP806, SW, "sw", "swin", AXP806_PWR_OUT_CTRL2, BIT(7)),
298};
299
300static const struct regulator_linear_range axp809_dcdc4_ranges[] = {
301 REGULATOR_LINEAR_RANGE(600000, 0x0, 0x2f, 20000),
302 REGULATOR_LINEAR_RANGE(1800000, 0x30, 0x38, 100000),
303};
304
257static const struct regulator_desc axp809_regulators[] = { 305static const struct regulator_desc axp809_regulators[] = {
258 AXP_DESC(AXP809, DCDC1, "dcdc1", "vin1", 1600, 3400, 100, 306 AXP_DESC(AXP809, DCDC1, "dcdc1", "vin1", 1600, 3400, 100,
259 AXP22X_DCDC1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(1)), 307 AXP22X_DCDC1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(1)),
@@ -278,7 +326,7 @@ static const struct regulator_desc axp809_regulators[] = {
278 AXP22X_ALDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(7)), 326 AXP22X_ALDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(7)),
279 AXP_DESC(AXP809, ALDO3, "aldo3", "aldoin", 700, 3300, 100, 327 AXP_DESC(AXP809, ALDO3, "aldo3", "aldoin", 700, 3300, 100,
280 AXP22X_ALDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(5)), 328 AXP22X_ALDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(5)),
281 AXP_DESC_RANGES(AXP809, DLDO1, "dldo1", "dldoin", axp809_dldo1_ranges, 329 AXP_DESC_RANGES(AXP809, DLDO1, "dldo1", "dldoin", axp806_cldo2_ranges,
282 32, AXP22X_DLDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, 330 32, AXP22X_DLDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2,
283 BIT(3)), 331 BIT(3)),
284 AXP_DESC(AXP809, DLDO2, "dldo2", "dldoin", 700, 3300, 100, 332 AXP_DESC(AXP809, DLDO2, "dldo2", "dldoin", 700, 3300, 100,
@@ -302,6 +350,7 @@ static const struct regulator_desc axp809_regulators[] = {
302static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq) 350static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq)
303{ 351{
304 struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); 352 struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
353 unsigned int reg = AXP20X_DCDC_FREQ;
305 u32 min, max, def, step; 354 u32 min, max, def, step;
306 355
307 switch (axp20x->variant) { 356 switch (axp20x->variant) {
@@ -312,6 +361,14 @@ static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq)
312 def = 1500; 361 def = 1500;
313 step = 75; 362 step = 75;
314 break; 363 break;
364 case AXP806_ID:
365 /*
366 * AXP806 DCDC work frequency setting has the same range and
367 * step as AXP22X, but at a different register.
368 * Fall through to the check below.
369 * (See include/linux/mfd/axp20x.h)
370 */
371 reg = AXP806_DCDC_FREQ_CTRL;
315 case AXP221_ID: 372 case AXP221_ID:
316 case AXP223_ID: 373 case AXP223_ID:
317 case AXP809_ID: 374 case AXP809_ID:
@@ -343,7 +400,7 @@ static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq)
343 400
344 dcdcfreq = (dcdcfreq - min) / step; 401 dcdcfreq = (dcdcfreq - min) / step;
345 402
346 return regmap_update_bits(axp20x->regmap, AXP20X_DCDC_FREQ, 403 return regmap_update_bits(axp20x->regmap, reg,
347 AXP20X_FREQ_DCDC_MASK, dcdcfreq); 404 AXP20X_FREQ_DCDC_MASK, dcdcfreq);
348} 405}
349 406
@@ -377,6 +434,7 @@ static int axp20x_regulator_parse_dt(struct platform_device *pdev)
377static int axp20x_set_dcdc_workmode(struct regulator_dev *rdev, int id, u32 workmode) 434static int axp20x_set_dcdc_workmode(struct regulator_dev *rdev, int id, u32 workmode)
378{ 435{
379 struct axp20x_dev *axp20x = rdev_get_drvdata(rdev); 436 struct axp20x_dev *axp20x = rdev_get_drvdata(rdev);
437 unsigned int reg = AXP20X_DCDC_MODE;
380 unsigned int mask; 438 unsigned int mask;
381 439
382 switch (axp20x->variant) { 440 switch (axp20x->variant) {
@@ -392,6 +450,13 @@ static int axp20x_set_dcdc_workmode(struct regulator_dev *rdev, int id, u32 work
392 workmode <<= ffs(mask) - 1; 450 workmode <<= ffs(mask) - 1;
393 break; 451 break;
394 452
453 case AXP806_ID:
454 reg = AXP806_DCDC_MODE_CTRL2;
455 /*
456 * AXP806 DCDC regulator IDs have the same range as AXP22X.
457 * Fall through to the check below.
458 * (See include/linux/mfd/axp20x.h)
459 */
395 case AXP221_ID: 460 case AXP221_ID:
396 case AXP223_ID: 461 case AXP223_ID:
397 case AXP809_ID: 462 case AXP809_ID:
@@ -408,7 +473,34 @@ static int axp20x_set_dcdc_workmode(struct regulator_dev *rdev, int id, u32 work
408 return -EINVAL; 473 return -EINVAL;
409 } 474 }
410 475
411 return regmap_update_bits(rdev->regmap, AXP20X_DCDC_MODE, mask, workmode); 476 return regmap_update_bits(rdev->regmap, reg, mask, workmode);
477}
478
479/*
480 * This function checks whether a regulator is part of a poly-phase
481 * output setup based on the registers settings. Returns true if it is.
482 */
483static bool axp20x_is_polyphase_slave(struct axp20x_dev *axp20x, int id)
484{
485 u32 reg = 0;
486
487 /* Only AXP806 has poly-phase outputs */
488 if (axp20x->variant != AXP806_ID)
489 return false;
490
491 regmap_read(axp20x->regmap, AXP806_DCDC_MODE_CTRL2, &reg);
492
493 switch (id) {
494 case AXP806_DCDCB:
495 return (((reg & GENMASK(7, 6)) == BIT(6)) ||
496 ((reg & GENMASK(7, 6)) == BIT(7)));
497 case AXP806_DCDCC:
498 return ((reg & GENMASK(7, 6)) == BIT(7));
499 case AXP806_DCDCE:
500 return !!(reg & BIT(5));
501 }
502
503 return false;
412} 504}
413 505
414static int axp20x_regulator_probe(struct platform_device *pdev) 506static int axp20x_regulator_probe(struct platform_device *pdev)
@@ -440,6 +532,10 @@ static int axp20x_regulator_probe(struct platform_device *pdev)
440 drivevbus = of_property_read_bool(pdev->dev.parent->of_node, 532 drivevbus = of_property_read_bool(pdev->dev.parent->of_node,
441 "x-powers,drive-vbus-en"); 533 "x-powers,drive-vbus-en");
442 break; 534 break;
535 case AXP806_ID:
536 regulators = axp806_regulators;
537 nregulators = AXP806_REG_ID_MAX;
538 break;
443 case AXP809_ID: 539 case AXP809_ID:
444 regulators = axp809_regulators; 540 regulators = axp809_regulators;
445 nregulators = AXP809_REG_ID_MAX; 541 nregulators = AXP809_REG_ID_MAX;
@@ -458,6 +554,14 @@ static int axp20x_regulator_probe(struct platform_device *pdev)
458 struct regulator_desc *new_desc; 554 struct regulator_desc *new_desc;
459 555
460 /* 556 /*
557 * If this regulator is a slave in a poly-phase setup,
558 * skip it, as its controls are bound to the master
559 * regulator and won't work.
560 */
561 if (axp20x_is_polyphase_slave(axp20x, i))
562 continue;
563
564 /*
461 * Regulators DC1SW and DC5LDO are connected internally, 565 * Regulators DC1SW and DC5LDO are connected internally,
462 * so we have to handle their supply names separately. 566 * so we have to handle their supply names separately.
463 * 567 *