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

regulator: Improve WM831x DVS VSEL selection algorithm

Rather than using the maximum voltage we get passed to select the DVS
voltage to use remember the highest voltage we've ever seen. This improves
how the driver works when the consumer permits higher voltages than it
will ever selects in order to support the widest possible voltage range.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Signed-off-by: Liam Girdwood <lrg@slimlogic.co.uk>

authored by

Mark Brown and committed by
Liam Girdwood
88cda60e c439b8f4

+15 -37
+15 -37
drivers/regulator/wm831x-dcdc.c
··· 267 267 return vsel; 268 268 } 269 269 270 - static int wm831x_buckv_select_max_voltage(struct regulator_dev *rdev, 271 - int min_uV, int max_uV) 272 - { 273 - u16 vsel; 274 - 275 - if (max_uV < 600000 || max_uV > 1800000) 276 - return -EINVAL; 277 - 278 - vsel = ((max_uV - 600000) / 12500) + 8; 279 - 280 - if (wm831x_buckv_list_voltage(rdev, vsel) < min_uV || 281 - wm831x_buckv_list_voltage(rdev, vsel) < max_uV) 282 - return -EINVAL; 283 - 284 - return vsel; 285 - } 286 - 287 270 static int wm831x_buckv_set_dvs(struct regulator_dev *rdev, int state) 288 271 { 289 272 struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev); ··· 321 338 if (ret < 0) 322 339 return ret; 323 340 324 - /* Set the high voltage as the DVS voltage. This is optimised 325 - * for CPUfreq usage, most processors will keep the maximum 326 - * voltage constant and lower the minimum with the frequency. */ 327 - vsel = wm831x_buckv_select_max_voltage(rdev, min_uV, max_uV); 328 - if (vsel < 0) { 329 - /* This should never happen - at worst the same vsel 330 - * should be chosen */ 331 - WARN_ON(vsel < 0); 332 - return 0; 341 + /* 342 + * If this VSEL is higher than the last one we've seen then 343 + * remember it as the DVS VSEL. This is optimised for CPUfreq 344 + * usage where we want to get to the highest voltage very 345 + * quickly. 346 + */ 347 + if (vsel > dcdc->dvs_vsel) { 348 + ret = wm831x_set_bits(wm831x, dvs_reg, 349 + WM831X_DC1_DVS_VSEL_MASK, 350 + dcdc->dvs_vsel); 351 + if (ret == 0) 352 + dcdc->dvs_vsel = vsel; 353 + else 354 + dev_warn(wm831x->dev, 355 + "Failed to set DCDC DVS VSEL: %d\n", ret); 333 356 } 334 - 335 - /* Don't bother if it's the same VSEL we're already using */ 336 - if (vsel == dcdc->on_vsel) 337 - return 0; 338 - 339 - ret = wm831x_set_bits(wm831x, dvs_reg, WM831X_DC1_DVS_VSEL_MASK, vsel); 340 - if (ret == 0) 341 - dcdc->dvs_vsel = vsel; 342 - else 343 - dev_warn(wm831x->dev, "Failed to set DCDC DVS VSEL: %d\n", 344 - ret); 345 357 346 358 return 0; 347 359 }