aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpio/gpio-tc3589x.c
diff options
context:
space:
mode:
authorLee Jones <lee.jones@linaro.org>2012-09-07 07:14:58 -0400
committerLinus Walleij <linus.walleij@linaro.org>2012-09-12 17:15:42 -0400
commitefe4c9496a80253492942624dd23caa3ca6782c8 (patch)
treea9ef531e75d26f924d8734cd6094e54fffaa67e9 /drivers/gpio/gpio-tc3589x.c
parentee6691d74b0d1b75f1f3cc2b15ecb7da7748a46a (diff)
gpio: Provide the tc3589x GPIO expander driver with an IRQ domain
In preparation for Device Tree enablement all IRQ controllers should control their own IRQ domain. This patch provides just that for the tc3589x GPIO expander. CC: Grant Likely <grant.likely@secretlab.ca> Signed-off-by: Lee Jones <lee.jones@linaro.org> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
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);