diff options
Diffstat (limited to 'drivers/sh/intc.c')
| -rw-r--r-- | drivers/sh/intc.c | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/drivers/sh/intc.c b/drivers/sh/intc.c index 2269fbcaa182..7fb9b5c4669a 100644 --- a/drivers/sh/intc.c +++ b/drivers/sh/intc.c | |||
| @@ -22,6 +22,8 @@ | |||
| 22 | #include <linux/interrupt.h> | 22 | #include <linux/interrupt.h> |
| 23 | #include <linux/bootmem.h> | 23 | #include <linux/bootmem.h> |
| 24 | #include <linux/sh_intc.h> | 24 | #include <linux/sh_intc.h> |
| 25 | #include <linux/sysdev.h> | ||
| 26 | #include <linux/list.h> | ||
| 25 | 27 | ||
| 26 | #define _INTC_MK(fn, mode, addr_e, addr_d, width, shift) \ | 28 | #define _INTC_MK(fn, mode, addr_e, addr_d, width, shift) \ |
| 27 | ((shift) | ((width) << 5) | ((fn) << 9) | ((mode) << 13) | \ | 29 | ((shift) | ((width) << 5) | ((fn) << 9) | ((mode) << 13) | \ |
| @@ -40,6 +42,8 @@ struct intc_handle_int { | |||
| 40 | }; | 42 | }; |
| 41 | 43 | ||
| 42 | struct intc_desc_int { | 44 | struct intc_desc_int { |
| 45 | struct list_head list; | ||
| 46 | struct sys_device sysdev; | ||
| 43 | unsigned long *reg; | 47 | unsigned long *reg; |
| 44 | #ifdef CONFIG_SMP | 48 | #ifdef CONFIG_SMP |
| 45 | unsigned long *smp; | 49 | unsigned long *smp; |
| @@ -52,6 +56,8 @@ struct intc_desc_int { | |||
| 52 | struct irq_chip chip; | 56 | struct irq_chip chip; |
| 53 | }; | 57 | }; |
| 54 | 58 | ||
| 59 | static LIST_HEAD(intc_list); | ||
| 60 | |||
| 55 | #ifdef CONFIG_SMP | 61 | #ifdef CONFIG_SMP |
| 56 | #define IS_SMP(x) x.smp | 62 | #define IS_SMP(x) x.smp |
| 57 | #define INTC_REG(d, x, c) (d->reg[(x)] + ((d->smp[(x)] & 0xff) * c)) | 63 | #define INTC_REG(d, x, c) (d->reg[(x)] + ((d->smp[(x)] & 0xff) * c)) |
| @@ -232,6 +238,11 @@ static void intc_disable(unsigned int irq) | |||
| 232 | } | 238 | } |
| 233 | } | 239 | } |
| 234 | 240 | ||
| 241 | static int intc_set_wake(unsigned int irq, unsigned int on) | ||
| 242 | { | ||
| 243 | return 0; /* allow wakeup, but setup hardware in intc_suspend() */ | ||
| 244 | } | ||
| 245 | |||
| 235 | #if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A) | 246 | #if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A) |
| 236 | static void intc_mask_ack(unsigned int irq) | 247 | static void intc_mask_ack(unsigned int irq) |
| 237 | { | 248 | { |
| @@ -664,6 +675,9 @@ void __init register_intc_controller(struct intc_desc *desc) | |||
| 664 | 675 | ||
| 665 | d = alloc_bootmem(sizeof(*d)); | 676 | d = alloc_bootmem(sizeof(*d)); |
| 666 | 677 | ||
| 678 | INIT_LIST_HEAD(&d->list); | ||
| 679 | list_add(&d->list, &intc_list); | ||
| 680 | |||
| 667 | d->nr_reg = desc->mask_regs ? desc->nr_mask_regs * 2 : 0; | 681 | d->nr_reg = desc->mask_regs ? desc->nr_mask_regs * 2 : 0; |
| 668 | d->nr_reg += desc->prio_regs ? desc->nr_prio_regs * 2 : 0; | 682 | d->nr_reg += desc->prio_regs ? desc->nr_prio_regs * 2 : 0; |
| 669 | d->nr_reg += desc->sense_regs ? desc->nr_sense_regs : 0; | 683 | d->nr_reg += desc->sense_regs ? desc->nr_sense_regs : 0; |
| @@ -707,7 +721,11 @@ void __init register_intc_controller(struct intc_desc *desc) | |||
| 707 | d->chip.mask = intc_disable; | 721 | d->chip.mask = intc_disable; |
| 708 | d->chip.unmask = intc_enable; | 722 | d->chip.unmask = intc_enable; |
| 709 | d->chip.mask_ack = intc_disable; | 723 | d->chip.mask_ack = intc_disable; |
| 724 | d->chip.enable = intc_enable; | ||
| 725 | d->chip.disable = intc_disable; | ||
| 726 | d->chip.shutdown = intc_disable; | ||
| 710 | d->chip.set_type = intc_set_sense; | 727 | d->chip.set_type = intc_set_sense; |
| 728 | d->chip.set_wake = intc_set_wake; | ||
| 711 | 729 | ||
| 712 | #if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A) | 730 | #if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A) |
| 713 | if (desc->ack_regs) { | 731 | if (desc->ack_regs) { |
| @@ -758,3 +776,53 @@ void __init register_intc_controller(struct intc_desc *desc) | |||
| 758 | intc_register_irq(desc, d, vect->enum_id, evt2irq(vect->vect)); | 776 | intc_register_irq(desc, d, vect->enum_id, evt2irq(vect->vect)); |
| 759 | } | 777 | } |
| 760 | } | 778 | } |
| 779 | |||
| 780 | static int intc_suspend(struct sys_device *dev, pm_message_t state) | ||
| 781 | { | ||
| 782 | struct intc_desc_int *d; | ||
| 783 | struct irq_desc *desc; | ||
| 784 | int irq; | ||
| 785 | |||
| 786 | /* get intc controller associated with this sysdev */ | ||
| 787 | d = container_of(dev, struct intc_desc_int, sysdev); | ||
| 788 | |||
| 789 | /* enable wakeup irqs belonging to this intc controller */ | ||
| 790 | for_each_irq_desc(irq, desc) { | ||
| 791 | if ((desc->status & IRQ_WAKEUP) && (desc->chip == &d->chip)) | ||
| 792 | intc_enable(irq); | ||
| 793 | } | ||
| 794 | |||
| 795 | return 0; | ||
| 796 | } | ||
| 797 | |||
| 798 | static struct sysdev_class intc_sysdev_class = { | ||
| 799 | .name = "intc", | ||
| 800 | .suspend = intc_suspend, | ||
| 801 | }; | ||
| 802 | |||
| 803 | /* register this intc as sysdev to allow suspend/resume */ | ||
| 804 | static int __init register_intc_sysdevs(void) | ||
| 805 | { | ||
| 806 | struct intc_desc_int *d; | ||
| 807 | int error; | ||
| 808 | int id = 0; | ||
| 809 | |||
| 810 | error = sysdev_class_register(&intc_sysdev_class); | ||
| 811 | if (!error) { | ||
| 812 | list_for_each_entry(d, &intc_list, list) { | ||
| 813 | d->sysdev.id = id; | ||
| 814 | d->sysdev.cls = &intc_sysdev_class; | ||
| 815 | error = sysdev_register(&d->sysdev); | ||
| 816 | if (error) | ||
| 817 | break; | ||
| 818 | id++; | ||
| 819 | } | ||
| 820 | } | ||
| 821 | |||
| 822 | if (error) | ||
| 823 | pr_warning("intc: sysdev registration error\n"); | ||
| 824 | |||
| 825 | return error; | ||
| 826 | } | ||
| 827 | |||
| 828 | device_initcall(register_intc_sysdevs); | ||
