+
+#endif
+
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) || \
+ defined(CONFIG_ARCH_OMAP4)
+
+static int workaround_enabled;
+
+void omap2_gpio_prepare_for_retention(void)
+{
+ int i, c = 0;
+
+ /* Remove triggering for all non-wakeup GPIOs. Otherwise spurious
+ * IRQs will be generated. See OMAP2420 Errata item 1.101. */
+ for (i = 0; i < gpio_bank_count; i++) {
+ struct gpio_bank *bank = &gpio_bank[i];
+ u32 l1, l2;
+
+ if (!(bank->enabled_non_wakeup_gpios))
+ continue;
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+ bank->saved_datain = __raw_readl(bank->base + OMAP24XX_GPIO_DATAIN);
+ l1 = __raw_readl(bank->base + OMAP24XX_GPIO_FALLINGDETECT);
+ l2 = __raw_readl(bank->base + OMAP24XX_GPIO_RISINGDETECT);
+#endif
+#ifdef CONFIG_ARCH_OMAP4
+ bank->saved_datain = __raw_readl(bank->base +
+ OMAP4_GPIO_DATAIN);
+ l1 = __raw_readl(bank->base + OMAP4_GPIO_FALLINGDETECT);
+ l2 = __raw_readl(bank->base + OMAP4_GPIO_RISINGDETECT);
+#endif
+ bank->saved_fallingdetect = l1;
+ bank->saved_risingdetect = l2;
+ l1 &= ~bank->enabled_non_wakeup_gpios;
+ l2 &= ~bank->enabled_non_wakeup_gpios;
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+ __raw_writel(l1, bank->base + OMAP24XX_GPIO_FALLINGDETECT);
+ __raw_writel(l2, bank->base + OMAP24XX_GPIO_RISINGDETECT);
+#endif
+#ifdef CONFIG_ARCH_OMAP4
+ __raw_writel(l1, bank->base + OMAP4_GPIO_FALLINGDETECT);
+ __raw_writel(l2, bank->base + OMAP4_GPIO_RISINGDETECT);
+#endif
+ c++;
+ }
+ if (!c) {
+ workaround_enabled = 0;
+ return;
+ }
+ workaround_enabled = 1;
+}
+
+void omap2_gpio_resume_after_retention(void)
+{
+ int i;
+
+ if (!workaround_enabled)
+ return;
+ for (i = 0; i < gpio_bank_count; i++) {
+ struct gpio_bank *bank = &gpio_bank[i];
+ u32 l, gen, gen0, gen1;
+
+ if (!(bank->enabled_non_wakeup_gpios))
+ continue;
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+ __raw_writel(bank->saved_fallingdetect,
+ bank->base + OMAP24XX_GPIO_FALLINGDETECT);
+ __raw_writel(bank->saved_risingdetect,
+ bank->base + OMAP24XX_GPIO_RISINGDETECT);
+ l = __raw_readl(bank->base + OMAP24XX_GPIO_DATAIN);
+#endif
+#ifdef CONFIG_ARCH_OMAP4
+ __raw_writel(bank->saved_fallingdetect,
+ bank->base + OMAP4_GPIO_FALLINGDETECT);
+ __raw_writel(bank->saved_risingdetect,
+ bank->base + OMAP4_GPIO_RISINGDETECT);
+ l = __raw_readl(bank->base + OMAP4_GPIO_DATAIN);
+#endif
+ /* Check if any of the non-wakeup interrupt GPIOs have changed
+ * state. If so, generate an IRQ by software. This is
+ * horribly racy, but it's the best we can do to work around
+ * this silicon bug. */
+ l ^= bank->saved_datain;
+ l &= bank->non_wakeup_gpios;
+
+ /*
+ * No need to generate IRQs for the rising edge for gpio IRQs
+ * configured with falling edge only; and vice versa.
+ */
+ gen0 = l & bank->saved_fallingdetect;
+ gen0 &= bank->saved_datain;
+
+ gen1 = l & bank->saved_risingdetect;
+ gen1 &= ~(bank->saved_datain);
+
+ /* FIXME: Consider GPIO IRQs with level detections properly! */
+ gen = l & (~(bank->saved_fallingdetect) &
+ ~(bank->saved_risingdetect));
+ /* Consider all GPIO IRQs needed to be updated */
+ gen |= gen0 | gen1;
+
+ if (gen) {
+ u32 old0, old1;
+#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX)
+ old0 = __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT0);
+ old1 = __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT1);
+ __raw_writel(old0 | gen, bank->base +
+ OMAP24XX_GPIO_LEVELDETECT0);
+ __raw_writel(old1 | gen, bank->base +
+ OMAP24XX_GPIO_LEVELDETECT1);
+ __raw_writel(old0, bank->base + OMAP24XX_GPIO_LEVELDETECT0);
+ __raw_writel(old1, bank->base + OMAP24XX_GPIO_LEVELDETECT1);
+#endif
+#ifdef CONFIG_ARCH_OMAP4
+ old0 = __raw_readl(bank->base +
+ OMAP4_GPIO_LEVELDETECT0);
+ old1 = __raw_readl(bank->base +
+ OMAP4_GPIO_LEVELDETECT1);
+ __raw_writel(old0 | l, bank->base +
+ OMAP4_GPIO_LEVELDETECT0);
+ __raw_writel(old1 | l, bank->base +
+ OMAP4_GPIO_LEVELDETECT1);
+ __raw_writel(old0, bank->base +
+ OMAP4_GPIO_LEVELDETECT0);
+ __raw_writel(old1, bank->base +
+ OMAP4_GPIO_LEVELDETECT1);
+#endif
+ }
+ }
+
+}
+
+#endif
+
+#ifdef CONFIG_ARCH_OMAP34XX
+/* save the registers of bank 2-6 */
+void omap_gpio_save_context(void)
+{
+ int i;
+
+ /* saving banks from 2-6 only since GPIO1 is in WKUP */
+ for (i = 1; i < gpio_bank_count; i++) {
+ struct gpio_bank *bank = &gpio_bank[i];
+ gpio_context[i].sysconfig =
+ __raw_readl(bank->base + OMAP24XX_GPIO_SYSCONFIG);
+ gpio_context[i].irqenable1 =
+ __raw_readl(bank->base + OMAP24XX_GPIO_IRQENABLE1);
+ gpio_context[i].irqenable2 =
+ __raw_readl(bank->base + OMAP24XX_GPIO_IRQENABLE2);
+ gpio_context[i].wake_en =
+ __raw_readl(bank->base + OMAP24XX_GPIO_WAKE_EN);
+ gpio_context[i].ctrl =
+ __raw_readl(bank->base + OMAP24XX_GPIO_CTRL);
+ gpio_context[i].oe =
+ __raw_readl(bank->base + OMAP24XX_GPIO_OE);
+ gpio_context[i].leveldetect0 =
+ __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT0);
+ gpio_context[i].leveldetect1 =
+ __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT1);
+ gpio_context[i].risingdetect =
+ __raw_readl(bank->base + OMAP24XX_GPIO_RISINGDETECT);
+ gpio_context[i].fallingdetect =
+ __raw_readl(bank->base + OMAP24XX_GPIO_FALLINGDETECT);
+ gpio_context[i].dataout =
+ __raw_readl(bank->base + OMAP24XX_GPIO_DATAOUT);
+ gpio_context[i].setwkuena =
+ __raw_readl(bank->base + OMAP24XX_GPIO_SETWKUENA);
+ gpio_context[i].setdataout =
+ __raw_readl(bank->base + OMAP24XX_GPIO_SETDATAOUT);
+ }
+}
+
+/* restore the required registers of bank 2-6 */
+void omap_gpio_restore_context(void)
+{
+ int i;
+
+ for (i = 1; i < gpio_bank_count; i++) {
+ struct gpio_bank *bank = &gpio_bank[i];
+ __raw_writel(gpio_context[i].sysconfig,
+ bank->base + OMAP24XX_GPIO_SYSCONFIG);
+ __raw_writel(gpio_context[i].irqenable1,
+ bank->base + OMAP24XX_GPIO_IRQENABLE1);
+ __raw_writel(gpio_context[i].irqenable2,
+ bank->base + OMAP24XX_GPIO_IRQENABLE2);
+ __raw_writel(gpio_context[i].wake_en,
+ bank->base + OMAP24XX_GPIO_WAKE_EN);
+ __raw_writel(gpio_context[i].ctrl,
+ bank->base + OMAP24XX_GPIO_CTRL);
+ __raw_writel(gpio_context[i].oe,
+ bank->base + OMAP24XX_GPIO_OE);
+ __raw_writel(gpio_context[i].leveldetect0,
+ bank->base + OMAP24XX_GPIO_LEVELDETECT0);
+ __raw_writel(gpio_context[i].leveldetect1,
+ bank->base + OMAP24XX_GPIO_LEVELDETECT1);
+ __raw_writel(gpio_context[i].risingdetect,
+ bank->base + OMAP24XX_GPIO_RISINGDETECT);
+ __raw_writel(gpio_context[i].fallingdetect,
+ bank->base + OMAP24XX_GPIO_FALLINGDETECT);
+ __raw_writel(gpio_context[i].dataout,
+ bank->base + OMAP24XX_GPIO_DATAOUT);
+ __raw_writel(gpio_context[i].setwkuena,
+ bank->base + OMAP24XX_GPIO_SETWKUENA);
+ __raw_writel(gpio_context[i].setdataout,
+ bank->base + OMAP24XX_GPIO_SETDATAOUT);
+ }
+}