[PATCH 1/3] OMAP: PM: formalize idle notifications

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Currently in the idle path, we have custom function calls into device
code to handle device specific actions that need to be coordinated CPU
idle transitions. Rather than continue this ad-hoc method of calling
device code from the PM core, create a formal way for device/driver
code to register for idle notifications.

Idle notifications are done late in the idle path when interrupts are
disabled, hence use atomic notifier chains.  These notifications will
also be atomic with respect to CPU idle transitions.

Signed-off-by: Kevin Hilman <khilman@xxxxxxxxxxxxxxxxxxx>
---
 arch/arm/mach-omap2/pm.c                 |   26 ++++++++++++++++++++++++++
 arch/arm/mach-omap2/pm24xx.c             |    4 ++++
 arch/arm/mach-omap2/pm34xx.c             |    5 +++++
 arch/arm/plat-omap/include/plat/common.h |   11 +++++++++++
 4 files changed, 46 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c
index 59ca03b..343e8d6 100644
--- a/arch/arm/mach-omap2/pm.c
+++ b/arch/arm/mach-omap2/pm.c
@@ -13,6 +13,7 @@
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/err.h>
+#include <linux/notifier.h>
 
 #include <plat/omap-pm.h>
 #include <plat/omap_device.h>
@@ -28,6 +29,31 @@ static struct device *iva_dev;
 static struct device *l3_dev;
 static struct device *dsp_dev;
 
+/* idle notifications late in the idle path (atomic, interrupts disabled) */
+static ATOMIC_NOTIFIER_HEAD(idle_notifier);
+
+void omap_idle_notifier_register(struct notifier_block *n)
+{
+	atomic_notifier_chain_register(&idle_notifier, n);
+}
+EXPORT_SYMBOL_GPL(omap_idle_notifier_register);
+
+void omap_idle_notifier_unregister(struct notifier_block *n)
+{
+	atomic_notifier_chain_unregister(&idle_notifier, n);
+}
+EXPORT_SYMBOL_GPL(omap_idle_notifier_unregister);
+
+void omap_idle_notifier_start(void)
+{
+	atomic_notifier_call_chain(&idle_notifier, OMAP_IDLE_START, NULL);
+}
+
+void omap_idle_notifier_end(void)
+{
+	atomic_notifier_call_chain(&idle_notifier, OMAP_IDLE_END, NULL);
+}
+
 struct device *omap2_get_mpuss_device(void)
 {
 	WARN_ON_ONCE(!mpu_dev);
diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c
index a40457d..cb1b333 100644
--- a/arch/arm/mach-omap2/pm24xx.c
+++ b/arch/arm/mach-omap2/pm24xx.c
@@ -108,6 +108,8 @@ static void omap2_enter_full_retention(void)
 
 	omap2_gpio_prepare_for_idle(PWRDM_POWER_RET);
 
+	omap_idle_notifier_start();
+
 	if (omap2_pm_debug) {
 		omap2_pm_dump(0, 0, 0);
 		getnstimeofday(&ts_preidle);
@@ -140,6 +142,8 @@ no_sleep:
 		tmp = timespec_to_ns(&ts_idle) * NSEC_PER_USEC;
 		omap2_pm_dump(0, 1, tmp);
 	}
+
+	omap_idle_notifier_end();
 	omap2_gpio_resume_after_idle();
 
 	clk_enable(osc_ck);
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index 75c0cd1..713bd04 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -37,6 +37,7 @@
 #include <plat/prcm.h>
 #include <plat/gpmc.h>
 #include <plat/dma.h>
+#include <plat/common.h>
 
 #include <asm/tlbflush.h>
 
@@ -375,6 +376,8 @@ void omap_sram_idle(void)
 	if (pwrdm_read_pwrst(neon_pwrdm) == PWRDM_POWER_ON)
 		pwrdm_set_next_pwrst(neon_pwrdm, mpu_next_state);
 
+	omap_idle_notifier_start();
+
 	/* Enable IO-PAD and IO-CHAIN wakeups */
 	per_next_state = pwrdm_read_next_pwrst(per_pwrdm);
 	core_next_state = pwrdm_read_next_pwrst(core_pwrdm);
@@ -471,6 +474,8 @@ void omap_sram_idle(void)
 		omap3_disable_io_chain();
 	}
 
+	omap_idle_notifier_end();
+
 	pwrdm_post_transition();
 
 	omap2_clkdm_allow_idle(mpu_pwrdm->pwrdm_clkdms[0]);
diff --git a/arch/arm/plat-omap/include/plat/common.h b/arch/arm/plat-omap/include/plat/common.h
index a9d69a0..1ca32cf 100644
--- a/arch/arm/plat-omap/include/plat/common.h
+++ b/arch/arm/plat-omap/include/plat/common.h
@@ -27,6 +27,8 @@
 #ifndef __ARCH_ARM_MACH_OMAP_COMMON_H
 #define __ARCH_ARM_MACH_OMAP_COMMON_H
 
+#include <linux/notifier.h>
+
 #include <plat/i2c.h>
 
 struct sys_timer;
@@ -95,4 +97,13 @@ extern struct device *omap2_get_iva_device(void);
 extern struct device *omap2_get_l3_device(void);
 extern struct device *omap4_get_dsp_device(void);
 
+#define OMAP_IDLE_START 1
+#define OMAP_IDLE_END	2
+
+/* idle notifications late in the idle path (atomic, interrupts disabled) */
+extern void omap_idle_notifier_register(struct notifier_block *n);
+extern void omap_idle_notifier_unregister(struct notifier_block *n);
+extern void omap_idle_notifier_start(void);
+extern void omap_idle_notifier_end(void);
+
 #endif /* __ARCH_ARM_MACH_OMAP_COMMON_H */
-- 
1.7.2.1

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Arm (vger)]     [ARM Kernel]     [ARM MSM]     [Linux Tegra]     [Linux WPAN Networking]     [Linux Wireless Networking]     [Maemo Users]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux