diff options
Diffstat (limited to 'drivers/regulator/wm831x-dcdc.c')
-rw-r--r-- | drivers/regulator/wm831x-dcdc.c | 126 |
1 files changed, 65 insertions, 61 deletions
diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c index a0982e809851..bd3531d8b2ac 100644 --- a/drivers/regulator/wm831x-dcdc.c +++ b/drivers/regulator/wm831x-dcdc.c | |||
@@ -267,23 +267,6 @@ static int wm831x_buckv_select_min_voltage(struct regulator_dev *rdev, | |||
267 | return vsel; | 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 | static int wm831x_buckv_set_dvs(struct regulator_dev *rdev, int state) | 270 | static int wm831x_buckv_set_dvs(struct regulator_dev *rdev, int state) |
288 | { | 271 | { |
289 | struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev); | 272 | struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev); |
@@ -338,28 +321,23 @@ static int wm831x_buckv_set_voltage(struct regulator_dev *rdev, | |||
338 | if (ret < 0) | 321 | if (ret < 0) |
339 | return ret; | 322 | return ret; |
340 | 323 | ||
341 | /* Set the high voltage as the DVS voltage. This is optimised | 324 | /* |
342 | * for CPUfreq usage, most processors will keep the maximum | 325 | * If this VSEL is higher than the last one we've seen then |
343 | * voltage constant and lower the minimum with the frequency. */ | 326 | * remember it as the DVS VSEL. This is optimised for CPUfreq |
344 | vsel = wm831x_buckv_select_max_voltage(rdev, min_uV, max_uV); | 327 | * usage where we want to get to the highest voltage very |
345 | if (vsel < 0) { | 328 | * quickly. |
346 | /* This should never happen - at worst the same vsel | 329 | */ |
347 | * should be chosen */ | 330 | if (vsel > dcdc->dvs_vsel) { |
348 | WARN_ON(vsel < 0); | 331 | ret = wm831x_set_bits(wm831x, dvs_reg, |
349 | return 0; | 332 | WM831X_DC1_DVS_VSEL_MASK, |
333 | dcdc->dvs_vsel); | ||
334 | if (ret == 0) | ||
335 | dcdc->dvs_vsel = vsel; | ||
336 | else | ||
337 | dev_warn(wm831x->dev, | ||
338 | "Failed to set DCDC DVS VSEL: %d\n", ret); | ||
350 | } | 339 | } |
351 | 340 | ||
352 | /* Don't bother if it's the same VSEL we're already using */ | ||
353 | if (vsel == dcdc->on_vsel) | ||
354 | return 0; | ||
355 | |||
356 | ret = wm831x_set_bits(wm831x, dvs_reg, WM831X_DC1_DVS_VSEL_MASK, vsel); | ||
357 | if (ret == 0) | ||
358 | dcdc->dvs_vsel = vsel; | ||
359 | else | ||
360 | dev_warn(wm831x->dev, "Failed to set DCDC DVS VSEL: %d\n", | ||
361 | ret); | ||
362 | |||
363 | return 0; | 341 | return 0; |
364 | } | 342 | } |
365 | 343 | ||
@@ -456,27 +434,6 @@ static __devinit void wm831x_buckv_dvs_init(struct wm831x_dcdc *dcdc, | |||
456 | if (!pdata || !pdata->dvs_gpio) | 434 | if (!pdata || !pdata->dvs_gpio) |
457 | return; | 435 | return; |
458 | 436 | ||
459 | switch (pdata->dvs_control_src) { | ||
460 | case 1: | ||
461 | ctrl = 2 << WM831X_DC1_DVS_SRC_SHIFT; | ||
462 | break; | ||
463 | case 2: | ||
464 | ctrl = 3 << WM831X_DC1_DVS_SRC_SHIFT; | ||
465 | break; | ||
466 | default: | ||
467 | dev_err(wm831x->dev, "Invalid DVS control source %d for %s\n", | ||
468 | pdata->dvs_control_src, dcdc->name); | ||
469 | return; | ||
470 | } | ||
471 | |||
472 | ret = wm831x_set_bits(wm831x, dcdc->base + WM831X_DCDC_DVS_CONTROL, | ||
473 | WM831X_DC1_DVS_SRC_MASK, ctrl); | ||
474 | if (ret < 0) { | ||
475 | dev_err(wm831x->dev, "Failed to set %s DVS source: %d\n", | ||
476 | dcdc->name, ret); | ||
477 | return; | ||
478 | } | ||
479 | |||
480 | ret = gpio_request(pdata->dvs_gpio, "DCDC DVS"); | 437 | ret = gpio_request(pdata->dvs_gpio, "DCDC DVS"); |
481 | if (ret < 0) { | 438 | if (ret < 0) { |
482 | dev_err(wm831x->dev, "Failed to get %s DVS GPIO: %d\n", | 439 | dev_err(wm831x->dev, "Failed to get %s DVS GPIO: %d\n", |
@@ -498,17 +455,57 @@ static __devinit void wm831x_buckv_dvs_init(struct wm831x_dcdc *dcdc, | |||
498 | } | 455 | } |
499 | 456 | ||
500 | dcdc->dvs_gpio = pdata->dvs_gpio; | 457 | dcdc->dvs_gpio = pdata->dvs_gpio; |
458 | |||
459 | switch (pdata->dvs_control_src) { | ||
460 | case 1: | ||
461 | ctrl = 2 << WM831X_DC1_DVS_SRC_SHIFT; | ||
462 | break; | ||
463 | case 2: | ||
464 | ctrl = 3 << WM831X_DC1_DVS_SRC_SHIFT; | ||
465 | break; | ||
466 | default: | ||
467 | dev_err(wm831x->dev, "Invalid DVS control source %d for %s\n", | ||
468 | pdata->dvs_control_src, dcdc->name); | ||
469 | return; | ||
470 | } | ||
471 | |||
472 | /* If DVS_VSEL is set to the minimum value then raise it to ON_VSEL | ||
473 | * to make bootstrapping a bit smoother. | ||
474 | */ | ||
475 | if (!dcdc->dvs_vsel) { | ||
476 | ret = wm831x_set_bits(wm831x, | ||
477 | dcdc->base + WM831X_DCDC_DVS_CONTROL, | ||
478 | WM831X_DC1_DVS_VSEL_MASK, dcdc->on_vsel); | ||
479 | if (ret == 0) | ||
480 | dcdc->dvs_vsel = dcdc->on_vsel; | ||
481 | else | ||
482 | dev_warn(wm831x->dev, "Failed to set DVS_VSEL: %d\n", | ||
483 | ret); | ||
484 | } | ||
485 | |||
486 | ret = wm831x_set_bits(wm831x, dcdc->base + WM831X_DCDC_DVS_CONTROL, | ||
487 | WM831X_DC1_DVS_SRC_MASK, ctrl); | ||
488 | if (ret < 0) { | ||
489 | dev_err(wm831x->dev, "Failed to set %s DVS source: %d\n", | ||
490 | dcdc->name, ret); | ||
491 | } | ||
501 | } | 492 | } |
502 | 493 | ||
503 | static __devinit int wm831x_buckv_probe(struct platform_device *pdev) | 494 | static __devinit int wm831x_buckv_probe(struct platform_device *pdev) |
504 | { | 495 | { |
505 | struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); | 496 | struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); |
506 | struct wm831x_pdata *pdata = wm831x->dev->platform_data; | 497 | struct wm831x_pdata *pdata = wm831x->dev->platform_data; |
507 | int id = pdev->id % ARRAY_SIZE(pdata->dcdc); | 498 | int id; |
508 | struct wm831x_dcdc *dcdc; | 499 | struct wm831x_dcdc *dcdc; |
509 | struct resource *res; | 500 | struct resource *res; |
510 | int ret, irq; | 501 | int ret, irq; |
511 | 502 | ||
503 | if (pdata && pdata->wm831x_num) | ||
504 | id = (pdata->wm831x_num * 10) + 1; | ||
505 | else | ||
506 | id = 0; | ||
507 | id = pdev->id - id; | ||
508 | |||
512 | dev_dbg(&pdev->dev, "Probing DCDC%d\n", id + 1); | 509 | dev_dbg(&pdev->dev, "Probing DCDC%d\n", id + 1); |
513 | 510 | ||
514 | if (pdata == NULL || pdata->dcdc[id] == NULL) | 511 | if (pdata == NULL || pdata->dcdc[id] == NULL) |
@@ -545,7 +542,7 @@ static __devinit int wm831x_buckv_probe(struct platform_device *pdev) | |||
545 | } | 542 | } |
546 | dcdc->on_vsel = ret & WM831X_DC1_ON_VSEL_MASK; | 543 | dcdc->on_vsel = ret & WM831X_DC1_ON_VSEL_MASK; |
547 | 544 | ||
548 | ret = wm831x_reg_read(wm831x, dcdc->base + WM831X_DCDC_ON_CONFIG); | 545 | ret = wm831x_reg_read(wm831x, dcdc->base + WM831X_DCDC_DVS_CONTROL); |
549 | if (ret < 0) { | 546 | if (ret < 0) { |
550 | dev_err(wm831x->dev, "Failed to read DVS VSEL: %d\n", ret); | 547 | dev_err(wm831x->dev, "Failed to read DVS VSEL: %d\n", ret); |
551 | goto err; | 548 | goto err; |
@@ -709,11 +706,17 @@ static __devinit int wm831x_buckp_probe(struct platform_device *pdev) | |||
709 | { | 706 | { |
710 | struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); | 707 | struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); |
711 | struct wm831x_pdata *pdata = wm831x->dev->platform_data; | 708 | struct wm831x_pdata *pdata = wm831x->dev->platform_data; |
712 | int id = pdev->id % ARRAY_SIZE(pdata->dcdc); | 709 | int id; |
713 | struct wm831x_dcdc *dcdc; | 710 | struct wm831x_dcdc *dcdc; |
714 | struct resource *res; | 711 | struct resource *res; |
715 | int ret, irq; | 712 | int ret, irq; |
716 | 713 | ||
714 | if (pdata && pdata->wm831x_num) | ||
715 | id = (pdata->wm831x_num * 10) + 1; | ||
716 | else | ||
717 | id = 0; | ||
718 | id = pdev->id - id; | ||
719 | |||
717 | dev_dbg(&pdev->dev, "Probing DCDC%d\n", id + 1); | 720 | dev_dbg(&pdev->dev, "Probing DCDC%d\n", id + 1); |
718 | 721 | ||
719 | if (pdata == NULL || pdata->dcdc[id] == NULL) | 722 | if (pdata == NULL || pdata->dcdc[id] == NULL) |
@@ -1046,3 +1049,4 @@ MODULE_DESCRIPTION("WM831x DC-DC convertor driver"); | |||
1046 | MODULE_LICENSE("GPL"); | 1049 | MODULE_LICENSE("GPL"); |
1047 | MODULE_ALIAS("platform:wm831x-buckv"); | 1050 | MODULE_ALIAS("platform:wm831x-buckv"); |
1048 | MODULE_ALIAS("platform:wm831x-buckp"); | 1051 | MODULE_ALIAS("platform:wm831x-buckp"); |
1052 | MODULE_ALIAS("platform:wm831x-epe"); | ||