aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/plat-s5p/irq-gpioint.c106
1 files changed, 46 insertions, 60 deletions
diff --git a/arch/arm/plat-s5p/irq-gpioint.c b/arch/arm/plat-s5p/irq-gpioint.c
index 3b6bf89d1739..79a7b1c5a57e 100644
--- a/arch/arm/plat-s5p/irq-gpioint.c
+++ b/arch/arm/plat-s5p/irq-gpioint.c
@@ -22,77 +22,64 @@
22#include <plat/gpio-core.h> 22#include <plat/gpio-core.h>
23#include <plat/gpio-cfg.h> 23#include <plat/gpio-cfg.h>
24 24
25#define S5P_GPIOREG(x) (S5P_VA_GPIO + (x)) 25#define GPIO_BASE(chip) (((unsigned long)(chip)->base) & 0xFFFFF000u)
26 26
27#define GPIOINT_CON_OFFSET 0x700 27#define CON_OFFSET 0x700
28#define GPIOINT_MASK_OFFSET 0x900 28#define MASK_OFFSET 0x900
29#define GPIOINT_PEND_OFFSET 0xA00 29#define PEND_OFFSET 0xA00
30#define REG_OFFSET(x) ((x) << 2)
30 31
31static struct s3c_gpio_chip *irq_chips[S5P_GPIOINT_GROUP_MAXNR]; 32static struct s3c_gpio_chip *irq_chips[S5P_GPIOINT_GROUP_MAXNR];
32 33
33static int s5p_gpioint_get_group(struct irq_data *data)
34{
35 struct gpio_chip *chip = irq_data_get_irq_data(data);
36 struct s3c_gpio_chip *s3c_chip = container_of(chip,
37 struct s3c_gpio_chip, chip);
38 int group;
39
40 for (group = 0; group < S5P_GPIOINT_GROUP_MAXNR; group++)
41 if (s3c_chip == irq_chips[group])
42 break;
43
44 return group;
45}
46
47static int s5p_gpioint_get_offset(struct irq_data *data) 34static int s5p_gpioint_get_offset(struct irq_data *data)
48{ 35{
49 struct gpio_chip *chip = irq_data_get_irq_data(data); 36 struct s3c_gpio_chip *chip = irq_data_get_irq_data(data);
50 struct s3c_gpio_chip *s3c_chip = container_of(chip, 37 return data->irq - chip->irq_base;
51 struct s3c_gpio_chip, chip);
52
53 return data->irq - s3c_chip->irq_base;
54} 38}
55 39
56static void s5p_gpioint_ack(struct irq_data *data) 40static void s5p_gpioint_ack(struct irq_data *data)
57{ 41{
42 struct s3c_gpio_chip *chip = irq_data_get_irq_data(data);
58 int group, offset, pend_offset; 43 int group, offset, pend_offset;
59 unsigned int value; 44 unsigned int value;
60 45
61 group = s5p_gpioint_get_group(data); 46 group = chip->group;
62 offset = s5p_gpioint_get_offset(data); 47 offset = s5p_gpioint_get_offset(data);
63 pend_offset = group << 2; 48 pend_offset = REG_OFFSET(group);
64 49
65 value = __raw_readl(S5P_GPIOREG(GPIOINT_PEND_OFFSET) + pend_offset); 50 value = __raw_readl(GPIO_BASE(chip) + PEND_OFFSET + pend_offset);
66 value |= 1 << offset; 51 value |= BIT(offset);
67 __raw_writel(value, S5P_GPIOREG(GPIOINT_PEND_OFFSET) + pend_offset); 52 __raw_writel(value, GPIO_BASE(chip) + PEND_OFFSET + pend_offset);
68} 53}
69 54
70static void s5p_gpioint_mask(struct irq_data *data) 55static void s5p_gpioint_mask(struct irq_data *data)
71{ 56{
57 struct s3c_gpio_chip *chip = irq_data_get_irq_data(data);
72 int group, offset, mask_offset; 58 int group, offset, mask_offset;
73 unsigned int value; 59 unsigned int value;
74 60
75 group = s5p_gpioint_get_group(data); 61 group = chip->group;
76 offset = s5p_gpioint_get_offset(data); 62 offset = s5p_gpioint_get_offset(data);
77 mask_offset = group << 2; 63 mask_offset = REG_OFFSET(group);
78 64
79 value = __raw_readl(S5P_GPIOREG(GPIOINT_MASK_OFFSET) + mask_offset); 65 value = __raw_readl(GPIO_BASE(chip) + MASK_OFFSET + mask_offset);
80 value |= 1 << offset; 66 value |= BIT(offset);
81 __raw_writel(value, S5P_GPIOREG(GPIOINT_MASK_OFFSET) + mask_offset); 67 __raw_writel(value, GPIO_BASE(chip) + MASK_OFFSET + mask_offset);
82} 68}
83 69
84static void s5p_gpioint_unmask(struct irq_data *data) 70static void s5p_gpioint_unmask(struct irq_data *data)
85{ 71{
72 struct s3c_gpio_chip *chip = irq_data_get_irq_data(data);
86 int group, offset, mask_offset; 73 int group, offset, mask_offset;
87 unsigned int value; 74 unsigned int value;
88 75
89 group = s5p_gpioint_get_group(data); 76 group = chip->group;
90 offset = s5p_gpioint_get_offset(data); 77 offset = s5p_gpioint_get_offset(data);
91 mask_offset = group << 2; 78 mask_offset = REG_OFFSET(group);
92 79
93 value = __raw_readl(S5P_GPIOREG(GPIOINT_MASK_OFFSET) + mask_offset); 80 value = __raw_readl(GPIO_BASE(chip) + MASK_OFFSET + mask_offset);
94 value &= ~(1 << offset); 81 value &= ~BIT(offset);
95 __raw_writel(value, S5P_GPIOREG(GPIOINT_MASK_OFFSET) + mask_offset); 82 __raw_writel(value, GPIO_BASE(chip) + MASK_OFFSET + mask_offset);
96} 83}
97 84
98static void s5p_gpioint_mask_ack(struct irq_data *data) 85static void s5p_gpioint_mask_ack(struct irq_data *data)
@@ -103,12 +90,13 @@ static void s5p_gpioint_mask_ack(struct irq_data *data)
103 90
104static int s5p_gpioint_set_type(struct irq_data *data, unsigned int type) 91static int s5p_gpioint_set_type(struct irq_data *data, unsigned int type)
105{ 92{
93 struct s3c_gpio_chip *chip = irq_data_get_irq_data(data);
106 int group, offset, con_offset; 94 int group, offset, con_offset;
107 unsigned int value; 95 unsigned int value;
108 96
109 group = s5p_gpioint_get_group(data); 97 group = chip->group;
110 offset = s5p_gpioint_get_offset(data); 98 offset = s5p_gpioint_get_offset(data);
111 con_offset = group << 2; 99 con_offset = REG_OFFSET(group);
112 100
113 switch (type) { 101 switch (type) {
114 case IRQ_TYPE_EDGE_RISING: 102 case IRQ_TYPE_EDGE_RISING:
@@ -132,15 +120,15 @@ static int s5p_gpioint_set_type(struct irq_data *data, unsigned int type)
132 return -EINVAL; 120 return -EINVAL;
133 } 121 }
134 122
135 value = __raw_readl(S5P_GPIOREG(GPIOINT_CON_OFFSET) + con_offset); 123 value = __raw_readl(GPIO_BASE(chip) + CON_OFFSET + con_offset);
136 value &= ~(0x7 << (offset * 0x4)); 124 value &= ~(0x7 << (offset * 0x4));
137 value |= (type << (offset * 0x4)); 125 value |= (type << (offset * 0x4));
138 __raw_writel(value, S5P_GPIOREG(GPIOINT_CON_OFFSET) + con_offset); 126 __raw_writel(value, GPIO_BASE(chip) + CON_OFFSET + con_offset);
139 127
140 return 0; 128 return 0;
141} 129}
142 130
143struct irq_chip s5p_gpioint = { 131static struct irq_chip s5p_gpioint = {
144 .name = "s5p_gpioint", 132 .name = "s5p_gpioint",
145 .irq_ack = s5p_gpioint_ack, 133 .irq_ack = s5p_gpioint_ack,
146 .irq_mask = s5p_gpioint_mask, 134 .irq_mask = s5p_gpioint_mask,
@@ -151,30 +139,28 @@ struct irq_chip s5p_gpioint = {
151 139
152static void s5p_gpioint_handler(unsigned int irq, struct irq_desc *desc) 140static void s5p_gpioint_handler(unsigned int irq, struct irq_desc *desc)
153{ 141{
154 int group, offset, pend_offset, mask_offset; 142 int group, pend_offset, mask_offset;
155 int real_irq;
156 unsigned int pend, mask; 143 unsigned int pend, mask;
157 144
158 for (group = 0; group < S5P_GPIOINT_GROUP_MAXNR; group++) { 145 for (group = 0; group < S5P_GPIOINT_GROUP_MAXNR; group++) {
159 pend_offset = group << 2; 146 struct s3c_gpio_chip *chip = irq_chips[group];
160 pend = __raw_readl(S5P_GPIOREG(GPIOINT_PEND_OFFSET) + 147 if (!chip)
161 pend_offset); 148 continue;
149
150 pend_offset = REG_OFFSET(group);
151 pend = __raw_readl(GPIO_BASE(chip) + PEND_OFFSET + pend_offset);
162 if (!pend) 152 if (!pend)
163 continue; 153 continue;
164 154
165 mask_offset = group << 2; 155 mask_offset = REG_OFFSET(group);
166 mask = __raw_readl(S5P_GPIOREG(GPIOINT_MASK_OFFSET) + 156 mask = __raw_readl(GPIO_BASE(chip) + MASK_OFFSET + mask_offset);
167 mask_offset);
168 pend &= ~mask; 157 pend &= ~mask;
169 158
170 for (offset = 0; offset < 8; offset++) { 159 while (pend) {
171 if (pend & (1 << offset)) { 160 int offset = fls(pend) - 1;
172 struct s3c_gpio_chip *chip = irq_chips[group]; 161 int real_irq = chip->irq_base + offset;
173 if (chip) { 162 generic_handle_irq(real_irq);
174 real_irq = chip->irq_base + offset; 163 pend &= ~BIT(offset);
175 generic_handle_irq(real_irq);
176 }
177 }
178 } 164 }
179 } 165 }
180} 166}
@@ -202,7 +188,7 @@ static __init int s5p_gpioint_add(struct s3c_gpio_chip *chip)
202 for (i = 0; i < chip->chip.ngpio; i++) { 188 for (i = 0; i < chip->chip.ngpio; i++) {
203 irq = chip->irq_base + i; 189 irq = chip->irq_base + i;
204 set_irq_chip(irq, &s5p_gpioint); 190 set_irq_chip(irq, &s5p_gpioint);
205 set_irq_data(irq, &chip->chip); 191 set_irq_data(irq, chip);
206 set_irq_handler(irq, handle_level_irq); 192 set_irq_handler(irq, handle_level_irq);
207 set_irq_flags(irq, IRQF_VALID); 193 set_irq_flags(irq, IRQF_VALID);
208 } 194 }