diff options
author | Yoshinori Sato <ysato@users.sourceforge.jp> | 2015-05-09 13:30:47 -0400 |
---|---|---|
committer | Yoshinori Sato <ysato@users.sourceforge.jp> | 2015-06-23 00:35:56 -0400 |
commit | 8a7644821ae00b76e0c039f9128ee584dda146a8 (patch) | |
tree | 2852dc6bfe50f4fe73dbbf5bfad0c49299225054 | |
parent | 618b902d8c098f2fff188119da7b3184c4bc5483 (diff) |
h8300: IRQ chip driver
Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
-rw-r--r-- | Documentation/devicetree/bindings/interrupt-controller/renesas,h8300h-intc.txt | 22 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/interrupt-controller/renesas,h8s-intc.txt | 22 | ||||
-rw-r--r-- | drivers/irqchip/Kconfig | 8 | ||||
-rw-r--r-- | drivers/irqchip/Makefile | 2 | ||||
-rw-r--r-- | drivers/irqchip/irq-renesas-h8300h.c | 95 | ||||
-rw-r--r-- | drivers/irqchip/irq-renesas-h8s.c | 101 |
6 files changed, 250 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/interrupt-controller/renesas,h8300h-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/renesas,h8300h-intc.txt new file mode 100644 index 000000000000..56e8d82aff34 --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/renesas,h8300h-intc.txt | |||
@@ -0,0 +1,22 @@ | |||
1 | * H8/300H Interrupt controller | ||
2 | |||
3 | Required properties: | ||
4 | |||
5 | - compatible: has to be "renesas,h8300h-intc", "renesas,h8300-intc" as fallback. | ||
6 | - #interrupt-cells: has to be <2>: an interrupt index and flags, as defined in | ||
7 | interrupts.txt in this directory | ||
8 | - regs: Base address of interrupt controller registers. | ||
9 | |||
10 | Optional properties: | ||
11 | |||
12 | - any properties, listed in interrupts.txt, and any standard resource allocation | ||
13 | properties | ||
14 | |||
15 | Example: | ||
16 | |||
17 | h8intc: interrupt-controller@fee012 { | ||
18 | compatible = "renesas,h8300h-intc", "renesas,h8300-intc"; | ||
19 | #interrupt-cells = <2>; | ||
20 | interrupt-controller; | ||
21 | reg = <0xfee012 7>; | ||
22 | }; | ||
diff --git a/Documentation/devicetree/bindings/interrupt-controller/renesas,h8s-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/renesas,h8s-intc.txt new file mode 100644 index 000000000000..faded2b1559b --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/renesas,h8s-intc.txt | |||
@@ -0,0 +1,22 @@ | |||
1 | * H8S Interrupt controller | ||
2 | |||
3 | Required properties: | ||
4 | |||
5 | - compatible: has to be "renesas,h8s-intc", "renesas,h8300-intc" as fallback. | ||
6 | - #interrupt-cells: has to be <2>: an interrupt index and flags, as defined in | ||
7 | interrupts.txt in this directory | ||
8 | - regs: Base address of interrupt controller registers. | ||
9 | |||
10 | Optional properties: | ||
11 | |||
12 | - any properties, listed in interrupts.txt, and any standard resource allocation | ||
13 | properties | ||
14 | |||
15 | Example: | ||
16 | |||
17 | h8intc: interrupt-controller@fffe00 { | ||
18 | compatible = "renesas,h8s-intc", "renesas,h8300-intc"; | ||
19 | #interrupt-cells = <2>; | ||
20 | interrupt-controller; | ||
21 | reg = <0xfffe00 24>; | ||
22 | }; | ||
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 6de62a96e79c..998681587d1e 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig | |||
@@ -158,3 +158,11 @@ config KEYSTONE_IRQ | |||
158 | config MIPS_GIC | 158 | config MIPS_GIC |
159 | bool | 159 | bool |
160 | select MIPS_CM | 160 | select MIPS_CM |
161 | |||
162 | config RENESAS_H8300H_INTC | ||
163 | bool | ||
164 | select IRQ_DOMAIN | ||
165 | |||
166 | config RENESAS_H8S_INTC | ||
167 | bool | ||
168 | select IRQ_DOMAIN \ No newline at end of file | ||
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index dda4927e47a6..f8efb7087760 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile | |||
@@ -47,3 +47,5 @@ obj-$(CONFIG_KEYSTONE_IRQ) += irq-keystone.o | |||
47 | obj-$(CONFIG_MIPS_GIC) += irq-mips-gic.o | 47 | obj-$(CONFIG_MIPS_GIC) += irq-mips-gic.o |
48 | obj-$(CONFIG_ARCH_MEDIATEK) += irq-mtk-sysirq.o | 48 | obj-$(CONFIG_ARCH_MEDIATEK) += irq-mtk-sysirq.o |
49 | obj-$(CONFIG_ARCH_DIGICOLOR) += irq-digicolor.o | 49 | obj-$(CONFIG_ARCH_DIGICOLOR) += irq-digicolor.o |
50 | obj-$(CONFIG_RENESAS_H8300H_INTC) += irq-renesas-h8300h.o | ||
51 | obj-$(CONFIG_RENESAS_H8S_INTC) += irq-renesas-h8s.o | ||
diff --git a/drivers/irqchip/irq-renesas-h8300h.c b/drivers/irqchip/irq-renesas-h8300h.c new file mode 100644 index 000000000000..1870e6bd3dd9 --- /dev/null +++ b/drivers/irqchip/irq-renesas-h8300h.c | |||
@@ -0,0 +1,95 @@ | |||
1 | /* | ||
2 | * H8/300H interrupt controller driver | ||
3 | * | ||
4 | * Copyright 2015 Yoshinori Sato <ysato@users.sourceforge.jp> | ||
5 | */ | ||
6 | |||
7 | #include <linux/init.h> | ||
8 | #include <linux/irq.h> | ||
9 | #include <linux/irqchip.h> | ||
10 | #include <linux/of_address.h> | ||
11 | #include <linux/of_irq.h> | ||
12 | #include <asm/io.h> | ||
13 | |||
14 | #include "irqchip.h" | ||
15 | |||
16 | static const char ipr_bit[] = { | ||
17 | 7, 6, 5, 5, | ||
18 | 4, 4, 4, 4, 3, 3, 3, 3, | ||
19 | 2, 2, 2, 2, 1, 1, 1, 1, | ||
20 | 0, 0, 0, 0, 15, 15, 15, 15, | ||
21 | 14, 14, 14, 14, 13, 13, 13, 13, | ||
22 | -1, -1, -1, -1, 11, 11, 11, 11, | ||
23 | 10, 10, 10, 10, 9, 9, 9, 9, | ||
24 | }; | ||
25 | |||
26 | static void *intc_baseaddr; | ||
27 | |||
28 | #define IPR ((unsigned long)intc_baseaddr + 6) | ||
29 | |||
30 | static void h8300h_disable_irq(struct irq_data *data) | ||
31 | { | ||
32 | int bit; | ||
33 | int irq = data->irq - 12; | ||
34 | |||
35 | bit = ipr_bit[irq]; | ||
36 | if (bit >= 0) { | ||
37 | if (bit < 8) | ||
38 | ctrl_bclr(bit & 7, IPR); | ||
39 | else | ||
40 | ctrl_bclr(bit & 7, (IPR+1)); | ||
41 | } | ||
42 | } | ||
43 | |||
44 | static void h8300h_enable_irq(struct irq_data *data) | ||
45 | { | ||
46 | int bit; | ||
47 | int irq = data->irq - 12; | ||
48 | |||
49 | bit = ipr_bit[irq]; | ||
50 | if (bit >= 0) { | ||
51 | if (bit < 8) | ||
52 | ctrl_bset(bit & 7, IPR); | ||
53 | else | ||
54 | ctrl_bset(bit & 7, (IPR+1)); | ||
55 | } | ||
56 | } | ||
57 | |||
58 | struct irq_chip h8300h_irq_chip = { | ||
59 | .name = "H8/300H-INTC", | ||
60 | .irq_enable = h8300h_enable_irq, | ||
61 | .irq_disable = h8300h_disable_irq, | ||
62 | }; | ||
63 | |||
64 | static int irq_map(struct irq_domain *h, unsigned int virq, | ||
65 | irq_hw_number_t hw_irq_num) | ||
66 | { | ||
67 | irq_set_chip_and_handler(virq, &h8300h_irq_chip, handle_simple_irq); | ||
68 | |||
69 | return 0; | ||
70 | } | ||
71 | |||
72 | static struct irq_domain_ops irq_ops = { | ||
73 | .map = irq_map, | ||
74 | .xlate = irq_domain_xlate_onecell, | ||
75 | }; | ||
76 | |||
77 | static int __init h8300h_intc_of_init(struct device_node *intc, | ||
78 | struct device_node *parent) | ||
79 | { | ||
80 | struct irq_domain *domain; | ||
81 | |||
82 | intc_baseaddr = of_iomap(intc, 0); | ||
83 | BUG_ON(!intc_baseaddr); | ||
84 | |||
85 | /* All interrupt priority low */ | ||
86 | ctrl_outb(0x00, IPR + 0); | ||
87 | ctrl_outb(0x00, IPR + 1); | ||
88 | |||
89 | domain = irq_domain_add_linear(intc, NR_IRQS, &irq_ops, NULL); | ||
90 | BUG_ON(!domain); | ||
91 | irq_set_default_host(domain); | ||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | IRQCHIP_DECLARE(h8300h_intc, "renesas,h8300h-intc", h8300h_intc_of_init); | ||
diff --git a/drivers/irqchip/irq-renesas-h8s.c b/drivers/irqchip/irq-renesas-h8s.c new file mode 100644 index 000000000000..64425f4de7d9 --- /dev/null +++ b/drivers/irqchip/irq-renesas-h8s.c | |||
@@ -0,0 +1,101 @@ | |||
1 | /* | ||
2 | * H8S interrupt contoller driver | ||
3 | * | ||
4 | * Copyright 2015 Yoshinori Sato <ysato@users.sourceforge.jp> | ||
5 | */ | ||
6 | |||
7 | #include <linux/irq.h> | ||
8 | #include <linux/of_address.h> | ||
9 | #include <linux/of_irq.h> | ||
10 | #include <asm/io.h> | ||
11 | #include "irqchip.h" | ||
12 | |||
13 | static void *intc_baseaddr; | ||
14 | #define IPRA ((unsigned long)intc_baseaddr) | ||
15 | |||
16 | static const unsigned char ipr_table[] = { | ||
17 | 0x03, 0x02, 0x01, 0x00, 0x13, 0x12, 0x11, 0x10, /* 16 - 23 */ | ||
18 | 0x23, 0x22, 0x21, 0x20, 0x33, 0x32, 0x31, 0x30, /* 24 - 31 */ | ||
19 | 0x43, 0x42, 0x41, 0x40, 0x53, 0x53, 0x52, 0x52, /* 32 - 39 */ | ||
20 | 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, /* 40 - 47 */ | ||
21 | 0x50, 0x50, 0x50, 0x50, 0x63, 0x63, 0x63, 0x63, /* 48 - 55 */ | ||
22 | 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, /* 56 - 63 */ | ||
23 | 0x61, 0x61, 0x61, 0x61, 0x60, 0x60, 0x60, 0x60, /* 64 - 71 */ | ||
24 | 0x73, 0x73, 0x73, 0x73, 0x72, 0x72, 0x72, 0x72, /* 72 - 79 */ | ||
25 | 0x71, 0x71, 0x71, 0x71, 0x70, 0x83, 0x82, 0x81, /* 80 - 87 */ | ||
26 | 0x80, 0x80, 0x80, 0x80, 0x93, 0x93, 0x93, 0x93, /* 88 - 95 */ | ||
27 | 0x92, 0x92, 0x92, 0x92, 0x91, 0x91, 0x91, 0x91, /* 96 - 103 */ | ||
28 | 0x90, 0x90, 0x90, 0x90, 0xa3, 0xa3, 0xa3, 0xa3, /* 104 - 111 */ | ||
29 | 0xa2, 0xa2, 0xa2, 0xa2, 0xa1, 0xa1, 0xa1, 0xa1, /* 112 - 119 */ | ||
30 | 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, /* 120 - 127 */ | ||
31 | }; | ||
32 | |||
33 | static void h8s_disable_irq(struct irq_data *data) | ||
34 | { | ||
35 | int pos; | ||
36 | unsigned int addr; | ||
37 | unsigned short pri; | ||
38 | int irq = data->irq; | ||
39 | |||
40 | addr = IPRA + ((ipr_table[irq - 16] & 0xf0) >> 3); | ||
41 | pos = (ipr_table[irq - 16] & 0x0f) * 4; | ||
42 | pri = ~(0x000f << pos); | ||
43 | pri &= ctrl_inw(addr); | ||
44 | ctrl_outw(pri, addr); | ||
45 | } | ||
46 | |||
47 | static void h8s_enable_irq(struct irq_data *data) | ||
48 | { | ||
49 | int pos; | ||
50 | unsigned int addr; | ||
51 | unsigned short pri; | ||
52 | int irq = data->irq; | ||
53 | |||
54 | addr = IPRA + ((ipr_table[irq - 16] & 0xf0) >> 3); | ||
55 | pos = (ipr_table[irq - 16] & 0x0f) * 4; | ||
56 | pri = ~(0x000f << pos); | ||
57 | pri &= ctrl_inw(addr); | ||
58 | pri |= 1 << pos; | ||
59 | ctrl_outw(pri, addr); | ||
60 | } | ||
61 | |||
62 | struct irq_chip h8s_irq_chip = { | ||
63 | .name = "H8S-INTC", | ||
64 | .irq_enable = h8s_enable_irq, | ||
65 | .irq_disable = h8s_disable_irq, | ||
66 | }; | ||
67 | |||
68 | static __init int irq_map(struct irq_domain *h, unsigned int virq, | ||
69 | irq_hw_number_t hw_irq_num) | ||
70 | { | ||
71 | irq_set_chip_and_handler(virq, &h8s_irq_chip, handle_simple_irq); | ||
72 | |||
73 | return 0; | ||
74 | } | ||
75 | |||
76 | static struct irq_domain_ops irq_ops = { | ||
77 | .map = irq_map, | ||
78 | .xlate = irq_domain_xlate_onecell, | ||
79 | }; | ||
80 | |||
81 | static int __init h8s_intc_of_init(struct device_node *intc, | ||
82 | struct device_node *parent) | ||
83 | { | ||
84 | struct irq_domain *domain; | ||
85 | int n; | ||
86 | |||
87 | intc_baseaddr = of_iomap(intc, 0); | ||
88 | BUG_ON(!intc_baseaddr); | ||
89 | |||
90 | /* All interrupt priority is 0 (disable) */ | ||
91 | /* IPRA to IPRK */ | ||
92 | for (n = 0; n <= 'k' - 'a'; n++) | ||
93 | ctrl_outw(0x0000, IPRA + (n * 2)); | ||
94 | |||
95 | domain = irq_domain_add_linear(intc, NR_IRQS, &irq_ops, NULL); | ||
96 | BUG_ON(!domain); | ||
97 | irq_set_default_host(domain); | ||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | IRQCHIP_DECLARE(h8s_intc, "renesas,h8s-intc", h8s_intc_of_init); | ||