[ARM] tegra: irq: Add set_wake and set_type support for suspend
authorColin Cross <ccross@android.com>
Mon, 4 Oct 2010 07:25:16 +0000 (00:25 -0700)
committerColin Cross <ccross@android.com>
Wed, 6 Oct 2010 23:26:26 +0000 (16:26 -0700)
Change-Id: Ic18e0c92462a590b759752662bd7d67aaf8a371a
Signed-off-by: Colin Cross <ccross@android.com>
arch/arm/mach-tegra/include/mach/legacy_irq.h
arch/arm/mach-tegra/irq.c
arch/arm/mach-tegra/legacy_irq.c

index d898c0e3d905bee030f2a126a8b449dfe44cf1a8..3a2bfab9e54ff114f438e1c2a2af34d77add94d0 100644 (file)
@@ -31,5 +31,6 @@ int tegra_legacy_irq_set_wake(int irq, int enable);
 void tegra_legacy_irq_set_lp1_wake_mask(void);
 void tegra_legacy_irq_restore_mask(void);
 void tegra_init_legacy_irq(void);
-
+void tegra_legacy_irq_suspend(void);
+void tegra_legacy_irq_resume(void);
 #endif
index 8f47a9c1a30cfc05ce69a6d711c5e77e3c8ec6bf..ced7007c0610f4276af252b430fd4240579be34f 100644 (file)
@@ -54,6 +54,51 @@ static void pmc_32kwritel(u32 val, unsigned long offs)
        udelay(130);
 }
 
+int tegra_set_lp0_wake(int irq, int enable)
+{
+       int wake = tegra_irq_to_wake(irq);
+
+       if (wake < 0)
+               return -EINVAL;
+
+       if (enable)
+               tegra_lp0_wake_enb |= 1 << wake;
+       else
+               tegra_lp0_wake_enb &= ~(1 << wake);
+
+       return 0;
+}
+
+int tegra_set_lp0_wake_type(int irq, int flow_type)
+{
+       int wake = tegra_irq_to_wake(irq);
+
+       if (wake < 0)
+               return 0;
+
+       switch (flow_type) {
+       case IRQF_TRIGGER_FALLING:
+       case IRQF_TRIGGER_LOW:
+               tegra_lp0_wake_level &= ~(1 << wake);
+               tegra_lp0_wake_level_any &= ~(1 << wake);
+               break;
+       case IRQF_TRIGGER_HIGH:
+       case IRQF_TRIGGER_RISING:
+               tegra_lp0_wake_level |= 1 << wake;
+               tegra_lp0_wake_level_any &= ~(1 << wake);
+               break;
+
+       case IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING:
+               tegra_lp0_wake_level_any |= 1 << wake;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+
 int tegra_set_lp1_wake(int irq, int enable)
 {
        return tegra_legacy_irq_set_wake(irq, enable);
@@ -97,6 +142,33 @@ void tegra_set_lp0_wake_pads(u32 wake_enb, u32 wake_level, u32 wake_any)
        writel(wake_enb, pmc + PMC_WAKE_MASK);
 }
 
+static void tegra_irq_handle_wake(void)
+{
+       int wake;
+       int irq;
+       struct irq_desc *desc;
+
+       unsigned long wake_status = readl(pmc + PMC_WAKE_STATUS);
+       for_each_set_bit(wake, &wake_status, sizeof(wake_status) * 8) {
+               irq = tegra_wake_to_irq(wake);
+               if (!irq) {
+                       pr_info("Resume caused by WAKE%d\n", wake);
+                       continue;
+               }
+
+               desc = irq_to_desc(irq);
+               if (!desc || !desc->action || !desc->action->name) {
+                       pr_info("Resume caused by WAKE%d, irq %d\n", wake, irq);
+                       continue;
+               }
+
+               pr_info("Resume caused by WAKE%d, %s\n", wake,
+                       desc->action->name);
+
+               generic_handle_irq(irq);
+       }
+}
+
 static void tegra_mask(unsigned int irq)
 {
        gic_mask_irq(irq);
@@ -109,11 +181,34 @@ static void tegra_unmask(unsigned int irq)
        tegra_legacy_unmask_irq(irq);
 }
 
+static int tegra_set_wake(unsigned int irq, unsigned int enable)
+{
+       int ret;
+       ret = tegra_set_lp1_wake(irq, enable);
+       if (ret)
+               return ret;
+
+       if (tegra_get_suspend_mode() == TEGRA_SUSPEND_LP0)
+               return tegra_set_lp0_wake(irq, enable);
+
+       return 0;
+}
+
+static int tegra_set_type(unsigned int irq, unsigned int flow_type)
+{
+       if (tegra_get_suspend_mode() == TEGRA_SUSPEND_LP0)
+               return tegra_set_lp0_wake_type(irq, flow_type);
+
+       return 0;
+}
+
 static struct irq_chip tegra_irq = {
        .name           = "PPI",
        .ack            = gic_ack_irq,
        .mask           = tegra_mask,
        .unmask         = tegra_unmask,
+       .set_wake       = tegra_set_wake,
+       .set_type       = tegra_set_type,
 #ifdef CONFIG_SMP
        .set_affinity   = gic_set_cpu,
 #endif
@@ -136,3 +231,14 @@ void __init tegra_init_irq(void)
                set_irq_flags(irq, IRQF_VALID);
        }
 }
+
+void tegra_irq_suspend(void)
+{
+       tegra_legacy_irq_suspend();
+}
+
+void tegra_irq_resume(void)
+{
+       tegra_legacy_irq_resume();
+       tegra_irq_handle_wake();
+}
index 38eb719a4f53517688871d00e613486367231302..5a6197bacbb10fc7656097c5651c51f2f31c1951 100644 (file)
@@ -179,7 +179,7 @@ static u32 cop_ier[NUM_ICTLRS];
 static u32 cpu_ier[NUM_ICTLRS];
 static u32 cpu_iep[NUM_ICTLRS];
 
-void tegra_irq_suspend(void)
+void tegra_legacy_irq_suspend(void)
 {
        unsigned long flags;
        int i;
@@ -195,7 +195,7 @@ void tegra_irq_suspend(void)
        local_irq_restore(flags);
 }
 
-void tegra_irq_resume(void)
+void tegra_legacy_irq_resume(void)
 {
        unsigned long flags;
        int i;