From 0ff56cd85a2c5104a36d84662b9180c219e8604e Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 14 Feb 2011 18:08:51 +0100 Subject: gpio/sx150x: Do not access I2C from mask/unmask functions irq_chip->irq_mask/unmask are called with interrupts disabled and irq_desc->lock held. So we cannot access i2c from this context. That's what irq_bus_sync_unlock() is for. Store the masked information in the chip data structure and update the i2c bus from the irq_bus_sync_unlock() callback. This does not need a while(pending) loop because the update to this is always serialized via the bus lock, so we never have more than one pin update pending. Signed-off-by: Thomas Gleixner Cc: Andrew Morton Cc: Gregory Bean Cc: Jean Delvare Cc: Lennert Buytenhek Signed-off-by: Grant Likely --- drivers/gpio/sx150x.c | 54 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 17 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/sx150x.c b/drivers/gpio/sx150x.c index e60be0015c9b..d2f874c3d3d5 100644 --- a/drivers/gpio/sx150x.c +++ b/drivers/gpio/sx150x.c @@ -25,6 +25,8 @@ #include #include +#define NO_UPDATE_PENDING -1 + struct sx150x_device_data { u8 reg_pullup; u8 reg_pulldn; @@ -47,8 +49,11 @@ struct sx150x_chip { const struct sx150x_device_data *dev_cfg; int irq_summary; int irq_base; + int irq_update; u32 irq_sense; - unsigned long irq_set_type_pending; + u32 irq_masked; + u32 dev_sense; + u32 dev_masked; struct irq_chip irq_chip; struct mutex lock; }; @@ -312,9 +317,8 @@ static void sx150x_irq_mask(struct irq_data *d) chip = container_of(ic, struct sx150x_chip, irq_chip); n = d->irq - chip->irq_base; - - sx150x_write_cfg(chip, n, 1, chip->dev_cfg->reg_irq_mask, 1); - sx150x_write_cfg(chip, n, 2, chip->dev_cfg->reg_sense, 0); + chip->irq_masked |= (1 << n); + chip->irq_update = n; } static void sx150x_irq_unmask(struct irq_data *d) @@ -326,9 +330,8 @@ static void sx150x_irq_unmask(struct irq_data *d) chip = container_of(ic, struct sx150x_chip, irq_chip); n = d->irq - chip->irq_base; - sx150x_write_cfg(chip, n, 1, chip->dev_cfg->reg_irq_mask, 0); - sx150x_write_cfg(chip, n, 2, chip->dev_cfg->reg_sense, - chip->irq_sense >> (n * 2)); + chip->irq_masked &= ~(1 << n); + chip->irq_update = n; } static int sx150x_irq_set_type(struct irq_data *d, unsigned int flow_type) @@ -350,7 +353,7 @@ static int sx150x_irq_set_type(struct irq_data *d, unsigned int flow_type) chip->irq_sense &= ~(3UL << (n * 2)); chip->irq_sense |= val << (n * 2); - chip->irq_set_type_pending |= BIT(n); + chip->irq_update = n; return 0; } @@ -404,15 +407,29 @@ static void sx150x_irq_bus_sync_unlock(struct irq_data *d) chip = container_of(ic, struct sx150x_chip, irq_chip); - while (chip->irq_set_type_pending) { - n = __ffs(chip->irq_set_type_pending); - chip->irq_set_type_pending &= ~BIT(n); - if (!(irq_to_desc(n + chip->irq_base)->status & IRQ_MASKED)) - sx150x_write_cfg(chip, n, 2, - chip->dev_cfg->reg_sense, - chip->irq_sense >> (n * 2)); - } + if (chip->irq_update == NO_UPDATE_PENDING) + goto out; + + n = chip->irq_update; + chip->irq_update = NO_UPDATE_PENDING; + /* Avoid updates if nothing changed */ + if (chip->dev_sense == chip->irq_sense && + chip->dev_sense == chip->irq_masked) + goto out; + + chip->dev_sense = chip->irq_sense; + chip->dev_masked = chip->irq_masked; + + if (chip->irq_masked & (1 << n)) { + sx150x_write_cfg(chip, n, 1, chip->dev_cfg->reg_irq_mask, 1); + sx150x_write_cfg(chip, n, 2, chip->dev_cfg->reg_sense, 0); + } else { + sx150x_write_cfg(chip, n, 1, chip->dev_cfg->reg_irq_mask, 0); + sx150x_write_cfg(chip, n, 2, chip->dev_cfg->reg_sense, + chip->irq_sense >> (n * 2)); + } +out: mutex_unlock(&chip->lock); } @@ -445,8 +462,11 @@ static void sx150x_init_chip(struct sx150x_chip *chip, chip->irq_chip.irq_bus_sync_unlock = sx150x_irq_bus_sync_unlock; chip->irq_summary = -1; chip->irq_base = -1; + chip->irq_masked = ~0; chip->irq_sense = 0; - chip->irq_set_type_pending = 0; + chip->dev_masked = ~0; + chip->dev_sense = 0; + chip->irq_update = NO_UPDATE_PENDING; } static int sx150x_init_io(struct sx150x_chip *chip, u8 base, u16 cfg) -- cgit v1.2.3 From 1648237dc2053bfd6ade3ce3dca3716d53cf9dcf Mon Sep 17 00:00:00 2001 From: Dirk Eibach Date: Thu, 24 Feb 2011 10:20:43 +0100 Subject: gpio/pca953x: Fix wrong pointer type pca953x_get_alt_pdata() uses uint16_t* as result type for of_get_property(), but numeric of values are __be32. Checking for negative values is bogus because of-property values are unsigned by definition. Instead check for proper property size. v3: - assume big-endian properties - check property size v2: - removed bogus check for negative property values Signed-off-by: Dirk Eibach Signed-off-by: Grant Likely --- drivers/gpio/pca953x.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c index a261972f603d..694b0f9c4b6c 100644 --- a/drivers/gpio/pca953x.c +++ b/drivers/gpio/pca953x.c @@ -448,7 +448,8 @@ pca953x_get_alt_pdata(struct i2c_client *client) { struct pca953x_platform_data *pdata; struct device_node *node; - const uint16_t *val; + const __be32 *val; + int size; node = client->dev.of_node; if (node == NULL) @@ -461,13 +462,13 @@ pca953x_get_alt_pdata(struct i2c_client *client) } pdata->gpio_base = -1; - val = of_get_property(node, "linux,gpio-base", NULL); + val = of_get_property(node, "linux,gpio-base", &size); if (val) { - if (*val < 0) - dev_warn(&client->dev, - "invalid gpio-base in device tree\n"); + if (size != sizeof(*val)) + dev_warn(&client->dev, "%s: wrong linux,gpio-base\n", + node->full_name); else - pdata->gpio_base = *val; + pdata->gpio_base = be32_to_cpup(val); } val = of_get_property(node, "polarity", NULL); -- cgit v1.2.3 From 0b7bb77fd55903ff9dc7c0474c49002aa6b9c78c Mon Sep 17 00:00:00 2001 From: Peter Korsgaard Date: Wed, 9 Mar 2011 17:56:30 +0100 Subject: gpio/mcp23s08: support mcp23s17 variant mpc23s17 is very similar to the mcp23s08, except that registers are 16bit wide, so extend the interface to work with both variants. The s17 variant also has an additional address pin, so adjust platform data structure to support up to 8 devices per SPI chipselect. Signed-off-by: Peter Korsgaard Signed-off-by: Grant Likely --- drivers/gpio/Kconfig | 6 +- drivers/gpio/mcp23s08.c | 191 ++++++++++++++++++++++++++++++++++++------------ 2 files changed, 146 insertions(+), 51 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 664660e56335..9573b330f647 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -368,11 +368,11 @@ config GPIO_MAX7301 GPIO driver for Maxim MAX7301 SPI-based GPIO expander. config GPIO_MCP23S08 - tristate "Microchip MCP23S08 I/O expander" + tristate "Microchip MCP23Sxx I/O expander" depends on SPI_MASTER help - SPI driver for Microchip MCP23S08 I/O expander. This provides - a GPIO interface supporting inputs and outputs. + SPI driver for Microchip MCP23S08/MPC23S17 I/O expanders. + This provides a GPIO interface supporting inputs and outputs. config GPIO_MC33880 tristate "Freescale MC33880 high-side/low-side switch" diff --git a/drivers/gpio/mcp23s08.c b/drivers/gpio/mcp23s08.c index 69f6f1955a31..40e076083ec0 100644 --- a/drivers/gpio/mcp23s08.c +++ b/drivers/gpio/mcp23s08.c @@ -10,7 +10,13 @@ #include #include #include +#include +/** + * MCP types supported by driver + */ +#define MCP_TYPE_S08 0 +#define MCP_TYPE_S17 1 /* Registers are all 8 bits wide. * @@ -35,27 +41,38 @@ #define MCP_GPIO 0x09 #define MCP_OLAT 0x0a +struct mcp23s08; + +struct mcp23s08_ops { + int (*read)(struct mcp23s08 *mcp, unsigned reg); + int (*write)(struct mcp23s08 *mcp, unsigned reg, unsigned val); + int (*read_regs)(struct mcp23s08 *mcp, unsigned reg, + u16 *vals, unsigned n); +}; + struct mcp23s08 { struct spi_device *spi; u8 addr; - u8 cache[11]; + u16 cache[11]; /* lock protects the cached values */ struct mutex lock; struct gpio_chip chip; struct work_struct work; + + const struct mcp23s08_ops *ops; }; -/* A given spi_device can represent up to four mcp23s08 chips +/* A given spi_device can represent up to eight mcp23sxx chips * sharing the same chipselect but using different addresses * (e.g. chips #0 and #3 might be populated, but not #1 or $2). * Driver data holds all the per-chip data. */ struct mcp23s08_driver_data { unsigned ngpio; - struct mcp23s08 *mcp[4]; + struct mcp23s08 *mcp[8]; struct mcp23s08 chip[]; }; @@ -70,7 +87,7 @@ static int mcp23s08_read(struct mcp23s08 *mcp, unsigned reg) return (status < 0) ? status : rx[0]; } -static int mcp23s08_write(struct mcp23s08 *mcp, unsigned reg, u8 val) +static int mcp23s08_write(struct mcp23s08 *mcp, unsigned reg, unsigned val) { u8 tx[3]; @@ -81,17 +98,81 @@ static int mcp23s08_write(struct mcp23s08 *mcp, unsigned reg, u8 val) } static int -mcp23s08_read_regs(struct mcp23s08 *mcp, unsigned reg, u8 *vals, unsigned n) +mcp23s08_read_regs(struct mcp23s08 *mcp, unsigned reg, u16 *vals, unsigned n) { - u8 tx[2]; + u8 tx[2], *tmp; + int status; if ((n + reg) > sizeof mcp->cache) return -EINVAL; tx[0] = mcp->addr | 0x01; tx[1] = reg; - return spi_write_then_read(mcp->spi, tx, sizeof tx, vals, n); + + tmp = (u8 *)vals; + status = spi_write_then_read(mcp->spi, tx, sizeof tx, tmp, n); + if (status >= 0) { + while (n--) + vals[n] = tmp[n]; /* expand to 16bit */ + } + return status; +} + +static int mcp23s17_read(struct mcp23s08 *mcp, unsigned reg) +{ + u8 tx[2], rx[2]; + int status; + + tx[0] = mcp->addr | 0x01; + tx[1] = reg << 1; + status = spi_write_then_read(mcp->spi, tx, sizeof tx, rx, sizeof rx); + return (status < 0) ? status : (rx[0] | (rx[1] << 8)); +} + +static int mcp23s17_write(struct mcp23s08 *mcp, unsigned reg, unsigned val) +{ + u8 tx[4]; + + tx[0] = mcp->addr; + tx[1] = reg << 1; + tx[2] = val; + tx[3] = val >> 8; + return spi_write_then_read(mcp->spi, tx, sizeof tx, NULL, 0); +} + +static int +mcp23s17_read_regs(struct mcp23s08 *mcp, unsigned reg, u16 *vals, unsigned n) +{ + u8 tx[2]; + int status; + + if ((n + reg) > sizeof mcp->cache) + return -EINVAL; + tx[0] = mcp->addr | 0x01; + tx[1] = reg << 1; + + status = spi_write_then_read(mcp->spi, tx, sizeof tx, + (u8 *)vals, n * 2); + if (status >= 0) { + while (n--) + vals[n] = __le16_to_cpu((__le16)vals[n]); + } + + return status; } +static const struct mcp23s08_ops mcp23s08_ops = { + .read = mcp23s08_read, + .write = mcp23s08_write, + .read_regs = mcp23s08_read_regs, +}; + +static const struct mcp23s08_ops mcp23s17_ops = { + .read = mcp23s17_read, + .write = mcp23s17_write, + .read_regs = mcp23s17_read_regs, +}; + + /*----------------------------------------------------------------------*/ static int mcp23s08_direction_input(struct gpio_chip *chip, unsigned offset) @@ -101,7 +182,7 @@ static int mcp23s08_direction_input(struct gpio_chip *chip, unsigned offset) mutex_lock(&mcp->lock); mcp->cache[MCP_IODIR] |= (1 << offset); - status = mcp23s08_write(mcp, MCP_IODIR, mcp->cache[MCP_IODIR]); + status = mcp->ops->write(mcp, MCP_IODIR, mcp->cache[MCP_IODIR]); mutex_unlock(&mcp->lock); return status; } @@ -114,7 +195,7 @@ static int mcp23s08_get(struct gpio_chip *chip, unsigned offset) mutex_lock(&mcp->lock); /* REVISIT reading this clears any IRQ ... */ - status = mcp23s08_read(mcp, MCP_GPIO); + status = mcp->ops->read(mcp, MCP_GPIO); if (status < 0) status = 0; else { @@ -127,20 +208,20 @@ static int mcp23s08_get(struct gpio_chip *chip, unsigned offset) static int __mcp23s08_set(struct mcp23s08 *mcp, unsigned mask, int value) { - u8 olat = mcp->cache[MCP_OLAT]; + unsigned olat = mcp->cache[MCP_OLAT]; if (value) olat |= mask; else olat &= ~mask; mcp->cache[MCP_OLAT] = olat; - return mcp23s08_write(mcp, MCP_OLAT, olat); + return mcp->ops->write(mcp, MCP_OLAT, olat); } static void mcp23s08_set(struct gpio_chip *chip, unsigned offset, int value) { struct mcp23s08 *mcp = container_of(chip, struct mcp23s08, chip); - u8 mask = 1 << offset; + unsigned mask = 1 << offset; mutex_lock(&mcp->lock); __mcp23s08_set(mcp, mask, value); @@ -151,14 +232,14 @@ static int mcp23s08_direction_output(struct gpio_chip *chip, unsigned offset, int value) { struct mcp23s08 *mcp = container_of(chip, struct mcp23s08, chip); - u8 mask = 1 << offset; + unsigned mask = 1 << offset; int status; mutex_lock(&mcp->lock); status = __mcp23s08_set(mcp, mask, value); if (status == 0) { mcp->cache[MCP_IODIR] &= ~mask; - status = mcp23s08_write(mcp, MCP_IODIR, mcp->cache[MCP_IODIR]); + status = mcp->ops->write(mcp, MCP_IODIR, mcp->cache[MCP_IODIR]); } mutex_unlock(&mcp->lock); return status; @@ -184,16 +265,16 @@ static void mcp23s08_dbg_show(struct seq_file *s, struct gpio_chip *chip) mcp = container_of(chip, struct mcp23s08, chip); /* NOTE: we only handle one bank for now ... */ - bank = '0' + ((mcp->addr >> 1) & 0x3); + bank = '0' + ((mcp->addr >> 1) & 0x7); mutex_lock(&mcp->lock); - t = mcp23s08_read_regs(mcp, 0, mcp->cache, sizeof mcp->cache); + t = mcp->ops->read_regs(mcp, 0, mcp->cache, ARRAY_SIZE(mcp->cache)); if (t < 0) { seq_printf(s, " I/O ERROR %d\n", t); goto done; } - for (t = 0, mask = 1; t < 8; t++, mask <<= 1) { + for (t = 0, mask = 1; t < chip->ngpio; t++, mask <<= 1) { const char *label; label = gpiochip_is_requested(chip, t); @@ -219,28 +300,33 @@ done: /*----------------------------------------------------------------------*/ static int mcp23s08_probe_one(struct spi_device *spi, unsigned addr, - unsigned base, unsigned pullups) + unsigned type, unsigned base, unsigned pullups) { struct mcp23s08_driver_data *data = spi_get_drvdata(spi); struct mcp23s08 *mcp = data->mcp[addr]; int status; - int do_update = 0; mutex_init(&mcp->lock); mcp->spi = spi; mcp->addr = 0x40 | (addr << 1); - mcp->chip.label = "mcp23s08", - mcp->chip.direction_input = mcp23s08_direction_input; mcp->chip.get = mcp23s08_get; mcp->chip.direction_output = mcp23s08_direction_output; mcp->chip.set = mcp23s08_set; mcp->chip.dbg_show = mcp23s08_dbg_show; + if (type == MCP_TYPE_S17) { + mcp->ops = &mcp23s17_ops; + mcp->chip.ngpio = 16; + mcp->chip.label = "mcp23s17"; + } else { + mcp->ops = &mcp23s08_ops; + mcp->chip.ngpio = 8; + mcp->chip.label = "mcp23s08"; + } mcp->chip.base = base; - mcp->chip.ngpio = 8; mcp->chip.can_sleep = 1; mcp->chip.dev = &spi->dev; mcp->chip.owner = THIS_MODULE; @@ -248,45 +334,39 @@ static int mcp23s08_probe_one(struct spi_device *spi, unsigned addr, /* verify MCP_IOCON.SEQOP = 0, so sequential reads work, * and MCP_IOCON.HAEN = 1, so we work with all chips. */ - status = mcp23s08_read(mcp, MCP_IOCON); + status = mcp->ops->read(mcp, MCP_IOCON); if (status < 0) goto fail; if ((status & IOCON_SEQOP) || !(status & IOCON_HAEN)) { - status &= ~IOCON_SEQOP; - status |= IOCON_HAEN; - status = mcp23s08_write(mcp, MCP_IOCON, (u8) status); + /* mcp23s17 has IOCON twice, make sure they are in sync */ + status &= ~(IOCON_SEQOP | (IOCON_SEQOP << 8)); + status |= IOCON_HAEN | (IOCON_HAEN << 8); + status = mcp->ops->write(mcp, MCP_IOCON, status); if (status < 0) goto fail; } /* configure ~100K pullups */ - status = mcp23s08_write(mcp, MCP_GPPU, pullups); + status = mcp->ops->write(mcp, MCP_GPPU, pullups); if (status < 0) goto fail; - status = mcp23s08_read_regs(mcp, 0, mcp->cache, sizeof mcp->cache); + status = mcp->ops->read_regs(mcp, 0, mcp->cache, ARRAY_SIZE(mcp->cache)); if (status < 0) goto fail; /* disable inverter on input */ if (mcp->cache[MCP_IPOL] != 0) { mcp->cache[MCP_IPOL] = 0; - do_update = 1; + status = mcp->ops->write(mcp, MCP_IPOL, 0); + if (status < 0) + goto fail; } /* disable irqs */ if (mcp->cache[MCP_GPINTEN] != 0) { mcp->cache[MCP_GPINTEN] = 0; - do_update = 1; - } - - if (do_update) { - u8 tx[4]; - - tx[0] = mcp->addr; - tx[1] = MCP_IPOL; - memcpy(&tx[2], &mcp->cache[MCP_IPOL], sizeof(tx) - 2); - status = spi_write_then_read(mcp->spi, tx, sizeof tx, NULL, 0); + status = mcp->ops->write(mcp, MCP_GPINTEN, 0); if (status < 0) goto fail; } @@ -305,19 +385,26 @@ static int mcp23s08_probe(struct spi_device *spi) unsigned addr; unsigned chips = 0; struct mcp23s08_driver_data *data; - int status; + int status, type; unsigned base; + type = spi_get_device_id(spi)->driver_data; + pdata = spi->dev.platform_data; if (!pdata || !gpio_is_valid(pdata->base)) { dev_dbg(&spi->dev, "invalid or missing platform data\n"); return -EINVAL; } - for (addr = 0; addr < 4; addr++) { + for (addr = 0; addr < ARRAY_SIZE(pdata->chip); addr++) { if (!pdata->chip[addr].is_present) continue; chips++; + if ((type == MCP_TYPE_S08) && (addr > 3)) { + dev_err(&spi->dev, + "mcp23s08 only supports address 0..3\n"); + return -EINVAL; + } } if (!chips) return -ENODEV; @@ -329,16 +416,17 @@ static int mcp23s08_probe(struct spi_device *spi) spi_set_drvdata(spi, data); base = pdata->base; - for (addr = 0; addr < 4; addr++) { + for (addr = 0; addr < ARRAY_SIZE(pdata->chip); addr++) { if (!pdata->chip[addr].is_present) continue; chips--; data->mcp[addr] = &data->chip[chips]; - status = mcp23s08_probe_one(spi, addr, base, - pdata->chip[addr].pullups); + status = mcp23s08_probe_one(spi, addr, type, base, + pdata->chip[addr].pullups); if (status < 0) goto fail; - base += 8; + + base += (type == MCP_TYPE_S17) ? 16 : 8; } data->ngpio = base - pdata->base; @@ -358,7 +446,7 @@ static int mcp23s08_probe(struct spi_device *spi) return 0; fail: - for (addr = 0; addr < 4; addr++) { + for (addr = 0; addr < ARRAY_SIZE(data->mcp); addr++) { int tmp; if (!data->mcp[addr]) @@ -388,7 +476,7 @@ static int mcp23s08_remove(struct spi_device *spi) } } - for (addr = 0; addr < 4; addr++) { + for (addr = 0; addr < ARRAY_SIZE(data->mcp); addr++) { int tmp; if (!data->mcp[addr]) @@ -405,9 +493,17 @@ static int mcp23s08_remove(struct spi_device *spi) return status; } +static const struct spi_device_id mcp23s08_ids[] = { + { "mcp23s08", MCP_TYPE_S08 }, + { "mcp23s17", MCP_TYPE_S17 }, + { }, +}; +MODULE_DEVICE_TABLE(spi, mcp23s08_ids); + static struct spi_driver mcp23s08_driver = { .probe = mcp23s08_probe, .remove = mcp23s08_remove, + .id_table = mcp23s08_ids, .driver = { .name = "mcp23s08", .owner = THIS_MODULE, @@ -432,4 +528,3 @@ static void __exit mcp23s08_exit(void) module_exit(mcp23s08_exit); MODULE_LICENSE("GPL"); -MODULE_ALIAS("spi:mcp23s08"); -- cgit v1.2.3 From 98f51ca98054b1268a7fdfe51d93c86a449ae87c Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 10 Mar 2011 16:48:34 +0800 Subject: gpio: add MODULE_DEVICE_TABLE to pch_gpio and ml_ioh_gpio The device table is required to load modules based on modaliases. After adding MODULE_DEVICE_TABLE, below entries will be added to modules.pcimap: pch_gpio 0x00008086 0x00008803 0xffffffff 0xffffffff 0x00000000 0x00000000 0x0 ml_ioh_gpio 0x000010db 0x0000802e 0xffffffff 0xffffffff 0x00000000 0x00000000 0x0 Signed-off-by: Axel Lin Signed-off-by: Grant Likely --- drivers/gpio/ml_ioh_gpio.c | 1 + drivers/gpio/pch_gpio.c | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers/gpio') diff --git a/drivers/gpio/ml_ioh_gpio.c b/drivers/gpio/ml_ioh_gpio.c index cead8e6ff345..7f6f01a4b145 100644 --- a/drivers/gpio/ml_ioh_gpio.c +++ b/drivers/gpio/ml_ioh_gpio.c @@ -326,6 +326,7 @@ static DEFINE_PCI_DEVICE_TABLE(ioh_gpio_pcidev_id) = { { PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x802E) }, { 0, } }; +MODULE_DEVICE_TABLE(pci, ioh_gpio_pcidev_id); static struct pci_driver ioh_gpio_driver = { .name = "ml_ioh_gpio", diff --git a/drivers/gpio/pch_gpio.c b/drivers/gpio/pch_gpio.c index 0eba0a75c804..2c6af8705103 100644 --- a/drivers/gpio/pch_gpio.c +++ b/drivers/gpio/pch_gpio.c @@ -286,6 +286,7 @@ static DEFINE_PCI_DEVICE_TABLE(pch_gpio_pcidev_id) = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8803) }, { 0, } }; +MODULE_DEVICE_TABLE(pci, pch_gpio_pcidev_id); static struct pci_driver pch_gpio_driver = { .name = "pch_gpio", -- cgit v1.2.3 From fc1599f7b0f6aff566237342ade28f2981186cc9 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 10 Mar 2011 17:10:45 +0800 Subject: gpio: Use __devexit at necessary places The function gen_74x164_remove and mc33880_remove are used only wrapped by __devexit_p so define it using __devexit. Signed-off-by: Axel Lin Signed-off-by: Grant Likely --- drivers/gpio/74x164.c | 2 +- drivers/gpio/mc33880.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/74x164.c b/drivers/gpio/74x164.c index d91ff4c282e9..84e070219839 100644 --- a/drivers/gpio/74x164.c +++ b/drivers/gpio/74x164.c @@ -133,7 +133,7 @@ exit_destroy: return ret; } -static int gen_74x164_remove(struct spi_device *spi) +static int __devexit gen_74x164_remove(struct spi_device *spi) { struct gen_74x164_chip *chip; int ret; diff --git a/drivers/gpio/mc33880.c b/drivers/gpio/mc33880.c index 935479da6705..00f6d24c669d 100644 --- a/drivers/gpio/mc33880.c +++ b/drivers/gpio/mc33880.c @@ -146,7 +146,7 @@ exit_destroy: return ret; } -static int mc33880_remove(struct spi_device *spi) +static int __devexit mc33880_remove(struct spi_device *spi) { struct mc33880 *mc; int ret; -- cgit v1.2.3 From 36885ff0e6563687e6152da6d311abbf83c0198f Mon Sep 17 00:00:00 2001 From: Nikanth Karthikesan Date: Tue, 15 Mar 2011 10:59:23 +0530 Subject: gpio/cs5535-gpio: Fix section mismatch Fix section mismatch by annotating using variable name suffix. Signed-off-by: Nikanth Karthikesan Signed-off-by: Grant Likely --- drivers/gpio/cs5535-gpio.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/cs5535-gpio.c b/drivers/gpio/cs5535-gpio.c index 0d05ea7d499b..6e16cba56ad2 100644 --- a/drivers/gpio/cs5535-gpio.c +++ b/drivers/gpio/cs5535-gpio.c @@ -373,7 +373,7 @@ static int __devexit cs5535_gpio_remove(struct platform_device *pdev) return 0; } -static struct platform_driver cs5535_gpio_drv = { +static struct platform_driver cs5535_gpio_driver = { .driver = { .name = DRV_NAME, .owner = THIS_MODULE, @@ -384,12 +384,12 @@ static struct platform_driver cs5535_gpio_drv = { static int __init cs5535_gpio_init(void) { - return platform_driver_register(&cs5535_gpio_drv); + return platform_driver_register(&cs5535_gpio_driver); } static void __exit cs5535_gpio_exit(void) { - platform_driver_unregister(&cs5535_gpio_drv); + platform_driver_unregister(&cs5535_gpio_driver); } module_init(cs5535_gpio_init); -- cgit v1.2.3 From 61ab3fe57e45f365caf73d567926040bdb475217 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 17 Mar 2011 19:32:46 +0000 Subject: gpio; Make Intel chipset gpio drivers depend on x86 Nothing outside of x86 can use that code. Reported-by: Stephen Rothwell Signed-off-by: Thomas Gleixner Signed-off-by: Grant Likely --- drivers/gpio/Kconfig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 9573b330f647..b46442d7d66e 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -101,7 +101,7 @@ config GPIO_VR41XX config GPIO_SCH tristate "Intel SCH GPIO" - depends on GPIOLIB && PCI + depends on GPIOLIB && PCI && X86 select MFD_CORE select LPC_SCH help @@ -321,13 +321,13 @@ config GPIO_BT8XX config GPIO_LANGWELL bool "Intel Langwell/Penwell GPIO support" - depends on PCI + depends on PCI && X86 help Say Y here to support Intel Langwell/Penwell GPIO. config GPIO_PCH tristate "PCH GPIO of Intel Topcliff" - depends on PCI + depends on PCI && X86 help This driver is for PCH(Platform controller Hub) GPIO of Intel Topcliff which is an IOH(Input/Output Hub) for x86 embedded processor. -- cgit v1.2.3 From 20e2aa916f6b56e6b1d9e34f4c6e8183d27cb81f Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 17 Mar 2011 19:32:49 +0000 Subject: gpio/langwell: Fix broken irq_eoi change. commit 0766d20fd (langwell_gpio: modify EOI handling following change of kernel irq subsystem) changes - desc->chip->eoi(irq); + + if (desc->chip->irq_eoi) + desc->chip->irq_eoi(irq_get_irq_data(irq)); + else + dev_warn(pg->chip.dev, "missing EOI handler for irq %d\n", irq); With the following explanation: "Latest kernel has many changes in IRQ subsystem and its interfaces, like adding irq_eoi" for struct irq_chip, this patch will make it support both the new and old interface." This is completely bogus. #1) The changelog does not match the patch at all #2) This driver relies on the assumption that it sits behind an eoi capable interrupt line. If the implementation of the underlying chip changes from eoi to irq_eoi then this driver has to follow that change and not add a total bogosity. #3) Just mechanically changing eoi to irq_eoi without checking the background of that change is sloppy at best. Remove the sillyness and retrieve the interrupt data from irq_desc directly. No need to go through a sparse irq lookup. Reported-by: Stephen Rothwell Signed-off-by: Thomas Gleixner Cc: Feng Tang Cc: Alek Du Cc: Alan Cox Cc: Andrew Morton Signed-off-by: Grant Likely --- drivers/gpio/langwell_gpio.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/langwell_gpio.c b/drivers/gpio/langwell_gpio.c index 54d70a47afc1..bb10156422e3 100644 --- a/drivers/gpio/langwell_gpio.c +++ b/drivers/gpio/langwell_gpio.c @@ -187,10 +187,11 @@ MODULE_DEVICE_TABLE(pci, lnw_gpio_ids); static void lnw_irq_handler(unsigned irq, struct irq_desc *desc) { - struct lnw_gpio *lnw = get_irq_data(irq); - u32 base, gpio; + struct irq_data *data = irq_desc_get_irq_data(desc); + struct lnw_gpio *lnw = irq_data_get_irq_handler_data(data); + struct irq_chip *chip = irq_data_get_irq_chip(data); + u32 base, gpio, gedr_v; void __iomem *gedr; - u32 gedr_v; /* check GPIO controller to check which pin triggered the interrupt */ for (base = 0; base < lnw->chip.ngpio; base += 32) { @@ -207,11 +208,7 @@ static void lnw_irq_handler(unsigned irq, struct irq_desc *desc) writel(gedr_v, gedr); } - if (desc->chip->irq_eoi) - desc->chip->irq_eoi(irq_get_irq_data(irq)); - else - dev_warn(lnw->chip.dev, "missing EOI handler for irq %d\n", irq); - + chip->irq_eoi(data); } static int __devinit lnw_gpio_probe(struct pci_dev *pdev, -- cgit v1.2.3 From 674db90690a5988bdaa3bb2a54619c0de50d31e9 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 17 Mar 2011 19:32:52 +0000 Subject: gpio/langwell: Convert irq name space Convert to the new irq function names. Signed-off-by: Thomas Gleixner Cc: Feng Tang Cc: Alek Du Cc: Alan Cox Signed-off-by: Grant Likely --- drivers/gpio/langwell_gpio.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/langwell_gpio.c b/drivers/gpio/langwell_gpio.c index bb10156422e3..6efc4e60aca7 100644 --- a/drivers/gpio/langwell_gpio.c +++ b/drivers/gpio/langwell_gpio.c @@ -276,12 +276,12 @@ static int __devinit lnw_gpio_probe(struct pci_dev *pdev, dev_err(&pdev->dev, "langwell gpiochip_add error %d\n", retval); goto err5; } - set_irq_data(pdev->irq, lnw); - set_irq_chained_handler(pdev->irq, lnw_irq_handler); + irq_set_handler_data(pdev->irq, lnw); + irq_set_chained_handler(pdev->irq, lnw_irq_handler); for (i = 0; i < lnw->chip.ngpio; i++) { - set_irq_chip_and_handler_name(i + lnw->irq_base, &lnw_irqchip, - handle_simple_irq, "demux"); - set_irq_chip_data(i + lnw->irq_base, lnw); + irq_set_chip_and_handler_name(i + lnw->irq_base, &lnw_irqchip, + handle_simple_irq, "demux"); + irq_set_chip_data(i + lnw->irq_base, lnw); } spin_lock_init(&lnw->lock); -- cgit v1.2.3 From 732063b92bb727b27e61580ce278dddefe31c6ad Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 17 Mar 2011 19:32:55 +0000 Subject: gpio/langwell: Simplify demux loop Use __ffs() to find the pending interrupt source instead of looping 32 times. Signed-off-by: Thomas Gleixner Cc: Feng Tang Cc: Alek Du Cc: Alan Cox Signed-off-by: Grant Likely --- drivers/gpio/langwell_gpio.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/langwell_gpio.c b/drivers/gpio/langwell_gpio.c index 6efc4e60aca7..f658af016f44 100644 --- a/drivers/gpio/langwell_gpio.c +++ b/drivers/gpio/langwell_gpio.c @@ -191,19 +191,20 @@ static void lnw_irq_handler(unsigned irq, struct irq_desc *desc) struct lnw_gpio *lnw = irq_data_get_irq_handler_data(data); struct irq_chip *chip = irq_data_get_irq_chip(data); u32 base, gpio, gedr_v; + unsigned long pending; void __iomem *gedr; /* check GPIO controller to check which pin triggered the interrupt */ for (base = 0; base < lnw->chip.ngpio; base += 32) { gedr = gpio_reg(&lnw->chip, base, GEDR); - gedr_v = readl(gedr); + gedr_v = pending = readl(gedr); if (!gedr_v) continue; - for (gpio = base; gpio < base + 32; gpio++) - if (gedr_v & BIT(gpio % 32)) { - pr_debug("pin %d triggered\n", gpio); - generic_handle_irq(lnw->irq_base + gpio); - } + while (pending) { + gpio = __ffs(pending) - 1; + pending &= ~BIT(gpio); + generic_handle_irq(lnw->irq_base + base + gpio); + } /* clear the edge detect status bit */ writel(gedr_v, gedr); } -- cgit v1.2.3 From 84bead6c38b0374e6e7db06b3097f0e700b8f148 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 17 Mar 2011 19:32:58 +0000 Subject: gpio/langwell: Clear edge bit before handling I don't have the specs for this beast, but it looks a lot like the PXA GPIO block. Though I bet it's the same IP and the driver should have reused the PXA code. Acknowleding the edge detect status after handling one or more gpio interrupts looks wrong. We might lose an edge which came in while we handled the previous one. Signed-off-by: Thomas Gleixner Acked-by: Alek Du Signed-off-by: Grant Likely --- drivers/gpio/langwell_gpio.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers/gpio') diff --git a/drivers/gpio/langwell_gpio.c b/drivers/gpio/langwell_gpio.c index f658af016f44..560ab648cf18 100644 --- a/drivers/gpio/langwell_gpio.c +++ b/drivers/gpio/langwell_gpio.c @@ -190,23 +190,22 @@ static void lnw_irq_handler(unsigned irq, struct irq_desc *desc) struct irq_data *data = irq_desc_get_irq_data(desc); struct lnw_gpio *lnw = irq_data_get_irq_handler_data(data); struct irq_chip *chip = irq_data_get_irq_chip(data); - u32 base, gpio, gedr_v; + u32 base, gpio, mask; unsigned long pending; void __iomem *gedr; /* check GPIO controller to check which pin triggered the interrupt */ for (base = 0; base < lnw->chip.ngpio; base += 32) { gedr = gpio_reg(&lnw->chip, base, GEDR); - gedr_v = pending = readl(gedr); - if (!gedr_v) - continue; + pending = readl(gedr); while (pending) { gpio = __ffs(pending) - 1; - pending &= ~BIT(gpio); + mask = BIT(gpio); + pending &= ~mask; + /* Clear before handling so we can't lose an edge */ + writel(mask, gedr); generic_handle_irq(lnw->irq_base + base + gpio); } - /* clear the edge detect status bit */ - writel(gedr_v, gedr); } chip->irq_eoi(data); -- cgit v1.2.3