]>
Commit | Line | Data |
---|---|---|
5ad36c5f EG |
1 | /* |
2 | * Copyright (C) 2010 Google, Inc. | |
3 | * | |
4 | * Author: | |
5 | * Colin Cross <ccross@google.com> | |
6 | * | |
460907bc GK |
7 | * Copyright (C) 2010, NVIDIA Corporation |
8 | * | |
5ad36c5f EG |
9 | * This software is licensed under the terms of the GNU General Public |
10 | * License version 2, as published by the Free Software Foundation, and | |
11 | * may be copied, distributed, and modified under those terms. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | */ | |
19 | ||
20 | #include <linux/kernel.h> | |
3524b70e | 21 | #include <linux/delay.h> |
5ad36c5f EG |
22 | #include <linux/init.h> |
23 | #include <linux/interrupt.h> | |
24 | #include <linux/irq.h> | |
25 | #include <linux/io.h> | |
26 | ||
27 | #include <asm/hardware/gic.h> | |
28 | ||
29 | #include <mach/iomap.h> | |
3524b70e | 30 | #include <mach/legacy_irq.h> |
2ea67fd1 | 31 | #include <mach/suspend.h> |
5ad36c5f EG |
32 | |
33 | #include "board.h" | |
34 | ||
3524b70e CC |
35 | #define PMC_CTRL 0x0 |
36 | #define PMC_CTRL_LATCH_WAKEUPS (1 << 5) | |
37 | #define PMC_WAKE_MASK 0xc | |
38 | #define PMC_WAKE_LEVEL 0x10 | |
39 | #define PMC_WAKE_STATUS 0x14 | |
40 | #define PMC_SW_WAKE_STATUS 0x18 | |
41 | #define PMC_DPD_SAMPLE 0x20 | |
460907bc | 42 | |
3524b70e | 43 | static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE); |
460907bc | 44 | |
3524b70e CC |
45 | static u32 tegra_lp0_wake_enb; |
46 | static u32 tegra_lp0_wake_level; | |
47 | static u32 tegra_lp0_wake_level_any; | |
460907bc | 48 | |
cc939754 CC |
49 | static void (*tegra_gic_mask_irq)(struct irq_data *d); |
50 | static void (*tegra_gic_unmask_irq)(struct irq_data *d); | |
26d902c0 | 51 | static void (*tegra_gic_ack_irq)(struct irq_data *d); |
460907bc | 52 | |
3524b70e CC |
53 | /* ensures that sufficient time is passed for a register write to |
54 | * serialize into the 32KHz domain */ | |
55 | static void pmc_32kwritel(u32 val, unsigned long offs) | |
56 | { | |
57 | writel(val, pmc + offs); | |
58 | udelay(130); | |
59 | } | |
460907bc | 60 | |
3524b70e | 61 | int tegra_set_lp1_wake(int irq, int enable) |
460907bc | 62 | { |
3524b70e | 63 | return tegra_legacy_irq_set_wake(irq, enable); |
460907bc GK |
64 | } |
65 | ||
3524b70e | 66 | void tegra_set_lp0_wake_pads(u32 wake_enb, u32 wake_level, u32 wake_any) |
460907bc | 67 | { |
3524b70e CC |
68 | u32 temp; |
69 | u32 status; | |
70 | u32 lvl; | |
71 | ||
72 | wake_level &= wake_enb; | |
73 | wake_any &= wake_enb; | |
74 | ||
75 | wake_level |= (tegra_lp0_wake_level & tegra_lp0_wake_enb); | |
76 | wake_any |= (tegra_lp0_wake_level_any & tegra_lp0_wake_enb); | |
77 | ||
78 | wake_enb |= tegra_lp0_wake_enb; | |
79 | ||
80 | pmc_32kwritel(0, PMC_SW_WAKE_STATUS); | |
81 | temp = readl(pmc + PMC_CTRL); | |
82 | temp |= PMC_CTRL_LATCH_WAKEUPS; | |
83 | pmc_32kwritel(temp, PMC_CTRL); | |
84 | temp &= ~PMC_CTRL_LATCH_WAKEUPS; | |
85 | pmc_32kwritel(temp, PMC_CTRL); | |
86 | status = readl(pmc + PMC_SW_WAKE_STATUS); | |
87 | lvl = readl(pmc + PMC_WAKE_LEVEL); | |
88 | ||
89 | /* flip the wakeup trigger for any-edge triggered pads | |
90 | * which are currently asserting as wakeups */ | |
91 | lvl ^= status; | |
92 | lvl &= wake_any; | |
93 | ||
94 | wake_level |= lvl; | |
95 | ||
96 | writel(wake_level, pmc + PMC_WAKE_LEVEL); | |
97 | /* Enable DPD sample to trigger sampling pads data and direction | |
98 | * in which pad will be driven during lp0 mode*/ | |
99 | writel(0x1, pmc + PMC_DPD_SAMPLE); | |
100 | ||
101 | writel(wake_enb, pmc + PMC_WAKE_MASK); | |
460907bc GK |
102 | } |
103 | ||
3524b70e CC |
104 | static void tegra_mask(struct irq_data *d) |
105 | { | |
106 | tegra_gic_mask_irq(d); | |
107 | tegra_legacy_mask_irq(d->irq); | |
108 | } | |
460907bc | 109 | |
3524b70e | 110 | static void tegra_unmask(struct irq_data *d) |
460907bc | 111 | { |
3524b70e CC |
112 | tegra_gic_unmask_irq(d); |
113 | tegra_legacy_unmask_irq(d->irq); | |
460907bc | 114 | } |
460907bc | 115 | |
26d902c0 CC |
116 | static void tegra_ack(struct irq_data *d) |
117 | { | |
118 | tegra_legacy_force_irq_clr(d->irq); | |
119 | tegra_gic_ack_irq(d); | |
120 | } | |
121 | ||
122 | static int tegra_retrigger(struct irq_data *d) | |
123 | { | |
124 | tegra_legacy_force_irq_set(d->irq); | |
125 | return 1; | |
126 | } | |
127 | ||
460907bc | 128 | static struct irq_chip tegra_irq = { |
3524b70e | 129 | .name = "PPI", |
26d902c0 | 130 | .irq_ack = tegra_ack, |
3524b70e CC |
131 | .irq_mask = tegra_mask, |
132 | .irq_unmask = tegra_unmask, | |
26d902c0 | 133 | .irq_retrigger = tegra_retrigger, |
460907bc GK |
134 | }; |
135 | ||
5ad36c5f EG |
136 | void __init tegra_init_irq(void) |
137 | { | |
460907bc GK |
138 | struct irq_chip *gic; |
139 | unsigned int i; | |
3524b70e | 140 | int irq; |
460907bc | 141 | |
3524b70e | 142 | tegra_init_legacy_irq(); |
460907bc | 143 | |
b580b899 RK |
144 | gic_init(0, 29, IO_ADDRESS(TEGRA_ARM_INT_DIST_BASE), |
145 | IO_ADDRESS(TEGRA_ARM_PERIF_BASE + 0x100)); | |
460907bc | 146 | |
6845664a | 147 | gic = irq_get_chip(29); |
cc939754 CC |
148 | tegra_gic_unmask_irq = gic->irq_unmask; |
149 | tegra_gic_mask_irq = gic->irq_mask; | |
26d902c0 | 150 | tegra_gic_ack_irq = gic->irq_ack; |
460907bc | 151 | #ifdef CONFIG_SMP |
37337a8d | 152 | tegra_irq.irq_set_affinity = gic->irq_set_affinity; |
460907bc GK |
153 | #endif |
154 | ||
3524b70e CC |
155 | for (i = 0; i < INT_MAIN_NR; i++) { |
156 | irq = INT_PRI_BASE + i; | |
6845664a TG |
157 | irq_set_chip(irq, &tegra_irq); |
158 | irq_set_handler(irq, handle_level_irq); | |
3524b70e | 159 | set_irq_flags(irq, IRQF_VALID); |
460907bc | 160 | } |
460907bc | 161 | } |