Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 54021
b: refs/heads/master
c: 3ac4fa9
h: refs/heads/master
i:
  54019: 72ac3c0
v: v3
  • Loading branch information
Juha Yrjola authored and Russell King committed May 5, 2007
1 parent f80ca6e commit 2a6d564
Show file tree
Hide file tree
Showing 2 changed files with 137 additions and 19 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 14f1c3bf51b78d916a6aff9c9b5e6689e3e006e7
refs/heads/master: 3ac4fa99291a60329e9c9424ac3e67bb4f9564f5
154 changes: 136 additions & 18 deletions trunk/arch/arm/plat-omap/gpio.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

Expand Down Expand Up @@ -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,
Expand All @@ -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)
{
Expand Down Expand Up @@ -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;
Expand All @@ -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);
Expand All @@ -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;
Expand Down Expand Up @@ -651,15 +686,33 @@ 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);
else
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);
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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

/*
Expand Down

0 comments on commit 2a6d564

Please sign in to comment.