@@ -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);
@@ -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);
@@ -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]);
@@ -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 */