diff options
author | Lee Jones <lee.jones@linaro.org> | 2013-02-04 03:33:13 -0500 |
---|---|---|
committer | Lee Jones <lee.jones@linaro.org> | 2013-02-04 03:33:13 -0500 |
commit | 5f8aaef4fdf97bfe504ff2c78244a53a145917dc (patch) | |
tree | 208d3e78144a06c6db90f46908786d0df0de94f0 /drivers/mfd/ab8500-gpadc.c | |
parent | 8f0eb43be5f461a28341fe724686f265b0719dd3 (diff) |
mfd: ab8500-gpadc: Add runtime pm support
Add runtime pm support to speed up multiple ADC reads in a row.
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Signed-off-by: Jonas Aaberg <jonas.aberg@stericsson.com>
Reviewed-by: Ulf HANSSON <ulf.hansson@stericsson.com>
Diffstat (limited to 'drivers/mfd/ab8500-gpadc.c')
-rw-r--r-- | drivers/mfd/ab8500-gpadc.c | 70 |
1 files changed, 64 insertions, 6 deletions
diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c index 61b176fc457b..580f1008d67a 100644 --- a/drivers/mfd/ab8500-gpadc.c +++ b/drivers/mfd/ab8500-gpadc.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/interrupt.h> | 12 | #include <linux/interrupt.h> |
13 | #include <linux/spinlock.h> | 13 | #include <linux/spinlock.h> |
14 | #include <linux/delay.h> | 14 | #include <linux/delay.h> |
15 | #include <linux/pm_runtime.h> | ||
15 | #include <linux/platform_device.h> | 16 | #include <linux/platform_device.h> |
16 | #include <linux/completion.h> | 17 | #include <linux/completion.h> |
17 | #include <linux/regulator/consumer.h> | 18 | #include <linux/regulator/consumer.h> |
@@ -82,6 +83,9 @@ | |||
82 | /* This is used to not lose precision when dividing to get gain and offset */ | 83 | /* This is used to not lose precision when dividing to get gain and offset */ |
83 | #define CALIB_SCALE 1000 | 84 | #define CALIB_SCALE 1000 |
84 | 85 | ||
86 | /* Time in ms before disabling regulator */ | ||
87 | #define GPADC_AUDOSUSPEND_DELAY 1 | ||
88 | |||
85 | enum cal_channels { | 89 | enum cal_channels { |
86 | ADC_INPUT_VMAIN = 0, | 90 | ADC_INPUT_VMAIN = 0, |
87 | ADC_INPUT_BTEMP, | 91 | ADC_INPUT_BTEMP, |
@@ -282,8 +286,9 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel) | |||
282 | return -ENODEV; | 286 | return -ENODEV; |
283 | 287 | ||
284 | mutex_lock(&gpadc->ab8500_gpadc_lock); | 288 | mutex_lock(&gpadc->ab8500_gpadc_lock); |
289 | |||
285 | /* Enable VTVout LDO this is required for GPADC */ | 290 | /* Enable VTVout LDO this is required for GPADC */ |
286 | regulator_enable(gpadc->regu); | 291 | pm_runtime_get_sync(gpadc->dev); |
287 | 292 | ||
288 | /* Check if ADC is not busy, lock and proceed */ | 293 | /* Check if ADC is not busy, lock and proceed */ |
289 | do { | 294 | do { |
@@ -397,8 +402,10 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel) | |||
397 | dev_err(gpadc->dev, "gpadc_conversion: disable gpadc failed\n"); | 402 | dev_err(gpadc->dev, "gpadc_conversion: disable gpadc failed\n"); |
398 | goto out; | 403 | goto out; |
399 | } | 404 | } |
400 | /* Disable VTVout LDO this is required for GPADC */ | 405 | |
401 | regulator_disable(gpadc->regu); | 406 | pm_runtime_mark_last_busy(gpadc->dev); |
407 | pm_runtime_put_autosuspend(gpadc->dev); | ||
408 | |||
402 | mutex_unlock(&gpadc->ab8500_gpadc_lock); | 409 | mutex_unlock(&gpadc->ab8500_gpadc_lock); |
403 | 410 | ||
404 | return (high_data << 8) | low_data; | 411 | return (high_data << 8) | low_data; |
@@ -412,7 +419,9 @@ out: | |||
412 | */ | 419 | */ |
413 | (void) abx500_set_register_interruptible(gpadc->dev, AB8500_GPADC, | 420 | (void) abx500_set_register_interruptible(gpadc->dev, AB8500_GPADC, |
414 | AB8500_GPADC_CTRL1_REG, DIS_GPADC); | 421 | AB8500_GPADC_CTRL1_REG, DIS_GPADC); |
415 | regulator_disable(gpadc->regu); | 422 | |
423 | pm_runtime_put(gpadc->dev); | ||
424 | |||
416 | mutex_unlock(&gpadc->ab8500_gpadc_lock); | 425 | mutex_unlock(&gpadc->ab8500_gpadc_lock); |
417 | dev_err(gpadc->dev, | 426 | dev_err(gpadc->dev, |
418 | "gpadc_conversion: Failed to AD convert channel %d\n", channel); | 427 | "gpadc_conversion: Failed to AD convert channel %d\n", channel); |
@@ -571,6 +580,30 @@ static void ab8500_gpadc_read_calibration_data(struct ab8500_gpadc *gpadc) | |||
571 | gpadc->cal_data[ADC_INPUT_VBAT].offset); | 580 | gpadc->cal_data[ADC_INPUT_VBAT].offset); |
572 | } | 581 | } |
573 | 582 | ||
583 | static int ab8500_gpadc_runtime_suspend(struct device *dev) | ||
584 | { | ||
585 | struct ab8500_gpadc *gpadc = dev_get_drvdata(dev); | ||
586 | |||
587 | regulator_disable(gpadc->regu); | ||
588 | return 0; | ||
589 | } | ||
590 | |||
591 | static int ab8500_gpadc_runtime_resume(struct device *dev) | ||
592 | { | ||
593 | struct ab8500_gpadc *gpadc = dev_get_drvdata(dev); | ||
594 | |||
595 | regulator_enable(gpadc->regu); | ||
596 | return 0; | ||
597 | } | ||
598 | |||
599 | static int ab8500_gpadc_runtime_idle(struct device *dev) | ||
600 | { | ||
601 | struct ab8500_gpadc *gpadc = dev_get_drvdata(dev); | ||
602 | |||
603 | pm_runtime_suspend(dev); | ||
604 | return 0; | ||
605 | } | ||
606 | |||
574 | static int ab8500_gpadc_probe(struct platform_device *pdev) | 607 | static int ab8500_gpadc_probe(struct platform_device *pdev) |
575 | { | 608 | { |
576 | int ret = 0; | 609 | int ret = 0; |
@@ -615,6 +648,16 @@ static int ab8500_gpadc_probe(struct platform_device *pdev) | |||
615 | dev_err(gpadc->dev, "failed to get vtvout LDO\n"); | 648 | dev_err(gpadc->dev, "failed to get vtvout LDO\n"); |
616 | goto fail_irq; | 649 | goto fail_irq; |
617 | } | 650 | } |
651 | |||
652 | platform_set_drvdata(pdev, gpadc); | ||
653 | |||
654 | regulator_enable(gpadc->regu); | ||
655 | |||
656 | pm_runtime_set_autosuspend_delay(gpadc->dev, GPADC_AUDOSUSPEND_DELAY); | ||
657 | pm_runtime_use_autosuspend(gpadc->dev); | ||
658 | pm_runtime_set_active(gpadc->dev); | ||
659 | pm_runtime_enable(gpadc->dev); | ||
660 | |||
618 | ab8500_gpadc_read_calibration_data(gpadc); | 661 | ab8500_gpadc_read_calibration_data(gpadc); |
619 | list_add_tail(&gpadc->node, &ab8500_gpadc_list); | 662 | list_add_tail(&gpadc->node, &ab8500_gpadc_list); |
620 | dev_dbg(gpadc->dev, "probe success\n"); | 663 | dev_dbg(gpadc->dev, "probe success\n"); |
@@ -635,19 +678,34 @@ static int ab8500_gpadc_remove(struct platform_device *pdev) | |||
635 | list_del(&gpadc->node); | 678 | list_del(&gpadc->node); |
636 | /* remove interrupt - completion of Sw ADC conversion */ | 679 | /* remove interrupt - completion of Sw ADC conversion */ |
637 | free_irq(gpadc->irq, gpadc); | 680 | free_irq(gpadc->irq, gpadc); |
638 | /* disable VTVout LDO that is being used by GPADC */ | 681 | |
639 | regulator_put(gpadc->regu); | 682 | pm_runtime_get_sync(gpadc->dev); |
683 | pm_runtime_disable(gpadc->dev); | ||
684 | |||
685 | regulator_disable(gpadc->regu); | ||
686 | |||
687 | pm_runtime_set_suspended(gpadc->dev); | ||
688 | |||
689 | pm_runtime_put_noidle(gpadc->dev); | ||
690 | |||
640 | kfree(gpadc); | 691 | kfree(gpadc); |
641 | gpadc = NULL; | 692 | gpadc = NULL; |
642 | return 0; | 693 | return 0; |
643 | } | 694 | } |
644 | 695 | ||
696 | static const struct dev_pm_ops ab8500_gpadc_pm_ops = { | ||
697 | SET_RUNTIME_PM_OPS(ab8500_gpadc_runtime_suspend, | ||
698 | ab8500_gpadc_runtime_resume, | ||
699 | ab8500_gpadc_runtime_idle) | ||
700 | }; | ||
701 | |||
645 | static struct platform_driver ab8500_gpadc_driver = { | 702 | static struct platform_driver ab8500_gpadc_driver = { |
646 | .probe = ab8500_gpadc_probe, | 703 | .probe = ab8500_gpadc_probe, |
647 | .remove = ab8500_gpadc_remove, | 704 | .remove = ab8500_gpadc_remove, |
648 | .driver = { | 705 | .driver = { |
649 | .name = "ab8500-gpadc", | 706 | .name = "ab8500-gpadc", |
650 | .owner = THIS_MODULE, | 707 | .owner = THIS_MODULE, |
708 | .pm = &ab8500_gpadc_pm_ops, | ||
651 | }, | 709 | }, |
652 | }; | 710 | }; |
653 | 711 | ||