gpio: mcp23s08: Add option to configure IRQ output polarity as active high
authorAlexander Stein <alexander.stein@systec-electronic.com>
Mon, 1 Dec 2014 07:26:00 +0000 (08:26 +0100)
committerLinus Walleij <linus.walleij@linaro.org>
Wed, 3 Dec 2014 13:34:45 +0000 (14:34 +0100)
Default is active low, but if property is specified in DT set INTPOL flag.

Signed-off-by: Alexander Stein <alexander.stein@systec-electronic.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Documentation/devicetree/bindings/gpio/gpio-mcp23s08.txt
drivers/gpio/gpio-mcp23s08.c

index c306a2d..f3332b9 100644 (file)
@@ -57,6 +57,8 @@ Optional device specific properties:
         occurred on. If it is not set, the interrupt are only generated for the
         bank they belong to.
         On devices with only one interrupt output this property is useless.
         occurred on. If it is not set, the interrupt are only generated for the
         bank they belong to.
         On devices with only one interrupt output this property is useless.
+- microchip,irq-active-high: Sets the INTPOL flag in the IOCON register. This
+        configures the IRQ output polarity as active high.
 
 Example I2C (with interrupt):
 gpiom1: gpio@20 {
 
 Example I2C (with interrupt):
 gpiom1: gpio@20 {
index 0d58440..93ee7da 100644 (file)
@@ -65,6 +65,7 @@ struct mcp23s08_ops {
 
 struct mcp23s08 {
        u8                      addr;
 
 struct mcp23s08 {
        u8                      addr;
+       bool                    irq_active_high;
 
        u16                     cache[11];
        u16                     irq_rise;
 
        u16                     cache[11];
        u16                     irq_rise;
@@ -476,6 +477,7 @@ static int mcp23s08_irq_setup(struct mcp23s08 *mcp)
 {
        struct gpio_chip *chip = &mcp->chip;
        int err, irq, j;
 {
        struct gpio_chip *chip = &mcp->chip;
        int err, irq, j;
+       unsigned long irqflags = IRQF_ONESHOT | IRQF_SHARED;
 
        mutex_init(&mcp->irq_lock);
 
 
        mutex_init(&mcp->irq_lock);
 
@@ -484,10 +486,13 @@ static int mcp23s08_irq_setup(struct mcp23s08 *mcp)
        if (!mcp->irq_domain)
                return -ENODEV;
 
        if (!mcp->irq_domain)
                return -ENODEV;
 
+       if (mcp->irq_active_high)
+               irqflags |= IRQF_TRIGGER_HIGH;
+       else
+               irqflags |= IRQF_TRIGGER_LOW;
+
        err = devm_request_threaded_irq(chip->dev, mcp->irq, NULL, mcp23s08_irq,
        err = devm_request_threaded_irq(chip->dev, mcp->irq, NULL, mcp23s08_irq,
-                                       IRQF_TRIGGER_LOW | IRQF_ONESHOT |
-                                       IRQF_SHARED,
-                                       dev_name(chip->dev), mcp);
+                                       irqflags, dev_name(chip->dev), mcp);
        if (err != 0) {
                dev_err(chip->dev, "unable to request IRQ#%d: %d\n",
                        mcp->irq, err);
        if (err != 0) {
                dev_err(chip->dev, "unable to request IRQ#%d: %d\n",
                        mcp->irq, err);
@@ -589,6 +594,7 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
 
        mcp->data = data;
        mcp->addr = addr;
 
        mcp->data = data;
        mcp->addr = addr;
+       mcp->irq_active_high = false;
 
        mcp->chip.direction_input = mcp23s08_direction_input;
        mcp->chip.get = mcp23s08_get;
 
        mcp->chip.direction_input = mcp23s08_direction_input;
        mcp->chip.get = mcp23s08_get;
@@ -648,14 +654,24 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
                goto fail;
 
        mcp->irq_controller = pdata->irq_controller;
                goto fail;
 
        mcp->irq_controller = pdata->irq_controller;
-       if (mcp->irq && mcp->irq_controller && (type == MCP_TYPE_017))
-               mirror = pdata->mirror;
+       if (mcp->irq && mcp->irq_controller) {
+               mcp->irq_active_high = of_property_read_bool(mcp->chip.of_node,
+                               "microchip,irq-active-high");
 
 
-       if ((status & IOCON_SEQOP) || !(status & IOCON_HAEN) || mirror) {
+               if (type == MCP_TYPE_017)
+                       mirror = pdata->mirror;
+       }
+
+       if ((status & IOCON_SEQOP) || !(status & IOCON_HAEN) || mirror ||
+            mcp->irq_active_high) {
                /* mcp23s17 has IOCON twice, make sure they are in sync */
                status &= ~(IOCON_SEQOP | (IOCON_SEQOP << 8));
                status |= IOCON_HAEN | (IOCON_HAEN << 8);
                /* mcp23s17 has IOCON twice, make sure they are in sync */
                status &= ~(IOCON_SEQOP | (IOCON_SEQOP << 8));
                status |= IOCON_HAEN | (IOCON_HAEN << 8);
-               status &= ~(IOCON_INTPOL | (IOCON_INTPOL << 8));
+               if (mcp->irq_active_high)
+                       status |= IOCON_INTPOL | (IOCON_INTPOL << 8);
+               else
+                       status &= ~(IOCON_INTPOL | (IOCON_INTPOL << 8));
+
                if (mirror)
                        status |= IOCON_MIRROR | (IOCON_MIRROR << 8);
 
                if (mirror)
                        status |= IOCON_MIRROR | (IOCON_MIRROR << 8);