diff options
author | Rafał Miłecki <zajec5@gmail.com> | 2014-01-13 13:56:08 -0500 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2014-01-24 16:39:54 -0500 |
commit | 7c1bc0da3206de789a71c4aae8ac44d580bc5578 (patch) | |
tree | 4b73ed9000e7b1f1dbff5f6530b163ac7de1158b /drivers/ssb/driver_gpio.c | |
parent | 89fb3ac8621ba78cf11cc7bb1eb0991d204d5b18 (diff) |
ssb: gpio: add own IRQ domain
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
Acked-by: Hauke Mehrtens <hauke@hauke-m.de>
Acked-by: Michael Buesch <m@bues.ch>
Signed-off-by: John Crispin <blogic@openwrt.org>
Patchwork: http://patchwork.linux-mips.org/patch/6342/
Diffstat (limited to 'drivers/ssb/driver_gpio.c')
-rw-r--r-- | drivers/ssb/driver_gpio.c | 306 |
1 files changed, 290 insertions, 16 deletions
diff --git a/drivers/ssb/driver_gpio.c b/drivers/ssb/driver_gpio.c index dc109de228c6..ba350d2035c0 100644 --- a/drivers/ssb/driver_gpio.c +++ b/drivers/ssb/driver_gpio.c | |||
@@ -9,16 +9,40 @@ | |||
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/gpio.h> | 11 | #include <linux/gpio.h> |
12 | #include <linux/irq.h> | ||
13 | #include <linux/interrupt.h> | ||
14 | #include <linux/irqdomain.h> | ||
12 | #include <linux/export.h> | 15 | #include <linux/export.h> |
13 | #include <linux/ssb/ssb.h> | 16 | #include <linux/ssb/ssb.h> |
14 | 17 | ||
15 | #include "ssb_private.h" | 18 | #include "ssb_private.h" |
16 | 19 | ||
20 | |||
21 | /************************************************** | ||
22 | * Shared | ||
23 | **************************************************/ | ||
24 | |||
17 | static struct ssb_bus *ssb_gpio_get_bus(struct gpio_chip *chip) | 25 | static struct ssb_bus *ssb_gpio_get_bus(struct gpio_chip *chip) |
18 | { | 26 | { |
19 | return container_of(chip, struct ssb_bus, gpio); | 27 | return container_of(chip, struct ssb_bus, gpio); |
20 | } | 28 | } |
21 | 29 | ||
30 | #if IS_ENABLED(CONFIG_SSB_EMBEDDED) | ||
31 | static int ssb_gpio_to_irq(struct gpio_chip *chip, unsigned gpio) | ||
32 | { | ||
33 | struct ssb_bus *bus = ssb_gpio_get_bus(chip); | ||
34 | |||
35 | if (bus->bustype == SSB_BUSTYPE_SSB) | ||
36 | return irq_find_mapping(bus->irq_domain, gpio); | ||
37 | else | ||
38 | return -EINVAL; | ||
39 | } | ||
40 | #endif | ||
41 | |||
42 | /************************************************** | ||
43 | * ChipCommon | ||
44 | **************************************************/ | ||
45 | |||
22 | static int ssb_gpio_chipco_get_value(struct gpio_chip *chip, unsigned gpio) | 46 | static int ssb_gpio_chipco_get_value(struct gpio_chip *chip, unsigned gpio) |
23 | { | 47 | { |
24 | struct ssb_bus *bus = ssb_gpio_get_bus(chip); | 48 | struct ssb_bus *bus = ssb_gpio_get_bus(chip); |
@@ -74,19 +98,129 @@ static void ssb_gpio_chipco_free(struct gpio_chip *chip, unsigned gpio) | |||
74 | ssb_chipco_gpio_pullup(&bus->chipco, 1 << gpio, 0); | 98 | ssb_chipco_gpio_pullup(&bus->chipco, 1 << gpio, 0); |
75 | } | 99 | } |
76 | 100 | ||
77 | static int ssb_gpio_chipco_to_irq(struct gpio_chip *chip, unsigned gpio) | 101 | #if IS_ENABLED(CONFIG_SSB_EMBEDDED) |
102 | static void ssb_gpio_irq_chipco_mask(struct irq_data *d) | ||
78 | { | 103 | { |
79 | struct ssb_bus *bus = ssb_gpio_get_bus(chip); | 104 | struct ssb_bus *bus = irq_data_get_irq_chip_data(d); |
105 | int gpio = irqd_to_hwirq(d); | ||
80 | 106 | ||
81 | if (bus->bustype == SSB_BUSTYPE_SSB) | 107 | ssb_chipco_gpio_intmask(&bus->chipco, BIT(gpio), 0); |
82 | return ssb_mips_irq(bus->chipco.dev) + 2; | 108 | } |
83 | else | 109 | |
84 | return -EINVAL; | 110 | static void ssb_gpio_irq_chipco_unmask(struct irq_data *d) |
111 | { | ||
112 | struct ssb_bus *bus = irq_data_get_irq_chip_data(d); | ||
113 | int gpio = irqd_to_hwirq(d); | ||
114 | u32 val = ssb_chipco_gpio_in(&bus->chipco, BIT(gpio)); | ||
115 | |||
116 | ssb_chipco_gpio_polarity(&bus->chipco, BIT(gpio), val); | ||
117 | ssb_chipco_gpio_intmask(&bus->chipco, BIT(gpio), BIT(gpio)); | ||
118 | } | ||
119 | |||
120 | static struct irq_chip ssb_gpio_irq_chipco_chip = { | ||
121 | .name = "SSB-GPIO-CC", | ||
122 | .irq_mask = ssb_gpio_irq_chipco_mask, | ||
123 | .irq_unmask = ssb_gpio_irq_chipco_unmask, | ||
124 | }; | ||
125 | |||
126 | static irqreturn_t ssb_gpio_irq_chipco_handler(int irq, void *dev_id) | ||
127 | { | ||
128 | struct ssb_bus *bus = dev_id; | ||
129 | struct ssb_chipcommon *chipco = &bus->chipco; | ||
130 | u32 val = chipco_read32(chipco, SSB_CHIPCO_GPIOIN); | ||
131 | u32 mask = chipco_read32(chipco, SSB_CHIPCO_GPIOIRQ); | ||
132 | u32 pol = chipco_read32(chipco, SSB_CHIPCO_GPIOPOL); | ||
133 | unsigned long irqs = (val ^ pol) & mask; | ||
134 | int gpio; | ||
135 | |||
136 | if (!irqs) | ||
137 | return IRQ_NONE; | ||
138 | |||
139 | for_each_set_bit(gpio, &irqs, bus->gpio.ngpio) | ||
140 | generic_handle_irq(ssb_gpio_to_irq(&bus->gpio, gpio)); | ||
141 | ssb_chipco_gpio_polarity(chipco, irqs, val & irqs); | ||
142 | |||
143 | return IRQ_HANDLED; | ||
144 | } | ||
145 | |||
146 | static int ssb_gpio_irq_chipco_domain_init(struct ssb_bus *bus) | ||
147 | { | ||
148 | struct ssb_chipcommon *chipco = &bus->chipco; | ||
149 | struct gpio_chip *chip = &bus->gpio; | ||
150 | int gpio, hwirq, err; | ||
151 | |||
152 | if (bus->bustype != SSB_BUSTYPE_SSB) | ||
153 | return 0; | ||
154 | |||
155 | bus->irq_domain = irq_domain_add_linear(NULL, chip->ngpio, | ||
156 | &irq_domain_simple_ops, chipco); | ||
157 | if (!bus->irq_domain) { | ||
158 | err = -ENODEV; | ||
159 | goto err_irq_domain; | ||
160 | } | ||
161 | for (gpio = 0; gpio < chip->ngpio; gpio++) { | ||
162 | int irq = irq_create_mapping(bus->irq_domain, gpio); | ||
163 | |||
164 | irq_set_chip_data(irq, bus); | ||
165 | irq_set_chip_and_handler(irq, &ssb_gpio_irq_chipco_chip, | ||
166 | handle_simple_irq); | ||
167 | } | ||
168 | |||
169 | hwirq = ssb_mips_irq(bus->chipco.dev) + 2; | ||
170 | err = request_irq(hwirq, ssb_gpio_irq_chipco_handler, IRQF_SHARED, | ||
171 | "gpio", bus); | ||
172 | if (err) | ||
173 | goto err_req_irq; | ||
174 | |||
175 | ssb_chipco_gpio_intmask(&bus->chipco, ~0, 0); | ||
176 | chipco_set32(chipco, SSB_CHIPCO_IRQMASK, SSB_CHIPCO_IRQ_GPIO); | ||
177 | |||
178 | return 0; | ||
179 | |||
180 | err_req_irq: | ||
181 | for (gpio = 0; gpio < chip->ngpio; gpio++) { | ||
182 | int irq = irq_find_mapping(bus->irq_domain, gpio); | ||
183 | |||
184 | irq_dispose_mapping(irq); | ||
185 | } | ||
186 | irq_domain_remove(bus->irq_domain); | ||
187 | err_irq_domain: | ||
188 | return err; | ||
189 | } | ||
190 | |||
191 | static void ssb_gpio_irq_chipco_domain_exit(struct ssb_bus *bus) | ||
192 | { | ||
193 | struct ssb_chipcommon *chipco = &bus->chipco; | ||
194 | struct gpio_chip *chip = &bus->gpio; | ||
195 | int gpio; | ||
196 | |||
197 | if (bus->bustype != SSB_BUSTYPE_SSB) | ||
198 | return; | ||
199 | |||
200 | chipco_mask32(chipco, SSB_CHIPCO_IRQMASK, ~SSB_CHIPCO_IRQ_GPIO); | ||
201 | free_irq(ssb_mips_irq(bus->chipco.dev) + 2, chipco); | ||
202 | for (gpio = 0; gpio < chip->ngpio; gpio++) { | ||
203 | int irq = irq_find_mapping(bus->irq_domain, gpio); | ||
204 | |||
205 | irq_dispose_mapping(irq); | ||
206 | } | ||
207 | irq_domain_remove(bus->irq_domain); | ||
208 | } | ||
209 | #else | ||
210 | static int ssb_gpio_irq_chipco_domain_init(struct ssb_bus *bus) | ||
211 | { | ||
212 | return 0; | ||
85 | } | 213 | } |
86 | 214 | ||
215 | static void ssb_gpio_irq_chipco_domain_exit(struct ssb_bus *bus) | ||
216 | { | ||
217 | } | ||
218 | #endif | ||
219 | |||
87 | static int ssb_gpio_chipco_init(struct ssb_bus *bus) | 220 | static int ssb_gpio_chipco_init(struct ssb_bus *bus) |
88 | { | 221 | { |
89 | struct gpio_chip *chip = &bus->gpio; | 222 | struct gpio_chip *chip = &bus->gpio; |
223 | int err; | ||
90 | 224 | ||
91 | chip->label = "ssb_chipco_gpio"; | 225 | chip->label = "ssb_chipco_gpio"; |
92 | chip->owner = THIS_MODULE; | 226 | chip->owner = THIS_MODULE; |
@@ -96,7 +230,9 @@ static int ssb_gpio_chipco_init(struct ssb_bus *bus) | |||
96 | chip->set = ssb_gpio_chipco_set_value; | 230 | chip->set = ssb_gpio_chipco_set_value; |
97 | chip->direction_input = ssb_gpio_chipco_direction_input; | 231 | chip->direction_input = ssb_gpio_chipco_direction_input; |
98 | chip->direction_output = ssb_gpio_chipco_direction_output; | 232 | chip->direction_output = ssb_gpio_chipco_direction_output; |
99 | chip->to_irq = ssb_gpio_chipco_to_irq; | 233 | #if IS_ENABLED(CONFIG_SSB_EMBEDDED) |
234 | chip->to_irq = ssb_gpio_to_irq; | ||
235 | #endif | ||
100 | chip->ngpio = 16; | 236 | chip->ngpio = 16; |
101 | /* There is just one SoC in one device and its GPIO addresses should be | 237 | /* There is just one SoC in one device and its GPIO addresses should be |
102 | * deterministic to address them more easily. The other buses could get | 238 | * deterministic to address them more easily. The other buses could get |
@@ -106,9 +242,23 @@ static int ssb_gpio_chipco_init(struct ssb_bus *bus) | |||
106 | else | 242 | else |
107 | chip->base = -1; | 243 | chip->base = -1; |
108 | 244 | ||
109 | return gpiochip_add(chip); | 245 | err = ssb_gpio_irq_chipco_domain_init(bus); |
246 | if (err) | ||
247 | return err; | ||
248 | |||
249 | err = gpiochip_add(chip); | ||
250 | if (err) { | ||
251 | ssb_gpio_irq_chipco_domain_exit(bus); | ||
252 | return err; | ||
253 | } | ||
254 | |||
255 | return 0; | ||
110 | } | 256 | } |
111 | 257 | ||
258 | /************************************************** | ||
259 | * EXTIF | ||
260 | **************************************************/ | ||
261 | |||
112 | #ifdef CONFIG_SSB_DRIVER_EXTIF | 262 | #ifdef CONFIG_SSB_DRIVER_EXTIF |
113 | 263 | ||
114 | static int ssb_gpio_extif_get_value(struct gpio_chip *chip, unsigned gpio) | 264 | static int ssb_gpio_extif_get_value(struct gpio_chip *chip, unsigned gpio) |
@@ -145,19 +295,127 @@ static int ssb_gpio_extif_direction_output(struct gpio_chip *chip, | |||
145 | return 0; | 295 | return 0; |
146 | } | 296 | } |
147 | 297 | ||
148 | static int ssb_gpio_extif_to_irq(struct gpio_chip *chip, unsigned gpio) | 298 | #if IS_ENABLED(CONFIG_SSB_EMBEDDED) |
299 | static void ssb_gpio_irq_extif_mask(struct irq_data *d) | ||
149 | { | 300 | { |
150 | struct ssb_bus *bus = ssb_gpio_get_bus(chip); | 301 | struct ssb_bus *bus = irq_data_get_irq_chip_data(d); |
302 | int gpio = irqd_to_hwirq(d); | ||
151 | 303 | ||
152 | if (bus->bustype == SSB_BUSTYPE_SSB) | 304 | ssb_extif_gpio_intmask(&bus->extif, BIT(gpio), 0); |
153 | return ssb_mips_irq(bus->extif.dev) + 2; | 305 | } |
154 | else | 306 | |
155 | return -EINVAL; | 307 | static void ssb_gpio_irq_extif_unmask(struct irq_data *d) |
308 | { | ||
309 | struct ssb_bus *bus = irq_data_get_irq_chip_data(d); | ||
310 | int gpio = irqd_to_hwirq(d); | ||
311 | u32 val = ssb_extif_gpio_in(&bus->extif, BIT(gpio)); | ||
312 | |||
313 | ssb_extif_gpio_polarity(&bus->extif, BIT(gpio), val); | ||
314 | ssb_extif_gpio_intmask(&bus->extif, BIT(gpio), BIT(gpio)); | ||
315 | } | ||
316 | |||
317 | static struct irq_chip ssb_gpio_irq_extif_chip = { | ||
318 | .name = "SSB-GPIO-EXTIF", | ||
319 | .irq_mask = ssb_gpio_irq_extif_mask, | ||
320 | .irq_unmask = ssb_gpio_irq_extif_unmask, | ||
321 | }; | ||
322 | |||
323 | static irqreturn_t ssb_gpio_irq_extif_handler(int irq, void *dev_id) | ||
324 | { | ||
325 | struct ssb_bus *bus = dev_id; | ||
326 | struct ssb_extif *extif = &bus->extif; | ||
327 | u32 val = ssb_read32(extif->dev, SSB_EXTIF_GPIO_IN); | ||
328 | u32 mask = ssb_read32(extif->dev, SSB_EXTIF_GPIO_INTMASK); | ||
329 | u32 pol = ssb_read32(extif->dev, SSB_EXTIF_GPIO_INTPOL); | ||
330 | unsigned long irqs = (val ^ pol) & mask; | ||
331 | int gpio; | ||
332 | |||
333 | if (!irqs) | ||
334 | return IRQ_NONE; | ||
335 | |||
336 | for_each_set_bit(gpio, &irqs, bus->gpio.ngpio) | ||
337 | generic_handle_irq(ssb_gpio_to_irq(&bus->gpio, gpio)); | ||
338 | ssb_extif_gpio_polarity(extif, irqs, val & irqs); | ||
339 | |||
340 | return IRQ_HANDLED; | ||
341 | } | ||
342 | |||
343 | static int ssb_gpio_irq_extif_domain_init(struct ssb_bus *bus) | ||
344 | { | ||
345 | struct ssb_extif *extif = &bus->extif; | ||
346 | struct gpio_chip *chip = &bus->gpio; | ||
347 | int gpio, hwirq, err; | ||
348 | |||
349 | if (bus->bustype != SSB_BUSTYPE_SSB) | ||
350 | return 0; | ||
351 | |||
352 | bus->irq_domain = irq_domain_add_linear(NULL, chip->ngpio, | ||
353 | &irq_domain_simple_ops, extif); | ||
354 | if (!bus->irq_domain) { | ||
355 | err = -ENODEV; | ||
356 | goto err_irq_domain; | ||
357 | } | ||
358 | for (gpio = 0; gpio < chip->ngpio; gpio++) { | ||
359 | int irq = irq_create_mapping(bus->irq_domain, gpio); | ||
360 | |||
361 | irq_set_chip_data(irq, bus); | ||
362 | irq_set_chip_and_handler(irq, &ssb_gpio_irq_extif_chip, | ||
363 | handle_simple_irq); | ||
364 | } | ||
365 | |||
366 | hwirq = ssb_mips_irq(bus->extif.dev) + 2; | ||
367 | err = request_irq(hwirq, ssb_gpio_irq_extif_handler, IRQF_SHARED, | ||
368 | "gpio", bus); | ||
369 | if (err) | ||
370 | goto err_req_irq; | ||
371 | |||
372 | ssb_extif_gpio_intmask(&bus->extif, ~0, 0); | ||
373 | |||
374 | return 0; | ||
375 | |||
376 | err_req_irq: | ||
377 | for (gpio = 0; gpio < chip->ngpio; gpio++) { | ||
378 | int irq = irq_find_mapping(bus->irq_domain, gpio); | ||
379 | |||
380 | irq_dispose_mapping(irq); | ||
381 | } | ||
382 | irq_domain_remove(bus->irq_domain); | ||
383 | err_irq_domain: | ||
384 | return err; | ||
385 | } | ||
386 | |||
387 | static void ssb_gpio_irq_extif_domain_exit(struct ssb_bus *bus) | ||
388 | { | ||
389 | struct ssb_extif *extif = &bus->extif; | ||
390 | struct gpio_chip *chip = &bus->gpio; | ||
391 | int gpio; | ||
392 | |||
393 | if (bus->bustype != SSB_BUSTYPE_SSB) | ||
394 | return; | ||
395 | |||
396 | free_irq(ssb_mips_irq(bus->extif.dev) + 2, extif); | ||
397 | for (gpio = 0; gpio < chip->ngpio; gpio++) { | ||
398 | int irq = irq_find_mapping(bus->irq_domain, gpio); | ||
399 | |||
400 | irq_dispose_mapping(irq); | ||
401 | } | ||
402 | irq_domain_remove(bus->irq_domain); | ||
156 | } | 403 | } |
404 | #else | ||
405 | static int ssb_gpio_irq_extif_domain_init(struct ssb_bus *bus) | ||
406 | { | ||
407 | return 0; | ||
408 | } | ||
409 | |||
410 | static void ssb_gpio_irq_extif_domain_exit(struct ssb_bus *bus) | ||
411 | { | ||
412 | } | ||
413 | #endif | ||
157 | 414 | ||
158 | static int ssb_gpio_extif_init(struct ssb_bus *bus) | 415 | static int ssb_gpio_extif_init(struct ssb_bus *bus) |
159 | { | 416 | { |
160 | struct gpio_chip *chip = &bus->gpio; | 417 | struct gpio_chip *chip = &bus->gpio; |
418 | int err; | ||
161 | 419 | ||
162 | chip->label = "ssb_extif_gpio"; | 420 | chip->label = "ssb_extif_gpio"; |
163 | chip->owner = THIS_MODULE; | 421 | chip->owner = THIS_MODULE; |
@@ -165,7 +423,9 @@ static int ssb_gpio_extif_init(struct ssb_bus *bus) | |||
165 | chip->set = ssb_gpio_extif_set_value; | 423 | chip->set = ssb_gpio_extif_set_value; |
166 | chip->direction_input = ssb_gpio_extif_direction_input; | 424 | chip->direction_input = ssb_gpio_extif_direction_input; |
167 | chip->direction_output = ssb_gpio_extif_direction_output; | 425 | chip->direction_output = ssb_gpio_extif_direction_output; |
168 | chip->to_irq = ssb_gpio_extif_to_irq; | 426 | #if IS_ENABLED(CONFIG_SSB_EMBEDDED) |
427 | chip->to_irq = ssb_gpio_to_irq; | ||
428 | #endif | ||
169 | chip->ngpio = 5; | 429 | chip->ngpio = 5; |
170 | /* There is just one SoC in one device and its GPIO addresses should be | 430 | /* There is just one SoC in one device and its GPIO addresses should be |
171 | * deterministic to address them more easily. The other buses could get | 431 | * deterministic to address them more easily. The other buses could get |
@@ -175,7 +435,17 @@ static int ssb_gpio_extif_init(struct ssb_bus *bus) | |||
175 | else | 435 | else |
176 | chip->base = -1; | 436 | chip->base = -1; |
177 | 437 | ||
178 | return gpiochip_add(chip); | 438 | err = ssb_gpio_irq_extif_domain_init(bus); |
439 | if (err) | ||
440 | return err; | ||
441 | |||
442 | err = gpiochip_add(chip); | ||
443 | if (err) { | ||
444 | ssb_gpio_irq_extif_domain_exit(bus); | ||
445 | return err; | ||
446 | } | ||
447 | |||
448 | return 0; | ||
179 | } | 449 | } |
180 | 450 | ||
181 | #else | 451 | #else |
@@ -185,6 +455,10 @@ static int ssb_gpio_extif_init(struct ssb_bus *bus) | |||
185 | } | 455 | } |
186 | #endif | 456 | #endif |
187 | 457 | ||
458 | /************************************************** | ||
459 | * Init | ||
460 | **************************************************/ | ||
461 | |||
188 | int ssb_gpio_init(struct ssb_bus *bus) | 462 | int ssb_gpio_init(struct ssb_bus *bus) |
189 | { | 463 | { |
190 | if (ssb_chipco_available(&bus->chipco)) | 464 | if (ssb_chipco_available(&bus->chipco)) |