summaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel
diff options
context:
space:
mode:
authorJon Hunter <jon-hunter@ti.com>2012-05-31 13:05:20 -0500
committerWill Deacon <will.deacon@arm.com>2012-08-23 11:35:51 +0100
commit7be2958e97b37256b8016db39ac6cf51f711e390 (patch)
treec6e0194dcdfbb600a709715ffb4888cd35052cc8 /arch/arm/kernel
parentfea7a08acb13524b47711625eebea40a0ede69a0 (diff)
ARM: PMU: Add runtime PM Support
Add runtime PM support to the ARM PMU driver so that devices such as OMAP supporting dynamic PM can use the platform->runtime_* hooks to initialise hardware at runtime. Without having these runtime PM hooks in place any configuration of the PMU hardware would be lost when low power states are entered and hence would prevent PMU from working. This change also replaces the PMU platform functions enable_irq and disable_irq added by Ming Lei with runtime_resume and runtime_suspend funtions. Ming had added the enable_irq and disable_irq functions as a method to configure the cross trigger interface on OMAP4 for routing the PMU interrupts. By adding runtime PM support, we can move the code called by enable_irq and disable_irq into the runtime PM callbacks runtime_resume and runtime_suspend. Cc: Ming Lei <ming.lei@canonical.com> Cc: Benoit Cousson <b-cousson@ti.com> Cc: Paul Walmsley <paul@pwsan.com> Cc: Kevin Hilman <khilman@ti.com> Signed-off-by: Jon Hunter <jon-hunter@ti.com> Signed-off-by: Will Deacon <will.deacon@arm.com>
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r--arch/arm/kernel/perf_event.c41
1 files changed, 33 insertions, 8 deletions
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index ab243b87118..c44647ef735 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -20,6 +20,7 @@
#include <linux/platform_device.h>
#include <linux/spinlock.h>
#include <linux/uaccess.h>
+#include <linux/pm_runtime.h>
#include <asm/cputype.h>
#include <asm/irq.h>
@@ -364,8 +365,6 @@ armpmu_release_hardware(struct arm_pmu *armpmu)
{
int i, irq, irqs;
struct platform_device *pmu_device = armpmu->plat_device;
- struct arm_pmu_platdata *plat =
- dev_get_platdata(&pmu_device->dev);
irqs = min(pmu_device->num_resources, num_possible_cpus());
@@ -373,13 +372,11 @@ armpmu_release_hardware(struct arm_pmu *armpmu)
if (!cpumask_test_and_clear_cpu(i, &armpmu->active_irqs))
continue;
irq = platform_get_irq(pmu_device, i);
- if (irq >= 0) {
- if (plat && plat->disable_irq)
- plat->disable_irq(irq);
+ if (irq >= 0)
free_irq(irq, armpmu);
- }
}
+ pm_runtime_put_sync(&pmu_device->dev);
release_pmu(armpmu->type);
}
@@ -412,6 +409,8 @@ armpmu_reserve_hardware(struct arm_pmu *armpmu)
return -ENODEV;
}
+ pm_runtime_get_sync(&pmu_device->dev);
+
for (i = 0; i < irqs; ++i) {
err = 0;
irq = platform_get_irq(pmu_device, i);
@@ -437,8 +436,7 @@ armpmu_reserve_hardware(struct arm_pmu *armpmu)
irq);
armpmu_release_hardware(armpmu);
return err;
- } else if (plat && plat->enable_irq)
- plat->enable_irq(irq);
+ }
cpumask_set_cpu(i, &armpmu->active_irqs);
}
@@ -581,6 +579,28 @@ static void armpmu_disable(struct pmu *pmu)
armpmu->stop();
}
+#ifdef CONFIG_PM_RUNTIME
+static int armpmu_runtime_resume(struct device *dev)
+{
+ struct arm_pmu_platdata *plat = dev_get_platdata(dev);
+
+ if (plat && plat->runtime_resume)
+ return plat->runtime_resume(dev);
+
+ return 0;
+}
+
+static int armpmu_runtime_suspend(struct device *dev)
+{
+ struct arm_pmu_platdata *plat = dev_get_platdata(dev);
+
+ if (plat && plat->runtime_suspend)
+ return plat->runtime_suspend(dev);
+
+ return 0;
+}
+#endif
+
static void __init armpmu_init(struct arm_pmu *armpmu)
{
atomic_set(&armpmu->active_events, 0);
@@ -647,9 +667,14 @@ static int __devinit armpmu_device_probe(struct platform_device *pdev)
return 0;
}
+static const struct dev_pm_ops armpmu_dev_pm_ops = {
+ SET_RUNTIME_PM_OPS(armpmu_runtime_suspend, armpmu_runtime_resume, NULL)
+};
+
static struct platform_driver armpmu_driver = {
.driver = {
.name = "arm-pmu",
+ .pm = &armpmu_dev_pm_ops,
.of_match_table = armpmu_of_device_ids,
},
.probe = armpmu_device_probe,