gpio: pcf857x: Switch to use gpiolib irqchip helpers
authorGeert Uytterhoeven <geert+renesas@glider.be>
Thu, 5 Feb 2015 15:49:08 +0000 (16:49 +0100)
committerLinus Walleij <linus.walleij@linaro.org>
Wed, 4 Mar 2015 12:48:34 +0000 (13:48 +0100)
Switch the PCF857x GPIO driver to use the gpiolib irqchip helpers.
This driver uses a nested threaded interrupt, hence handle_nested_irq()
and gpiochip_set_chained_irqchip() must be used.

Note that this removes the checks added in commit 21fd3cd1874a2ac8
("gpio: pcf857x: call the gpio user handler iff gpio_to_irq is done"),
as the interrupt mappings are no longer created on-demand by the driver,
but by gpiochip_irqchip_add() during initialization.

Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
drivers/gpio/Kconfig
drivers/gpio/gpio-pcf857x.c

index 09bc70b3875b57969d1e7df3fa3a3ea2e8a2b20a..249845a47624d922d46d4537e52b02b446fec8e9 100644 (file)
@@ -604,6 +604,7 @@ config GPIO_PCA953X_IRQ
 config GPIO_PCF857X
        tristate "PCF857x, PCA{85,96}7x, and MAX732[89] I2C GPIO expanders"
        depends on I2C
+       select GPIOLIB_IRQCHIP
        select IRQ_DOMAIN
        help
          Say yes here to provide access to most "quasi-bidirectional" I2C
