diff options
Diffstat (limited to 'drivers/regulator')
-rw-r--r-- | drivers/regulator/helpers.c | 43 |
1 files changed, 30 insertions, 13 deletions
diff --git a/drivers/regulator/helpers.c b/drivers/regulator/helpers.c index d49268336553..6e1ace660b8c 100644 --- a/drivers/regulator/helpers.c +++ b/drivers/regulator/helpers.c @@ -161,6 +161,32 @@ int regulator_get_voltage_sel_pickable_regmap(struct regulator_dev *rdev) } EXPORT_SYMBOL_GPL(regulator_get_voltage_sel_pickable_regmap); +static int write_separate_vsel_and_range(struct regulator_dev *rdev, + unsigned int sel, unsigned int range) +{ + bool range_updated; + int ret; + + ret = regmap_update_bits_base(rdev->regmap, rdev->desc->vsel_range_reg, + rdev->desc->vsel_range_mask, + range, &range_updated, false, false); + if (ret) + return ret; + + /* + * Some PMICs treat the vsel_reg same as apply-bit. Force it to be + * written if the range changed, even if the old selector was same as + * the new one + */ + if (rdev->desc->range_applied_by_vsel && range_updated) + return regmap_write_bits(rdev->regmap, + rdev->desc->vsel_reg, + rdev->desc->vsel_mask, sel); + + return regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg, + rdev->desc->vsel_mask, sel); +} + /** * regulator_set_voltage_sel_pickable_regmap - pickable range set_voltage_sel * @@ -199,21 +225,12 @@ int regulator_set_voltage_sel_pickable_regmap(struct regulator_dev *rdev, range = rdev->desc->linear_range_selectors_bitfield[i]; range <<= ffs(rdev->desc->vsel_range_mask) - 1; - if (rdev->desc->vsel_reg == rdev->desc->vsel_range_reg) { - ret = regmap_update_bits(rdev->regmap, - rdev->desc->vsel_reg, + if (rdev->desc->vsel_reg == rdev->desc->vsel_range_reg) + ret = regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg, rdev->desc->vsel_range_mask | rdev->desc->vsel_mask, sel | range); - } else { - ret = regmap_update_bits(rdev->regmap, - rdev->desc->vsel_range_reg, - rdev->desc->vsel_range_mask, range); - if (ret) - return ret; - - ret = regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg, - rdev->desc->vsel_mask, sel); - } + else + ret = write_separate_vsel_and_range(rdev, sel, range); if (ret) return ret; |