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

regulator: Implement WM831x BuckWise DC-DC convertor DVS support

The BuckWise DC-DC convertors in WM831x devices support switching to
a second output voltage using the logic level on one of the device
pins. This is intended to allow rapid voltage switching for uses like
cpufreq, replacing the I2C or SPI write used to configure the voltage
of the regulator with a much faster GPIO status change.

This is implemented by keeping the DVS voltage configured as the
maximum voltage permitted for the regulator. If a request is made
for the maximum voltage then the GPIO is used to switch to the DVS
voltage, otherwise the normal ON voltage is updated and used. This
follows the idiom used by most cpufreq drivers, which drop the
minimum voltage as the core frequency is dropped but use a constant
maximum - raising the voltage should normally be fast, but lowering
it may be slower.

Configuration of the DVS MFP on the device should be done externally,
for example via OTP.

Support is present in the hardware for monitoring the status of the
transition using a second GPIO. This is not currently implemented
but platform data is provided for it - the driver currently assumes
that the device will be configured to transition immediately - but
platform data is provided to reduce merge issues once it is.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Acked-by: Samuel Ortiz <sameo@linux.intel.com>
Signed-off-by: Liam Girdwood <lrg@slimlogic.co.uk>

authored by

Mark Brown and committed by
Liam Girdwood
e24a04c4 27f37e4b