index 236708ad0a5ba0ab9c0ee95a8d2db648e930cb29..126c937321013445c3239f93aa3b995005ac52c4 100644 (file)
@@ -88,11 +88,9 @@ struct pcf857x {
        struct gpio_chip        chip;
        struct i2c_client       *client;
        struct mutex            lock;           /* protect 'out' */
-       struct irq_domain       *irq_domain;    /* for irq demux  */
        spinlock_t              slock;          /* protect irq demux */
        unsigned                out;            /* software latch */
        unsigned                status;         /* current status */
-       unsigned                irq_mapped;     /* mapped gpio irqs */
 
        int (*write)(struct i2c_client *client, unsigned data);
        int (*read)(struct i2c_client *client);
@@ -182,18 +180,6 @@ static void pcf857x_set(struct gpio_chip *chip, unsigned offset, int value)
 
 /*-------------------------------------------------------------------------*/
 
-static int pcf857x_to_irq(struct gpio_chip *chip, unsigned offset)
-{
-       struct pcf857x *gpio = container_of(chip, struct pcf857x, chip);
-       int ret;
-
-       ret = irq_create_mapping(gpio->irq_domain, offset);
-       if (ret > 0)
-               gpio->irq_mapped |= (1 << offset);
-
-       return ret;
-}
-
 static irqreturn_t pcf857x_irq(int irq, void *data)
 {
        struct pcf857x  *gpio = data;
@@ -208,9 +194,9 @@ static irqreturn_t pcf857x_irq(int irq, void *data)
         * interrupt source, just to avoid bad irqs
         */
 
-       change = ((gpio->status ^ status) & gpio->irq_mapped);
+       change = (gpio->status ^ status);
        for_each_set_bit(i, &change, gpio->chip.ngpio)
-               generic_handle_irq(irq_find_mapping(gpio->irq_domain, i));
+               handle_nested_irq(irq_find_mapping(gpio->chip.irqdomain, i));
        gpio->status = status;
 
        spin_unlock_irqrestore(&gpio->slock, flags);
@@ -218,66 +204,6 @@ static irqreturn_t pcf857x_irq(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-static int pcf857x_irq_domain_map(struct irq_domain *domain, unsigned int irq,
-                                irq_hw_number_t hw)
-{
-       struct pcf857x *gpio = domain->host_data;
-
-       irq_set_chip_and_handler(irq,
-                                &dummy_irq_chip,
-                                handle_level_irq);
-#ifdef CONFIG_ARM
-       set_irq_flags(irq, IRQF_VALID);
-#else
-       irq_set_noprobe(irq);
-#endif
-       gpio->irq_mapped |= (1 << hw);
-
-       return 0;
-}
-
-static struct irq_domain_ops pcf857x_irq_domain_ops = {
-       .map    = pcf857x_irq_domain_map,
-};
-
-static void pcf857x_irq_domain_cleanup(struct pcf857x *gpio)
-{
-       if (gpio->irq_domain)
-               irq_domain_remove(gpio->irq_domain);
-
-}
-
-static int pcf857x_irq_domain_init(struct pcf857x *gpio,
-                                  struct i2c_client *client)
-{
-       int status;
-
-       gpio->irq_domain = irq_domain_add_linear(client->dev.of_node,
-                                                gpio->chip.ngpio,
-                                                &pcf857x_irq_domain_ops,
-                                                gpio);
-       if (!gpio->irq_domain)
-               goto fail;
-
-       /* enable real irq */
-       status = devm_request_threaded_irq(&client->dev, client->irq,
-                               NULL, pcf857x_irq, IRQF_ONESHOT |
-                               IRQF_TRIGGER_FALLING | IRQF_SHARED,
-                               dev_name(&client->dev), gpio);
-
-       if (status)
-               goto fail;
-
-       /* enable gpio_to_irq() */
-       gpio->chip.to_irq       = pcf857x_to_irq;
-
-       return 0;
-
-fail:
-       pcf857x_irq_domain_cleanup(gpio);
-       return -EINVAL;
-}
-
 /*-------------------------------------------------------------------------*/
 
 static int pcf857x_probe(struct i2c_client *client,
@@ -314,15 +240,6 @@ static int pcf857x_probe(struct i2c_client *client,
        gpio->chip.direction_output     = pcf857x_output;
        gpio->chip.ngpio                = id->driver_data;
 
-       /* enable gpio_to_irq() if platform has settings */
-       if (client->irq) {
-               status = pcf857x_irq_domain_init(gpio, client);
-               if (status < 0) {
-                       dev_err(&client->dev, "irq_domain init failed\n");
-                       goto fail_irq_domain;
-               }
-       }
-
        /* NOTE:  the OnSemi jlc1562b is also largely compatible with
         * these parts, notably for output.  It has a low-resolution
         * DAC instead of pin change IRQs; and its inputs can be the
@@ -398,6 +315,26 @@ static int pcf857x_probe(struct i2c_client *client,
        if (status < 0)
                goto fail;
 
+       /* Enable irqchip if we have an interrupt */
+       if (client->irq) {
+               status = gpiochip_irqchip_add(&gpio->chip, &dummy_irq_chip, 0,
+                                             handle_level_irq, IRQ_TYPE_NONE);
+               if (status) {
+                       dev_err(&client->dev, "cannot add irqchip\n");
+                       goto fail_irq;
+               }
+
+               status = devm_request_threaded_irq(&client->dev, client->irq,
+                                       NULL, pcf857x_irq, IRQF_ONESHOT |
+                                       IRQF_TRIGGER_FALLING | IRQF_SHARED,
+                                       dev_name(&client->dev), gpio);
+               if (status)
+                       goto fail_irq;
+
+               gpiochip_set_chained_irqchip(&gpio->chip, &dummy_irq_chip,
+                                            client->irq, NULL);
+       }
+
        /* Let platform code set up the GPIOs and their users.
         * Now is the first time anyone could use them.
         */
@@ -413,13 +350,12 @@ static int pcf857x_probe(struct i2c_client *client,
 
        return 0;
 
-fail:
-       if (client->irq)
-               pcf857x_irq_domain_cleanup(gpio);
+fail_irq:
+       gpiochip_remove(&gpio->chip);
 
-fail_irq_domain:
-       dev_dbg(&client->dev, "probe error %d for '%s'\n",
-               status, client->name);
+fail:
+       dev_dbg(&client->dev, "probe error %d for '%s'\n", status,
+               client->name);
 
        return status;
 }
@@ -441,9 +377,6 @@ static int pcf857x_remove(struct i2c_client *client)
                }
        }
 
-       if (client->irq)
-               pcf857x_irq_domain_cleanup(gpio);
-
        gpiochip_remove(&gpio->chip);
        return status;
 }