aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpio/gpio-tc3589x.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpio/gpio-tc3589x.c')
-rw-r--r--drivers/gpio/gpio-tc3589x.c98
1 files changed, 70 insertions, 28 deletions
diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/gpio-tc3589x.c
index 2a82e8999a4..6e890093397 100644
--- a/drivers/gpio/gpio-tc3589x.c
+++ b/drivers/gpio/gpio-tc3589x.c
@@ -12,6 +12,7 @@
12#include <linux/slab.h> 12#include <linux/slab.h>
13#include <linux/gpio.h> 13#include <linux/gpio.h>
14#include <linux/irq.h> 14#include <linux/irq.h>
15#include <linux/irqdomain.h>
15#include <linux/interrupt.h> 16#include <linux/interrupt.h>
16#include <linux/mfd/tc3589x.h> 17#include <linux/mfd/tc3589x.h>
17 18
@@ -29,6 +30,7 @@ struct tc3589x_gpio {
29 struct tc3589x *tc3589x; 30 struct tc3589x *tc3589x;
30 struct device *dev; 31 struct device *dev;
31 struct mutex irq_lock; 32 struct mutex irq_lock;
33 struct irq_domain *domain;
32 34
33 int irq_base; 35 int irq_base;
34 36
@@ -92,11 +94,28 @@ static int tc3589x_gpio_direction_input(struct gpio_chip *chip,
92 return tc3589x_set_bits(tc3589x, reg, 1 << pos, 0); 94 return tc3589x_set_bits(tc3589x, reg, 1 << pos, 0);
93} 95}
94 96
97/**
98 * tc3589x_gpio_irq_get_virq(): Map an interrupt on a chip to a virtual IRQ
99 *
100 * @tc3589x_gpio: tc3589x_gpio_irq controller to operate on.
101 * @irq: index of the interrupt requested in the chip IRQs
102 *
103 * Useful for drivers to request their own IRQs.
104 */
105static int tc3589x_gpio_irq_get_virq(struct tc3589x_gpio *tc3589x_gpio,
106 int irq)
107{
108 if (!tc3589x_gpio)
109 return -EINVAL;
110
111 return irq_create_mapping(tc3589x_gpio->domain, irq);
112}
113
95static int tc3589x_gpio_to_irq(struct gpio_chip *chip, unsigned offset) 114static int tc3589x_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
96{ 115{
97 struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip); 116 struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip);
98 117
99 return tc3589x_gpio->irq_base + offset; 118 return tc3589x_gpio_irq_get_virq(tc3589x_gpio, offset);
100} 119}
101 120
102static struct gpio_chip template_chip = { 121static struct gpio_chip template_chip = {
@@ -113,7 +132,7 @@ static struct gpio_chip template_chip = {
113static int tc3589x_gpio_irq_set_type(struct irq_data *d, unsigned int type) 132static int tc3589x_gpio_irq_set_type(struct irq_data *d, unsigned int type)
114{ 133{
115 struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d); 134 struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d);
116 int offset = d->irq - tc3589x_gpio->irq_base; 135 int offset = d->hwirq;
117 int regoffset = offset / 8; 136 int regoffset = offset / 8;
118 int mask = 1 << (offset % 8); 137 int mask = 1 << (offset % 8);
119 138
@@ -175,7 +194,7 @@ static void tc3589x_gpio_irq_sync_unlock(struct irq_data *d)
175static void tc3589x_gpio_irq_mask(struct irq_data *d) 194static void tc3589x_gpio_irq_mask(struct irq_data *d)
176{ 195{
177 struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d); 196 struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d);
178 int offset = d->irq - tc3589x_gpio->irq_base; 197 int offset = d->hwirq;
179 int regoffset = offset / 8; 198 int regoffset = offset / 8;
180 int mask = 1 << (offset % 8); 199 int mask = 1 << (offset % 8);
181 200
@@ -185,7 +204,7 @@ static void tc3589x_gpio_irq_mask(struct irq_data *d)
185static void tc3589x_gpio_irq_unmask(struct irq_data *d) 204static void tc3589x_gpio_irq_unmask(struct irq_data *d)
186{ 205{
187 struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d); 206 struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d);
188 int offset = d->irq - tc3589x_gpio->irq_base; 207 int offset = d->hwirq;
189 int regoffset = offset / 8; 208 int regoffset = offset / 8;
190 int mask = 1 << (offset % 8); 209 int mask = 1 << (offset % 8);
191 210
@@ -222,8 +241,9 @@ static irqreturn_t tc3589x_gpio_irq(int irq, void *dev)
222 while (stat) { 241 while (stat) {
223 int bit = __ffs(stat); 242 int bit = __ffs(stat);
224 int line = i * 8 + bit; 243 int line = i * 8 + bit;
244 int virq = tc3589x_gpio_irq_get_virq(tc3589x_gpio, line);
225 245
226 handle_nested_irq(tc3589x_gpio->irq_base + line); 246 handle_nested_irq(virq);
227 stat &= ~(1 << bit); 247 stat &= ~(1 << bit);
228 } 248 }
229 249
@@ -233,38 +253,60 @@ static irqreturn_t tc3589x_gpio_irq(int irq, void *dev)
233 return IRQ_HANDLED; 253 return IRQ_HANDLED;
234} 254}
235 255
236static int tc3589x_gpio_irq_init(struct tc3589x_gpio *tc3589x_gpio) 256static int tc3589x_gpio_irq_map(struct irq_domain *d, unsigned int virq,
257 irq_hw_number_t hwirq)
237{ 258{
238 int base = tc3589x_gpio->irq_base; 259 struct tc3589x *tc3589x_gpio = d->host_data;
239 int irq;
240 260
241 for (irq = base; irq < base + tc3589x_gpio->chip.ngpio; irq++) { 261 irq_set_chip_data(virq, tc3589x_gpio);
242 irq_set_chip_data(irq, tc3589x_gpio); 262 irq_set_chip_and_handler(virq, &tc3589x_gpio_irq_chip,
243 irq_set_chip_and_handler(irq, &tc3589x_gpio_irq_chip, 263 handle_simple_irq);
244 handle_simple_irq); 264 irq_set_nested_thread(virq, 1);
245 irq_set_nested_thread(irq, 1);
246#ifdef CONFIG_ARM 265#ifdef CONFIG_ARM
247 set_irq_flags(irq, IRQF_VALID); 266 set_irq_flags(virq, IRQF_VALID);
248#else 267#else
249 irq_set_noprobe(irq); 268 irq_set_noprobe(virq);
250#endif 269#endif
251 }
252 270
253 return 0; 271 return 0;
254} 272}
255 273
256static void tc3589x_gpio_irq_remove(struct tc3589x_gpio *tc3589x_gpio) 274static void tc3589x_gpio_irq_unmap(struct irq_domain *d, unsigned int virq)
257{ 275{
258 int base = tc3589x_gpio->irq_base;
259 int irq;
260
261 for (irq = base; irq < base + tc3589x_gpio->chip.ngpio; irq++) {
262#ifdef CONFIG_ARM 276#ifdef CONFIG_ARM
263 set_irq_flags(irq, 0); 277 set_irq_flags(virq, 0);
264#endif 278#endif
265 irq_set_chip_and_handler(irq, NULL, NULL); 279 irq_set_chip_and_handler(virq, NULL, NULL);
266 irq_set_chip_data(irq, NULL); 280 irq_set_chip_data(virq, NULL);
281}
282
283static struct irq_domain_ops tc3589x_irq_ops = {
284 .map = tc3589x_gpio_irq_map,
285 .unmap = tc3589x_gpio_irq_unmap,
286 .xlate = irq_domain_xlate_twocell,
287};
288
289static int tc3589x_gpio_irq_init(struct tc3589x_gpio *tc3589x_gpio)
290{
291 int base = tc3589x_gpio->irq_base;
292
293 if (base) {
294 tc3589x_gpio->domain = irq_domain_add_legacy(
295 NULL, tc3589x_gpio->chip.ngpio, base,
296 0, &tc3589x_irq_ops, tc3589x_gpio);
267 } 297 }
298 else {
299 tc3589x_gpio->domain = irq_domain_add_linear(
300 NULL, tc3589x_gpio->chip.ngpio,
301 &tc3589x_irq_ops, tc3589x_gpio);
302 }
303
304 if (!tc3589x_gpio->domain) {
305 dev_err(tc3589x_gpio->dev, "Failed to create irqdomain\n");
306 return -ENOSYS;
307 }
308
309 return 0;
268} 310}
269 311
270static int __devinit tc3589x_gpio_probe(struct platform_device *pdev) 312static int __devinit tc3589x_gpio_probe(struct platform_device *pdev)
@@ -299,6 +341,9 @@ static int __devinit tc3589x_gpio_probe(struct platform_device *pdev)
299 341
300 tc3589x_gpio->irq_base = tc3589x->irq_base + TC3589x_INT_GPIO(0); 342 tc3589x_gpio->irq_base = tc3589x->irq_base + TC3589x_INT_GPIO(0);
301 343
344 tc3589x_gpio->irq_base = tc3589x->irq_base ?
345 tc3589x->irq_base + TC3589x_INT_GPIO(0) : 0;
346
302 /* Bring the GPIO module out of reset */ 347 /* Bring the GPIO module out of reset */
303 ret = tc3589x_set_bits(tc3589x, TC3589x_RSTCTRL, 348 ret = tc3589x_set_bits(tc3589x, TC3589x_RSTCTRL,
304 TC3589x_RSTCTRL_GPIRST, 0); 349 TC3589x_RSTCTRL_GPIRST, 0);
@@ -313,7 +358,7 @@ static int __devinit tc3589x_gpio_probe(struct platform_device *pdev)
313 "tc3589x-gpio", tc3589x_gpio); 358 "tc3589x-gpio", tc3589x_gpio);
314 if (ret) { 359 if (ret) {
315 dev_err(&pdev->dev, "unable to get irq: %d\n", ret); 360 dev_err(&pdev->dev, "unable to get irq: %d\n", ret);
316 goto out_removeirq; 361 goto out_free;
317 } 362 }
318 363
319 ret = gpiochip_add(&tc3589x_gpio->chip); 364 ret = gpiochip_add(&tc3589x_gpio->chip);
@@ -331,8 +376,6 @@ static int __devinit tc3589x_gpio_probe(struct platform_device *pdev)
331 376
332out_freeirq: 377out_freeirq:
333 free_irq(irq, tc3589x_gpio); 378 free_irq(irq, tc3589x_gpio);
334out_removeirq:
335 tc3589x_gpio_irq_remove(tc3589x_gpio);
336out_free: 379out_free:
337 kfree(tc3589x_gpio); 380 kfree(tc3589x_gpio);
338 return ret; 381 return ret;
@@ -357,7 +400,6 @@ static int __devexit tc3589x_gpio_remove(struct platform_device *pdev)
357 } 400 }
358 401
359 free_irq(irq, tc3589x_gpio); 402 free_irq(irq, tc3589x_gpio);
360 tc3589x_gpio_irq_remove(tc3589x_gpio);
361 403
362 platform_set_drvdata(pdev, NULL); 404 platform_set_drvdata(pdev, NULL);
363 kfree(tc3589x_gpio); 405 kfree(tc3589x_gpio);