]>
Commit | Line | Data |
---|---|---|
1a59d1b8 | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
c53c9cf6 AV |
2 | /* |
3 | * arch/arm/mach-ks8695/irq.c | |
4 | * | |
5 | * Copyright (C) 2006 Ben Dooks <ben@simtec.co.uk> | |
6 | * Copyright (C) 2006 Simtec Electronics | |
c53c9cf6 AV |
7 | */ |
8 | ||
9 | #include <linux/init.h> | |
10 | #include <linux/module.h> | |
11 | #include <linux/interrupt.h> | |
12 | #include <linux/ioport.h> | |
edbaa603 | 13 | #include <linux/device.h> |
fced80c7 | 14 | #include <linux/io.h> |
c53c9cf6 | 15 | |
a09e64fb | 16 | #include <mach/hardware.h> |
c53c9cf6 | 17 | #include <asm/irq.h> |
c53c9cf6 AV |
18 | |
19 | #include <asm/mach/irq.h> | |
20 | ||
a09e64fb RK |
21 | #include <mach/regs-irq.h> |
22 | #include <mach/regs-gpio.h> | |
c53c9cf6 | 23 | |
3cdb791b | 24 | static void ks8695_irq_mask(struct irq_data *d) |
c53c9cf6 AV |
25 | { |
26 | unsigned long inten; | |
27 | ||
28 | inten = __raw_readl(KS8695_IRQ_VA + KS8695_INTEN); | |
3cdb791b | 29 | inten &= ~(1 << d->irq); |
c53c9cf6 AV |
30 | |
31 | __raw_writel(inten, KS8695_IRQ_VA + KS8695_INTEN); | |
32 | } | |
33 | ||
3cdb791b | 34 | static void ks8695_irq_unmask(struct irq_data *d) |
c53c9cf6 AV |
35 | { |
36 | unsigned long inten; | |
37 | ||
38 | inten = __raw_readl(KS8695_IRQ_VA + KS8695_INTEN); | |
3cdb791b | 39 | inten |= (1 << d->irq); |
c53c9cf6 AV |
40 | |
41 | __raw_writel(inten, KS8695_IRQ_VA + KS8695_INTEN); | |
42 | } | |
43 | ||
3cdb791b | 44 | static void ks8695_irq_ack(struct irq_data *d) |
c53c9cf6 | 45 | { |
3cdb791b | 46 | __raw_writel((1 << d->irq), KS8695_IRQ_VA + KS8695_INTST); |
c53c9cf6 AV |
47 | } |
48 | ||
49 | ||
50 | static struct irq_chip ks8695_irq_level_chip; | |
51 | static struct irq_chip ks8695_irq_edge_chip; | |
52 | ||
53 | ||
3cdb791b | 54 | static int ks8695_irq_set_type(struct irq_data *d, unsigned int type) |
c53c9cf6 AV |
55 | { |
56 | unsigned long ctrl, mode; | |
57 | unsigned short level_triggered = 0; | |
58 | ||
59 | ctrl = __raw_readl(KS8695_GPIO_VA + KS8695_IOPC); | |
60 | ||
61 | switch (type) { | |
6cab4860 | 62 | case IRQ_TYPE_LEVEL_HIGH: |
c53c9cf6 AV |
63 | mode = IOPC_TM_HIGH; |
64 | level_triggered = 1; | |
65 | break; | |
6cab4860 | 66 | case IRQ_TYPE_LEVEL_LOW: |
c53c9cf6 AV |
67 | mode = IOPC_TM_LOW; |
68 | level_triggered = 1; | |
69 | break; | |
6cab4860 | 70 | case IRQ_TYPE_EDGE_RISING: |
c53c9cf6 AV |
71 | mode = IOPC_TM_RISING; |
72 | break; | |
6cab4860 | 73 | case IRQ_TYPE_EDGE_FALLING: |
c53c9cf6 AV |
74 | mode = IOPC_TM_FALLING; |
75 | break; | |
6cab4860 | 76 | case IRQ_TYPE_EDGE_BOTH: |
c53c9cf6 AV |
77 | mode = IOPC_TM_EDGE; |
78 | break; | |
79 | default: | |
80 | return -EINVAL; | |
81 | } | |
82 | ||
3cdb791b | 83 | switch (d->irq) { |
c53c9cf6 AV |
84 | case KS8695_IRQ_EXTERN0: |
85 | ctrl &= ~IOPC_IOEINT0TM; | |
86 | ctrl |= IOPC_IOEINT0_MODE(mode); | |
87 | break; | |
88 | case KS8695_IRQ_EXTERN1: | |
89 | ctrl &= ~IOPC_IOEINT1TM; | |
90 | ctrl |= IOPC_IOEINT1_MODE(mode); | |
91 | break; | |
92 | case KS8695_IRQ_EXTERN2: | |
93 | ctrl &= ~IOPC_IOEINT2TM; | |
94 | ctrl |= IOPC_IOEINT2_MODE(mode); | |
95 | break; | |
96 | case KS8695_IRQ_EXTERN3: | |
97 | ctrl &= ~IOPC_IOEINT3TM; | |
98 | ctrl |= IOPC_IOEINT3_MODE(mode); | |
99 | break; | |
100 | default: | |
101 | return -EINVAL; | |
102 | } | |
103 | ||
104 | if (level_triggered) { | |
f38c02f3 TG |
105 | irq_set_chip_and_handler(d->irq, &ks8695_irq_level_chip, |
106 | handle_level_irq); | |
c53c9cf6 AV |
107 | } |
108 | else { | |
f38c02f3 TG |
109 | irq_set_chip_and_handler(d->irq, &ks8695_irq_edge_chip, |
110 | handle_edge_irq); | |
c53c9cf6 AV |
111 | } |
112 | ||
113 | __raw_writel(ctrl, KS8695_GPIO_VA + KS8695_IOPC); | |
114 | return 0; | |
115 | } | |
116 | ||
117 | static struct irq_chip ks8695_irq_level_chip = { | |
3cdb791b LB |
118 | .irq_ack = ks8695_irq_mask, |
119 | .irq_mask = ks8695_irq_mask, | |
120 | .irq_unmask = ks8695_irq_unmask, | |
121 | .irq_set_type = ks8695_irq_set_type, | |
c53c9cf6 AV |
122 | }; |
123 | ||
124 | static struct irq_chip ks8695_irq_edge_chip = { | |
3cdb791b LB |
125 | .irq_ack = ks8695_irq_ack, |
126 | .irq_mask = ks8695_irq_mask, | |
127 | .irq_unmask = ks8695_irq_unmask, | |
128 | .irq_set_type = ks8695_irq_set_type, | |
c53c9cf6 AV |
129 | }; |
130 | ||
131 | void __init ks8695_init_irq(void) | |
132 | { | |
133 | unsigned int irq; | |
134 | ||
135 | /* Disable all interrupts initially */ | |
136 | __raw_writel(0, KS8695_IRQ_VA + KS8695_INTMC); | |
137 | __raw_writel(0, KS8695_IRQ_VA + KS8695_INTEN); | |
138 | ||
139 | for (irq = 0; irq < NR_IRQS; irq++) { | |
140 | switch (irq) { | |
141 | /* Level-triggered interrupts */ | |
142 | case KS8695_IRQ_BUS_ERROR: | |
143 | case KS8695_IRQ_UART_MODEM_STATUS: | |
144 | case KS8695_IRQ_UART_LINE_STATUS: | |
145 | case KS8695_IRQ_UART_RX: | |
146 | case KS8695_IRQ_COMM_TX: | |
147 | case KS8695_IRQ_COMM_RX: | |
f38c02f3 TG |
148 | irq_set_chip_and_handler(irq, |
149 | &ks8695_irq_level_chip, | |
150 | handle_level_irq); | |
c53c9cf6 AV |
151 | break; |
152 | ||
153 | /* Edge-triggered interrupts */ | |
154 | default: | |
3cdb791b LB |
155 | /* clear pending bit */ |
156 | ks8695_irq_ack(irq_get_irq_data(irq)); | |
f38c02f3 TG |
157 | irq_set_chip_and_handler(irq, |
158 | &ks8695_irq_edge_chip, | |
159 | handle_edge_irq); | |
c53c9cf6 AV |
160 | } |
161 | ||
e8d36d5d | 162 | irq_clear_status_flags(irq, IRQ_NOREQUEST); |
c53c9cf6 AV |
163 | } |
164 | } |