Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

regulator: max8998: Add charger regulator

The max8998 has a current regulator for charging control. The
charger driver in drivers/power/supply/max8998_charger.c has a
comment in it stating that 'charger control is done by a current
regulator "CHARGER"', but this regulator was never added until
now.

The current values have been extracted from a downstream driver
for the SGH-T959V.

Signed-off-by: Jonathan Bakker <xc-racer2@live.ca>
Link: https://lore.kernel.org/r/BN6PR04MB0660E1F4A3D5A348BE88311CA3BA0@BN6PR04MB0660.namprd04.prod.outlook.com
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Jonathan Bakker and committed by
Mark Brown
4ffea5e0 a24490e0

+106
+105
drivers/regulator/max8998.c
··· 33 33 unsigned int buck2_idx; 34 34 }; 35 35 36 + static const unsigned int charger_current_table[] = { 37 + 90000, 380000, 475000, 550000, 570000, 600000, 700000, 800000, 38 + }; 39 + 36 40 static int max8998_get_enable_register(struct regulator_dev *rdev, 37 41 int *reg, int *shift) 38 42 { ··· 67 63 *reg = MAX8998_REG_CHGR2; 68 64 *shift = 7 - (ldo - MAX8998_ESAFEOUT1); 69 65 break; 66 + case MAX8998_CHARGER: 67 + *reg = MAX8998_REG_CHGR2; 68 + *shift = 0; 69 + break; 70 70 default: 71 71 return -EINVAL; 72 72 } ··· 94 86 return ret; 95 87 96 88 return val & (1 << shift); 89 + } 90 + 91 + static int max8998_ldo_is_enabled_inverted(struct regulator_dev *rdev) 92 + { 93 + return (!max8998_ldo_is_enabled(rdev)); 97 94 } 98 95 99 96 static int max8998_ldo_enable(struct regulator_dev *rdev) ··· 371 358 return 0; 372 359 } 373 360 361 + int max8998_set_current_limit(struct regulator_dev *rdev, 362 + int min_uA, int max_uA) 363 + { 364 + struct max8998_data *max8998 = rdev_get_drvdata(rdev); 365 + struct i2c_client *i2c = max8998->iodev->i2c; 366 + unsigned int n_currents = rdev->desc->n_current_limits; 367 + int i, sel = -1; 368 + 369 + if (n_currents == 0) 370 + return -EINVAL; 371 + 372 + if (rdev->desc->curr_table) { 373 + const unsigned int *curr_table = rdev->desc->curr_table; 374 + bool ascend = curr_table[n_currents - 1] > curr_table[0]; 375 + 376 + /* search for closest to maximum */ 377 + if (ascend) { 378 + for (i = n_currents - 1; i >= 0; i--) { 379 + if (min_uA <= curr_table[i] && 380 + curr_table[i] <= max_uA) { 381 + sel = i; 382 + break; 383 + } 384 + } 385 + } else { 386 + for (i = 0; i < n_currents; i++) { 387 + if (min_uA <= curr_table[i] && 388 + curr_table[i] <= max_uA) { 389 + sel = i; 390 + break; 391 + } 392 + } 393 + } 394 + } 395 + 396 + if (sel < 0) 397 + return -EINVAL; 398 + 399 + sel <<= ffs(rdev->desc->csel_mask) - 1; 400 + 401 + return max8998_update_reg(i2c, rdev->desc->csel_reg, 402 + sel, rdev->desc->csel_mask); 403 + } 404 + 405 + int max8998_get_current_limit(struct regulator_dev *rdev) 406 + { 407 + struct max8998_data *max8998 = rdev_get_drvdata(rdev); 408 + struct i2c_client *i2c = max8998->iodev->i2c; 409 + u8 val; 410 + int ret; 411 + 412 + ret = max8998_read_reg(i2c, rdev->desc->csel_reg, &val); 413 + if (ret != 0) 414 + return ret; 415 + 416 + val &= rdev->desc->csel_mask; 417 + val >>= ffs(rdev->desc->csel_mask) - 1; 418 + 419 + if (rdev->desc->curr_table) { 420 + if (val >= rdev->desc->n_current_limits) 421 + return -EINVAL; 422 + 423 + return rdev->desc->curr_table[val]; 424 + } 425 + 426 + return -EINVAL; 427 + } 428 + 374 429 static const struct regulator_ops max8998_ldo_ops = { 375 430 .list_voltage = regulator_list_voltage_linear, 376 431 .map_voltage = regulator_map_voltage_linear, ··· 460 379 .set_voltage_time_sel = max8998_set_voltage_buck_time_sel, 461 380 }; 462 381 382 + static const struct regulator_ops max8998_charger_ops = { 383 + .set_current_limit = max8998_set_current_limit, 384 + .get_current_limit = max8998_get_current_limit, 385 + .is_enabled = max8998_ldo_is_enabled_inverted, 386 + /* Swapped as register is inverted */ 387 + .enable = max8998_ldo_disable, 388 + .disable = max8998_ldo_enable, 389 + }; 390 + 463 391 static const struct regulator_ops max8998_others_ops = { 464 392 .is_enabled = max8998_ldo_is_enabled, 465 393 .enable = max8998_ldo_enable, ··· 484 394 .uV_step = (_step), \ 485 395 .n_voltages = ((_max) - (_min)) / (_step) + 1, \ 486 396 .type = REGULATOR_VOLTAGE, \ 397 + .owner = THIS_MODULE, \ 398 + } 399 + 400 + #define MAX8998_CURRENT_REG(_name, _ops, _table, _reg, _mask) \ 401 + { \ 402 + .name = #_name, \ 403 + .id = MAX8998_##_name, \ 404 + .ops = _ops, \ 405 + .curr_table = _table, \ 406 + .n_current_limits = ARRAY_SIZE(_table), \ 407 + .csel_reg = _reg, \ 408 + .csel_mask = _mask, \ 409 + .type = REGULATOR_CURRENT, \ 487 410 .owner = THIS_MODULE, \ 488 411 } 489 412 ··· 535 432 MAX8998_OTHERS_REG(ENVICHG, MAX8998_ENVICHG), 536 433 MAX8998_OTHERS_REG(ESAFEOUT1, MAX8998_ESAFEOUT1), 537 434 MAX8998_OTHERS_REG(ESAFEOUT2, MAX8998_ESAFEOUT2), 435 + MAX8998_CURRENT_REG(CHARGER, &max8998_charger_ops, 436 + charger_current_table, MAX8998_REG_CHGR1, 0x7), 538 437 }; 539 438 540 439 static int max8998_pmic_dt_parse_dvs_gpio(struct max8998_dev *iodev,
+1
include/linux/mfd/max8998.h
··· 39 39 MAX8998_ENVICHG, 40 40 MAX8998_ESAFEOUT1, 41 41 MAX8998_ESAFEOUT2, 42 + MAX8998_CHARGER, 42 43 }; 43 44 44 45 /**