diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-18 13:56:02 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-18 13:56:02 -0400 |
commit | b061c59c27e0385e53c961d9fbd18c1c078d9823 (patch) | |
tree | 56240ef8e98e9e4712ee58aa8e6e3d51f6ab001f /drivers/gpio | |
parent | 99f4065bac7b8c3f829334b4218a5c2e68cbe440 (diff) | |
parent | 568a60eda2e90a11bb3d7f8ef3f6800e9b60d4e5 (diff) |
Merge branch 'spi/next' of git://git.secretlab.ca/git/linux-2.6
* 'spi/next' of git://git.secretlab.ca/git/linux-2.6: (34 commits)
spi/dw_spi: move dw_spi.h into drivers/spi
spi/dw_spi: Fix missing header
gpio/langwell: Clear edge bit before handling
gpio/langwell: Simplify demux loop
gpio/langwell: Convert irq name space
gpio/langwell: Fix broken irq_eoi change.
gpio; Make Intel chipset gpio drivers depend on x86
gpio/cs5535-gpio: Fix section mismatch
spi/rtc-{ds1390,ds3234,m41t94}: Use spi_get_drvdata() for SPI devices
spi/davinci: Support DMA transfers larger than 65535 words
spi/davinci: Use correct length parameter to dma_map_single calls
gpio: Use __devexit at necessary places
gpio: add MODULE_DEVICE_TABLE to pch_gpio and ml_ioh_gpio
gpio/mcp23s08: support mcp23s17 variant
of_mmc_spi: add card detect irq support
spi/omap_mcspi: catch xfers of non-multiple SPI word size
spi/omap_mcspi: Off-by-one error in finding the right divisor
gpio/pca953x: Fix wrong pointer type
spi/pl022: rid dangling labels
spi: add support for SuperH SPI
...
Diffstat (limited to 'drivers/gpio')
-rw-r--r-- | drivers/gpio/74x164.c | 2 | ||||
-rw-r--r-- | drivers/gpio/Kconfig | 12 | ||||
-rw-r--r-- | drivers/gpio/cs5535-gpio.c | 6 | ||||
-rw-r--r-- | drivers/gpio/langwell_gpio.c | 43 | ||||
-rw-r--r-- | drivers/gpio/mc33880.c | 2 | ||||
-rw-r--r-- | drivers/gpio/mcp23s08.c | 191 | ||||
-rw-r--r-- | drivers/gpio/pca953x.c | 13 | ||||
-rw-r--r-- | drivers/gpio/sx150x.c | 54 |
8 files changed, 218 insertions, 105 deletions
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: | |||
133 | return ret; | 133 | return ret; |
134 | } | 134 | } |
135 | 135 | ||
136 | static int gen_74x164_remove(struct spi_device *spi) | 136 | static int __devexit gen_74x164_remove(struct spi_device *spi) |
137 | { | 137 | { |
138 | struct gen_74x164_chip *chip; | 138 | struct gen_74x164_chip *chip; |
139 | int ret; | 139 | int ret; |
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 664660e56335..b46442d7d66e 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig | |||
@@ -101,7 +101,7 @@ config GPIO_VR41XX | |||
101 | 101 | ||
102 | config GPIO_SCH | 102 | config GPIO_SCH |
103 | tristate "Intel SCH GPIO" | 103 | tristate "Intel SCH GPIO" |
104 | depends on GPIOLIB && PCI | 104 | depends on GPIOLIB && PCI && X86 |
105 | select MFD_CORE | 105 | select MFD_CORE |
106 | select LPC_SCH | 106 | select LPC_SCH |
107 | help | 107 | help |
@@ -321,13 +321,13 @@ config GPIO_BT8XX | |||
321 | 321 | ||
322 | config GPIO_LANGWELL | 322 | config GPIO_LANGWELL |
323 | bool "Intel Langwell/Penwell GPIO support" | 323 | bool "Intel Langwell/Penwell GPIO support" |
324 | depends on PCI | 324 | depends on PCI && X86 |
325 | help | 325 | help |
326 | Say Y here to support Intel Langwell/Penwell GPIO. | 326 | Say Y here to support Intel Langwell/Penwell GPIO. |
327 | 327 | ||
328 | config GPIO_PCH | 328 | config GPIO_PCH |
329 | tristate "PCH GPIO of Intel Topcliff" | 329 | tristate "PCH GPIO of Intel Topcliff" |
330 | depends on PCI | 330 | depends on PCI && X86 |
331 | help | 331 | help |
332 | This driver is for PCH(Platform controller Hub) GPIO of Intel Topcliff | 332 | This driver is for PCH(Platform controller Hub) GPIO of Intel Topcliff |
333 | which is an IOH(Input/Output Hub) for x86 embedded processor. | 333 | which is an IOH(Input/Output Hub) for x86 embedded processor. |
@@ -368,11 +368,11 @@ config GPIO_MAX7301 | |||
368 | GPIO driver for Maxim MAX7301 SPI-based GPIO expander. | 368 | GPIO driver for Maxim MAX7301 SPI-based GPIO expander. |
369 | 369 | ||
370 | config GPIO_MCP23S08 | 370 | config GPIO_MCP23S08 |
371 | tristate "Microchip MCP23S08 I/O expander" | 371 | tristate "Microchip MCP23Sxx I/O expander" |
372 | depends on SPI_MASTER | 372 | depends on SPI_MASTER |
373 | help | 373 | help |
374 | SPI driver for Microchip MCP23S08 I/O expander. This provides | 374 | SPI driver for Microchip MCP23S08/MPC23S17 I/O expanders. |
375 | a GPIO interface supporting inputs and outputs. | 375 | This provides a GPIO interface supporting inputs and outputs. |
376 | 376 | ||
377 | config GPIO_MC33880 | 377 | config GPIO_MC33880 |
378 | tristate "Freescale MC33880 high-side/low-side switch" | 378 | tristate "Freescale MC33880 high-side/low-side switch" |
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) | |||
373 | return 0; | 373 | return 0; |
374 | } | 374 | } |
375 | 375 | ||
376 | static struct platform_driver cs5535_gpio_drv = { | 376 | static struct platform_driver cs5535_gpio_driver = { |
377 | .driver = { | 377 | .driver = { |
378 | .name = DRV_NAME, | 378 | .name = DRV_NAME, |
379 | .owner = THIS_MODULE, | 379 | .owner = THIS_MODULE, |
@@ -384,12 +384,12 @@ static struct platform_driver cs5535_gpio_drv = { | |||
384 | 384 | ||
385 | static int __init cs5535_gpio_init(void) | 385 | static int __init cs5535_gpio_init(void) |
386 | { | 386 | { |
387 | return platform_driver_register(&cs5535_gpio_drv); | 387 | return platform_driver_register(&cs5535_gpio_driver); |
388 | } | 388 | } |
389 | 389 | ||
390 | static void __exit cs5535_gpio_exit(void) | 390 | static void __exit cs5535_gpio_exit(void) |
391 | { | 391 | { |
392 | platform_driver_unregister(&cs5535_gpio_drv); | 392 | platform_driver_unregister(&cs5535_gpio_driver); |
393 | } | 393 | } |
394 | 394 | ||
395 | module_init(cs5535_gpio_init); | 395 | module_init(cs5535_gpio_init); |
diff --git a/drivers/gpio/langwell_gpio.c b/drivers/gpio/langwell_gpio.c index 54d70a47afc1..560ab648cf18 100644 --- a/drivers/gpio/langwell_gpio.c +++ b/drivers/gpio/langwell_gpio.c | |||
@@ -187,31 +187,28 @@ MODULE_DEVICE_TABLE(pci, lnw_gpio_ids); | |||
187 | 187 | ||
188 | static void lnw_irq_handler(unsigned irq, struct irq_desc *desc) | 188 | static void lnw_irq_handler(unsigned irq, struct irq_desc *desc) |
189 | { | 189 | { |
190 | struct lnw_gpio *lnw = get_irq_data(irq); | 190 | struct irq_data *data = irq_desc_get_irq_data(desc); |
191 | u32 base, gpio; | 191 | struct lnw_gpio *lnw = irq_data_get_irq_handler_data(data); |
192 | struct irq_chip *chip = irq_data_get_irq_chip(data); | ||
193 | u32 base, gpio, mask; | ||
194 | unsigned long pending; | ||
192 | void __iomem *gedr; | 195 | void __iomem *gedr; |
193 | u32 gedr_v; | ||
194 | 196 | ||
195 | /* check GPIO controller to check which pin triggered the interrupt */ | 197 | /* check GPIO controller to check which pin triggered the interrupt */ |
196 | for (base = 0; base < lnw->chip.ngpio; base += 32) { | 198 | for (base = 0; base < lnw->chip.ngpio; base += 32) { |
197 | gedr = gpio_reg(&lnw->chip, base, GEDR); | 199 | gedr = gpio_reg(&lnw->chip, base, GEDR); |
198 | gedr_v = readl(gedr); | 200 | pending = readl(gedr); |
199 | if (!gedr_v) | 201 | while (pending) { |
200 | continue; | 202 | gpio = __ffs(pending) - 1; |
201 | for (gpio = base; gpio < base + 32; gpio++) | 203 | mask = BIT(gpio); |
202 | if (gedr_v & BIT(gpio % 32)) { | 204 | pending &= ~mask; |
203 | pr_debug("pin %d triggered\n", gpio); | 205 | /* Clear before handling so we can't lose an edge */ |
204 | generic_handle_irq(lnw->irq_base + gpio); | 206 | writel(mask, gedr); |
205 | } | 207 | generic_handle_irq(lnw->irq_base + base + gpio); |
206 | /* clear the edge detect status bit */ | 208 | } |
207 | writel(gedr_v, gedr); | ||
208 | } | 209 | } |
209 | 210 | ||
210 | if (desc->chip->irq_eoi) | 211 | chip->irq_eoi(data); |
211 | desc->chip->irq_eoi(irq_get_irq_data(irq)); | ||
212 | else | ||
213 | dev_warn(lnw->chip.dev, "missing EOI handler for irq %d\n", irq); | ||
214 | |||
215 | } | 212 | } |
216 | 213 | ||
217 | static int __devinit lnw_gpio_probe(struct pci_dev *pdev, | 214 | static int __devinit lnw_gpio_probe(struct pci_dev *pdev, |
@@ -279,12 +276,12 @@ static int __devinit lnw_gpio_probe(struct pci_dev *pdev, | |||
279 | dev_err(&pdev->dev, "langwell gpiochip_add error %d\n", retval); | 276 | dev_err(&pdev->dev, "langwell gpiochip_add error %d\n", retval); |
280 | goto err5; | 277 | goto err5; |
281 | } | 278 | } |
282 | set_irq_data(pdev->irq, lnw); | 279 | irq_set_handler_data(pdev->irq, lnw); |
283 | set_irq_chained_handler(pdev->irq, lnw_irq_handler); | 280 | irq_set_chained_handler(pdev->irq, lnw_irq_handler); |
284 | for (i = 0; i < lnw->chip.ngpio; i++) { | 281 | for (i = 0; i < lnw->chip.ngpio; i++) { |
285 | set_irq_chip_and_handler_name(i + lnw->irq_base, &lnw_irqchip, | 282 | irq_set_chip_and_handler_name(i + lnw->irq_base, &lnw_irqchip, |
286 | handle_simple_irq, "demux"); | 283 | handle_simple_irq, "demux"); |
287 | set_irq_chip_data(i + lnw->irq_base, lnw); | 284 | irq_set_chip_data(i + lnw->irq_base, lnw); |
288 | } | 285 | } |
289 | 286 | ||
290 | spin_lock_init(&lnw->lock); | 287 | spin_lock_init(&lnw->lock); |
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: | |||
146 | return ret; | 146 | return ret; |
147 | } | 147 | } |
148 | 148 | ||
149 | static int mc33880_remove(struct spi_device *spi) | 149 | static int __devexit mc33880_remove(struct spi_device *spi) |
150 | { | 150 | { |
151 | struct mc33880 *mc; | 151 | struct mc33880 *mc; |
152 | int ret; | 152 | int ret; |
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 @@ | |||
10 | #include <linux/spi/spi.h> | 10 | #include <linux/spi/spi.h> |
11 | #include <linux/spi/mcp23s08.h> | 11 | #include <linux/spi/mcp23s08.h> |
12 | #include <linux/slab.h> | 12 | #include <linux/slab.h> |
13 | #include <asm/byteorder.h> | ||
13 | 14 | ||
15 | /** | ||
16 | * MCP types supported by driver | ||
17 | */ | ||
18 | #define MCP_TYPE_S08 0 | ||
19 | #define MCP_TYPE_S17 1 | ||
14 | 20 | ||
15 | /* Registers are all 8 bits wide. | 21 | /* Registers are all 8 bits wide. |
16 | * | 22 | * |
@@ -35,27 +41,38 @@ | |||
35 | #define MCP_GPIO 0x09 | 41 | #define MCP_GPIO 0x09 |
36 | #define MCP_OLAT 0x0a | 42 | #define MCP_OLAT 0x0a |
37 | 43 | ||
44 | struct mcp23s08; | ||
45 | |||
46 | struct mcp23s08_ops { | ||
47 | int (*read)(struct mcp23s08 *mcp, unsigned reg); | ||
48 | int (*write)(struct mcp23s08 *mcp, unsigned reg, unsigned val); | ||
49 | int (*read_regs)(struct mcp23s08 *mcp, unsigned reg, | ||
50 | u16 *vals, unsigned n); | ||
51 | }; | ||
52 | |||
38 | struct mcp23s08 { | 53 | struct mcp23s08 { |
39 | struct spi_device *spi; | 54 | struct spi_device *spi; |
40 | u8 addr; | 55 | u8 addr; |
41 | 56 | ||
42 | u8 cache[11]; | 57 | u16 cache[11]; |
43 | /* lock protects the cached values */ | 58 | /* lock protects the cached values */ |
44 | struct mutex lock; | 59 | struct mutex lock; |
45 | 60 | ||
46 | struct gpio_chip chip; | 61 | struct gpio_chip chip; |
47 | 62 | ||
48 | struct work_struct work; | 63 | struct work_struct work; |
64 | |||
65 | const struct mcp23s08_ops *ops; | ||
49 | }; | 66 | }; |
50 | 67 | ||
51 | /* A given spi_device can represent up to four mcp23s08 chips | 68 | /* A given spi_device can represent up to eight mcp23sxx chips |
52 | * sharing the same chipselect but using different addresses | 69 | * sharing the same chipselect but using different addresses |
53 | * (e.g. chips #0 and #3 might be populated, but not #1 or $2). | 70 | * (e.g. chips #0 and #3 might be populated, but not #1 or $2). |
54 | * Driver data holds all the per-chip data. | 71 | * Driver data holds all the per-chip data. |
55 | */ | 72 | */ |
56 | struct mcp23s08_driver_data { | 73 | struct mcp23s08_driver_data { |
57 | unsigned ngpio; | 74 | unsigned ngpio; |
58 | struct mcp23s08 *mcp[4]; | 75 | struct mcp23s08 *mcp[8]; |
59 | struct mcp23s08 chip[]; | 76 | struct mcp23s08 chip[]; |
60 | }; | 77 | }; |
61 | 78 | ||
@@ -70,7 +87,7 @@ static int mcp23s08_read(struct mcp23s08 *mcp, unsigned reg) | |||
70 | return (status < 0) ? status : rx[0]; | 87 | return (status < 0) ? status : rx[0]; |
71 | } | 88 | } |
72 | 89 | ||
73 | static int mcp23s08_write(struct mcp23s08 *mcp, unsigned reg, u8 val) | 90 | static int mcp23s08_write(struct mcp23s08 *mcp, unsigned reg, unsigned val) |
74 | { | 91 | { |
75 | u8 tx[3]; | 92 | u8 tx[3]; |
76 | 93 | ||
@@ -81,17 +98,81 @@ static int mcp23s08_write(struct mcp23s08 *mcp, unsigned reg, u8 val) | |||
81 | } | 98 | } |
82 | 99 | ||
83 | static int | 100 | static int |
84 | mcp23s08_read_regs(struct mcp23s08 *mcp, unsigned reg, u8 *vals, unsigned n) | 101 | mcp23s08_read_regs(struct mcp23s08 *mcp, unsigned reg, u16 *vals, unsigned n) |
85 | { | 102 | { |
86 | u8 tx[2]; | 103 | u8 tx[2], *tmp; |
104 | int status; | ||
87 | 105 | ||
88 | if ((n + reg) > sizeof mcp->cache) | 106 | if ((n + reg) > sizeof mcp->cache) |
89 | return -EINVAL; | 107 | return -EINVAL; |
90 | tx[0] = mcp->addr | 0x01; | 108 | tx[0] = mcp->addr | 0x01; |
91 | tx[1] = reg; | 109 | tx[1] = reg; |
92 | return spi_write_then_read(mcp->spi, tx, sizeof tx, vals, n); | 110 | |
111 | tmp = (u8 *)vals; | ||
112 | status = spi_write_then_read(mcp->spi, tx, sizeof tx, tmp, n); | ||
113 | if (status >= 0) { | ||
114 | while (n--) | ||
115 | vals[n] = tmp[n]; /* expand to 16bit */ | ||
116 | } | ||
117 | return status; | ||
118 | } | ||
119 | |||
120 | static int mcp23s17_read(struct mcp23s08 *mcp, unsigned reg) | ||
121 | { | ||
122 | u8 tx[2], rx[2]; | ||
123 | int status; | ||
124 | |||
125 | tx[0] = mcp->addr | 0x01; | ||
126 | tx[1] = reg << 1; | ||
127 | status = spi_write_then_read(mcp->spi, tx, sizeof tx, rx, sizeof rx); | ||
128 | return (status < 0) ? status : (rx[0] | (rx[1] << 8)); | ||
129 | } | ||
130 | |||
131 | static int mcp23s17_write(struct mcp23s08 *mcp, unsigned reg, unsigned val) | ||
132 | { | ||
133 | u8 tx[4]; | ||
134 | |||
135 | tx[0] = mcp->addr; | ||
136 | tx[1] = reg << 1; | ||
137 | tx[2] = val; | ||
138 | tx[3] = val >> 8; | ||
139 | return spi_write_then_read(mcp->spi, tx, sizeof tx, NULL, 0); | ||
140 | } | ||
141 | |||
142 | static int | ||
143 | mcp23s17_read_regs(struct mcp23s08 *mcp, unsigned reg, u16 *vals, unsigned n) | ||
144 | { | ||
145 | u8 tx[2]; | ||
146 | int status; | ||
147 | |||
148 | if ((n + reg) > sizeof mcp->cache) | ||
149 | return -EINVAL; | ||
150 | tx[0] = mcp->addr | 0x01; | ||
151 | tx[1] = reg << 1; | ||
152 | |||
153 | status = spi_write_then_read(mcp->spi, tx, sizeof tx, | ||
154 | (u8 *)vals, n * 2); | ||
155 | if (status >= 0) { | ||
156 | while (n--) | ||
157 | vals[n] = __le16_to_cpu((__le16)vals[n]); | ||
158 | } | ||
159 | |||
160 | return status; | ||
93 | } | 161 | } |
94 | 162 | ||
163 | static const struct mcp23s08_ops mcp23s08_ops = { | ||
164 | .read = mcp23s08_read, | ||
165 | .write = mcp23s08_write, | ||
166 | .read_regs = mcp23s08_read_regs, | ||
167 | }; | ||
168 | |||
169 | static const struct mcp23s08_ops mcp23s17_ops = { | ||
170 | .read = mcp23s17_read, | ||
171 | .write = mcp23s17_write, | ||
172 | .read_regs = mcp23s17_read_regs, | ||
173 | }; | ||
174 | |||
175 | |||
95 | /*----------------------------------------------------------------------*/ | 176 | /*----------------------------------------------------------------------*/ |
96 | 177 | ||
97 | static int mcp23s08_direction_input(struct gpio_chip *chip, unsigned offset) | 178 | 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) | |||
101 | 182 | ||
102 | mutex_lock(&mcp->lock); | 183 | mutex_lock(&mcp->lock); |
103 | mcp->cache[MCP_IODIR] |= (1 << offset); | 184 | mcp->cache[MCP_IODIR] |= (1 << offset); |
104 | status = mcp23s08_write(mcp, MCP_IODIR, mcp->cache[MCP_IODIR]); | 185 | status = mcp->ops->write(mcp, MCP_IODIR, mcp->cache[MCP_IODIR]); |
105 | mutex_unlock(&mcp->lock); | 186 | mutex_unlock(&mcp->lock); |
106 | return status; | 187 | return status; |
107 | } | 188 | } |
@@ -114,7 +195,7 @@ static int mcp23s08_get(struct gpio_chip *chip, unsigned offset) | |||
114 | mutex_lock(&mcp->lock); | 195 | mutex_lock(&mcp->lock); |
115 | 196 | ||
116 | /* REVISIT reading this clears any IRQ ... */ | 197 | /* REVISIT reading this clears any IRQ ... */ |
117 | status = mcp23s08_read(mcp, MCP_GPIO); | 198 | status = mcp->ops->read(mcp, MCP_GPIO); |
118 | if (status < 0) | 199 | if (status < 0) |
119 | status = 0; | 200 | status = 0; |
120 | else { | 201 | else { |
@@ -127,20 +208,20 @@ static int mcp23s08_get(struct gpio_chip *chip, unsigned offset) | |||
127 | 208 | ||
128 | static int __mcp23s08_set(struct mcp23s08 *mcp, unsigned mask, int value) | 209 | static int __mcp23s08_set(struct mcp23s08 *mcp, unsigned mask, int value) |
129 | { | 210 | { |
130 | u8 olat = mcp->cache[MCP_OLAT]; | 211 | unsigned olat = mcp->cache[MCP_OLAT]; |
131 | 212 | ||
132 | if (value) | 213 | if (value) |
133 | olat |= mask; | 214 | olat |= mask; |
134 | else | 215 | else |
135 | olat &= ~mask; | 216 | olat &= ~mask; |
136 | mcp->cache[MCP_OLAT] = olat; | 217 | mcp->cache[MCP_OLAT] = olat; |
137 | return mcp23s08_write(mcp, MCP_OLAT, olat); | 218 | return mcp->ops->write(mcp, MCP_OLAT, olat); |
138 | } | 219 | } |
139 | 220 | ||
140 | static void mcp23s08_set(struct gpio_chip *chip, unsigned offset, int value) | 221 | static void mcp23s08_set(struct gpio_chip *chip, unsigned offset, int value) |
141 | { | 222 | { |
142 | struct mcp23s08 *mcp = container_of(chip, struct mcp23s08, chip); | 223 | struct mcp23s08 *mcp = container_of(chip, struct mcp23s08, chip); |
143 | u8 mask = 1 << offset; | 224 | unsigned mask = 1 << offset; |
144 | 225 | ||
145 | mutex_lock(&mcp->lock); | 226 | mutex_lock(&mcp->lock); |
146 | __mcp23s08_set(mcp, mask, value); | 227 | __mcp23s08_set(mcp, mask, value); |
@@ -151,14 +232,14 @@ static int | |||
151 | mcp23s08_direction_output(struct gpio_chip *chip, unsigned offset, int value) | 232 | mcp23s08_direction_output(struct gpio_chip *chip, unsigned offset, int value) |
152 | { | 233 | { |
153 | struct mcp23s08 *mcp = container_of(chip, struct mcp23s08, chip); | 234 | struct mcp23s08 *mcp = container_of(chip, struct mcp23s08, chip); |
154 | u8 mask = 1 << offset; | 235 | unsigned mask = 1 << offset; |
155 | int status; | 236 | int status; |
156 | 237 | ||
157 | mutex_lock(&mcp->lock); | 238 | mutex_lock(&mcp->lock); |
158 | status = __mcp23s08_set(mcp, mask, value); | 239 | status = __mcp23s08_set(mcp, mask, value); |
159 | if (status == 0) { | 240 | if (status == 0) { |
160 | mcp->cache[MCP_IODIR] &= ~mask; | 241 | mcp->cache[MCP_IODIR] &= ~mask; |
161 | status = mcp23s08_write(mcp, MCP_IODIR, mcp->cache[MCP_IODIR]); | 242 | status = mcp->ops->write(mcp, MCP_IODIR, mcp->cache[MCP_IODIR]); |
162 | } | 243 | } |
163 | mutex_unlock(&mcp->lock); | 244 | mutex_unlock(&mcp->lock); |
164 | return status; | 245 | return status; |
@@ -184,16 +265,16 @@ static void mcp23s08_dbg_show(struct seq_file *s, struct gpio_chip *chip) | |||
184 | mcp = container_of(chip, struct mcp23s08, chip); | 265 | mcp = container_of(chip, struct mcp23s08, chip); |
185 | 266 | ||
186 | /* NOTE: we only handle one bank for now ... */ | 267 | /* NOTE: we only handle one bank for now ... */ |
187 | bank = '0' + ((mcp->addr >> 1) & 0x3); | 268 | bank = '0' + ((mcp->addr >> 1) & 0x7); |
188 | 269 | ||
189 | mutex_lock(&mcp->lock); | 270 | mutex_lock(&mcp->lock); |
190 | t = mcp23s08_read_regs(mcp, 0, mcp->cache, sizeof mcp->cache); | 271 | t = mcp->ops->read_regs(mcp, 0, mcp->cache, ARRAY_SIZE(mcp->cache)); |
191 | if (t < 0) { | 272 | if (t < 0) { |
192 | seq_printf(s, " I/O ERROR %d\n", t); | 273 | seq_printf(s, " I/O ERROR %d\n", t); |
193 | goto done; | 274 | goto done; |
194 | } | 275 | } |
195 | 276 | ||
196 | for (t = 0, mask = 1; t < 8; t++, mask <<= 1) { | 277 | for (t = 0, mask = 1; t < chip->ngpio; t++, mask <<= 1) { |
197 | const char *label; | 278 | const char *label; |
198 | 279 | ||
199 | label = gpiochip_is_requested(chip, t); | 280 | label = gpiochip_is_requested(chip, t); |
@@ -219,28 +300,33 @@ done: | |||
219 | /*----------------------------------------------------------------------*/ | 300 | /*----------------------------------------------------------------------*/ |
220 | 301 | ||
221 | static int mcp23s08_probe_one(struct spi_device *spi, unsigned addr, | 302 | static int mcp23s08_probe_one(struct spi_device *spi, unsigned addr, |
222 | unsigned base, unsigned pullups) | 303 | unsigned type, unsigned base, unsigned pullups) |
223 | { | 304 | { |
224 | struct mcp23s08_driver_data *data = spi_get_drvdata(spi); | 305 | struct mcp23s08_driver_data *data = spi_get_drvdata(spi); |
225 | struct mcp23s08 *mcp = data->mcp[addr]; | 306 | struct mcp23s08 *mcp = data->mcp[addr]; |
226 | int status; | 307 | int status; |
227 | int do_update = 0; | ||
228 | 308 | ||
229 | mutex_init(&mcp->lock); | 309 | mutex_init(&mcp->lock); |
230 | 310 | ||
231 | mcp->spi = spi; | 311 | mcp->spi = spi; |
232 | mcp->addr = 0x40 | (addr << 1); | 312 | mcp->addr = 0x40 | (addr << 1); |
233 | 313 | ||
234 | mcp->chip.label = "mcp23s08", | ||
235 | |||
236 | mcp->chip.direction_input = mcp23s08_direction_input; | 314 | mcp->chip.direction_input = mcp23s08_direction_input; |
237 | mcp->chip.get = mcp23s08_get; | 315 | mcp->chip.get = mcp23s08_get; |
238 | mcp->chip.direction_output = mcp23s08_direction_output; | 316 | mcp->chip.direction_output = mcp23s08_direction_output; |
239 | mcp->chip.set = mcp23s08_set; | 317 | mcp->chip.set = mcp23s08_set; |
240 | mcp->chip.dbg_show = mcp23s08_dbg_show; | 318 | mcp->chip.dbg_show = mcp23s08_dbg_show; |
241 | 319 | ||
320 | if (type == MCP_TYPE_S17) { | ||
321 | mcp->ops = &mcp23s17_ops; | ||
322 | mcp->chip.ngpio = 16; | ||
323 | mcp->chip.label = "mcp23s17"; | ||
324 | } else { | ||
325 | mcp->ops = &mcp23s08_ops; | ||
326 | mcp->chip.ngpio = 8; | ||
327 | mcp->chip.label = "mcp23s08"; | ||
328 | } | ||
242 | mcp->chip.base = base; | 329 | mcp->chip.base = base; |
243 | mcp->chip.ngpio = 8; | ||
244 | mcp->chip.can_sleep = 1; | 330 | mcp->chip.can_sleep = 1; |
245 | mcp->chip.dev = &spi->dev; | 331 | mcp->chip.dev = &spi->dev; |
246 | mcp->chip.owner = THIS_MODULE; | 332 | mcp->chip.owner = THIS_MODULE; |
@@ -248,45 +334,39 @@ static int mcp23s08_probe_one(struct spi_device *spi, unsigned addr, | |||
248 | /* verify MCP_IOCON.SEQOP = 0, so sequential reads work, | 334 | /* verify MCP_IOCON.SEQOP = 0, so sequential reads work, |
249 | * and MCP_IOCON.HAEN = 1, so we work with all chips. | 335 | * and MCP_IOCON.HAEN = 1, so we work with all chips. |
250 | */ | 336 | */ |
251 | status = mcp23s08_read(mcp, MCP_IOCON); | 337 | status = mcp->ops->read(mcp, MCP_IOCON); |
252 | if (status < 0) | 338 | if (status < 0) |
253 | goto fail; | 339 | goto fail; |
254 | if ((status & IOCON_SEQOP) || !(status & IOCON_HAEN)) { | 340 | if ((status & IOCON_SEQOP) || !(status & IOCON_HAEN)) { |
255 | status &= ~IOCON_SEQOP; | 341 | /* mcp23s17 has IOCON twice, make sure they are in sync */ |
256 | status |= IOCON_HAEN; | 342 | status &= ~(IOCON_SEQOP | (IOCON_SEQOP << 8)); |
257 | status = mcp23s08_write(mcp, MCP_IOCON, (u8) status); | 343 | status |= IOCON_HAEN | (IOCON_HAEN << 8); |
344 | status = mcp->ops->write(mcp, MCP_IOCON, status); | ||
258 | if (status < 0) | 345 | if (status < 0) |
259 | goto fail; | 346 | goto fail; |
260 | } | 347 | } |
261 | 348 | ||
262 | /* configure ~100K pullups */ | 349 | /* configure ~100K pullups */ |
263 | status = mcp23s08_write(mcp, MCP_GPPU, pullups); | 350 | status = mcp->ops->write(mcp, MCP_GPPU, pullups); |
264 | if (status < 0) | 351 | if (status < 0) |
265 | goto fail; | 352 | goto fail; |
266 | 353 | ||
267 | status = mcp23s08_read_regs(mcp, 0, mcp->cache, sizeof mcp->cache); | 354 | status = mcp->ops->read_regs(mcp, 0, mcp->cache, ARRAY_SIZE(mcp->cache)); |
268 | if (status < 0) | 355 | if (status < 0) |
269 | goto fail; | 356 | goto fail; |
270 | 357 | ||
271 | /* disable inverter on input */ | 358 | /* disable inverter on input */ |
272 | if (mcp->cache[MCP_IPOL] != 0) { | 359 | if (mcp->cache[MCP_IPOL] != 0) { |
273 | mcp->cache[MCP_IPOL] = 0; | 360 | mcp->cache[MCP_IPOL] = 0; |
274 | do_update = 1; | 361 | status = mcp->ops->write(mcp, MCP_IPOL, 0); |
362 | if (status < 0) | ||
363 | goto fail; | ||
275 | } | 364 | } |
276 | 365 | ||
277 | /* disable irqs */ | 366 | /* disable irqs */ |
278 | if (mcp->cache[MCP_GPINTEN] != 0) { | 367 | if (mcp->cache[MCP_GPINTEN] != 0) { |
279 | mcp->cache[MCP_GPINTEN] = 0; | 368 | mcp->cache[MCP_GPINTEN] = 0; |
280 | do_update = 1; | 369 | status = mcp->ops->write(mcp, MCP_GPINTEN, 0); |
281 | } | ||
282 | |||
283 | if (do_update) { | ||
284 | u8 tx[4]; | ||
285 | |||
286 | tx[0] = mcp->addr; | ||
287 | tx[1] = MCP_IPOL; | ||
288 | memcpy(&tx[2], &mcp->cache[MCP_IPOL], sizeof(tx) - 2); | ||
289 | status = spi_write_then_read(mcp->spi, tx, sizeof tx, NULL, 0); | ||
290 | if (status < 0) | 370 | if (status < 0) |
291 | goto fail; | 371 | goto fail; |
292 | } | 372 | } |
@@ -305,19 +385,26 @@ static int mcp23s08_probe(struct spi_device *spi) | |||
305 | unsigned addr; | 385 | unsigned addr; |
306 | unsigned chips = 0; | 386 | unsigned chips = 0; |
307 | struct mcp23s08_driver_data *data; | 387 | struct mcp23s08_driver_data *data; |
308 | int status; | 388 | int status, type; |
309 | unsigned base; | 389 | unsigned base; |
310 | 390 | ||
391 | type = spi_get_device_id(spi)->driver_data; | ||
392 | |||
311 | pdata = spi->dev.platform_data; | 393 | pdata = spi->dev.platform_data; |
312 | if (!pdata || !gpio_is_valid(pdata->base)) { | 394 | if (!pdata || !gpio_is_valid(pdata->base)) { |
313 | dev_dbg(&spi->dev, "invalid or missing platform data\n"); | 395 | dev_dbg(&spi->dev, "invalid or missing platform data\n"); |
314 | return -EINVAL; | 396 | return -EINVAL; |
315 | } | 397 | } |
316 | 398 | ||
317 | for (addr = 0; addr < 4; addr++) { | 399 | for (addr = 0; addr < ARRAY_SIZE(pdata->chip); addr++) { |
318 | if (!pdata->chip[addr].is_present) | 400 | if (!pdata->chip[addr].is_present) |
319 | continue; | 401 | continue; |
320 | chips++; | 402 | chips++; |
403 | if ((type == MCP_TYPE_S08) && (addr > 3)) { | ||
404 | dev_err(&spi->dev, | ||
405 | "mcp23s08 only supports address 0..3\n"); | ||
406 | return -EINVAL; | ||
407 | } | ||
321 | } | 408 | } |
322 | if (!chips) | 409 | if (!chips) |
323 | return -ENODEV; | 410 | return -ENODEV; |
@@ -329,16 +416,17 @@ static int mcp23s08_probe(struct spi_device *spi) | |||
329 | spi_set_drvdata(spi, data); | 416 | spi_set_drvdata(spi, data); |
330 | 417 | ||
331 | base = pdata->base; | 418 | base = pdata->base; |
332 | for (addr = 0; addr < 4; addr++) { | 419 | for (addr = 0; addr < ARRAY_SIZE(pdata->chip); addr++) { |
333 | if (!pdata->chip[addr].is_present) | 420 | if (!pdata->chip[addr].is_present) |
334 | continue; | 421 | continue; |
335 | chips--; | 422 | chips--; |
336 | data->mcp[addr] = &data->chip[chips]; | 423 | data->mcp[addr] = &data->chip[chips]; |
337 | status = mcp23s08_probe_one(spi, addr, base, | 424 | status = mcp23s08_probe_one(spi, addr, type, base, |
338 | pdata->chip[addr].pullups); | 425 | pdata->chip[addr].pullups); |
339 | if (status < 0) | 426 | if (status < 0) |
340 | goto fail; | 427 | goto fail; |
341 | base += 8; | 428 | |
429 | base += (type == MCP_TYPE_S17) ? 16 : 8; | ||
342 | } | 430 | } |
343 | data->ngpio = base - pdata->base; | 431 | data->ngpio = base - pdata->base; |
344 | 432 | ||
@@ -358,7 +446,7 @@ static int mcp23s08_probe(struct spi_device *spi) | |||
358 | return 0; | 446 | return 0; |
359 | 447 | ||
360 | fail: | 448 | fail: |
361 | for (addr = 0; addr < 4; addr++) { | 449 | for (addr = 0; addr < ARRAY_SIZE(data->mcp); addr++) { |
362 | int tmp; | 450 | int tmp; |
363 | 451 | ||
364 | if (!data->mcp[addr]) | 452 | if (!data->mcp[addr]) |
@@ -388,7 +476,7 @@ static int mcp23s08_remove(struct spi_device *spi) | |||
388 | } | 476 | } |
389 | } | 477 | } |
390 | 478 | ||
391 | for (addr = 0; addr < 4; addr++) { | 479 | for (addr = 0; addr < ARRAY_SIZE(data->mcp); addr++) { |
392 | int tmp; | 480 | int tmp; |
393 | 481 | ||
394 | if (!data->mcp[addr]) | 482 | if (!data->mcp[addr]) |
@@ -405,9 +493,17 @@ static int mcp23s08_remove(struct spi_device *spi) | |||
405 | return status; | 493 | return status; |
406 | } | 494 | } |
407 | 495 | ||
496 | static const struct spi_device_id mcp23s08_ids[] = { | ||
497 | { "mcp23s08", MCP_TYPE_S08 }, | ||
498 | { "mcp23s17", MCP_TYPE_S17 }, | ||
499 | { }, | ||
500 | }; | ||
501 | MODULE_DEVICE_TABLE(spi, mcp23s08_ids); | ||
502 | |||
408 | static struct spi_driver mcp23s08_driver = { | 503 | static struct spi_driver mcp23s08_driver = { |
409 | .probe = mcp23s08_probe, | 504 | .probe = mcp23s08_probe, |
410 | .remove = mcp23s08_remove, | 505 | .remove = mcp23s08_remove, |
506 | .id_table = mcp23s08_ids, | ||
411 | .driver = { | 507 | .driver = { |
412 | .name = "mcp23s08", | 508 | .name = "mcp23s08", |
413 | .owner = THIS_MODULE, | 509 | .owner = THIS_MODULE, |
@@ -432,4 +528,3 @@ static void __exit mcp23s08_exit(void) | |||
432 | module_exit(mcp23s08_exit); | 528 | module_exit(mcp23s08_exit); |
433 | 529 | ||
434 | MODULE_LICENSE("GPL"); | 530 | MODULE_LICENSE("GPL"); |
435 | MODULE_ALIAS("spi:mcp23s08"); | ||
diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c index b473429eee75..2fc25dec7cf5 100644 --- a/drivers/gpio/pca953x.c +++ b/drivers/gpio/pca953x.c | |||
@@ -462,7 +462,8 @@ pca953x_get_alt_pdata(struct i2c_client *client) | |||
462 | { | 462 | { |
463 | struct pca953x_platform_data *pdata; | 463 | struct pca953x_platform_data *pdata; |
464 | struct device_node *node; | 464 | struct device_node *node; |
465 | const uint16_t *val; | 465 | const __be32 *val; |
466 | int size; | ||
466 | 467 | ||
467 | node = client->dev.of_node; | 468 | node = client->dev.of_node; |
468 | if (node == NULL) | 469 | if (node == NULL) |
@@ -475,13 +476,13 @@ pca953x_get_alt_pdata(struct i2c_client *client) | |||
475 | } | 476 | } |
476 | 477 | ||
477 | pdata->gpio_base = -1; | 478 | pdata->gpio_base = -1; |
478 | val = of_get_property(node, "linux,gpio-base", NULL); | 479 | val = of_get_property(node, "linux,gpio-base", &size); |
479 | if (val) { | 480 | if (val) { |
480 | if (*val < 0) | 481 | if (size != sizeof(*val)) |
481 | dev_warn(&client->dev, | 482 | dev_warn(&client->dev, "%s: wrong linux,gpio-base\n", |
482 | "invalid gpio-base in device tree\n"); | 483 | node->full_name); |
483 | else | 484 | else |
484 | pdata->gpio_base = *val; | 485 | pdata->gpio_base = be32_to_cpup(val); |
485 | } | 486 | } |
486 | 487 | ||
487 | val = of_get_property(node, "polarity", NULL); | 488 | val = of_get_property(node, "polarity", NULL); |
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 @@ | |||
25 | #include <linux/workqueue.h> | 25 | #include <linux/workqueue.h> |
26 | #include <linux/i2c/sx150x.h> | 26 | #include <linux/i2c/sx150x.h> |
27 | 27 | ||
28 | #define NO_UPDATE_PENDING -1 | ||
29 | |||
28 | struct sx150x_device_data { | 30 | struct sx150x_device_data { |
29 | u8 reg_pullup; | 31 | u8 reg_pullup; |
30 | u8 reg_pulldn; | 32 | u8 reg_pulldn; |
@@ -47,8 +49,11 @@ struct sx150x_chip { | |||
47 | const struct sx150x_device_data *dev_cfg; | 49 | const struct sx150x_device_data *dev_cfg; |
48 | int irq_summary; | 50 | int irq_summary; |
49 | int irq_base; | 51 | int irq_base; |
52 | int irq_update; | ||
50 | u32 irq_sense; | 53 | u32 irq_sense; |
51 | unsigned long irq_set_type_pending; | 54 | u32 irq_masked; |
55 | u32 dev_sense; | ||
56 | u32 dev_masked; | ||
52 | struct irq_chip irq_chip; | 57 | struct irq_chip irq_chip; |
53 | struct mutex lock; | 58 | struct mutex lock; |
54 | }; | 59 | }; |
@@ -312,9 +317,8 @@ static void sx150x_irq_mask(struct irq_data *d) | |||
312 | 317 | ||
313 | chip = container_of(ic, struct sx150x_chip, irq_chip); | 318 | chip = container_of(ic, struct sx150x_chip, irq_chip); |
314 | n = d->irq - chip->irq_base; | 319 | n = d->irq - chip->irq_base; |
315 | 320 | chip->irq_masked |= (1 << n); | |
316 | sx150x_write_cfg(chip, n, 1, chip->dev_cfg->reg_irq_mask, 1); | 321 | chip->irq_update = n; |
317 | sx150x_write_cfg(chip, n, 2, chip->dev_cfg->reg_sense, 0); | ||
318 | } | 322 | } |
319 | 323 | ||
320 | static void sx150x_irq_unmask(struct irq_data *d) | 324 | static void sx150x_irq_unmask(struct irq_data *d) |
@@ -326,9 +330,8 @@ static void sx150x_irq_unmask(struct irq_data *d) | |||
326 | chip = container_of(ic, struct sx150x_chip, irq_chip); | 330 | chip = container_of(ic, struct sx150x_chip, irq_chip); |
327 | n = d->irq - chip->irq_base; | 331 | n = d->irq - chip->irq_base; |
328 | 332 | ||
329 | sx150x_write_cfg(chip, n, 1, chip->dev_cfg->reg_irq_mask, 0); | 333 | chip->irq_masked &= ~(1 << n); |
330 | sx150x_write_cfg(chip, n, 2, chip->dev_cfg->reg_sense, | 334 | chip->irq_update = n; |
331 | chip->irq_sense >> (n * 2)); | ||
332 | } | 335 | } |
333 | 336 | ||
334 | static int sx150x_irq_set_type(struct irq_data *d, unsigned int flow_type) | 337 | 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) | |||
350 | 353 | ||
351 | chip->irq_sense &= ~(3UL << (n * 2)); | 354 | chip->irq_sense &= ~(3UL << (n * 2)); |
352 | chip->irq_sense |= val << (n * 2); | 355 | chip->irq_sense |= val << (n * 2); |
353 | chip->irq_set_type_pending |= BIT(n); | 356 | chip->irq_update = n; |
354 | return 0; | 357 | return 0; |
355 | } | 358 | } |
356 | 359 | ||
@@ -404,15 +407,29 @@ static void sx150x_irq_bus_sync_unlock(struct irq_data *d) | |||
404 | 407 | ||
405 | chip = container_of(ic, struct sx150x_chip, irq_chip); | 408 | chip = container_of(ic, struct sx150x_chip, irq_chip); |
406 | 409 | ||
407 | while (chip->irq_set_type_pending) { | 410 | if (chip->irq_update == NO_UPDATE_PENDING) |
408 | n = __ffs(chip->irq_set_type_pending); | 411 | goto out; |
409 | chip->irq_set_type_pending &= ~BIT(n); | 412 | |
410 | if (!(irq_to_desc(n + chip->irq_base)->status & IRQ_MASKED)) | 413 | n = chip->irq_update; |
411 | sx150x_write_cfg(chip, n, 2, | 414 | chip->irq_update = NO_UPDATE_PENDING; |
412 | chip->dev_cfg->reg_sense, | ||
413 | chip->irq_sense >> (n * 2)); | ||
414 | } | ||
415 | 415 | ||
416 | /* Avoid updates if nothing changed */ | ||
417 | if (chip->dev_sense == chip->irq_sense && | ||
418 | chip->dev_sense == chip->irq_masked) | ||
419 | goto out; | ||
420 | |||
421 | chip->dev_sense = chip->irq_sense; | ||
422 | chip->dev_masked = chip->irq_masked; | ||
423 | |||
424 | if (chip->irq_masked & (1 << n)) { | ||
425 | sx150x_write_cfg(chip, n, 1, chip->dev_cfg->reg_irq_mask, 1); | ||
426 | sx150x_write_cfg(chip, n, 2, chip->dev_cfg->reg_sense, 0); | ||
427 | } else { | ||
428 | sx150x_write_cfg(chip, n, 1, chip->dev_cfg->reg_irq_mask, 0); | ||
429 | sx150x_write_cfg(chip, n, 2, chip->dev_cfg->reg_sense, | ||
430 | chip->irq_sense >> (n * 2)); | ||
431 | } | ||
432 | out: | ||
416 | mutex_unlock(&chip->lock); | 433 | mutex_unlock(&chip->lock); |
417 | } | 434 | } |
418 | 435 | ||
@@ -445,8 +462,11 @@ static void sx150x_init_chip(struct sx150x_chip *chip, | |||
445 | chip->irq_chip.irq_bus_sync_unlock = sx150x_irq_bus_sync_unlock; | 462 | chip->irq_chip.irq_bus_sync_unlock = sx150x_irq_bus_sync_unlock; |
446 | chip->irq_summary = -1; | 463 | chip->irq_summary = -1; |
447 | chip->irq_base = -1; | 464 | chip->irq_base = -1; |
465 | chip->irq_masked = ~0; | ||
448 | chip->irq_sense = 0; | 466 | chip->irq_sense = 0; |
449 | chip->irq_set_type_pending = 0; | 467 | chip->dev_masked = ~0; |
468 | chip->dev_sense = 0; | ||
469 | chip->irq_update = NO_UPDATE_PENDING; | ||
450 | } | 470 | } |
451 | 471 | ||
452 | static int sx150x_init_io(struct sx150x_chip *chip, u8 base, u16 cfg) | 472 | static int sx150x_init_io(struct sx150x_chip *chip, u8 base, u16 cfg) |