aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-s5pc100/gpiolib.c1
-rw-r--r--arch/arm/mach-s5pv210/gpiolib.c1
-rw-r--r--arch/arm/plat-s5p/irq-gpioint.c68
-rw-r--r--arch/arm/plat-samsung/include/plat/gpio-cfg.h16
4 files changed, 76 insertions, 10 deletions
diff --git a/arch/arm/mach-s5pc100/gpiolib.c b/arch/arm/mach-s5pc100/gpiolib.c
index 20856eb7dd51..2842394b28b5 100644
--- a/arch/arm/mach-s5pc100/gpiolib.c
+++ b/arch/arm/mach-s5pc100/gpiolib.c
@@ -348,6 +348,7 @@ static __init int s5pc100_gpiolib_init(void)
348 } 348 }
349 349
350 samsung_gpiolib_add_4bit_chips(s5pc100_gpio_chips, nr_chips); 350 samsung_gpiolib_add_4bit_chips(s5pc100_gpio_chips, nr_chips);
351 s5p_register_gpioint_bank(IRQ_GPIOINT, 0, S5P_GPIOINT_GROUP_MAXNR);
351 352
352 return 0; 353 return 0;
353} 354}
diff --git a/arch/arm/mach-s5pv210/gpiolib.c b/arch/arm/mach-s5pv210/gpiolib.c
index ab673effd767..1ba20a703e05 100644
--- a/arch/arm/mach-s5pv210/gpiolib.c
+++ b/arch/arm/mach-s5pv210/gpiolib.c
@@ -281,6 +281,7 @@ static __init int s5pv210_gpiolib_init(void)
281 } 281 }
282 282
283 samsung_gpiolib_add_4bit_chips(s5pv210_gpio_4bit, nr_chips); 283 samsung_gpiolib_add_4bit_chips(s5pv210_gpio_4bit, nr_chips);
284 s5p_register_gpioint_bank(IRQ_GPIOINT, 0, S5P_GPIOINT_GROUP_MAXNR);
284 285
285 return 0; 286 return 0;
286} 287}
diff --git a/arch/arm/plat-s5p/irq-gpioint.c b/arch/arm/plat-s5p/irq-gpioint.c
index 79a7b1c5a57e..cd87d3256e03 100644
--- a/arch/arm/plat-s5p/irq-gpioint.c
+++ b/arch/arm/plat-s5p/irq-gpioint.c
@@ -17,6 +17,7 @@
17#include <linux/irq.h> 17#include <linux/irq.h>
18#include <linux/io.h> 18#include <linux/io.h>
19#include <linux/gpio.h> 19#include <linux/gpio.h>
20#include <linux/slab.h>
20 21
21#include <mach/map.h> 22#include <mach/map.h>
22#include <plat/gpio-core.h> 23#include <plat/gpio-core.h>
@@ -29,7 +30,16 @@
29#define PEND_OFFSET 0xA00 30#define PEND_OFFSET 0xA00
30#define REG_OFFSET(x) ((x) << 2) 31#define REG_OFFSET(x) ((x) << 2)
31 32
32static struct s3c_gpio_chip *irq_chips[S5P_GPIOINT_GROUP_MAXNR]; 33struct s5p_gpioint_bank {
34 struct list_head list;
35 int start;
36 int nr_groups;
37 int irq;
38 struct s3c_gpio_chip **chips;
39 void (*handler)(unsigned int, struct irq_desc *);
40};
41
42LIST_HEAD(banks);
33 43
34static int s5p_gpioint_get_offset(struct irq_data *data) 44static int s5p_gpioint_get_offset(struct irq_data *data)
35{ 45{
@@ -139,11 +149,12 @@ static struct irq_chip s5p_gpioint = {
139 149
140static void s5p_gpioint_handler(unsigned int irq, struct irq_desc *desc) 150static void s5p_gpioint_handler(unsigned int irq, struct irq_desc *desc)
141{ 151{
152 struct s5p_gpioint_bank *bank = get_irq_data(irq);
142 int group, pend_offset, mask_offset; 153 int group, pend_offset, mask_offset;
143 unsigned int pend, mask; 154 unsigned int pend, mask;
144 155
145 for (group = 0; group < S5P_GPIOINT_GROUP_MAXNR; group++) { 156 for (group = 0; group < bank->nr_groups; group++) {
146 struct s3c_gpio_chip *chip = irq_chips[group]; 157 struct s3c_gpio_chip *chip = bank->chips[group];
147 if (!chip) 158 if (!chip)
148 continue; 159 continue;
149 160
@@ -168,23 +179,44 @@ static void s5p_gpioint_handler(unsigned int irq, struct irq_desc *desc)
168static __init int s5p_gpioint_add(struct s3c_gpio_chip *chip) 179static __init int s5p_gpioint_add(struct s3c_gpio_chip *chip)
169{ 180{
170 static int used_gpioint_groups = 0; 181 static int used_gpioint_groups = 0;
171 static bool handler_registered = 0;
172 int irq, group = chip->group; 182 int irq, group = chip->group;
173 int i; 183 int i;
184 struct s5p_gpioint_bank *bank = NULL;
174 185
175 if (used_gpioint_groups >= S5P_GPIOINT_GROUP_COUNT) 186 if (used_gpioint_groups >= S5P_GPIOINT_GROUP_COUNT)
176 return -ENOMEM; 187 return -ENOMEM;
177 188
189 list_for_each_entry(bank, &banks, list) {
190 if (group >= bank->start &&
191 group < bank->start + bank->nr_groups)
192 break;
193 }
194 if (!bank)
195 return -EINVAL;
196
197 if (!bank->handler) {
198 bank->chips = kzalloc(sizeof(struct s3c_gpio_chip *) *
199 bank->nr_groups, GFP_KERNEL);
200 if (!bank->chips)
201 return -ENOMEM;
202
203 set_irq_chained_handler(bank->irq, s5p_gpioint_handler);
204 set_irq_data(bank->irq, bank);
205 bank->handler = s5p_gpioint_handler;
206 printk(KERN_INFO "Registered chained gpio int handler for interrupt %d.\n",
207 bank->irq);
208 }
209
210 /*
211 * chained GPIO irq has been sucessfully registered, allocate new gpio
212 * int group and assign irq nubmers
213 */
214
178 chip->irq_base = S5P_GPIOINT_BASE + 215 chip->irq_base = S5P_GPIOINT_BASE +
179 used_gpioint_groups * S5P_GPIOINT_GROUP_SIZE; 216 used_gpioint_groups * S5P_GPIOINT_GROUP_SIZE;
180 used_gpioint_groups++; 217 used_gpioint_groups++;
181 218
182 if (!handler_registered) { 219 bank->chips[group - bank->start] = chip;
183 set_irq_chained_handler(IRQ_GPIOINT, s5p_gpioint_handler);
184 handler_registered = 1;
185 }
186
187 irq_chips[group] = chip;
188 for (i = 0; i < chip->chip.ngpio; i++) { 220 for (i = 0; i < chip->chip.ngpio; i++) {
189 irq = chip->irq_base + i; 221 irq = chip->irq_base + i;
190 set_irq_chip(irq, &s5p_gpioint); 222 set_irq_chip(irq, &s5p_gpioint);
@@ -221,3 +253,19 @@ int __init s5p_register_gpio_interrupt(int pin)
221 } 253 }
222 return ret; 254 return ret;
223} 255}
256
257int __init s5p_register_gpioint_bank(int chain_irq, int start, int nr_groups)
258{
259 struct s5p_gpioint_bank *bank;
260
261 bank = kzalloc(sizeof(*bank), GFP_KERNEL);
262 if (!bank)
263 return -ENOMEM;
264
265 bank->start = start;
266 bank->nr_groups = nr_groups;
267 bank->irq = chain_irq;
268
269 list_add_tail(&bank->list, &banks);
270 return 0;
271}
diff --git a/arch/arm/plat-samsung/include/plat/gpio-cfg.h b/arch/arm/plat-samsung/include/plat/gpio-cfg.h
index e4b5cf126fa9..5e04fa6eda74 100644
--- a/arch/arm/plat-samsung/include/plat/gpio-cfg.h
+++ b/arch/arm/plat-samsung/include/plat/gpio-cfg.h
@@ -225,4 +225,20 @@ extern int s5p_gpio_set_drvstr(unsigned int pin, s5p_gpio_drvstr_t drvstr);
225 */ 225 */
226extern int s5p_register_gpio_interrupt(int pin); 226extern int s5p_register_gpio_interrupt(int pin);
227 227
228/** s5p_register_gpioint_bank() - add gpio bank for further gpio interrupt
229 * registration (see s5p_register_gpio_interrupt function)
230 * @chain_irq: chained irq number for the gpio int handler for this bank
231 * @start: start gpio group number of this bank
232 * @nr_groups: number of gpio groups handled by this bank
233 *
234 * This functions registers initial information about gpio banks that
235 * can be later used by the s5p_register_gpio_interrupt() function to
236 * enable support for gpio interrupt for particular gpio group.
237 */
238#ifdef CONFIG_S5P_GPIO_INT
239extern int s5p_register_gpioint_bank(int chain_irq, int start, int nr_groups);
240#else
241#define s5p_register_gpioint_bank(chain_irq, start, nr_groups) do { } while (0)
242#endif
243
228#endif /* __PLAT_GPIO_CFG_H */ 244#endif /* __PLAT_GPIO_CFG_H */