pinctrl-mcp23s08: 1 changed pin -> multiple interrupts

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hello,
I had problems with pinctrl-mcp23s08 driver.
I use it with MCP23008 chip. Half of the chip is used by gpio-keys,
other half is eventually used via sysfs.
Pushing a key caused interrupts for all the 4 keys. In result - no
keyboard codes generated.
I found that problem was in mcp23s08_get() that being called by isr
for each changed pin clobbers the cached_gpio.
With following patch driver works for me.

Regards,
Dmitry


diff --git a/drivers/pinctrl/pinctrl-mcp23s08.c
b/drivers/pinctrl/pinctrl-mcp23s08.c
index 3e40d42..27ce202 100644
--- a/drivers/pinctrl/pinctrl-mcp23s08.c
+++ b/drivers/pinctrl/pinctrl-mcp23s08.c
@@ -63,6 +63,7 @@ struct mcp23s08 {
  int irq;
  bool irq_controller;
  int cached_gpio;
+ int cached_gpinten;
  /* lock protects regmap access with bypass/cache flags */
  struct mutex lock;

@@ -401,6 +402,9 @@ static int mcp23s08_get(struct gpio_chip *chip,
unsigned offset)
  struct mcp23s08 *mcp = gpiochip_get_data(chip);
  int status, ret;

+ if (mcp->cached_gpinten & (1 << offset))
+ return !!(mcp->cached_gpio & (1 << offset));
+
  mutex_lock(&mcp->lock);

  /* REVISIT reading this clears any IRQ ... */
@@ -486,15 +490,15 @@ static irqreturn_t mcp23s08_irq(int irq, void *data)
  mcp->cached_gpio = gpio;
  mutex_unlock(&mcp->lock);

+ dev_dbg(mcp->chip.parent,
+ "intcap 0x%04X intf 0x%04X gpio_orig 0x%04X gpio 0x%04X\n",
+ intcap, intf, gpio_orig, gpio);
+
  if (intf == 0) {
  /* There is no interrupt pending */
  return IRQ_HANDLED;
  }

- dev_dbg(mcp->chip.parent,
- "intcap 0x%04X intf 0x%04X gpio_orig 0x%04X gpio 0x%04X\n",
- intcap, intf, gpio_orig, gpio);
-
  for (i = 0; i < mcp->chip.ngpio; i++) {
  /* We must check all of the inputs on the chip,
  * otherwise we may not notice a change on >=2 pins.
@@ -514,6 +518,9 @@ static irqreturn_t mcp23s08_irq(int irq, void *data)
  * to see if the input has changed.
  */

+ if (!(mcp->cached_gpinten & BIT(i)))
+ continue;
+
  intf_set = intf & BIT(i);
  if (i < 8 && intf_set)
  intcap_mask = 0x00FF;
@@ -552,6 +559,7 @@ static void mcp23s08_irq_mask(struct irq_data *data)
  unsigned int pos = data->hwirq;

  mcp_set_bit(mcp, MCP_GPINTEN, pos, false);
+ mcp->cached_gpinten &= ~BIT(pos);
 }

 static void mcp23s08_irq_unmask(struct irq_data *data)
@@ -561,6 +569,7 @@ static void mcp23s08_irq_unmask(struct irq_data *data)
  unsigned int pos = data->hwirq;

  mcp_set_bit(mcp, MCP_GPINTEN, pos, true);
+ mcp->cached_gpinten |= BIT(pos);
 }

 static int mcp23s08_irq_set_type(struct irq_data *data, unsigned int type)
@@ -891,6 +900,8 @@ static int mcp23s08_probe_one(struct mcp23s08
*mcp, struct device *dev,
  goto fail;
  }

+ mcp_read(mcp, MCP_GPIO, &mcp->cached_gpio);  // initial value
+
  ret = devm_gpiochip_add_data(dev, &mcp->chip, mcp);
  if (ret < 0)
  goto fail;
--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux SPI]     [Linux Kernel]     [Linux ARM (vger)]     [Linux ARM MSM]     [Linux Omap]     [Linux Arm]     [Linux Tegra]     [Fedora ARM]     [Linux for Samsung SOC]     [eCos]     [Linux Fastboot]     [Gcc Help]     [Git]     [DCCP]     [IETF Announce]     [Security]     [Linux MIPS]     [Yosemite Campsites]

  Powered by Linux