Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 328463
b: refs/heads/master
c: efe4c94
h: refs/heads/master
i:
  328461: 6d6e7b0
  328459: 26817ac
  328455: 675bd7b
  328447: b003e5e
v: v3
  • Loading branch information
Lee Jones authored and Linus Walleij committed Sep 12, 2012
1 parent 9b72e75 commit 2055462
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 29 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: ee6691d74b0d1b75f1f3cc2b15ecb7da7748a46a
refs/heads/master: efe4c9496a80253492942624dd23caa3ca6782c8
98 changes: 70 additions & 28 deletions trunk/drivers/gpio/gpio-tc3589x.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/interrupt.h>
#include <linux/mfd/tc3589x.h>

Expand All @@ -29,6 +30,7 @@ struct tc3589x_gpio {
struct tc3589x *tc3589x;
struct device *dev;
struct mutex irq_lock;
struct irq_domain *domain;

int irq_base;

Expand Down Expand Up @@ -92,11 +94,28 @@ static int tc3589x_gpio_direction_input(struct gpio_chip *chip,
return tc3589x_set_bits(tc3589x, reg, 1 << pos, 0);
}

/**
* tc3589x_gpio_irq_get_virq(): Map an interrupt on a chip to a virtual IRQ
*
* @tc3589x_gpio: tc3589x_gpio_irq controller to operate on.
* @irq: index of the interrupt requested in the chip IRQs
*
* Useful for drivers to request their own IRQs.
*/
static int tc3589x_gpio_irq_get_virq(struct tc3589x_gpio *tc3589x_gpio,
int irq)
{
if (!tc3589x_gpio)
return -EINVAL;

return irq_create_mapping(tc3589x_gpio->domain, irq);
}

static int tc3589x_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip);

return tc3589x_gpio->irq_base + offset;
return tc3589x_gpio_irq_get_virq(tc3589x_gpio, offset);
}

