diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2020-06-01 11:45:02 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2020-06-01 11:45:02 -0700 |
commit | d30fc97c60682f9bf5d6898ab370de0007e96742 (patch) | |
tree | 88958b8b4a308532b271c4c44aa893a85e95d08b /drivers/regulator/max8998.c | |
parent | a36de5ebac2bea1d30e9ad103b4f841a2c4bb61b (diff) | |
parent | 5fb565b69dabd5a256fc116702331b54a4621dc9 (diff) | |
download | linux-d30fc97c60682f9bf5d6898ab370de0007e96742.tar.bz2 |
Merge tag 'regulator-v5.8' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator
Pull regulator updates from Mark Brown:
"The big change in this release is that Matti Vaittinen has factored
out the linear ranges support into a separate library in lib/ since it
is also useful for at least the power subsystem (and most likely
others too), it helps subsystems which need to map register values
into more useful real world values do so with minimal per-driver code.
- Factoring out of the linear ranges support into a library in lib/
from Matti Vaittinen.
- Trace points for bypass mode.
- Use the consumer name in debugfs to make it easier to understand.
- New drivers for Maxim MAX77826 and MAX8998"
* tag 'regulator-v5.8' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator: (23 commits)
regulator: max8998: max8998_set_current_limit() can be static
dt-bindings: regulator: Convert anatop regulator to json-schema
regulator: core: Add regulator bypass trace points
regulator: extract voltage balancing code to the separate function
regulator/mfd: max8998: Document charger regulator
regulator: max8998: Add charger regulator
MAINTAINERS: Add maintainer entry for linear ranges helper
regulator: bd718x7: remove voltage change restriction from BD71847 LDOs
lib: linear_ranges: Add missing MODULE_LICENSE()
regulator: use linear_ranges helper
power: supply: bd70528: rename linear_range to avoid collision
lib/test_linear_ranges: add a test for the 'linear_ranges'
lib: add linear ranges helpers
regulator: db8500-prcmu: Use true,false for bool variable
regulator: bd718x7: remove voltage change restriction from BD71847
regulator: max77826: Remove erroneous additionalProperties
regulator: qcom-rpmh: Fix typos in pm8150 and pm8150l
regulator: Document bindings for max77826
regulator: max77826: Add max77826 regulator driver
regulator: tps80031: remove redundant assignment to variables ret and val
...
Diffstat (limited to 'drivers/regulator/max8998.c')
-rw-r--r-- | drivers/regulator/max8998.c | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c index 60599c3bb845..340413bba0c5 100644 --- a/drivers/regulator/max8998.c +++ b/drivers/regulator/max8998.c @@ -33,6 +33,10 @@ struct max8998_data { unsigned int buck2_idx; }; +static const unsigned int charger_current_table[] = { + 90000, 380000, 475000, 550000, 570000, 600000, 700000, 800000, +}; + static int max8998_get_enable_register(struct regulator_dev *rdev, int *reg, int *shift) { @@ -63,6 +67,10 @@ static int max8998_get_enable_register(struct regulator_dev *rdev, *reg = MAX8998_REG_CHGR2; *shift = 7 - (ldo - MAX8998_ESAFEOUT1); break; + case MAX8998_CHARGER: + *reg = MAX8998_REG_CHGR2; + *shift = 0; + break; default: return -EINVAL; } @@ -88,6 +96,11 @@ static int max8998_ldo_is_enabled(struct regulator_dev *rdev) return val & (1 << shift); } +static int max8998_ldo_is_enabled_inverted(struct regulator_dev *rdev) +{ + return (!max8998_ldo_is_enabled(rdev)); +} + static int max8998_ldo_enable(struct regulator_dev *rdev) { struct max8998_data *max8998 = rdev_get_drvdata(rdev); @@ -358,6 +371,74 @@ static int max8998_set_voltage_buck_time_sel(struct regulator_dev *rdev, return 0; } +static int max8998_set_current_limit(struct regulator_dev *rdev, + int min_uA, int max_uA) +{ + struct max8998_data *max8998 = rdev_get_drvdata(rdev); + struct i2c_client *i2c = max8998->iodev->i2c; + unsigned int n_currents = rdev->desc->n_current_limits; + int i, sel = -1; + + if (n_currents == 0) + return -EINVAL; + + if (rdev->desc->curr_table) { + const unsigned int *curr_table = rdev->desc->curr_table; + bool ascend = curr_table[n_currents - 1] > curr_table[0]; + + /* search for closest to maximum */ + if (ascend) { + for (i = n_currents - 1; i >= 0; i--) { + if (min_uA <= curr_table[i] && + curr_table[i] <= max_uA) { + sel = i; + break; + } + } + } else { + for (i = 0; i < n_currents; i++) { + if (min_uA <= curr_table[i] && + curr_table[i] <= max_uA) { + sel = i; + break; + } + } + } + } + + if (sel < 0) + return -EINVAL; + + sel <<= ffs(rdev->desc->csel_mask) - 1; + + return max8998_update_reg(i2c, rdev->desc->csel_reg, + sel, rdev->desc->csel_mask); +} + +int max8998_get_current_limit(struct regulator_dev *rdev) +{ + struct max8998_data *max8998 = rdev_get_drvdata(rdev); + struct i2c_client *i2c = max8998->iodev->i2c; + u8 val; + int ret; + + ret = max8998_read_reg(i2c, rdev->desc->csel_reg, &val); + if (ret != 0) + return ret; + + val &= rdev->desc->csel_mask; + val >>= ffs(rdev->desc->csel_mask) - 1; + + if (rdev->desc->curr_table) { + if (val >= rdev->desc->n_current_limits) + return -EINVAL; + + return rdev->desc->curr_table[val]; + } + + return -EINVAL; +} + static const struct regulator_ops max8998_ldo_ops = { .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, @@ -379,6 +460,15 @@ static const struct regulator_ops max8998_buck_ops = { .set_voltage_time_sel = max8998_set_voltage_buck_time_sel, }; +static const struct regulator_ops max8998_charger_ops = { + .set_current_limit = max8998_set_current_limit, + .get_current_limit = max8998_get_current_limit, + .is_enabled = max8998_ldo_is_enabled_inverted, + /* Swapped as register is inverted */ + .enable = max8998_ldo_disable, + .disable = max8998_ldo_enable, +}; + static const struct regulator_ops max8998_others_ops = { .is_enabled = max8998_ldo_is_enabled, .enable = max8998_ldo_enable, @@ -397,6 +487,19 @@ static const struct regulator_ops max8998_others_ops = { .owner = THIS_MODULE, \ } +#define MAX8998_CURRENT_REG(_name, _ops, _table, _reg, _mask) \ + { \ + .name = #_name, \ + .id = MAX8998_##_name, \ + .ops = _ops, \ + .curr_table = _table, \ + .n_current_limits = ARRAY_SIZE(_table), \ + .csel_reg = _reg, \ + .csel_mask = _mask, \ + .type = REGULATOR_CURRENT, \ + .owner = THIS_MODULE, \ + } + #define MAX8998_OTHERS_REG(_name, _id) \ { \ .name = #_name, \ @@ -432,6 +535,8 @@ static const struct regulator_desc regulators[] = { MAX8998_OTHERS_REG(ENVICHG, MAX8998_ENVICHG), MAX8998_OTHERS_REG(ESAFEOUT1, MAX8998_ESAFEOUT1), MAX8998_OTHERS_REG(ESAFEOUT2, MAX8998_ESAFEOUT2), + MAX8998_CURRENT_REG(CHARGER, &max8998_charger_ops, + charger_current_table, MAX8998_REG_CHGR1, 0x7), }; static int max8998_pmic_dt_parse_dvs_gpio(struct max8998_dev *iodev, |