Date: | 2011-05-31 13:32:47 (12 years 6 months ago) |
---|---|
Author: | Lars C. |
Commit: | 5db3e85d4a66b3dcb3be1ab41de72163b3144a57 |
Message: | MIPS: JZ4740: Use generic irq chip Use the generic irq chip framework to implement the jz4740 INTC and GPIO irq chips. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Cc: Thomas Gleixner <tglx@linutronix.de> |
Files: |
arch/mips/Kconfig (1 diff) arch/mips/jz4740/gpio.c (9 diffs) arch/mips/jz4740/irq.c (5 diffs) arch/mips/jz4740/irq.h (1 diff) arch/mips/jz4740/pm.c (2 diffs) |
Change Details
arch/mips/Kconfig | ||
---|---|---|
212 | 212 | select HAVE_PWM |
213 | 213 | select HAVE_CLK |
214 | 214 | select CPU_SUPPORTS_CPUFREQ |
215 | select GENERIC_IRQ_CHIP | |
215 | 216 | |
216 | 217 | config LANTIQ |
217 | 218 | bool "Lantiq based platforms" |
arch/mips/jz4740/gpio.c | ||
---|---|---|
17 | 17 | #include <linux/module.h> |
18 | 18 | #include <linux/init.h> |
19 | 19 | |
20 | #include <linux/spinlock.h> | |
21 | #include <linux/syscore_ops.h> | |
22 | 20 | #include <linux/io.h> |
23 | 21 | #include <linux/gpio.h> |
24 | 22 | #include <linux/delay.h> |
... | ... | |
30 | 28 | |
31 | 29 | #include <asm/mach-jz4740/base.h> |
32 | 30 | |
31 | #include "irq.h" | |
32 | ||
33 | 33 | #define JZ4740_GPIO_BASE_A (32*0) |
34 | 34 | #define JZ4740_GPIO_BASE_B (32*1) |
35 | 35 | #define JZ4740_GPIO_BASE_C (32*2) |
... | ... | |
77 | 77 | struct jz_gpio_chip { |
78 | 78 | unsigned int irq; |
79 | 79 | unsigned int irq_base; |
80 | uint32_t wakeup; | |
81 | uint32_t suspend_mask; | |
82 | 80 | uint32_t edge_trigger_both; |
83 | 81 | |
84 | 82 | void __iomem *base; |
85 | 83 | |
86 | spinlock_t lock; | |
87 | ||
88 | 84 | struct gpio_chip gpio_chip; |
89 | 85 | }; |
90 | 86 | |
... | ... | |
102 | 98 | |
103 | 99 | static inline struct jz_gpio_chip *irq_to_jz_gpio_chip(struct irq_data *data) |
104 | 100 | { |
105 | return irq_data_get_irq_chip_data(data); | |
101 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); | |
102 | return gc->private; | |
106 | 103 | } |
107 | 104 | |
108 | 105 | static inline void jz_gpio_write_bit(unsigned int gpio, unsigned int reg) |
... | ... | |
329 | 326 | writel(IRQ_TO_BIT(data->irq), chip->base + reg); |
330 | 327 | } |
331 | 328 | |
332 | static void jz_gpio_irq_mask(struct irq_data *data) | |
333 | { | |
334 | jz_gpio_set_irq_bit(data, JZ_REG_GPIO_MASK_SET); | |
335 | }; | |
336 | ||
337 | 329 | static void jz_gpio_irq_unmask(struct irq_data *data) |
338 | 330 | { |
339 | 331 | struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(data); |
340 | 332 | |
341 | 333 | jz_gpio_check_trigger_both(chip, data->irq); |
342 | ||
343 | jz_gpio_set_irq_bit(data, JZ_REG_GPIO_MASK_CLEAR); | |
334 | irq_gc_unmask_enable_reg(data); | |
344 | 335 | }; |
345 | 336 | |
346 | 337 | /* TODO: Check if function is gpio */ |
... | ... | |
353 | 344 | |
354 | 345 | static void jz_gpio_irq_shutdown(struct irq_data *data) |
355 | 346 | { |
356 | jz_gpio_irq_mask(data); | |
347 | irq_gc_mask_disable_reg(data); | |
357 | 348 | |
358 | 349 | /* Set direction to input */ |
359 | 350 | jz_gpio_set_irq_bit(data, JZ_REG_GPIO_DIRECTION_CLEAR); |
360 | 351 | jz_gpio_set_irq_bit(data, JZ_REG_GPIO_SELECT_CLEAR); |
361 | 352 | } |
362 | 353 | |
363 | static void jz_gpio_irq_ack(struct irq_data *data) | |
364 | { | |
365 | jz_gpio_set_irq_bit(data, JZ_REG_GPIO_FLAG_CLEAR); | |
366 | }; | |
367 | ||
368 | 354 | static int jz_gpio_irq_set_type(struct irq_data *data, unsigned int flow_type) |
369 | 355 | { |
370 | 356 | struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(data); |
... | ... | |
408 | 394 | static int jz_gpio_irq_set_wake(struct irq_data *data, unsigned int on) |
409 | 395 | { |
410 | 396 | struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(data); |
411 | spin_lock(&chip->lock); | |
412 | if (on) | |
413 | chip->wakeup |= IRQ_TO_BIT(data->irq); | |
414 | else | |
415 | chip->wakeup &= ~IRQ_TO_BIT(data->irq); | |
416 | spin_unlock(&chip->lock); | |
417 | 397 | |
398 | irq_gc_set_wake(data, on); | |
418 | 399 | irq_set_irq_wake(chip->irq, on); |
400 | ||
419 | 401 | return 0; |
420 | 402 | } |
421 | 403 | |
422 | static struct irq_chip jz_gpio_irq_chip = { | |
423 | .name = "GPIO", | |
424 | .irq_mask = jz_gpio_irq_mask, | |
425 | .irq_unmask = jz_gpio_irq_unmask, | |
426 | .irq_ack = jz_gpio_irq_ack, | |
427 | .irq_startup = jz_gpio_irq_startup, | |
428 | .irq_shutdown = jz_gpio_irq_shutdown, | |
429 | .irq_set_type = jz_gpio_irq_set_type, | |
430 | .irq_set_wake = jz_gpio_irq_set_wake, | |
431 | .flags = IRQCHIP_SET_TYPE_MASKED, | |
432 | }; | |
433 | ||
434 | /* | |
435 | * This lock class tells lockdep that GPIO irqs are in a different | |
436 | * category than their parents, so it won't report false recursion. | |
437 | */ | |
438 | static struct lock_class_key gpio_lock_class; | |
439 | ||
440 | 404 | #define JZ4740_GPIO_CHIP(_bank) { \ |
441 | 405 | .irq_base = JZ4740_IRQ_GPIO_BASE_ ## _bank, \ |
442 | 406 | .gpio_chip = { \ |
... | ... | |
458 | 422 | JZ4740_GPIO_CHIP(D), |
459 | 423 | }; |
460 | 424 | |
461 | static void jz4740_gpio_suspend_chip(struct jz_gpio_chip *chip) | |
462 | { | |
463 | chip->suspend_mask = readl(chip->base + JZ_REG_GPIO_MASK); | |
464 | writel(~(chip->wakeup), chip->base + JZ_REG_GPIO_MASK_SET); | |
465 | writel(chip->wakeup, chip->base + JZ_REG_GPIO_MASK_CLEAR); | |
466 | } | |
467 | ||
468 | static int jz4740_gpio_suspend(void) | |
469 | { | |
470 | int i; | |
471 | ||
472 | for (i = 0; i < ARRAY_SIZE(jz4740_gpio_chips); i++) | |
473 | jz4740_gpio_suspend_chip(&jz4740_gpio_chips[i]); | |
474 | ||
475 | return 0; | |
476 | } | |
477 | ||
478 | static void jz4740_gpio_resume_chip(struct jz_gpio_chip *chip) | |
425 | static void jz4740_gpio_chip_init(struct jz_gpio_chip *chip, unsigned int id) | |
479 | 426 | { |
480 | uint32_t mask = chip->suspend_mask; | |
427 | struct irq_chip_generic *gc; | |
428 | struct irq_chip_type *ct; | |
481 | 429 | |
482 | writel(~mask, chip->base + JZ_REG_GPIO_MASK_CLEAR); | |
483 | writel(mask, chip->base + JZ_REG_GPIO_MASK_SET); | |
484 | } | |
430 | chip->base = ioremap(JZ4740_GPIO_BASE_ADDR + (id * 0x100), 0x100); | |
485 | 431 | |
486 | static void jz4740_gpio_resume(void) | |
487 | { | |
488 | int i; | |
432 | chip->irq = JZ4740_IRQ_INTC_GPIO(id); | |
433 | irq_set_handler_data(chip->irq, chip); | |
434 | irq_set_chained_handler(chip->irq, jz_gpio_irq_demux_handler); | |
489 | 435 | |
490 | for (i = ARRAY_SIZE(jz4740_gpio_chips) - 1; i >= 0 ; i--) | |
491 | jz4740_gpio_resume_chip(&jz4740_gpio_chips[i]); | |
492 | } | |
436 | gc = irq_alloc_generic_chip(chip->gpio_chip.label, 1, chip->irq_base, | |
437 | chip->base, handle_level_irq); | |
493 | 438 | |
494 | static struct syscore_ops jz4740_gpio_syscore_ops = { | |
495 | .suspend = jz4740_gpio_suspend, | |
496 | .resume = jz4740_gpio_resume, | |
497 | }; | |
439 | gc->wake_enabled = IRQ_MSK(chip->gpio_chip.ngpio); | |
440 | gc->private = chip; | |
498 | 441 | |
499 | static void jz4740_gpio_chip_init(struct jz_gpio_chip *chip, unsigned int id) | |
500 | { | |
501 | int irq; | |
442 | ct = gc->chip_types; | |
443 | ct->regs.enable = JZ_REG_GPIO_MASK_CLEAR; | |
444 | ct->regs.disable = JZ_REG_GPIO_MASK_SET; | |
445 | ct->regs.ack = JZ_REG_GPIO_FLAG_CLEAR; | |
502 | 446 | |
503 | spin_lock_init(&chip->lock); | |
447 | ct->chip.name = "GPIO"; | |
448 | ct->chip.irq_mask = irq_gc_mask_disable_reg; | |
449 | ct->chip.irq_unmask = jz_gpio_irq_unmask; | |
450 | ct->chip.irq_ack = irq_gc_ack; | |
451 | ct->chip.irq_suspend = jz4740_irq_suspend; | |
452 | ct->chip.irq_resume = jz4740_irq_resume; | |
453 | ct->chip.irq_startup = jz_gpio_irq_startup; | |
454 | ct->chip.irq_shutdown = jz_gpio_irq_shutdown; | |
455 | ct->chip.irq_set_type = jz_gpio_irq_set_type; | |
456 | ct->chip.irq_set_wake = jz_gpio_irq_set_wake; | |
457 | ct->chip.flags = IRQCHIP_SET_TYPE_MASKED; | |
504 | 458 | |
505 | chip->base = ioremap(JZ4740_GPIO_BASE_ADDR + (id * 0x100), 0x100); | |
459 | irq_setup_generic_chip(gc, IRQ_MSK(chip->gpio_chip.ngpio), | |
460 | IRQ_GC_INIT_NESTED_LOCK, 0, IRQ_NOPROBE | IRQ_LEVEL); | |
506 | 461 | |
507 | 462 | gpiochip_add(&chip->gpio_chip); |
508 | ||
509 | chip->irq = JZ4740_IRQ_INTC_GPIO(id); | |
510 | irq_set_handler_data(chip->irq, chip); | |
511 | irq_set_chained_handler(chip->irq, jz_gpio_irq_demux_handler); | |
512 | ||
513 | for (irq = chip->irq_base; irq < chip->irq_base + chip->gpio_chip.ngpio; ++irq) { | |
514 | irq_set_lockdep_class(irq, &gpio_lock_class); | |
515 | irq_set_chip_data(irq, chip); | |
516 | irq_set_chip_and_handler(irq, &jz_gpio_irq_chip, | |
517 | handle_level_irq); | |
518 | } | |
519 | 463 | } |
520 | 464 | |
521 | 465 | static int __init jz4740_gpio_init(void) |
... | ... | |
525 | 469 | for (i = 0; i < ARRAY_SIZE(jz4740_gpio_chips); ++i) |
526 | 470 | jz4740_gpio_chip_init(&jz4740_gpio_chips[i], i); |
527 | 471 | |
528 | register_syscore_ops(&jz4740_gpio_syscore_ops); | |
529 | ||
530 | 472 | printk(KERN_INFO "JZ4740 GPIO initialized\n"); |
531 | 473 | |
532 | 474 | return 0; |
arch/mips/jz4740/irq.c | ||
---|---|---|
32 | 32 | #include <asm/mach-jz4740/base.h> |
33 | 33 | |
34 | 34 | static void __iomem *jz_intc_base; |
35 | static uint32_t jz_intc_wakeup; | |
36 | static uint32_t jz_intc_saved; | |
37 | 35 | |
38 | 36 | #define JZ_REG_INTC_STATUS 0x00 |
39 | 37 | #define JZ_REG_INTC_MASK 0x04 |
... | ... | |
41 | 39 | #define JZ_REG_INTC_CLEAR_MASK 0x0c |
42 | 40 | #define JZ_REG_INTC_PENDING 0x10 |
43 | 41 | |
44 | #define IRQ_BIT(x) BIT((x) - JZ4740_IRQ_BASE) | |
45 | ||
46 | static inline unsigned long intc_irq_bit(struct irq_data *data) | |
42 | static irqreturn_t jz4740_cascade(int irq, void *data) | |
47 | 43 | { |
48 | return (unsigned long)irq_data_get_irq_chip_data(data); | |
49 | } | |
44 | uint32_t irq_reg; | |
50 | 45 | |
51 | static void intc_irq_unmask(struct irq_data *data) | |
52 | { | |
53 | writel(intc_irq_bit(data), jz_intc_base + JZ_REG_INTC_CLEAR_MASK); | |
54 | } | |
46 | irq_reg = readl(jz_intc_base + JZ_REG_INTC_PENDING); | |
55 | 47 | |
56 | static void intc_irq_mask(struct irq_data *data) | |
57 | { | |
58 | writel(intc_irq_bit(data), jz_intc_base + JZ_REG_INTC_SET_MASK); | |
48 | if (irq_reg) | |
49 | generic_handle_irq(__fls(irq_reg) + JZ4740_IRQ_BASE); | |
50 | ||
51 | return IRQ_HANDLED; | |
59 | 52 | } |
60 | 53 | |
61 | static int intc_irq_set_wake(struct irq_data *data, unsigned int on) | |
54 | static void jz4740_irq_set_mask(struct irq_chip_generic *gc, uint32_t mask) | |
62 | 55 | { |
63 | if (on) | |
64 | jz_intc_wakeup |= intc_irq_bit(data); | |
65 | else | |
66 | jz_intc_wakeup &= ~intc_irq_bit(data); | |
56 | struct irq_chip_regs *regs = &gc->chip_types->regs; | |
67 | 57 | |
68 | return 0; | |
58 | writel(mask, gc->reg_base + regs->enable); | |
59 | writel(~mask, gc->reg_base + regs->disable); | |
69 | 60 | } |
70 | 61 | |
71 | static struct irq_chip intc_irq_type = { | |
72 | .name = "INTC", | |
73 | .irq_mask = intc_irq_mask, | |
74 | .irq_mask_ack = intc_irq_mask, | |
75 | .irq_unmask = intc_irq_unmask, | |
76 | .irq_set_wake = intc_irq_set_wake, | |
77 | }; | |
78 | ||
79 | static irqreturn_t jz4740_cascade(int irq, void *data) | |
62 | void jz4740_irq_suspend(struct irq_data *data) | |
80 | 63 | { |
81 | uint32_t irq_reg; | |
82 | ||
83 | irq_reg = readl(jz_intc_base + JZ_REG_INTC_PENDING); | |
84 | ||
85 | if (irq_reg) | |
86 | generic_handle_irq(__fls(irq_reg) + JZ4740_IRQ_BASE); | |
64 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); | |
65 | jz4740_irq_set_mask(gc, gc->wake_active); | |
66 | } | |
87 | 67 | |
88 | return IRQ_HANDLED; | |
68 | void jz4740_irq_resume(struct irq_data *data) | |
69 | { | |
70 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); | |
71 | jz4740_irq_set_mask(gc, gc->mask_cache); | |
89 | 72 | } |
90 | 73 | |
91 | 74 | static struct irqaction jz4740_cascade_action = { |
... | ... | |
95 | 78 | |
96 | 79 | void __init arch_init_irq(void) |
97 | 80 | { |
98 | int i; | |
81 | struct irq_chip_generic *gc; | |
82 | struct irq_chip_type *ct; | |
83 | ||
99 | 84 | mips_cpu_irq_init(); |
100 | 85 | |
101 | 86 | jz_intc_base = ioremap(JZ4740_INTC_BASE_ADDR, 0x14); |
... | ... | |
103 | 88 | /* Mask all irqs */ |
104 | 89 | writel(0xffffffff, jz_intc_base + JZ_REG_INTC_SET_MASK); |
105 | 90 | |
106 | for (i = JZ4740_IRQ_BASE; i < JZ4740_IRQ_BASE + 32; i++) { | |
107 | irq_set_chip_data(i, (void *)IRQ_BIT(i)); | |
108 | irq_set_chip_and_handler(i, &intc_irq_type, handle_level_irq); | |
109 | } | |
91 | gc = irq_alloc_generic_chip("INTC", 1, JZ4740_IRQ_BASE, jz_intc_base, | |
92 | handle_level_irq); | |
93 | ||
94 | gc->wake_enabled = IRQ_MSK(32); | |
95 | ||
96 | ct = gc->chip_types; | |
97 | ct->regs.enable = JZ_REG_INTC_CLEAR_MASK; | |
98 | ct->regs.disable = JZ_REG_INTC_SET_MASK; | |
99 | ct->chip.irq_unmask = irq_gc_unmask_enable_reg; | |
100 | ct->chip.irq_mask = irq_gc_mask_disable_reg; | |
101 | ct->chip.irq_mask_ack = irq_gc_mask_disable_reg; | |
102 | ct->chip.irq_set_wake = irq_gc_set_wake; | |
103 | ct->chip.irq_suspend = jz4740_irq_suspend; | |
104 | ct->chip.irq_resume = jz4740_irq_resume; | |
105 | ||
106 | irq_setup_generic_chip(gc, IRQ_MSK(32), 0, 0, IRQ_NOPROBE | IRQ_LEVEL); | |
110 | 107 | |
111 | 108 | setup_irq(2, &jz4740_cascade_action); |
112 | 109 | } |
... | ... | |
122 | 119 | spurious_interrupt(); |
123 | 120 | } |
124 | 121 | |
125 | void jz4740_intc_suspend(void) | |
126 | { | |
127 | jz_intc_saved = readl(jz_intc_base + JZ_REG_INTC_MASK); | |
128 | writel(~jz_intc_wakeup, jz_intc_base + JZ_REG_INTC_SET_MASK); | |
129 | writel(jz_intc_wakeup, jz_intc_base + JZ_REG_INTC_CLEAR_MASK); | |
130 | } | |
131 | ||
132 | void jz4740_intc_resume(void) | |
133 | { | |
134 | writel(~jz_intc_saved, jz_intc_base + JZ_REG_INTC_CLEAR_MASK); | |
135 | writel(jz_intc_saved, jz_intc_base + JZ_REG_INTC_SET_MASK); | |
136 | } | |
137 | ||
138 | 122 | #ifdef CONFIG_DEBUG_FS |
139 | 123 | |
140 | 124 | static inline void intc_seq_reg(struct seq_file *s, const char *name, |
arch/mips/jz4740/irq.h | ||
---|---|---|
15 | 15 | #ifndef __MIPS_JZ4740_IRQ_H__ |
16 | 16 | #define __MIPS_JZ4740_IRQ_H__ |
17 | 17 | |
18 | extern void jz4740_intc_suspend(void); | |
19 | extern void jz4740_intc_resume(void); | |
18 | #include <linux/irq.h> | |
19 | ||
20 | extern void jz4740_irq_suspend(struct irq_data *data); | |
21 | extern void jz4740_irq_resume(struct irq_data *data); | |
20 | 22 | |
21 | 23 | #endif |
arch/mips/jz4740/pm.c | ||
---|---|---|
21 | 21 | #include <asm/mach-jz4740/clock.h> |
22 | 22 | |
23 | 23 | #include "clock.h" |
24 | #include "irq.h" | |
25 | 24 | |
26 | 25 | static int jz4740_pm_enter(suspend_state_t state) |
27 | 26 | { |
28 | jz4740_intc_suspend(); | |
29 | 27 | jz4740_clock_suspend(); |
30 | 28 | |
31 | 29 | jz4740_clock_set_wait_mode(JZ4740_WAIT_MODE_SLEEP); |
... | ... | |
37 | 35 | jz4740_clock_set_wait_mode(JZ4740_WAIT_MODE_IDLE); |
38 | 36 | |
39 | 37 | jz4740_clock_resume(); |
40 | jz4740_intc_resume(); | |
41 | 38 | |
42 | 39 | return 0; |
43 | 40 | } |
Branches:
ben-wpan
ben-wpan-stefan
5396a9238205f20f811ea57898980d3ca82df0b6
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9