static struct gpio_chip template_chip = {
Expand All @@ -113,7 +132,7 @@ static struct gpio_chip template_chip = {
static int tc3589x_gpio_irq_set_type(struct irq_data *d, unsigned int type)
{
struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d);
int offset = d->irq - tc3589x_gpio->irq_base;
int offset = d->hwirq;
int regoffset = offset / 8;
int mask = 1 << (offset % 8);

Expand Down Expand Up @@ -175,7 +194,7 @@ static void tc3589x_gpio_irq_sync_unlock(struct irq_data *d)
static void tc3589x_gpio_irq_mask(struct irq_data *d)
{
struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d);
int offset = d->irq - tc3589x_gpio->irq_base;
int offset = d->hwirq;
int regoffset = offset / 8;
int mask = 1 << (offset % 8);

Expand All @@ -185,7 +204,7 @@ static void tc3589x_gpio_irq_mask(struct irq_data *d)
static void tc3589x_gpio_irq_unmask(struct irq_data *d)
{
struct tc3589x_gpio *tc3589x_gpio = irq_data_get_irq_chip_data(d);
int offset = d->irq - tc3589x_gpio->irq_base;
int offset = d->hwirq;
int regoffset = offset / 8;
int mask = 1 << (offset % 8);

Expand Down Expand Up @@ -222,8 +241,9 @@ static irqreturn_t tc3589x_gpio_irq(int irq, void *dev)
while (stat) {
int bit = __ffs(stat);
int line = i * 8 + bit;
int virq = tc3589x_gpio_irq_get_virq(tc3589x_gpio, line);

handle_nested_irq(tc3589x_gpio->irq_base + line);
handle_nested_irq(virq);
stat &= ~(1 << bit);
}

Expand All @@ -233,38 +253,60 @@ static irqreturn_t tc3589x_gpio_irq(int irq, void *dev)
return IRQ_HANDLED;
}

static int tc3589x_gpio_irq_init(struct tc3589x_gpio *tc3589x_gpio)
static int tc3589x_gpio_irq_map(struct irq_domain *d, unsigned int virq,
irq_hw_number_t hwirq)
{
int base = tc3589x_gpio->irq_base;
int irq;
struct tc3589x *tc3589x_gpio = d->host_data;

for (irq = base; irq < base + tc3589x_gpio->chip.ngpio; irq++) {
irq_set_chip_data(irq, tc3589x_gpio);
irq_set_chip_and_handler(irq, &tc3589x_gpio_irq_chip,
handle_simple_irq);
irq_set_nested_thread(irq, 1);
irq_set_chip_data(virq, tc3589x_gpio);
irq_set_chip_and_handler(virq, &tc3589x_gpio_irq_chip,
handle_simple_irq);
irq_set_nested_thread(virq, 1);
#ifdef CONFIG_ARM
set_irq_flags(irq, IRQF_VALID);
set_irq_flags(virq, IRQF_VALID);
#else
irq_set_noprobe(irq);
irq_set_noprobe(virq);
#endif
}

return 0;
}

static void tc3589x_gpio_irq_remove(struct tc3589x_gpio *tc3589x_gpio)
static void tc3589x_gpio_irq_unmap(struct irq_domain *d, unsigned int virq)
{
int base = tc3589x_gpio->irq_base;
int irq;

for (irq = base; irq < base + tc3589x_gpio->chip.ngpio; irq++) {
#ifdef CONFIG_ARM
set_irq_flags(irq, 0);
set_irq_flags(virq, 0);
#endif
irq_set_chip_and_handler(irq, NULL, NULL);
irq_set_chip_data(irq, NULL);
irq_set_chip_and_handler(virq, NULL, NULL);
irq_set_chip_data(virq, NULL);
}

static struct irq_domain_ops tc3589x_irq_ops = {
.map = tc3589x_gpio_irq_map,
.unmap = tc3589x_gpio_irq_unmap,
.xlate = irq_domain_xlate_twocell,
};

static int tc3589x_gpio_irq_init(struct tc3589x_gpio *tc3589x_gpio)
{
int base = tc3589x_gpio->irq_base;

if (base) {
tc3589x_gpio->domain = irq_domain_add_legacy(
NULL, tc3589x_gpio->chip.ngpio, base,
0, &tc3589x_irq_ops, tc3589x_gpio);
}
else {
tc3589x_gpio->domain = irq_domain_add_linear(
NULL, tc3589x_gpio->chip.ngpio,
&tc3589x_irq_ops, tc3589x_gpio);
}

if (!tc3589x_gpio->domain) {
dev_err(tc3589x_gpio->dev, "Failed to create irqdomain\n");
return -ENOSYS;
}

return 0;
}

static int __devinit tc3589x_gpio_probe(struct platform_device *pdev)
Expand Down Expand Up @@ -299,6 +341,9 @@ static int __devinit tc3589x_gpio_probe(struct platform_device *pdev)

tc3589x_gpio->irq_base = tc3589x->irq_base + TC3589x_INT_GPIO(0);

tc3589x_gpio->irq_base = tc3589x->irq_base ?
tc3589x->irq_base + TC3589x_INT_GPIO(0) : 0;

/* Bring the GPIO module out of reset */
ret = tc3589x_set_bits(tc3589x, TC3589x_RSTCTRL,
TC3589x_RSTCTRL_GPIRST, 0);
Expand All @@ -313,7 +358,7 @@ static int __devinit tc3589x_gpio_probe(struct platform_device *pdev)
"tc3589x-gpio", tc3589x_gpio);
if (ret) {
dev_err(&pdev->dev, "unable to get irq: %d\n", ret);
goto out_removeirq;
goto out_free;
}

ret = gpiochip_add(&tc3589x_gpio->chip);
Expand All @@ -331,8 +376,6 @@ static int __devinit tc3589x_gpio_probe(struct platform_device *pdev)

out_freeirq:
free_irq(irq, tc3589x_gpio);
out_removeirq:
tc3589x_gpio_irq_remove(tc3589x_gpio);
out_free:
kfree(tc3589x_gpio);
return ret;
Expand All @@ -357,7 +400,6 @@ static int __devexit tc3589x_gpio_remove(struct platform_device *pdev)
}

free_irq(irq, tc3589x_gpio);
tc3589x_gpio_irq_remove(tc3589x_gpio);

platform_set_drvdata(pdev, NULL);
kfree(tc3589x_gpio);
Expand Down

0 comments on commit 2055462

Please sign in to comment.