|
@@ -82,3 +82,124 @@ static ssize_t idle_show(struct kobject *kobj, struct kobj_attribute *attr,
|
|
static ssize_t idle_store(struct kobject *kobj, struct kobj_attribute *attr,
|
|
static ssize_t idle_store(struct kobject *kobj, struct kobj_attribute *attr,
|
|
const char * buf, size_t n)
|
|
const char * buf, size_t n)
|
|
{
|
|
{
|
|
|
|
+ unsigned short value;
|
|
|
|
+ if (sscanf(buf, "%hu", &value) != 1 ||
|
|
|
|
+ (value != 0 && value != 1)) {
|
|
|
|
+ printk(KERN_ERR "idle_sleep_store: Invalid value\n");
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ }
|
|
|
|
+ enable_dyn_sleep = value;
|
|
|
|
+ return n;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static struct kobj_attribute sleep_while_idle_attr =
|
|
|
|
+ __ATTR(sleep_while_idle, 0644, idle_show, idle_store);
|
|
|
|
+
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
+static void (*omap_sram_suspend)(unsigned long r0, unsigned long r1) = NULL;
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * Let's power down on idle, but only if we are really
|
|
|
|
+ * idle, because once we start down the path of
|
|
|
|
+ * going idle we continue to do idle even if we get
|
|
|
|
+ * a clock tick interrupt . .
|
|
|
|
+ */
|
|
|
|
+void omap1_pm_idle(void)
|
|
|
|
+{
|
|
|
|
+ extern __u32 arm_idlect1_mask;
|
|
|
|
+ __u32 use_idlect1 = arm_idlect1_mask;
|
|
|
|
+ int do_sleep = 0;
|
|
|
|
+
|
|
|
|
+ local_fiq_disable();
|
|
|
|
+
|
|
|
|
+#if defined(CONFIG_OMAP_MPU_TIMER) && !defined(CONFIG_OMAP_DM_TIMER)
|
|
|
|
+#warning Enable 32kHz OS timer in order to allow sleep states in idle
|
|
|
|
+ use_idlect1 = use_idlect1 & ~(1 << 9);
|
|
|
|
+#else
|
|
|
|
+
|
|
|
|
+ while (enable_dyn_sleep) {
|
|
|
|
+
|
|
|
|
+#ifdef CONFIG_CBUS_TAHVO_USB
|
|
|
|
+ extern int vbus_active;
|
|
|
|
+ /* Clock requirements? */
|
|
|
|
+ if (vbus_active)
|
|
|
|
+ break;
|
|
|
|
+#endif
|
|
|
|
+ do_sleep = 1;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
+#ifdef CONFIG_OMAP_DM_TIMER
|
|
|
|
+ use_idlect1 = omap_dm_timer_modify_idlect_mask(use_idlect1);
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
+ if (omap_dma_running())
|
|
|
|
+ use_idlect1 &= ~(1 << 6);
|
|
|
|
+
|
|
|
|
+ /* We should be able to remove the do_sleep variable and multiple
|
|
|
|
+ * tests above as soon as drivers, timer and DMA code have been fixed.
|
|
|
|
+ * Even the sleep block count should become obsolete. */
|
|
|
|
+ if ((use_idlect1 != ~0) || !do_sleep) {
|
|
|
|
+
|
|
|
|
+ __u32 saved_idlect1 = omap_readl(ARM_IDLECT1);
|
|
|
|
+ if (cpu_is_omap15xx())
|
|
|
|
+ use_idlect1 &= OMAP1510_BIG_SLEEP_REQUEST;
|
|
|
|
+ else
|
|
|
|
+ use_idlect1 &= OMAP1610_IDLECT1_SLEEP_VAL;
|
|
|
|
+ omap_writel(use_idlect1, ARM_IDLECT1);
|
|
|
|
+ __asm__ volatile ("mcr p15, 0, r0, c7, c0, 4");
|
|
|
|
+ omap_writel(saved_idlect1, ARM_IDLECT1);
|
|
|
|
+
|
|
|
|
+ local_fiq_enable();
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ omap_sram_suspend(omap_readl(ARM_IDLECT1),
|
|
|
|
+ omap_readl(ARM_IDLECT2));
|
|
|
|
+
|
|
|
|
+ local_fiq_enable();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * Configuration of the wakeup event is board specific. For the
|
|
|
|
+ * moment we put it into this helper function. Later it may move
|
|
|
|
+ * to board specific files.
|
|
|
|
+ */
|
|
|
|
+static void omap_pm_wakeup_setup(void)
|
|
|
|
+{
|
|
|
|
+ u32 level1_wake = 0;
|
|
|
|
+ u32 level2_wake = OMAP_IRQ_BIT(INT_UART2);
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Turn off all interrupts except GPIO bank 1, L1-2nd level cascade,
|
|
|
|
+ * and the L2 wakeup interrupts: keypad and UART2. Note that the
|
|
|
|
+ * drivers must still separately call omap_set_gpio_wakeup() to
|
|
|
|
+ * wake up to a GPIO interrupt.
|
|
|
|
+ */
|
|
|
|
+ if (cpu_is_omap7xx())
|
|
|
|
+ level1_wake = OMAP_IRQ_BIT(INT_7XX_GPIO_BANK1) |
|
|
|
|
+ OMAP_IRQ_BIT(INT_7XX_IH2_IRQ);
|
|
|
|
+ else if (cpu_is_omap15xx())
|
|
|
|
+ level1_wake = OMAP_IRQ_BIT(INT_GPIO_BANK1) |
|
|
|
|
+ OMAP_IRQ_BIT(INT_1510_IH2_IRQ);
|
|
|
|
+ else if (cpu_is_omap16xx())
|
|
|
|
+ level1_wake = OMAP_IRQ_BIT(INT_GPIO_BANK1) |
|
|
|
|
+ OMAP_IRQ_BIT(INT_1610_IH2_IRQ);
|
|
|
|
+
|
|
|
|
+ omap_writel(~level1_wake, OMAP_IH1_MIR);
|
|
|
|
+
|
|
|
|
+ if (cpu_is_omap7xx()) {
|
|
|
|
+ omap_writel(~level2_wake, OMAP_IH2_0_MIR);
|
|
|
|
+ omap_writel(~(OMAP_IRQ_BIT(INT_7XX_WAKE_UP_REQ) |
|
|
|
|
+ OMAP_IRQ_BIT(INT_7XX_MPUIO_KEYPAD)),
|
|
|
|
+ OMAP_IH2_1_MIR);
|
|
|
|
+ } else if (cpu_is_omap15xx()) {
|
|
|
|
+ level2_wake |= OMAP_IRQ_BIT(INT_KEYBOARD);
|
|
|
|
+ omap_writel(~level2_wake, OMAP_IH2_MIR);
|
|
|
|
+ } else if (cpu_is_omap16xx()) {
|
|
|
|
+ level2_wake |= OMAP_IRQ_BIT(INT_KEYBOARD);
|
|
|
|
+ omap_writel(~level2_wake, OMAP_IH2_0_MIR);
|
|
|
|
+
|
|
|
|
+ /* INT_1610_WAKE_UP_REQ is needed for GPIO wakeup... */
|