diff options
author | Mark Brown <broonie@kernel.org> | 2017-11-10 21:33:18 +0000 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2017-11-10 21:33:18 +0000 |
commit | 46294d669cdfdcf8035c4b0d9a6c6a599926dc75 (patch) | |
tree | f91769a6ed54c9d40726da32ef5d1d1315f382c0 /drivers/regulator | |
parent | 39dae59d66acd86d1de24294bd2f343fd5e7a625 (diff) | |
parent | ab953b9db3a1169fbc675c8de3d2dab919ce3211 (diff) |
Merge remote-tracking branch 'regulator/fix/qcom-spmi' into regulator-linus
Diffstat (limited to 'drivers/regulator')
-rw-r--r-- | drivers/regulator/qcom_spmi-regulator.c | 39 |
1 files changed, 33 insertions, 6 deletions
diff --git a/drivers/regulator/qcom_spmi-regulator.c b/drivers/regulator/qcom_spmi-regulator.c index 16c5f84e06a7..c372b244f3da 100644 --- a/drivers/regulator/qcom_spmi-regulator.c +++ b/drivers/regulator/qcom_spmi-regulator.c @@ -593,13 +593,20 @@ static int spmi_sw_selector_to_hw(struct spmi_regulator *vreg, u8 *voltage_sel) { const struct spmi_voltage_range *range, *end; + unsigned offset; range = vreg->set_points->range; end = range + vreg->set_points->count; for (; range < end; range++) { if (selector < range->n_voltages) { - *voltage_sel = selector; + /* + * hardware selectors between set point min and real + * min are invalid so we ignore them + */ + offset = range->set_point_min_uV - range->min_uV; + offset /= range->step_uV; + *voltage_sel = selector + offset; *range_sel = range->range_sel; return 0; } @@ -613,15 +620,35 @@ static int spmi_sw_selector_to_hw(struct spmi_regulator *vreg, static int spmi_hw_selector_to_sw(struct spmi_regulator *vreg, u8 hw_sel, const struct spmi_voltage_range *range) { - int sw_sel = hw_sel; + unsigned sw_sel = 0; + unsigned offset, max_hw_sel; const struct spmi_voltage_range *r = vreg->set_points->range; - - while (r != range) { + const struct spmi_voltage_range *end = r + vreg->set_points->count; + + for (; r < end; r++) { + if (r == range && range->n_voltages) { + /* + * hardware selectors between set point min and real + * min and between set point max and real max are + * invalid so we return an error if they're + * programmed into the hardware + */ + offset = range->set_point_min_uV - range->min_uV; + offset /= range->step_uV; + if (hw_sel < offset) + return -EINVAL; + + max_hw_sel = range->set_point_max_uV - range->min_uV; + max_hw_sel /= range->step_uV; + if (hw_sel > max_hw_sel) + return -EINVAL; + + return sw_sel + hw_sel - offset; + } sw_sel += r->n_voltages; - r++; } - return sw_sel; + return -EINVAL; } static const struct spmi_voltage_range * |