diff options
-rw-r--r-- | arch/arm/mach-tegra/include/mach/legacy_irq.h | 2 | ||||
-rw-r--r-- | arch/arm/mach-tegra/irq.c | 52 | ||||
-rw-r--r-- | arch/arm/mach-tegra/pm-irq.c | 62 | ||||
-rw-r--r-- | arch/arm/mach-tegra/wakeups-t2.c | 69 | ||||
-rw-r--r-- | arch/arm/mach-tegra/wakeups-t3.c | 91 | ||||
-rw-r--r-- | arch/arm/mach-tegra/wakeups.c | 115 | ||||
-rw-r--r-- | arch/arm/mach-tegra/wakeups.h | 27 | ||||
-rw-r--r-- | drivers/gpio/gpio-tegra.c | 51 |
8 files changed, 312 insertions, 157 deletions
diff --git a/arch/arm/mach-tegra/include/mach/legacy_irq.h b/arch/arm/mach-tegra/include/mach/legacy_irq.h index 86f1ff7d06b0..3cd2d82c342f 100644 --- a/arch/arm/mach-tegra/include/mach/legacy_irq.h +++ b/arch/arm/mach-tegra/include/mach/legacy_irq.h @@ -19,5 +19,7 @@ #define _ARCH_ARM_MACH_TEGRA_LEGARY_IRQ_H void tegra_init_legacy_irq_cop(void); +/* lp1 wake interrupts enabled or disabled using this API */ +int tegra_update_lp1_irq_wake(unsigned int irq, bool enable); #endif diff --git a/arch/arm/mach-tegra/irq.c b/arch/arm/mach-tegra/irq.c index 450295d901dd..278912486f40 100644 --- a/arch/arm/mach-tegra/irq.c +++ b/arch/arm/mach-tegra/irq.c @@ -26,6 +26,7 @@ #include <asm/hardware/gic.h> #include <mach/iomap.h> +#include <mach/gpio.h> #include <mach/legacy_irq.h> #include "board.h" @@ -66,10 +67,34 @@ static void __iomem *ictlr_reg_base[] = { #ifdef CONFIG_PM_SLEEP static u32 cop_ier[NUM_ICTLRS]; +static u32 cop_iep[NUM_ICTLRS]; static u32 cpu_ier[NUM_ICTLRS]; static u32 cpu_iep[NUM_ICTLRS]; + +static u32 ictlr_wake_mask[NUM_ICTLRS]; +#endif + +int tegra_update_lp1_irq_wake(unsigned int irq, bool enable) +{ +#ifdef CONFIG_PM_SLEEP + u8 index; + u32 mask; + + if (irq < FIRST_LEGACY_IRQ || + irq >= FIRST_LEGACY_IRQ + NUM_ICTLRS * 32) + return -EINVAL; + + index = ((irq - FIRST_LEGACY_IRQ) >> 5); + mask = BIT((irq - FIRST_LEGACY_IRQ) % 32); + if (enable) + ictlr_wake_mask[index] |= mask; + else + ictlr_wake_mask[index] &= ~mask; #endif + return 0; +} + static inline void tegra_irq_write_mask(unsigned int irq, unsigned long reg) { void __iomem *base; @@ -131,11 +156,28 @@ static int tegra_set_type(struct irq_data *d, unsigned int flow_type) return tegra_pm_irq_set_wake_type(d->irq, flow_type); } - #ifdef CONFIG_PM_SLEEP +/* + * Caller ensures that tegra_set_wake (irq_set_wake callback) + * is called for non-gpio wake sources only + */ static int tegra_set_wake(struct irq_data *d, unsigned int enable) { - return tegra_pm_irq_set_wake(d->irq, enable); + int ret; + + /* pmc lp0 wake enable for non-gpio wake sources */ + ret = tegra_pm_irq_set_wake(d->irq, enable); + if (ret) + pr_err("Failed lp0 wake %s for irq=%d\n", + (enable ? "enable" : "disable"), d->irq); + + /* lp1 wake enable for wake sources */ + ret = tegra_update_lp1_irq_wake(d->irq, enable); + if (ret) + pr_err("Failed lp1 wake %s for irq=%d\n", + (enable ? "enable" : "disable"), d->irq); + + return ret; } static int tegra_legacy_irq_suspend(void) @@ -146,9 +188,13 @@ static int tegra_legacy_irq_suspend(void) local_irq_save(flags); for (i = 0; i < NUM_ICTLRS; i++) { void __iomem *ictlr = ictlr_reg_base[i]; + /* save interrupt state */ cpu_ier[i] = readl(ictlr + ICTLR_CPU_IER); cpu_iep[i] = readl(ictlr + ICTLR_CPU_IEP_CLASS); cop_ier[i] = readl(ictlr + ICTLR_COP_IER); + cop_iep[i] = readl(ictlr + ICTLR_COP_IEP_CLASS); + + /* disable COP interrupts */ writel(~0, ictlr + ICTLR_COP_IER_CLR); } local_irq_restore(flags); @@ -167,7 +213,7 @@ static void tegra_legacy_irq_resume(void) writel(cpu_iep[i], ictlr + ICTLR_CPU_IEP_CLASS); writel(~0ul, ictlr + ICTLR_CPU_IER_CLR); writel(cpu_ier[i], ictlr + ICTLR_CPU_IER_SET); - writel(0, ictlr + ICTLR_COP_IEP_CLASS); + writel(cop_iep[i], ictlr + ICTLR_COP_IEP_CLASS); writel(~0ul, ictlr + ICTLR_COP_IER_CLR); writel(cop_ier[i], ictlr + ICTLR_COP_IER_SET); } diff --git a/arch/arm/mach-tegra/pm-irq.c b/arch/arm/mach-tegra/pm-irq.c index 9b205f86f8b9..4a3f3c31830c 100644 --- a/arch/arm/mach-tegra/pm-irq.c +++ b/arch/arm/mach-tegra/pm-irq.c @@ -145,12 +145,15 @@ static inline void clear_pmc_sw_wake_status(void) int tegra_pm_irq_set_wake(int irq, int enable) { - int wake = tegra_irq_to_wake(irq); + struct wake_mask_types wake_msk; + int flow_type = -1; + int err; - if (wake == -EALREADY) { + err = tegra_irq_to_wake(irq, flow_type, &wake_msk); + if (err == -EALREADY) { /* EALREADY means wakeup event already accounted for */ return 0; - } else if (wake == -ENOTSUPP) { + } else if (err == -ENOTSUPP) { /* ENOTSUPP means LP0 not supported with this wake source */ WARN(enable && warn_prevent_lp0, "irq %d prevents lp0\n", irq); if (enable) @@ -158,46 +161,43 @@ int tegra_pm_irq_set_wake(int irq, int enable) else if (!WARN_ON(tegra_prevent_lp0 == 0)) tegra_prevent_lp0--; return 0; - } else if (wake < 0) { + } else if (err < 0) { return -EINVAL; } - if (enable) { - tegra_lp0_wake_enb |= 1ull << wake; - pr_info("Enabling wake%d\n", wake); - } else { - tegra_lp0_wake_enb &= ~(1ull << wake); - pr_info("Disabling wake%d\n", wake); - } + if (enable) + tegra_lp0_wake_enb |= (wake_msk.wake_mask_hi | + wake_msk.wake_mask_lo | wake_msk.wake_mask_any); + else + tegra_lp0_wake_enb &= ~(wake_msk.wake_mask_hi | + wake_msk.wake_mask_lo | wake_msk.wake_mask_any); return 0; } int tegra_pm_irq_set_wake_type(int irq, int flow_type) { - int wake = tegra_irq_to_wake(irq); + struct wake_mask_types wake_msk; + int err; + + err = tegra_irq_to_wake(irq, flow_type, &wake_msk); - if (wake < 0) + if (err < 0) return 0; - switch (flow_type) { - case IRQF_TRIGGER_FALLING: - case IRQF_TRIGGER_LOW: - tegra_lp0_wake_level &= ~(1ull << wake); - tegra_lp0_wake_level_any &= ~(1ull << wake); - break; - case IRQF_TRIGGER_HIGH: - case IRQF_TRIGGER_RISING: - tegra_lp0_wake_level |= (1ull << wake); - tegra_lp0_wake_level_any &= ~(1ull << wake); - break; - - case IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING: - tegra_lp0_wake_level_any |= (1ull << wake); - break; - default: - return -EINVAL; - } + /* configure LOW/FALLING polarity wake sources for an irq */ + tegra_lp0_wake_level &= ~wake_msk.wake_mask_lo; + tegra_lp0_wake_level_any &= ~wake_msk.wake_mask_lo; + + /* configure HIGH/RISING polarity wake sources for an irq */ + tegra_lp0_wake_level |= wake_msk.wake_mask_hi; + tegra_lp0_wake_level_any &= ~wake_msk.wake_mask_hi; + + /* + * configure RISING and FALLING i.e. ANY polarity wake + * sources for an irq + */ + tegra_lp0_wake_level_any |= wake_msk.wake_mask_any; return 0; } diff --git a/arch/arm/mach-tegra/wakeups-t2.c b/arch/arm/mach-tegra/wakeups-t2.c index 8079e6820145..adfe136c8118 100644 --- a/arch/arm/mach-tegra/wakeups-t2.c +++ b/arch/arm/mach-tegra/wakeups-t2.c @@ -24,39 +24,40 @@ #include "gpio-names.h" #include "wakeups.h" -static int tegra_wake_event_irq_t2[] = { - [0] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PO5), - [1] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PV3), - [2] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PL1), - [3] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PB6), - [4] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PN7), - [5] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PA0), - [6] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PU5), - [7] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PU6), - [8] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PC7), - [9] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS2), - [10] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PAA1), - [11] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PW3), - [12] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PW2), - [13] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PY6), - [14] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PV6), - [15] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PJ7), - [16] = INT_RTC, - [17] = INT_KBC, - [18] = INT_EXTERNAL_PMU, - [19] = -EINVAL, /* TEGRA_USB1_VBUS, */ - [20] = -EINVAL, /* TEGRA_USB3_VBUS, */ - [21] = -EINVAL, /* TEGRA_USB1_ID, */ - [22] = -EINVAL, /* TEGRA_USB3_ID, */ - [23] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PI5), - [24] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PV2), - [25] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS4), - [26] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS5), - [27] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS0), - [28] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PQ6), - [29] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PQ7), - [30] = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PN2), +static struct tegra_wake_info tegra_wake_event_data_t2[] = { + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PO5), POLARITY_NONE}, + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PV3), POLARITY_NONE}, + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PL1), POLARITY_NONE}, + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PB6), POLARITY_NONE}, + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PN7), POLARITY_NONE}, + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PA0), POLARITY_NONE}, + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PU5), POLARITY_NONE}, + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PU6), POLARITY_NONE}, + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PC7), POLARITY_NONE}, + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS2), POLARITY_NONE}, + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PAA1), POLARITY_NONE}, + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PW3), POLARITY_NONE}, + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PW2), POLARITY_NONE}, + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PY6), POLARITY_NONE}, + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PV6), POLARITY_NONE}, + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PJ7), POLARITY_NONE}, + {INT_RTC, POLARITY_NONE}, + {INT_KBC, POLARITY_NONE}, + {INT_EXTERNAL_PMU, POLARITY_NONE}, + {INT_USB, POLARITY_EDGE_ANY}, /* TEGRA_USB1_VBUS, */ + {-EINVAL, POLARITY_EDGE_ANY}, /* TEGRA_USB3_VBUS, */ + {-EINVAL, POLARITY_EDGE_ANY}, /* TEGRA_USB1_ID, */ + {-EINVAL, POLARITY_EDGE_ANY}, /* TEGRA_USB3_ID, */ + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PI5), POLARITY_NONE}, + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PV2), POLARITY_NONE}, + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS4), POLARITY_NONE}, + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS5), POLARITY_NONE}, + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS0), POLARITY_NONE}, + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PQ6), POLARITY_NONE}, + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PQ7), POLARITY_NONE}, + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PN2), POLARITY_NONE}, }; -int *tegra_wake_event_irq = tegra_wake_event_irq_t2; -unsigned int tegra_wake_event_irq_size = ARRAY_SIZE(tegra_wake_event_irq_t2); +struct tegra_wake_info *tegra_wake_event_data = tegra_wake_event_data_t2; +unsigned int tegra_wake_event_data_size = ARRAY_SIZE(tegra_wake_event_data_t2); + diff --git a/arch/arm/mach-tegra/wakeups-t3.c b/arch/arm/mach-tegra/wakeups-t3.c index 33dfb12f7211..ef471cb035db 100644 --- a/arch/arm/mach-tegra/wakeups-t3.c +++ b/arch/arm/mach-tegra/wakeups-t3.c @@ -24,50 +24,51 @@ #include "gpio-names.h" #include "wakeups.h" -static int tegra_wake_event_irq_t3[] = { - TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PO5), /* wake0 */ - TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PV1), /* wake1 */ - TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PL1), /* wake2 */ - TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PB6), /* wake3 */ - TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PN7), /* wake4 */ - TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PBB6), /* wake5 */ - TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PU5), /* wake6 */ - TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PU6), /* wake7 */ - TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PC7), /* wake8 */ - TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS2), /* wake9 */ - TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PAA1), /* wake10 */ - TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PW3), /* wake11 */ - TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PW2), /* wake12 */ - TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PY6), /* wake13 */ - TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PDD3), /* wake14 */ - TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PJ2), /* wake15 */ - INT_RTC, /* wake16 */ - INT_KBC, /* wake17 */ - INT_EXTERNAL_PMU, /* wake18 */ - -EINVAL, /* TEGRA_USB1_VBUS, */ /* wake19 */ - -EINVAL, /* TEGRA_USB2_VBUS, */ /* wake20 */ - -EINVAL, /* TEGRA_USB1_ID, */ /* wake21 */ - -EINVAL, /* TEGRA_USB2_ID, */ /* wake22 */ - TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PI5), /* wake23 */ - TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PV0), /* wake24 */ - TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS4), /* wake25 */ - TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS5), /* wake26 */ - TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS0), /* wake27 */ - TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS6), /* wake28 */ - TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS7), /* wake29 */ - TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PN2), /* wake30 */ - -EINVAL, /* not used */ /* wake31 */ - TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PO4), /* wake32 */ - TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PJ0), /* wake33 */ - TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PK2), /* wake34 */ - TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PI6), /* wake35 */ - TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PBB1), /* wake36 */ - -EINVAL, /* TEGRA_USB3_VBUS, */ /* wake37 */ - -EINVAL, /* TEGRA_USB3_ID, */ /* wake38 */ - INT_USB, /* TEGRA_USB1_UTMIP, */ /* wake39 */ - INT_USB2, /* TEGRA_USB2_UTMIP, */ /* wake40 */ - INT_USB3, /* TEGRA_USB3_UTMIP, */ /* wake41 */ +static struct tegra_wake_info tegra_wake_event_data_t3[] = { + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PO5), POLARITY_NONE}, /* wake0 */ + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PV1), POLARITY_NONE}, /* wake1 */ + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PL1), POLARITY_NONE}, /* wake2 */ + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PB6), POLARITY_NONE}, /* wake3 */ + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PN7), POLARITY_NONE}, /* wake4 */ + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PBB6), POLARITY_NONE}, /* wake5 */ + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PU5), POLARITY_NONE}, /* wake6 */ + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PU6), POLARITY_NONE}, /* wake7 */ + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PC7), POLARITY_NONE}, /* wake8 */ + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS2), POLARITY_NONE}, /* wake9 */ + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PAA1), POLARITY_NONE}, /* wake10 */ + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PW3), POLARITY_NONE}, /* wake11 */ + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PW2), POLARITY_NONE}, /* wake12 */ + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PY6), POLARITY_NONE}, /* wake13 */ + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PDD3), POLARITY_NONE}, /* wake14 */ + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PJ2), POLARITY_NONE}, /* wake15 */ + {INT_RTC, POLARITY_NONE}, /* wake16 */ + {INT_KBC, POLARITY_NONE}, /* wake17 */ + {INT_EXTERNAL_PMU, POLARITY_NONE}, /* wake18 */ + {INT_USB, POLARITY_EDGE_ANY}, /* TEGRA_USB1_VBUS, */ /* wake19 */ + {-EINVAL, POLARITY_EDGE_ANY}, /* TEGRA_USB2_VBUS, */ /* wake20 */ + {INT_USB, POLARITY_EDGE_ANY}, /* TEGRA_USB1_ID, */ /* wake21 */ + {-EINVAL, POLARITY_EDGE_ANY}, /* TEGRA_USB2_ID, */ /* wake22 */ + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PI5), POLARITY_NONE}, /* wake23 */ + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PV0), POLARITY_NONE}, /* wake24 */ + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS4), POLARITY_NONE}, /* wake25 */ + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS5), POLARITY_NONE}, /* wake26 */ + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS0), POLARITY_NONE}, /* wake27 */ + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS6), POLARITY_NONE}, /* wake28 */ + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS7), POLARITY_NONE}, /* wake29 */ + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PN2), POLARITY_NONE}, /* wake30 */ + {-EINVAL, POLARITY_NONE}, /* not used */ /* wake31 */ + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PO4), POLARITY_NONE}, /* wake32 */ + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PJ0), POLARITY_NONE}, /* wake33 */ + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PK2), POLARITY_NONE}, /* wake34 */ + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PI6), POLARITY_NONE}, /* wake35 */ + {TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PBB1), POLARITY_NONE}, /* wake36 */ + {-EINVAL, POLARITY_NONE}, /* TEGRA_USB3_VBUS, */ /* wake37 */ + {-EINVAL, POLARITY_NONE}, /* TEGRA_USB3_ID, */ /* wake38 */ + {INT_USB, POLARITY_LEVEL_HI}, /* TEGRA_USB1_UTMIP, */ /* wake39 */ + {INT_USB2, POLARITY_LEVEL_HI}, /* TEGRA_USB2_UTMIP, */ /* wake40 */ + {INT_USB3, POLARITY_LEVEL_HI} /* TEGRA_USB3_UTMIP, */ /* wake41 */ }; -int *tegra_wake_event_irq = tegra_wake_event_irq_t3; -unsigned int tegra_wake_event_irq_size = ARRAY_SIZE(tegra_wake_event_irq_t3); +struct tegra_wake_info *tegra_wake_event_data = tegra_wake_event_data_t3; +unsigned int tegra_wake_event_data_size = ARRAY_SIZE(tegra_wake_event_data_t3); + diff --git a/arch/arm/mach-tegra/wakeups.c b/arch/arm/mach-tegra/wakeups.c index d53563cf22ba..a52a4d50c074 100644 --- a/arch/arm/mach-tegra/wakeups.c +++ b/arch/arm/mach-tegra/wakeups.c @@ -27,48 +27,83 @@ #include "gpio-names.h" #include "wakeups.h" -extern int *tegra_wake_event_irq; -extern unsigned int tegra_wake_event_irq_size; +extern struct tegra_wake_info *tegra_wake_event_data; +extern unsigned int tegra_wake_event_data_size; -int tegra_irq_to_wake(int irq) +/* + * FIXME: unable to pass rising and falling + * flags from usb driver hence using polarity field + * from wake table to set wake_mask_any + * for selected usb wake sources - VBUS and ID + */ +static int update_wake_mask(unsigned int index, int flow_type, + struct wake_mask_types *wake_msk) { - int i; - int wake_irq; - int search_gpio; - static int last_wake = -1; - - /* Two level wake irq search for gpio based wakeups - - * 1. check for GPIO irq(based on tegra_wake_event_irq table) - * e.g. for a board, wake7 based on GPIO PU6 and irq==390 done first - * 2. check for gpio bank irq assuming search for GPIO irq - * preceded this search. - * e.g. in this step check for gpio bank irq GPIO6 irq==119 + int trigger_val; + /* + * set wake function calls with flow_type as -1 + * set wake type function calls update_wake_mask with + * the wake polarity */ - for (i = 0; i < tegra_wake_event_irq_size; i++) { - /* return if step 1 matches */ - if (tegra_wake_event_irq[i] == irq) { - pr_info("Wake%d for irq=%d\n", i, irq); - last_wake = i; - return i; + if (flow_type == -1) { + pr_debug("Wake%d flow_type=%d\n", + index, flow_type); + /* use argument wake_mask_hi to return mask */ + wake_msk->wake_mask_hi |= (1ULL << index); + } else { + trigger_val = (flow_type & IRQF_TRIGGER_MASK); + if ((tegra_wake_event_data[index].polarity == + POLARITY_EDGE_ANY) || + (trigger_val == + (IRQF_TRIGGER_RISING | + IRQF_TRIGGER_FALLING))) { + pr_debug("Wake%d flow_type=ANY\n", index); + wake_msk->wake_mask_any |= (1ULL << index); + } else if ((trigger_val == IRQF_TRIGGER_HIGH) || + (trigger_val == IRQF_TRIGGER_RISING)) { + pr_debug("Wake%d flow_type=HI\n", index); + wake_msk->wake_mask_hi |= (1ULL << index); + } else if ((trigger_val == IRQF_TRIGGER_LOW) || + (trigger_val == IRQF_TRIGGER_FALLING)) { + pr_debug("Wake%d flow_type=LO\n", index); + wake_msk->wake_mask_lo |= (1ULL << index); + } else { + pr_err("Error: Wake%d UNKNOWN flow_type=%d\n", + index, flow_type); + return -EINVAL; } + } + return 0; +} - /* step 2 below uses saved last_wake from step 1 - * in previous call */ - search_gpio = irq_to_gpio( - tegra_wake_event_irq[i]); - if (search_gpio < 0) - continue; - wake_irq = tegra_gpio_get_bank_int_nr(search_gpio); - if (wake_irq < 0) +int tegra_irq_to_wake(unsigned int irq, int flow_type, + struct wake_mask_types *wake_msk) +{ + int i; + int err; + + wake_msk->wake_mask_hi = 0ULL; + wake_msk->wake_mask_lo = 0ULL; + wake_msk->wake_mask_any = 0ULL; + /* + * check for irq based on tegra_wake_event_data table + */ + for (i = 0; i < tegra_wake_event_data_size; i++) { + if (tegra_wake_event_data[i].irq == irq) { + err = update_wake_mask(i, flow_type, wake_msk); + if (err) + return err; continue; - if ((last_wake == i) && - (wake_irq == irq)) { - pr_info("gpio bank wake found: wake%d for irq=%d\n", - i, irq); - return i; } } + if (wake_msk->wake_mask_hi || wake_msk->wake_mask_lo || + wake_msk->wake_mask_any) { + pr_debug("Enabling wake sources for irq=%d, mask hi=%#llx, lo=%#llx, any=%#llx, flow_type=%d\n", + irq, wake_msk->wake_mask_hi, wake_msk->wake_mask_lo, + wake_msk->wake_mask_any, flow_type); + return 0; + } return -EINVAL; } @@ -77,9 +112,19 @@ int tegra_wake_to_irq(int wake) if (wake < 0) return -EINVAL; - if (wake >= tegra_wake_event_irq_size) + if (wake >= tegra_wake_event_data_size) return -EINVAL; - return tegra_wake_event_irq[wake]; + return tegra_wake_event_data[wake].irq; +} + +int tegra_disable_wake_source(int wake) +{ + if (wake >= tegra_wake_event_data_size) + return -EINVAL; + + tegra_wake_event_data[wake].irq = -EINVAL; + + return 0; } diff --git a/arch/arm/mach-tegra/wakeups.h b/arch/arm/mach-tegra/wakeups.h index ab113649d534..6d2f5f077601 100644 --- a/arch/arm/mach-tegra/wakeups.h +++ b/arch/arm/mach-tegra/wakeups.h @@ -17,13 +17,32 @@ #ifndef __WAKEUPS_H_ #define __WAKEUPS_H_ -/* - * given irq number returns wake source index or negative value for error - */ -int tegra_irq_to_wake(int irq); +struct wake_mask_types { + u64 wake_mask_hi; + u64 wake_mask_lo; + u64 wake_mask_any; +}; + +/* sets 64-bit wake mask argument bits for wake sources given an irq */ +int tegra_irq_to_wake(unsigned int irq, int flow_type, + struct wake_mask_types *wake_msk); /* * given wake source index, returns irq number or negative value for error */ int tegra_wake_to_irq(int wake); +/* disable selected wake source setting for particular board */ +int tegra_disable_wake_source(int wake); + +enum wake_polarity { + POLARITY_NONE = 0, + POLARITY_LEVEL_HI, + POLARITY_LEVEL_LO, + POLARITY_EDGE_ANY +}; + +struct tegra_wake_info { + int irq; + enum wake_polarity polarity; +}; #endif /* end __WAKEUPS_H_ */ diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 17e9c1cfdf4e..49abdf016b26 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -32,6 +32,7 @@ #include <asm/mach/irq.h> #include <mach/iomap.h> +#include <mach/legacy_irq.h> #include <mach/pinmux.h> #include "../../../arch/arm/mach-tegra/pm-irq.h" @@ -90,6 +91,7 @@ struct tegra_gpio_bank { u32 oe[4]; u32 int_enb[4]; u32 int_lvl[4]; + u32 wake_enb[4]; #endif }; @@ -395,21 +397,60 @@ static int tegra_gpio_suspend(void) return 0; } +static int tegra_update_lp1_gpio_wake(struct irq_data *d, bool enable) +{ +#ifdef CONFIG_PM_SLEEP + struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d); + u8 mask; + u8 port_index; + u8 pin_index_in_bank; + u8 pin_in_port; + int gpio = d->irq - INT_GPIO_BASE; + + if (gpio < 0) + return -EIO; + pin_index_in_bank = (gpio & 0x1F); + port_index = pin_index_in_bank >> 3; + pin_in_port = (pin_index_in_bank & 0x7); + mask = BIT(pin_in_port); + if (enable) + bank->wake_enb[port_index] |= mask; + else + bank->wake_enb[port_index] &= ~mask; +#endif + + return 0; +} + static int tegra_gpio_irq_set_wake(struct irq_data *d, unsigned int enable) { struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d); int ret = 0; - ret = tegra_pm_irq_set_wake(d->irq, enable); + /* + * update LP1 mask for gpio port/pin interrupt + * LP1 enable independent of LP0 wake support + */ + ret = tegra_update_lp1_gpio_wake(d, enable); + if (ret) { + pr_err("Failed gpio lp1 %s for irq=%d, error=%d\n", + (enable ? "enable" : "disable"), d->irq, ret); + goto fail; + } + /* LP1 enable for bank interrupt */ + ret = tegra_update_lp1_irq_wake(bank->irq, enable); if (ret) - return ret; - - ret = irq_set_irq_wake(bank->irq, enable); + pr_err("Failed gpio lp1 %s for irq=%d, error=%d\n", + (enable ? "enable" : "disable"), bank->irq, ret); + /* LP0 */ + ret = tegra_pm_irq_set_wake(d->irq, enable); if (ret) - tegra_pm_irq_set_wake(d->irq, !enable); + pr_err("Failed gpio lp0 %s for irq=%d, error=%d\n", + (enable ? "enable" : "disable"), d->irq, ret); +fail: return ret; } #else |