diff options
author | Hui Wang <jason77.wang@gmail.com> | 2011-09-22 05:40:08 -0400 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2011-09-23 02:32:14 -0400 |
commit | 3439a397a8190b7e8d319959ec30e28c7ca14bab (patch) | |
tree | 8feab81ed1c843020bf516d82f5518f88381e3e4 /arch/arm/plat-mxc/avic.c | |
parent | 40d97b89bd3c902144a0757249d9d5d5cf314214 (diff) |
ARM i.MX avic: convert to use generic irq chip
Convert i.MX avic irq handler to use generic irq chip. This not only
provides a cleanup implementation of irq chip handler, but also
implements suspend/resume interface with the help of generic irq chip
interface.
Change mxc_irq_chip to a new structure mxc_extra_irq to handle fiq
and priority functions.
Signed-off-by: Hui Wang <jason77.wang@gmail.com>
Acked-by: Shawn Guo <shawn.guo@linaro.org>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'arch/arm/plat-mxc/avic.c')
-rw-r--r-- | arch/arm/plat-mxc/avic.c | 79 |
1 files changed, 56 insertions, 23 deletions
diff --git a/arch/arm/plat-mxc/avic.c b/arch/arm/plat-mxc/avic.c index 55d2534ec727..846636a29bd3 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 | |||
99 | /* Enable interrupt number "irq" in the AVIC */ | ||
100 | static void mxc_unmask_irq(struct irq_data *d) | ||
101 | { | ||
102 | __raw_writel(d->irq, avic_base + AVIC_INTENNUM); | ||
103 | } | ||
104 | 95 | ||
105 | static struct mxc_irq_chip mxc_avic_chip = { | 96 | static struct mxc_extra_irq avic_extra_irq = { |
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,56 @@ static struct mxc_irq_chip mxc_avic_chip = { | |||
116 | #endif | 102 | #endif |
117 | }; | 103 | }; |
118 | 104 | ||
105 | |||
106 | #ifdef CONFIG_PM | ||
107 | static void avic_irq_suspend(struct irq_data *d) | ||
108 | { | ||
109 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | ||
110 | struct irq_chip_type *ct = gc->chip_types; | ||
111 | int idx = gc->irq_base >> 5; | ||
112 | |||
113 | avic_saved_mask_reg[idx] = __raw_readl(avic_base + ct->regs.mask); | ||
114 | __raw_writel(gc->wake_active, avic_base + ct->regs.mask); | ||
115 | } | ||
116 | |||
117 | static void avic_irq_resume(struct irq_data *d) | ||
118 | { | ||
119 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | ||
120 | struct irq_chip_type *ct = gc->chip_types; | ||
121 | int idx = gc->irq_base >> 5; | ||
122 | |||
123 | __raw_writel(avic_saved_mask_reg[idx], avic_base + ct->regs.mask); | ||
124 | } | ||
125 | |||
126 | #else | ||
127 | #define avic_irq_suspend NULL | ||
128 | #define avic_irq_resume NULL | ||
129 | #endif | ||
130 | |||
131 | static __init void avic_init_gc(unsigned int irq_start) | ||
132 | { | ||
133 | struct irq_chip_generic *gc; | ||
134 | struct irq_chip_type *ct; | ||
135 | int idx = irq_start >> 5; | ||
136 | |||
137 | gc = irq_alloc_generic_chip("mxc-avic", 1, irq_start, avic_base, | ||
138 | handle_level_irq); | ||
139 | gc->private = &avic_extra_irq; | ||
140 | gc->wake_enabled = IRQ_MSK(32); | ||
141 | |||
142 | ct = gc->chip_types; | ||
143 | ct->chip.irq_mask = irq_gc_mask_clr_bit; | ||
144 | ct->chip.irq_unmask = irq_gc_mask_set_bit; | ||
145 | ct->chip.irq_ack = irq_gc_mask_clr_bit; | ||
146 | ct->chip.irq_set_wake = irq_gc_set_wake; | ||
147 | ct->chip.irq_suspend = avic_irq_suspend; | ||
148 | ct->chip.irq_resume = avic_irq_resume; | ||
149 | ct->regs.mask = !idx ? AVIC_INTENABLEL : AVIC_INTENABLEH; | ||
150 | ct->regs.ack = ct->regs.mask; | ||
151 | |||
152 | irq_setup_generic_chip(gc, IRQ_MSK(32), 0, IRQ_NOREQUEST, 0); | ||
153 | } | ||
154 | |||
119 | /* | 155 | /* |
120 | * This function initializes the AVIC hardware and disables all the | 156 | * This function initializes the AVIC hardware and disables all the |
121 | * interrupts. It registers the interrupt enable and disable functions | 157 | * interrupts. It registers the interrupt enable and disable functions |
@@ -140,11 +176,9 @@ void __init mxc_init_irq(void __iomem *irqbase) | |||
140 | /* all IRQ no FIQ */ | 176 | /* all IRQ no FIQ */ |
141 | __raw_writel(0, avic_base + AVIC_INTTYPEH); | 177 | __raw_writel(0, avic_base + AVIC_INTTYPEH); |
142 | __raw_writel(0, avic_base + AVIC_INTTYPEL); | 178 | __raw_writel(0, avic_base + AVIC_INTTYPEL); |
143 | for (i = 0; i < AVIC_NUM_IRQS; i++) { | 179 | |
144 | irq_set_chip_and_handler(i, &mxc_avic_chip.base, | 180 | for (i = 0; i < AVIC_NUM_IRQS; i += 32) |
145 | handle_level_irq); | 181 | avic_init_gc(i); |
146 | set_irq_flags(i, IRQF_VALID); | ||
147 | } | ||
148 | 182 | ||
149 | /* Set default priority value (0) for all IRQ's */ | 183 | /* Set default priority value (0) for all IRQ's */ |
150 | for (i = 0; i < 8; i++) | 184 | for (i = 0; i < 8; i++) |
@@ -157,4 +191,3 @@ void __init mxc_init_irq(void __iomem *irqbase) | |||
157 | 191 | ||
158 | printk(KERN_INFO "MXC IRQ initialized\n"); | 192 | printk(KERN_INFO "MXC IRQ initialized\n"); |
159 | } | 193 | } |
160 | |||