Skip to content

Commit

Permalink
gpio: mcp23s08: Add option to configure IRQ output polarity as active…
Browse files Browse the repository at this point in the history
… high

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>
  • Loading branch information
Alexander Stein authored and Linus Walleij committed Dec 3, 2014
1 parent 0e9a5ed commit a4e6355
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 7 deletions.
2 changes: 2 additions & 0 deletions Documentation/devicetree/bindings/gpio/gpio-mcp23s08.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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.
- 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 {
Expand Down
30 changes: 23 additions & 7 deletions drivers/gpio/gpio-mcp23s08.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ struct mcp23s08_ops {

struct mcp23s08 {
u8 addr;
bool irq_active_high;

u16 cache[11];
u16 irq_rise;
Expand Down Expand Up @@ -476,6 +477,7 @@ static int mcp23s08_irq_setup(struct mcp23s08 *mcp)
{
struct gpio_chip *chip = &mcp->chip;
int err, irq, j;
unsigned long irqflags = IRQF_ONESHOT | IRQF_SHARED;

mutex_init(&mcp->irq_lock);

Expand All @@ -484,10 +486,13 @@ static int mcp23s08_irq_setup(struct mcp23s08 *mcp)
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,
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);
Expand Down Expand Up @@ -589,6 +594,7 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,

mcp->data = data;
mcp->addr = addr;
mcp->irq_active_high = false;

mcp->chip.direction_input = mcp23s08_direction_input;
mcp->chip.get = mcp23s08_get;
Expand Down Expand Up @@ -648,14 +654,24 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
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);
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);

Expand Down

0 comments on commit a4e6355

Please sign in to comment.