+206 -18
+189 -18
drivers/regulator/wm831x-dcdc.c
··· 19 19 #include <linux/i2c.h> 20 20 #include <linux/platform_device.h> 21 21 #include <linux/regulator/driver.h> 22 + #include <linux/regulator/machine.h> 23 + #include <linux/gpio.h> 22 24 23 25 #include <linux/mfd/wm831x/core.h> 24 26 #include <linux/mfd/wm831x/regulator.h> ··· 41 39 #define WM831X_DCDC_CONTROL_2 1 42 40 #define WM831X_DCDC_ON_CONFIG 2 43 41 #define WM831X_DCDC_SLEEP_CONTROL 3 42 + #define WM831X_DCDC_DVS_CONTROL 4 44 43 45 44 /* 46 45 * Shared ··· 53 50 int base; 54 51 struct wm831x *wm831x; 55 52 struct regulator_dev *regulator; 53 + int dvs_gpio; 54 + int dvs_gpio_state; 55 + int on_vsel; 56 + int dvs_vsel; 56 57 }; 57 58 58 59 static int wm831x_dcdc_is_enabled(struct regulator_dev *rdev) ··· 247 240 return -EINVAL; 248 241 } 249 242 250 - static int wm831x_buckv_set_voltage_int(struct regulator_dev *rdev, int reg, 251 - int min_uV, int max_uV) 243 + static int wm831x_buckv_select_min_voltage(struct regulator_dev *rdev, 244 + int min_uV, int max_uV) 252 245 { 253 - struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev); 254 - struct wm831x *wm831x = dcdc->wm831x; 255 246 u16 vsel; 256 247 257 248 if (min_uV < 600000) ··· 262 257 if (wm831x_buckv_list_voltage(rdev, vsel) > max_uV) 263 258 return -EINVAL; 264 259 265 - return wm831x_set_bits(wm831x, reg, WM831X_DC1_ON_VSEL_MASK, vsel); 260 + return vsel; 261 + } 262 + 263 + static int wm831x_buckv_select_max_voltage(struct regulator_dev *rdev, 264 + int min_uV, int max_uV) 265 + { 266 + u16 vsel; 267 + 268 + if (max_uV < 600000 || max_uV > 1800000) 269 + return -EINVAL; 270 + 271 + vsel = ((max_uV - 600000) / 12500) + 8; 272 + 273 + if (wm831x_buckv_list_voltage(rdev, vsel) < min_uV || 274 + wm831x_buckv_list_voltage(rdev, vsel) < max_uV) 275 + return -EINVAL; 276 + 277 + return vsel; 278 + } 279 + 280 + static int wm831x_buckv_set_dvs(struct regulator_dev *rdev, int state) 281 + { 282 + struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev); 283 + 284 + if (state == dcdc->dvs_gpio_state) 285 + return 0; 286 + 287 + dcdc->dvs_gpio_state = state; 288 + gpio_set_value(dcdc->dvs_gpio, state); 289 + 290 + /* Should wait for DVS state change to be asserted if we have 291 + * a GPIO for it, for now assume the device is configured 292 + * for the fastest possible transition. 293 + */ 294 + 295 + return 0; 266 296 } 267 297 268 298 static int wm831x_buckv_set_voltage(struct regulator_dev *rdev, 269 - int min_uV, int max_uV) 299 + int min_uV, int max_uV) 270 300 { 271 301 struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev); 272 - u16 reg = dcdc->base + WM831X_DCDC_ON_CONFIG; 302 + struct wm831x *wm831x = dcdc->wm831x; 303 + int on_reg = dcdc->base + WM831X_DCDC_ON_CONFIG; 304 + int dvs_reg = dcdc->base + WM831X_DCDC_DVS_CONTROL; 305 + int vsel, ret; 273 306 274 - return wm831x_buckv_set_voltage_int(rdev, reg, min_uV, max_uV); 307 + vsel = wm831x_buckv_select_min_voltage(rdev, min_uV, max_uV); 308 + if (vsel < 0) 309 + return vsel; 310 + 311 + /* If this value is already set then do a GPIO update if we can */ 312 + if (dcdc->dvs_gpio && dcdc->on_vsel == vsel) 313 + return wm831x_buckv_set_dvs(rdev, 0); 314 + 315 + if (dcdc->dvs_gpio && dcdc->dvs_vsel == vsel) 316 + return wm831x_buckv_set_dvs(rdev, 1); 317 + 318 + /* Always set the ON status to the minimum voltage */ 319 + ret = wm831x_set_bits(wm831x, on_reg, WM831X_DC1_ON_VSEL_MASK, vsel); 320 + if (ret < 0) 321 + return ret; 322 + dcdc->on_vsel = vsel; 323 + 324 + if (!dcdc->dvs_gpio) 325 + return ret; 326 + 327 + /* Kick the voltage transition now */ 328 + ret = wm831x_buckv_set_dvs(rdev, 0); 329 + if (ret < 0) 330 + return ret; 331 + 332 + /* Set the high voltage as the DVS voltage. This is optimised 333 + * for CPUfreq usage, most processors will keep the maximum 334 + * voltage constant and lower the minimum with the frequency. */ 335 + vsel = wm831x_buckv_select_max_voltage(rdev, min_uV, max_uV); 336 + if (vsel < 0) { 337 + /* This should never happen - at worst the same vsel 338 + * should be chosen */ 339 + WARN_ON(vsel < 0); 340 + return 0; 341 + } 342 + 343 + /* Don't bother if it's the same VSEL we're already using */ 344 + if (vsel == dcdc->on_vsel) 345 + return 0; 346 + 347 + ret = wm831x_set_bits(wm831x, dvs_reg, WM831X_DC1_DVS_VSEL_MASK, vsel); 348 + if (ret == 0) 349 + dcdc->dvs_vsel = vsel; 350 + else 351 + dev_warn(wm831x->dev, "Failed to set DCDC DVS VSEL: %d\n", 352 + ret); 353 + 354 + return 0; 275 355 } 276 356 277 357 static int wm831x_buckv_set_suspend_voltage(struct regulator_dev *rdev, 278 - int uV) 358 + int uV) 279 359 { 280 360 struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev); 361 + struct wm831x *wm831x = dcdc->wm831x; 281 362 u16 reg = dcdc->base + WM831X_DCDC_SLEEP_CONTROL; 363 + int vsel; 282 364 283 - return wm831x_buckv_set_voltage_int(rdev, reg, uV, uV); 365 + vsel = wm831x_buckv_select_min_voltage(rdev, uV, uV); 366 + if (vsel < 0) 367 + return vsel; 368 + 369 + return wm831x_set_bits(wm831x, reg, WM831X_DC1_SLP_VSEL_MASK, vsel); 284 370 } 285 371 286 372 static int wm831x_buckv_get_voltage(struct regulator_dev *rdev) 287 373 { 288 374 struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev); 289 - struct wm831x *wm831x = dcdc->wm831x; 290 - u16 reg = dcdc->base + WM831X_DCDC_ON_CONFIG; 291 - int val; 292 375 293 - val = wm831x_reg_read(wm831x, reg); 294 - if (val < 0) 295 - return val; 296 - 297 - return wm831x_buckv_list_voltage(rdev, val & WM831X_DC1_ON_VSEL_MASK); 376 + if (dcdc->dvs_gpio && dcdc->dvs_gpio_state) 377 + return wm831x_buckv_list_voltage(rdev, dcdc->dvs_vsel); 378 + else 379 + return wm831x_buckv_list_voltage(rdev, dcdc->on_vsel); 298 380 } 299 381 300 382 /* Current limit options */ ··· 438 346 .set_suspend_mode = wm831x_dcdc_set_suspend_mode, 439 347 }; 440 348 349 + /* 350 + * Set up DVS control. We just log errors since we can still run 351 + * (with reduced performance) if we fail. 352 + */ 353 + static __devinit void wm831x_buckv_dvs_init(struct wm831x_dcdc *dcdc, 354 + struct wm831x_buckv_pdata *pdata) 355 + { 356 + struct wm831x *wm831x = dcdc->wm831x; 357 + int ret; 358 + u16 ctrl; 359 + 360 + if (!pdata || !pdata->dvs_gpio) 361 + return; 362 + 363 + switch (pdata->dvs_control_src) { 364 + case 1: 365 + ctrl = 2 << WM831X_DC1_DVS_SRC_SHIFT; 366 + break; 367 + case 2: 368 + ctrl = 3 << WM831X_DC1_DVS_SRC_SHIFT; 369 + break; 370 + default: 371 + dev_err(wm831x->dev, "Invalid DVS control source %d for %s\n", 372 + pdata->dvs_control_src, dcdc->name); 373 + return; 374 + } 375 + 376 + ret = wm831x_set_bits(wm831x, dcdc->base + WM831X_DCDC_DVS_CONTROL, 377 + WM831X_DC1_DVS_SRC_MASK, ctrl); 378 + if (ret < 0) { 379 + dev_err(wm831x->dev, "Failed to set %s DVS source: %d\n", 380 + dcdc->name, ret); 381 + return; 382 + } 383 + 384 + ret = gpio_request(pdata->dvs_gpio, "DCDC DVS"); 385 + if (ret < 0) { 386 + dev_err(wm831x->dev, "Failed to get %s DVS GPIO: %d\n", 387 + dcdc->name, ret); 388 + return; 389 + } 390 + 391 + /* gpiolib won't let us read the GPIO status so pick the higher 392 + * of the two existing voltages so we take it as platform data. 393 + */ 394 + dcdc->dvs_gpio_state = pdata->dvs_init_state; 395 + 396 + ret = gpio_direction_output(pdata->dvs_gpio, dcdc->dvs_gpio_state); 397 + if (ret < 0) { 398 + dev_err(wm831x->dev, "Failed to enable %s DVS GPIO: %d\n", 399 + dcdc->name, ret); 400 + gpio_free(pdata->dvs_gpio); 401 + return; 402 + } 403 + 404 + dcdc->dvs_gpio = pdata->dvs_gpio; 405 + } 406 + 441 407 static __devinit int wm831x_buckv_probe(struct platform_device *pdev) 442 408 { 443 409 struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); ··· 533 383 dcdc->desc.n_voltages = WM831X_BUCKV_MAX_SELECTOR + 1; 534 384 dcdc->desc.ops = &wm831x_buckv_ops; 535 385 dcdc->desc.owner = THIS_MODULE; 386 + 387 + ret = wm831x_reg_read(wm831x, dcdc->base + WM831X_DCDC_ON_CONFIG); 388 + if (ret < 0) { 389 + dev_err(wm831x->dev, "Failed to read ON VSEL: %d\n", ret); 390 + goto err; 391 + } 392 + dcdc->on_vsel = ret & WM831X_DC1_ON_VSEL_MASK; 393 + 394 + ret = wm831x_reg_read(wm831x, dcdc->base + WM831X_DCDC_ON_CONFIG); 395 + if (ret < 0) { 396 + dev_err(wm831x->dev, "Failed to read DVS VSEL: %d\n", ret); 397 + goto err; 398 + } 399 + dcdc->dvs_vsel = ret & WM831X_DC1_DVS_VSEL_MASK; 400 + 401 + if (pdata->dcdc[id]) 402 + wm831x_buckv_dvs_init(dcdc, pdata->dcdc[id]->driver_data); 536 403 537 404 dcdc->regulator = regulator_register(&dcdc->desc, &pdev->dev, 538 405 pdata->dcdc[id], dcdc); ··· 589 422 err_regulator: 590 423 regulator_unregister(dcdc->regulator); 591 424 err: 425 + if (dcdc->dvs_gpio) 426 + gpio_free(dcdc->dvs_gpio); 592 427 kfree(dcdc); 593 428 return ret; 594 429 } ··· 603 434 wm831x_free_irq(wm831x, platform_get_irq_byname(pdev, "HC"), dcdc); 604 435 wm831x_free_irq(wm831x, platform_get_irq_byname(pdev, "UV"), dcdc); 605 436 regulator_unregister(dcdc->regulator); 437 + if (dcdc->dvs_gpio) 438 + gpio_free(dcdc->dvs_gpio); 606 439 kfree(dcdc); 607 440 608 441 return 0;
+17
include/linux/mfd/wm831x/pdata.h
··· 41 41 int timeout; /** Charge cycle timeout, in minutes */ 42 42 }; 43 43 44 + /** 45 + * Configuration for the WM831x DC-DC BuckWise convertors. This 46 + * should be passed as driver_data in the regulator_init_data. 47 + * 48 + * Currently all the configuration is for the fast DVS switching 49 + * support of the devices. This allows MFPs on the device to be 50 + * configured as an input to switch between two output voltages, 51 + * allowing voltage transitions without the expense of an access over 52 + * I2C or SPI buses. 53 + */ 54 + struct wm831x_buckv_pdata { 55 + int dvs_gpio; /** CPU GPIO to use for DVS switching */ 56 + int dvs_control_src; /** Hardware DVS source to use (1 or 2) */ 57 + int dvs_init_state; /** DVS state to expect on startup */ 58 + int dvs_state_gpio; /** CPU GPIO to use for monitoring status */ 59 + }; 60 + 44 61 /* Sources for status LED configuration. Values are register values 45 62 * plus 1 to allow for a zero default for preserve. 46 63 */