Skip to contentSkip to conversation

gpio: sx150x: Add Semtech I2C sx150x gpio expander driver.

PATCH Superseded Gregory Bean 2 participants 2 messages Jul 20, 2010 – Jul 21, 2010

Subsystems (3)

v3 of 4 Superseded Latest is v4 →

lore
Share & tools
lore
#0 lore raw

PATCH v3 1/1 gpio: sx150x: Add Semtech I2C sx150x gpio expander driver.

Add support for Semtech SX150-series I2C GPIO expanders. Compatible models include:

8 bits: sx1508q
16 bits: sx1509q

---
 drivers/gpio/Kconfig       |   11 +
 drivers/gpio/Makefile      |    1 +
 drivers/gpio/sx150x.c      |  646 ++++++++++++++++++++++++++++++++++++++++++++
 include/linux/i2c/sx150x.h |   78 ++++++
 4 files changed, 736 insertions(+), 0 deletions(-)
 create mode 100644 drivers/gpio/sx150x.c
 create mode 100644 include/linux/i2c/sx150x.h
drivers/gpio/Kconfig +11 -0
index 7face91..f623953 100644
@@ -195,6 +195,17 @@ config GPIO_PCF857X
 	  This driver provides an in-kernel interface to those GPIOs using
 	  platform-neutral GPIO calls.
 
+config GPIO_SX150X
+	bool "Semtech SX150x I2C GPIO expander"
+	depends on I2C=y
+	default n
+	help
+	  Say yes here to provide support for Semtech SX150-series I2C
+	  GPIO expanders. Compatible models include:
+
+	  8 bits:  sx1508q
+	  16 bits: sx1509q
+
 config GPIO_TC35892
 	bool "TC35892 GPIOs"
 	depends on MFD_TC35892
drivers/gpio/Makefile +1 -0
index e53dcff..a69e060 100644
@@ -35,3 +35,4 @@ obj-$(CONFIG_GPIO_WM8994)	+= wm8994-gpio.o
 obj-$(CONFIG_GPIO_SCH)		+= sch_gpio.o
 obj-$(CONFIG_GPIO_RDC321X)	+= rdc321x-gpio.o
 obj-$(CONFIG_GPIO_JANZ_TTL)	+= janz-ttl.o
+obj-$(CONFIG_GPIO_SX150X)	+= sx150x.o
drivers/gpio/sx150x.c new file +646 -0

646 lines not on this page · raw message

include/linux/i2c/sx150x.h new file +78 -0

78 lines not on this page · raw message

Signature · 5 lines
1.7.0.4

--
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
#1 lore raw

On Tue, 20 Jul 2010 14:07:43 -0700
Gregory Bean <[email protected]> wrote:

Gregory,

Quoted 24 lines

Add support for Semtech SX150-series I2C GPIO expanders. Compatible models include:

8 bits: sx1508q
16 bits: sx1509q

drivers/gpio/sx150x.c new file +16 -0
+static int sx150x_irq_set_type(unsigned int irq, unsigned int flow_type)
+{
+	struct irq_chip *ic = get_irq_chip(irq);
+	struct sx150x_chip *chip;
+	unsigned n, val = 0;
+
+	if (flow_type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
+		return -EINVAL;
+
+	chip = container_of(ic, struct sx150x_chip, irq_chip);
+	n = irq - chip->irq_base;
+
+	if (flow_type & IRQ_TYPE_EDGE_RISING)
+		val |= 0x1;
+	if (flow_type & IRQ_TYPE_EDGE_FALLING)
+		val |= 0x2;

drivers/gpio/sx150x.c line 364

Quoted 10 lines
drivers/gpio/sx150x.c new file +10 -0
+
+	mutex_lock(&chip->mutex);
+	chip->irq_sense &= ~(3UL << (n * 2));
+	chip->irq_sense |= val << (n * 2);
+	if (!(irq_to_desc(irq)->status & IRQ_MASKED))
+		sx150x_write_cfg(chip, n, 2, chip->dev_cfg->reg_sense, val);
+	mutex_unlock(&chip->mutex);
+
+	return 0;
+}

Several problems here:
* This can be called from request_threaded irq(), which means the mutex is already taken (via the bus_lock method).
* On the same path, __setup_irq will disable local interrupts before calling this function. Bad things will happen if your I2C controller wants to sleep. pca953x had the same problem, see a2cb9aeb3c9b2475955cec328487484034f414e4 for a potential solution.

drivers/gpio/sx150x.c line 376

Quoted 11 lines
drivers/gpio/sx150x.c new file +11 -0
+static irqreturn_t sx150x_irq_thread_fn(int irq, void *dev_id)
+{
+	struct sx150x_chip *chip = (struct sx150x_chip *)dev_id;
+	unsigned nhandled = 0;
+	unsigned sub_irq;
+	unsigned n;
+	s32 err;
+	u8 val;
+	int i;
+
+	mutex_lock(&chip->mutex);

This looks wrong... The whole purpose of the genirq framework is that it takes care of most of the locking for you if you provide the bus_lock/unlock methods. You should only use direct locking to protect against races from the gpiolib framework.

Quoted 13 lines
drivers/gpio/sx150x.c new file +13 -0
+	for (i = (chip->dev_cfg->ngpios / 8) - 1; i >= 0; --i) {
+		err = sx150x_i2c_read(chip->client,
+				      chip->dev_cfg->reg_irq_src - i,
+				      &val);
+		if (err < 0)
+			continue;
+
+		sx150x_i2c_write(chip->client,
+				chip->dev_cfg->reg_irq_src - i,
+				val);
+		for (n = 0; n < 8; ++n) {
+			if (val & (1 << n)) {
+				sub_irq = chip->irq_base + (i * 8) + n;

drivers/gpio/sx150x.c line 399

Quoted 10 lines
drivers/gpio/sx150x.c new file +10 -0
+				handle_nested_irq(sub_irq);
+				++nhandled;
+			}
+		}
+	}
+	mutex_unlock(&chip->mutex);
+
+	return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE);
+}
+

Cheers,

	M.
Signature · 4 lines
Enforcement officers may use a hand-held detection device to measure
both the direction and the strength of a TV signal. This makes it easy
for us to locate TV receiving equipment in even the hardest-to-reach
places.