diff options
Diffstat (limited to 'arch/arm/plat-mxc/avic.c')
-rw-r--r-- | arch/arm/plat-mxc/avic.c | 91 |
1 files changed, 68 insertions, 23 deletions
diff --git a/arch/arm/plat-mxc/avic.c b/arch/arm/plat-mxc/avic.c index 55d2534ec727..8875fb415f68 100644 --- a/arch/arm/plat-mxc/avic.c +++ b/arch/arm/plat-mxc/avic.c | |||
@@ -50,6 +50,8 @@ | |||
50 | 50 | ||
51 | void __iomem *avic_base; | 51 | void __iomem *avic_base; |
52 | 52 | ||
53 | static u32 avic_saved_mask_reg[2]; | ||
54 | |||
53 | #ifdef CONFIG_MXC_IRQ_PRIOR | 55 | #ifdef CONFIG_MXC_IRQ_PRIOR |
54 | static int avic_irq_set_priority(unsigned char irq, unsigned char prio) | 56 | static int avic_irq_set_priority(unsigned char irq, unsigned char prio) |
55 | { | 57 | { |
@@ -90,24 +92,8 @@ static int avic_set_irq_fiq(unsigned int irq, unsigned int type) | |||
90 | } | 92 | } |
91 | #endif /* CONFIG_FIQ */ | 93 | #endif /* CONFIG_FIQ */ |
92 | 94 | ||
93 | /* Disable interrupt number "irq" in the AVIC */ | ||
94 | static void mxc_mask_irq(struct irq_data *d) | ||
95 | { | ||
96 | __raw_writel(d->irq, avic_base + AVIC_INTDISNUM); | ||
97 | } | ||
98 | 95 | ||
99 | /* Enable interrupt number "irq" in the AVIC */ | 96 | static struct mxc_extra_irq avic_extra_irq = { |
100 | static void mxc_unmask_irq(struct irq_data *d) | ||
101 | { | ||
102 | __raw_writel(d->irq, avic_base + AVIC_INTENNUM); | ||
103 | } | ||
104 | |||
105 | static struct mxc_irq_chip mxc_avic_chip = { | ||
106 | .base = { | ||
107 | .irq_ack = mxc_mask_irq, | ||
108 | .irq_mask = mxc_mask_irq, | ||
109 | .irq_unmask = mxc_unmask_irq, | ||
110 | }, | ||
111 | #ifdef CONFIG_MXC_IRQ_PRIOR | 97 | #ifdef CONFIG_MXC_IRQ_PRIOR |
112 | .set_priority = avic_irq_set_priority, | 98 | .set_priority = avic_irq_set_priority, |
113 | #endif | 99 | #endif |
@@ -116,6 +102,68 @@ static struct mxc_irq_chip mxc_avic_chip = { | |||
116 | #endif | 102 | #endif |
117 | }; | 103 | }; |
118 | 104 | ||
105 | #ifdef CONFIG_PM | ||
106 | static void avic_irq_suspend(struct irq_data *d) | ||
107 | { | ||
108 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | ||
109 | struct irq_chip_type *ct = gc->chip_types; | ||
110 | int idx = gc->irq_base >> 5; | ||
111 | |||
112 | avic_saved_mask_reg[idx] = __raw_readl(avic_base + ct->regs.mask); | ||
113 | __raw_writel(gc->wake_active, avic_base + ct->regs.mask); | ||
114 | } | ||
115 | |||
116 | static void avic_irq_resume(struct irq_data *d) | ||
117 | { | ||
118 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | ||
119 | struct irq_chip_type *ct = gc->chip_types; | ||
120 | int idx = gc->irq_base >> 5; | ||
121 | |||
122 | __raw_writel(avic_saved_mask_reg[idx], avic_base + ct->regs.mask); | ||
123 | } | ||
124 | |||
125 | #else | ||
126 | #define avic_irq_suspend NULL | ||
127 | #define avic_irq_resume NULL | ||
128 | #endif | ||
129 | |||
130 | static __init void avic_init_gc(unsigned int irq_start) | ||
131 | { | ||
132 | struct irq_chip_generic *gc; | ||
133 | struct irq_chip_type *ct; | ||
134 | int idx = irq_start >> 5; | ||
135 | |||
136 | gc = irq_alloc_generic_chip("mxc-avic", 1, irq_start, avic_base, | ||
137 | handle_level_irq); | ||
138 | gc->private = &avic_extra_irq; | ||
139 | gc->wake_enabled = IRQ_MSK(32); | ||
140 | |||
141 | ct = gc->chip_types; | ||
142 | ct->chip.irq_mask = irq_gc_mask_clr_bit; | ||
143 | ct->chip.irq_unmask = irq_gc_mask_set_bit; | ||
144 | ct->chip.irq_ack = irq_gc_mask_clr_bit; | ||
145 | ct->chip.irq_set_wake = irq_gc_set_wake; | ||
146 | ct->chip.irq_suspend = avic_irq_suspend; | ||
147 | ct->chip.irq_resume = avic_irq_resume; | ||
148 | ct->regs.mask = !idx ? AVIC_INTENABLEL : AVIC_INTENABLEH; | ||
149 | ct->regs.ack = ct->regs.mask; | ||
150 | |||
151 | irq_setup_generic_chip(gc, IRQ_MSK(32), 0, IRQ_NOREQUEST, 0); | ||
152 | } | ||
153 | |||
154 | asmlinkage void __exception_irq_entry avic_handle_irq(struct pt_regs *regs) | ||
155 | { | ||
156 | u32 nivector; | ||
157 | |||
158 | do { | ||
159 | nivector = __raw_readl(avic_base + AVIC_NIVECSR) >> 16; | ||
160 | if (nivector == 0xffff) | ||
161 | break; | ||
162 | |||
163 | handle_IRQ(nivector, regs); | ||
164 | } while (1); | ||
165 | } | ||
166 | |||
119 | /* | 167 | /* |
120 | * This function initializes the AVIC hardware and disables all the | 168 | * This function initializes the AVIC hardware and disables all the |
121 | * interrupts. It registers the interrupt enable and disable functions | 169 | * interrupts. It registers the interrupt enable and disable functions |
@@ -140,11 +188,9 @@ void __init mxc_init_irq(void __iomem *irqbase) | |||
140 | /* all IRQ no FIQ */ | 188 | /* all IRQ no FIQ */ |
141 | __raw_writel(0, avic_base + AVIC_INTTYPEH); | 189 | __raw_writel(0, avic_base + AVIC_INTTYPEH); |
142 | __raw_writel(0, avic_base + AVIC_INTTYPEL); | 190 | __raw_writel(0, avic_base + AVIC_INTTYPEL); |
143 | for (i = 0; i < AVIC_NUM_IRQS; i++) { | 191 | |
144 | irq_set_chip_and_handler(i, &mxc_avic_chip.base, | 192 | for (i = 0; i < AVIC_NUM_IRQS; i += 32) |
145 | handle_level_irq); | 193 | avic_init_gc(i); |
146 | set_irq_flags(i, IRQF_VALID); | ||
147 | } | ||
148 | 194 | ||
149 | /* Set default priority value (0) for all IRQ's */ | 195 | /* Set default priority value (0) for all IRQ's */ |
150 | for (i = 0; i < 8; i++) | 196 | for (i = 0; i < 8; i++) |
@@ -157,4 +203,3 @@ void __init mxc_init_irq(void __iomem *irqbase) | |||
157 | 203 | ||
158 | printk(KERN_INFO "MXC IRQ initialized\n"); | 204 | printk(KERN_INFO "MXC IRQ initialized\n"); |
159 | } | 205 | } |
160 | |||