|
@@ -117,8 +117,18 @@ struct gpio_bank {
|
|
|
u16 virtual_irq_start;
|
|
|
int method;
|
|
|
u32 reserved_map;
|
|
|
+#if defined (CONFIG_ARCH_OMAP16XX) || defined (CONFIG_ARCH_OMAP24XX)
|
|
|
u32 suspend_wakeup;
|
|
|
u32 saved_wakeup;
|
|
|
+#endif
|
|
|
+#ifdef CONFIG_ARCH_OMAP24XX
|
|
|
+ u32 non_wakeup_gpios;
|
|
|
+ u32 enabled_non_wakeup_gpios;
|
|
|
+
|
|
|
+ u32 saved_datain;
|
|
|
+ u32 saved_fallingdetect;
|
|
|
+ u32 saved_risingdetect;
|
|
|
+#endif
|
|
|
spinlock_t lock;
|
|
|
};
|
|
|
|
|
@@ -397,8 +407,10 @@ do { \
|
|
|
__raw_writel(l, base + reg); \
|
|
|
} while(0)
|
|
|
|
|
|
-static inline void set_24xx_gpio_triggering(void __iomem *base, int gpio, int trigger)
|
|
|
+#ifdef CONFIG_ARCH_OMAP24XX
|
|
|
+static inline void set_24xx_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger)
|
|
|
{
|
|
|
+ void __iomem *base = bank->base;
|
|
|
u32 gpio_bit = 1 << gpio;
|
|
|
|
|
|
MOD_REG_BIT(OMAP24XX_GPIO_LEVELDETECT0, gpio_bit,
|
|
@@ -409,9 +421,21 @@ static inline void set_24xx_gpio_triggering(void __iomem *base, int gpio, int tr
|
|
|
trigger & __IRQT_RISEDGE);
|
|
|
MOD_REG_BIT(OMAP24XX_GPIO_FALLINGDETECT, gpio_bit,
|
|
|
trigger & __IRQT_FALEDGE);
|
|
|
+ if (likely(!(bank->non_wakeup_gpios & gpio_bit))) {
|
|
|
+ if (trigger != 0)
|
|
|
+ __raw_writel(1 << gpio, bank->base + OMAP24XX_GPIO_SETWKUENA);
|
|
|
+ else
|
|
|
+ __raw_writel(1 << gpio, bank->base + OMAP24XX_GPIO_CLEARWKUENA);
|
|
|
+ } else {
|
|
|
+ if (trigger != 0)
|
|
|
+ bank->enabled_non_wakeup_gpios |= gpio_bit;
|
|
|
+ else
|
|
|
+ bank->enabled_non_wakeup_gpios &= ~gpio_bit;
|
|
|
+ }
|
|
|
/* FIXME: Possibly do 'set_irq_handler(j, handle_level_irq)' if only level
|
|
|
* triggering requested. */
|
|
|
}
|
|
|
+#endif
|
|
|
|
|
|
static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger)
|
|
|
{
|
|
@@ -439,6 +463,7 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger)
|
|
|
else
|
|
|
goto bad;
|
|
|
break;
|
|
|
+#ifdef CONFIG_ARCH_OMAP16XX
|
|
|
case METHOD_GPIO_1610:
|
|
|
if (gpio & 0x08)
|
|
|
reg += OMAP1610_GPIO_EDGE_CTRL2;
|
|
@@ -454,7 +479,14 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger)
|
|
|
l |= 2 << (gpio << 1);
|
|
|
if (trigger & __IRQT_FALEDGE)
|
|
|
l |= 1 << (gpio << 1);
|
|
|
+ if (trigger)
|
|
|
+ /* Enable wake-up during idle for dynamic tick */
|
|
|
+ __raw_writel(1 << gpio, bank->base + OMAP1610_GPIO_SET_WAKEUPENA);
|
|
|
+ else
|
|
|
+ __raw_writel(1 << gpio, bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA);
|
|
|
break;
|
|
|
+#endif
|
|
|
+#ifdef CONFIG_ARCH_OMAP730
|
|
|
case METHOD_GPIO_730:
|
|
|
reg += OMAP730_GPIO_INT_CONTROL;
|
|
|
l = __raw_readl(reg);
|
|
@@ -465,9 +497,12 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger)
|
|
|
else
|
|
|
goto bad;
|
|
|
break;
|
|
|
+#endif
|
|
|
+#ifdef CONFIG_ARCH_OMAP24XX
|
|
|
case METHOD_GPIO_24XX:
|
|
|
- set_24xx_gpio_triggering(reg, gpio, trigger);
|
|
|
+ set_24xx_gpio_triggering(bank, gpio, trigger);
|
|
|
break;
|
|
|
+#endif
|
|
|
default:
|
|
|
BUG();
|
|
|
goto bad;
|
|
@@ -651,8 +686,8 @@ static inline void _set_gpio_irqenable(struct gpio_bank *bank, int gpio, int ena
|
|
|
static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable)
|
|
|
{
|
|
|
switch (bank->method) {
|
|
|
+#ifdef CONFIG_ARCH_OMAP16XX
|
|
|
case METHOD_GPIO_1610:
|
|
|
- case METHOD_GPIO_24XX:
|
|
|
spin_lock(&bank->lock);
|
|
|
if (enable)
|
|
|
bank->suspend_wakeup |= (1 << gpio);
|
|
@@ -660,6 +695,24 @@ static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable)
|
|
|
bank->suspend_wakeup &= ~(1 << gpio);
|
|
|
spin_unlock(&bank->lock);
|
|
|
return 0;
|
|
|
+#endif
|
|
|
+#ifdef CONFIG_ARCH_OMAP24XX
|
|
|
+ case METHOD_GPIO_24XX:
|
|
|
+ spin_lock(&bank->lock);
|
|
|
+ if (enable) {
|
|
|
+ if (bank->non_wakeup_gpios & (1 << gpio)) {
|
|
|
+ printk(KERN_ERR "Unable to enable wakeup on"
|
|
|
+ "non-wakeup GPIO%d\n",
|
|
|
+ (bank - gpio_bank) * 32 + gpio);
|
|
|
+ spin_unlock(&bank->lock);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ bank->suspend_wakeup |= (1 << gpio);
|
|
|
+ } else
|
|
|
+ bank->suspend_wakeup &= ~(1 << gpio);
|
|
|
+ spin_unlock(&bank->lock);
|
|
|
+ return 0;
|
|
|
+#endif
|
|
|
default:
|
|
|
printk(KERN_ERR "Can't enable GPIO wakeup for method %i\n",
|
|
|
bank->method);
|
|
@@ -720,20 +773,6 @@ int omap_request_gpio(int gpio)
|
|
|
reg = bank->base + OMAP1510_GPIO_PIN_CONTROL;
|
|
|
__raw_writel(__raw_readl(reg) | (1 << get_gpio_index(gpio)), reg);
|
|
|
}
|
|
|
-#endif
|
|
|
-#ifdef CONFIG_ARCH_OMAP16XX
|
|
|
- if (bank->method == METHOD_GPIO_1610) {
|
|
|
- /* Enable wake-up during idle for dynamic tick */
|
|
|
- void __iomem *reg = bank->base + OMAP1610_GPIO_SET_WAKEUPENA;
|
|
|
- __raw_writel(1 << get_gpio_index(gpio), reg);
|
|
|
- }
|
|
|
-#endif
|
|
|
-#ifdef CONFIG_ARCH_OMAP24XX
|
|
|
- if (bank->method == METHOD_GPIO_24XX) {
|
|
|
- /* Enable wake-up during idle for dynamic tick */
|
|
|
- void __iomem *reg = bank->base + OMAP24XX_GPIO_SETWKUENA;
|
|
|
- __raw_writel(1 << get_gpio_index(gpio), reg);
|
|
|
- }
|
|
|
#endif
|
|
|
spin_unlock(&bank->lock);
|
|
|
|
|
@@ -1080,13 +1119,18 @@ static int __init _omap_gpio_init(void)
|
|
|
#endif
|
|
|
#ifdef CONFIG_ARCH_OMAP24XX
|
|
|
if (bank->method == METHOD_GPIO_24XX) {
|
|
|
+ static const u32 non_wakeup_gpios[] = {
|
|
|
+ 0xe203ffc0, 0x08700040
|
|
|
+ };
|
|
|
+
|
|
|
__raw_writel(0x00000000, bank->base + OMAP24XX_GPIO_IRQENABLE1);
|
|
|
__raw_writel(0xffffffff, bank->base + OMAP24XX_GPIO_IRQSTATUS1);
|
|
|
__raw_writew(0x0015, bank->base + OMAP24XX_GPIO_SYSCONFIG);
|
|
|
|
|
|
/* Initialize interface clock ungated, module enabled */
|
|
|
__raw_writel(0, bank->base + OMAP24XX_GPIO_CTRL);
|
|
|
-
|
|
|
+ if (i < ARRAY_SIZE(non_wakeup_gpios))
|
|
|
+ bank->non_wakeup_gpios = non_wakeup_gpios[i];
|
|
|
gpio_count = 32;
|
|
|
}
|
|
|
#endif
|
|
@@ -1200,6 +1244,80 @@ static struct sys_device omap_gpio_device = {
|
|
|
.id = 0,
|
|
|
.cls = &omap_gpio_sysclass,
|
|
|
};
|
|
|
+
|
|
|
+#endif
|
|
|
+
|
|
|
+#ifdef CONFIG_ARCH_OMAP24XX
|
|
|
+
|
|
|
+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;
|
|
|
+ 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);
|
|
|
+ bank->saved_fallingdetect = l1;
|
|
|
+ bank->saved_risingdetect = l2;
|
|
|
+ l1 &= ~bank->enabled_non_wakeup_gpios;
|
|
|
+ l2 &= ~bank->enabled_non_wakeup_gpios;
|
|
|
+ __raw_writel(l1, bank->base + OMAP24XX_GPIO_FALLINGDETECT);
|
|
|
+ __raw_writel(l2, bank->base + OMAP24XX_GPIO_RISINGDETECT);
|
|
|
+ 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;
|
|
|
+
|
|
|
+ if (!(bank->enabled_non_wakeup_gpios))
|
|
|
+ continue;
|
|
|
+ __raw_writel(bank->saved_fallingdetect,
|
|
|
+ bank->base + OMAP24XX_GPIO_FALLINGDETECT);
|
|
|
+ __raw_writel(bank->saved_risingdetect,
|
|
|
+ bank->base + OMAP24XX_GPIO_RISINGDETECT);
|
|
|
+ /* 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 = __raw_readl(bank->base + OMAP24XX_GPIO_DATAIN);
|
|
|
+ l ^= bank->saved_datain;
|
|
|
+ l &= bank->non_wakeup_gpios;
|
|
|
+ if (l) {
|
|
|
+ u32 old0, old1;
|
|
|
+
|
|
|
+ old0 = __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT0);
|
|
|
+ old1 = __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT1);
|
|
|
+ __raw_writel(old0 | l, bank->base + OMAP24XX_GPIO_LEVELDETECT0);
|
|
|
+ __raw_writel(old1 | l, bank->base + OMAP24XX_GPIO_LEVELDETECT1);
|
|
|
+ __raw_writel(old0, bank->base + OMAP24XX_GPIO_LEVELDETECT0);
|
|
|
+ __raw_writel(old1, bank->base + OMAP24XX_GPIO_LEVELDETECT1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
#endif
|
|
|
|
|
|
/*
|