Blame view
drivers/gpio/gpio-pcf857x.c
12.5 KB
15fae37d9
|
1 |
/* |
c103de240
|
2 |
* Driver for pcf857x, pca857x, and pca967x I2C GPIO expanders |
15fae37d9
|
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
* * Copyright (C) 2007 David Brownell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
d120c17fa
|
20 |
#include <linux/gpio.h> |
15fae37d9
|
21 |
#include <linux/i2c.h> |
b6480faee
|
22 |
#include <linux/platform_data/pcf857x.h> |
6e20a0a42
|
23 24 25 |
#include <linux/interrupt.h> #include <linux/irq.h> #include <linux/irqdomain.h> |
c990d6cb3
|
26 |
#include <linux/kernel.h> |
bb207ef1e
|
27 |
#include <linux/module.h> |
63f57cd45
|
28 29 |
#include <linux/of.h> #include <linux/of_device.h> |
c990d6cb3
|
30 |
#include <linux/slab.h> |
6e20a0a42
|
31 |
#include <linux/spinlock.h> |
15fae37d9
|
32 |
|
15fae37d9
|
33 |
|
3760f7367
|
34 35 |
static const struct i2c_device_id pcf857x_id[] = { { "pcf8574", 8 }, |
4ba2ccb83
|
36 |
{ "pcf8574a", 8 }, |
3760f7367
|
37 38 39 40 41 42 43 44 45 |
{ "pca8574", 8 }, { "pca9670", 8 }, { "pca9672", 8 }, { "pca9674", 8 }, { "pcf8575", 16 }, { "pca8575", 16 }, { "pca9671", 16 }, { "pca9673", 16 }, { "pca9675", 16 }, |
1673ad52b
|
46 47 |
{ "max7328", 8 }, { "max7329", 8 }, |
3760f7367
|
48 49 50 |
{ } }; MODULE_DEVICE_TABLE(i2c, pcf857x_id); |
63f57cd45
|
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
#ifdef CONFIG_OF static const struct of_device_id pcf857x_of_table[] = { { .compatible = "nxp,pcf8574" }, { .compatible = "nxp,pcf8574a" }, { .compatible = "nxp,pca8574" }, { .compatible = "nxp,pca9670" }, { .compatible = "nxp,pca9672" }, { .compatible = "nxp,pca9674" }, { .compatible = "nxp,pcf8575" }, { .compatible = "nxp,pca8575" }, { .compatible = "nxp,pca9671" }, { .compatible = "nxp,pca9673" }, { .compatible = "nxp,pca9675" }, { .compatible = "maxim,max7328" }, { .compatible = "maxim,max7329" }, |
63f57cd45
|
66 67 68 69 |
{ } }; MODULE_DEVICE_TABLE(of, pcf857x_of_table); #endif |
15fae37d9
|
70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
/* * The pcf857x, pca857x, and pca967x chips only expose one read and one * write register. Writing a "one" bit (to match the reset state) lets * that pin be used as an input; it's not an open-drain model, but acts * a bit like one. This is described as "quasi-bidirectional"; read the * chip documentation for details. * * Many other I2C GPIO expander chips (like the pca953x models) have * more complex register models and more conventional circuitry using * push/pull drivers. They often use the same 0x20..0x27 addresses as * pcf857x parts, making the "legacy" I2C driver model problematic. */ struct pcf857x { struct gpio_chip chip; |
25f13440d
|
84 |
struct irq_chip irqchip; |
15fae37d9
|
85 |
struct i2c_client *client; |
1673ad52b
|
86 |
struct mutex lock; /* protect 'out' */ |
15fae37d9
|
87 |
unsigned out; /* software latch */ |
6e20a0a42
|
88 |
unsigned status; /* current status */ |
ffb8e44bd
|
89 |
unsigned int irq_parent; |
84f28998c
|
90 |
unsigned irq_enabled; /* enabled irqs */ |
0c65ddd46
|
91 92 93 |
int (*write)(struct i2c_client *client, unsigned data); int (*read)(struct i2c_client *client); |
15fae37d9
|
94 95 96 97 98 |
}; /*-------------------------------------------------------------------------*/ /* Talk to 8-bit I/O expander */ |
0c65ddd46
|
99 |
static int i2c_write_le8(struct i2c_client *client, unsigned data) |
15fae37d9
|
100 |
{ |
0c65ddd46
|
101 |
return i2c_smbus_write_byte(client, data); |
15fae37d9
|
102 |
} |
0c65ddd46
|
103 |
static int i2c_read_le8(struct i2c_client *client) |
15fae37d9
|
104 |
{ |
0c65ddd46
|
105 |
return (int)i2c_smbus_read_byte(client); |
15fae37d9
|
106 |
} |
15fae37d9
|
107 |
/* Talk to 16-bit I/O expander */ |
0c65ddd46
|
108 |
static int i2c_write_le16(struct i2c_client *client, unsigned word) |
15fae37d9
|
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
{ u8 buf[2] = { word & 0xff, word >> 8, }; int status; status = i2c_master_send(client, buf, 2); return (status < 0) ? status : 0; } static int i2c_read_le16(struct i2c_client *client) { u8 buf[2]; int status; status = i2c_master_recv(client, buf, 2); if (status < 0) return status; return (buf[1] << 8) | buf[0]; } |
0c65ddd46
|
127 128 129 |
/*-------------------------------------------------------------------------*/ static int pcf857x_input(struct gpio_chip *chip, unsigned offset) |
15fae37d9
|
130 |
{ |
597358e41
|
131 |
struct pcf857x *gpio = gpiochip_get_data(chip); |
1673ad52b
|
132 |
int status; |
15fae37d9
|
133 |
|
1673ad52b
|
134 |
mutex_lock(&gpio->lock); |
15fae37d9
|
135 |
gpio->out |= (1 << offset); |
0c65ddd46
|
136 |
status = gpio->write(gpio->client, gpio->out); |
1673ad52b
|
137 138 139 |
mutex_unlock(&gpio->lock); return status; |
15fae37d9
|
140 |
} |
0c65ddd46
|
141 |
static int pcf857x_get(struct gpio_chip *chip, unsigned offset) |
15fae37d9
|
142 |
{ |
597358e41
|
143 |
struct pcf857x *gpio = gpiochip_get_data(chip); |
15fae37d9
|
144 |
int value; |
0c65ddd46
|
145 |
value = gpio->read(gpio->client); |
40f805806
|
146 |
return (value < 0) ? value : !!(value & (1 << offset)); |
15fae37d9
|
147 |
} |
0c65ddd46
|
148 |
static int pcf857x_output(struct gpio_chip *chip, unsigned offset, int value) |
15fae37d9
|
149 |
{ |
597358e41
|
150 |
struct pcf857x *gpio = gpiochip_get_data(chip); |
15fae37d9
|
151 |
unsigned bit = 1 << offset; |
1673ad52b
|
152 |
int status; |
15fae37d9
|
153 |
|
1673ad52b
|
154 |
mutex_lock(&gpio->lock); |
15fae37d9
|
155 156 157 158 |
if (value) gpio->out |= bit; else gpio->out &= ~bit; |
0c65ddd46
|
159 |
status = gpio->write(gpio->client, gpio->out); |
1673ad52b
|
160 161 162 |
mutex_unlock(&gpio->lock); return status; |
15fae37d9
|
163 |
} |
0c65ddd46
|
164 |
static void pcf857x_set(struct gpio_chip *chip, unsigned offset, int value) |
15fae37d9
|
165 |
{ |
0c65ddd46
|
166 |
pcf857x_output(chip, offset, value); |
15fae37d9
|
167 168 169 |
} /*-------------------------------------------------------------------------*/ |
5c21d0087
|
170 171 172 |
static irqreturn_t pcf857x_irq(int irq, void *data) { struct pcf857x *gpio = data; |
049aaf9f7
|
173 |
unsigned long change, i, status; |
5c21d0087
|
174 175 |
status = gpio->read(gpio->client); |
21fd3cd18
|
176 177 178 179 |
/* * call the interrupt handler iff gpio is used as * interrupt source, just to avoid bad irqs */ |
049aaf9f7
|
180 |
mutex_lock(&gpio->lock); |
84f28998c
|
181 |
change = (gpio->status ^ status) & gpio->irq_enabled; |
5c21d0087
|
182 |
gpio->status = status; |
049aaf9f7
|
183 |
mutex_unlock(&gpio->lock); |
5c21d0087
|
184 |
|
049aaf9f7
|
185 186 |
for_each_set_bit(i, &change, gpio->chip.ngpio) handle_nested_irq(irq_find_mapping(gpio->chip.irqdomain, i)); |
5c21d0087
|
187 188 189 |
return IRQ_HANDLED; } |
b80eef95b
|
190 191 192 193 |
/* * NOP functions */ static void noop(struct irq_data *data) { } |
b80eef95b
|
194 195 196 |
static int pcf857x_irq_set_wake(struct irq_data *data, unsigned int on) { struct pcf857x *gpio = irq_data_get_irq_chip_data(data); |
84f28998c
|
197 |
|
ffb8e44bd
|
198 199 200 201 202 203 204 205 206 207 208 209 |
int error = 0; if (gpio->irq_parent) { error = irq_set_irq_wake(gpio->irq_parent, on); if (error) { dev_dbg(&gpio->client->dev, "irq %u doesn't support irq_set_wake ", gpio->irq_parent); gpio->irq_parent = 0; } } |
ffb8e44bd
|
210 |
return error; |
b80eef95b
|
211 |
} |
84f28998c
|
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 |
static void pcf857x_irq_enable(struct irq_data *data) { struct pcf857x *gpio = irq_data_get_irq_chip_data(data); gpio->irq_enabled |= (1 << data->hwirq); } static void pcf857x_irq_disable(struct irq_data *data) { struct pcf857x *gpio = irq_data_get_irq_chip_data(data); gpio->irq_enabled &= ~(1 << data->hwirq); } static void pcf857x_irq_bus_lock(struct irq_data *data) { struct pcf857x *gpio = irq_data_get_irq_chip_data(data); mutex_lock(&gpio->lock); } static void pcf857x_irq_bus_sync_unlock(struct irq_data *data) { struct pcf857x *gpio = irq_data_get_irq_chip_data(data); mutex_unlock(&gpio->lock); } |
6e20a0a42
|
239 |
/*-------------------------------------------------------------------------*/ |
d2653e927
|
240 241 |
static int pcf857x_probe(struct i2c_client *client, const struct i2c_device_id *id) |
15fae37d9
|
242 |
{ |
63f57cd45
|
243 244 |
struct pcf857x_platform_data *pdata = dev_get_platdata(&client->dev); struct device_node *np = client->dev.of_node; |
15fae37d9
|
245 |
struct pcf857x *gpio; |
63f57cd45
|
246 |
unsigned int n_latch = 0; |
15fae37d9
|
247 |
int status; |
63f57cd45
|
248 249 250 251 252 |
if (IS_ENABLED(CONFIG_OF) && np) of_property_read_u32(np, "lines-initial-states", &n_latch); else if (pdata) n_latch = pdata->n_latch; else |
a342d215c
|
253 254 |
dev_dbg(&client->dev, "no platform data "); |
15fae37d9
|
255 256 |
/* Allocate, initialize, and register this gpio_chip. */ |
f39f54af0
|
257 |
gpio = devm_kzalloc(&client->dev, sizeof(*gpio), GFP_KERNEL); |
15fae37d9
|
258 259 |
if (!gpio) return -ENOMEM; |
1673ad52b
|
260 |
mutex_init(&gpio->lock); |
0c65ddd46
|
261 |
gpio->chip.base = pdata ? pdata->gpio_base : -1; |
9fb1f39eb
|
262 |
gpio->chip.can_sleep = true; |
0d1bb2b3b
|
263 |
gpio->chip.parent = &client->dev; |
0c65ddd46
|
264 265 266 267 268 269 |
gpio->chip.owner = THIS_MODULE; gpio->chip.get = pcf857x_get; gpio->chip.set = pcf857x_set; gpio->chip.direction_input = pcf857x_input; gpio->chip.direction_output = pcf857x_output; gpio->chip.ngpio = id->driver_data; |
15fae37d9
|
270 271 272 273 274 275 276 277 278 279 280 281 |
/* NOTE: the OnSemi jlc1562b is also largely compatible with * these parts, notably for output. It has a low-resolution * DAC instead of pin change IRQs; and its inputs can be the * result of comparators. */ /* 8574 addresses are 0x20..0x27; 8574a uses 0x38..0x3f; * 9670, 9672, 9764, and 9764a use quite a variety. * * NOTE: we don't distinguish here between *4 and *4a parts. */ |
3760f7367
|
282 |
if (gpio->chip.ngpio == 8) { |
0c65ddd46
|
283 284 |
gpio->write = i2c_write_le8; gpio->read = i2c_read_le8; |
15fae37d9
|
285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 |
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE)) status = -EIO; /* fail if there's no chip present */ else status = i2c_smbus_read_byte(client); /* '75/'75c addresses are 0x20..0x27, just like the '74; * the '75c doesn't have a current source pulling high. * 9671, 9673, and 9765 use quite a variety of addresses. * * NOTE: we don't distinguish here between '75 and '75c parts. */ |
3760f7367
|
300 |
} else if (gpio->chip.ngpio == 16) { |
0c65ddd46
|
301 302 |
gpio->write = i2c_write_le16; gpio->read = i2c_read_le16; |
15fae37d9
|
303 304 305 306 307 308 309 |
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) status = -EIO; /* fail if there's no chip present */ else status = i2c_read_le16(client); |
a342d215c
|
310 311 312 313 314 |
} else { dev_dbg(&client->dev, "unsupported number of gpios "); status = -EINVAL; } |
15fae37d9
|
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 |
if (status < 0) goto fail; gpio->chip.label = client->name; gpio->client = client; i2c_set_clientdata(client, gpio); /* NOTE: these chips have strange "quasi-bidirectional" I/O pins. * We can't actually know whether a pin is configured (a) as output * and driving the signal low, or (b) as input and reporting a low * value ... without knowing the last value written since the chip * came out of reset (if any). We can't read the latched output. * * In short, the only reliable solution for setting up pin direction * is to do it explicitly. The setup() method can do that, but it * may cause transient glitching since it can't know the last value * written (some pins may need to be driven low). * |
63f57cd45
|
335 336 337 |
* Using n_latch avoids that trouble. When left initialized to zero, * our software copy of the "latch" then matches the chip's all-ones * reset state. Otherwise it flags pins to be driven low. |
15fae37d9
|
338 |
*/ |
63f57cd45
|
339 |
gpio->out = ~n_latch; |
6e20a0a42
|
340 |
gpio->status = gpio->out; |
15fae37d9
|
341 |
|
3aebfc9bd
|
342 |
status = devm_gpiochip_add_data(&client->dev, &gpio->chip, gpio); |
15fae37d9
|
343 344 |
if (status < 0) goto fail; |
a39294bdf
|
345 346 |
/* Enable irqchip if we have an interrupt */ if (client->irq) { |
25f13440d
|
347 348 349 350 351 352 353 354 355 |
gpio->irqchip.name = "pcf857x", gpio->irqchip.irq_enable = pcf857x_irq_enable, gpio->irqchip.irq_disable = pcf857x_irq_disable, gpio->irqchip.irq_ack = noop, gpio->irqchip.irq_mask = noop, gpio->irqchip.irq_unmask = noop, gpio->irqchip.irq_set_wake = pcf857x_irq_set_wake, gpio->irqchip.irq_bus_lock = pcf857x_irq_bus_lock, gpio->irqchip.irq_bus_sync_unlock = pcf857x_irq_bus_sync_unlock, |
d245b3f9b
|
356 |
status = gpiochip_irqchip_add_nested(&gpio->chip, |
25f13440d
|
357 |
&gpio->irqchip, |
d245b3f9b
|
358 359 |
0, handle_level_irq, IRQ_TYPE_NONE); |
a39294bdf
|
360 361 362 |
if (status) { dev_err(&client->dev, "cannot add irqchip "); |
3aebfc9bd
|
363 |
goto fail; |
a39294bdf
|
364 365 366 367 368 369 370 |
} status = devm_request_threaded_irq(&client->dev, client->irq, NULL, pcf857x_irq, IRQF_ONESHOT | IRQF_TRIGGER_FALLING | IRQF_SHARED, dev_name(&client->dev), gpio); if (status) |
3aebfc9bd
|
371 |
goto fail; |
a39294bdf
|
372 |
|
25f13440d
|
373 |
gpiochip_set_nested_irqchip(&gpio->chip, &gpio->irqchip, |
d245b3f9b
|
374 |
client->irq); |
ffb8e44bd
|
375 |
gpio->irq_parent = client->irq; |
a39294bdf
|
376 |
} |
15fae37d9
|
377 378 379 |
/* Let platform code set up the GPIOs and their users. * Now is the first time anyone could use them. */ |
49946f681
|
380 |
if (pdata && pdata->setup) { |
15fae37d9
|
381 382 383 384 385 386 387 |
status = pdata->setup(client, gpio->chip.base, gpio->chip.ngpio, pdata->context); if (status < 0) dev_warn(&client->dev, "setup --> %d ", status); } |
805f864eb
|
388 389 |
dev_info(&client->dev, "probed "); |
15fae37d9
|
390 |
return 0; |
a39294bdf
|
391 392 393 394 |
fail: dev_dbg(&client->dev, "probe error %d for '%s' ", status, client->name); |
e6b698f69
|
395 |
|
15fae37d9
|
396 397 398 399 400 |
return status; } static int pcf857x_remove(struct i2c_client *client) { |
e56aee189
|
401 |
struct pcf857x_platform_data *pdata = dev_get_platdata(&client->dev); |
15fae37d9
|
402 403 |
struct pcf857x *gpio = i2c_get_clientdata(client); int status = 0; |
49946f681
|
404 |
if (pdata && pdata->teardown) { |
15fae37d9
|
405 406 407 408 409 410 411 412 413 414 |
status = pdata->teardown(client, gpio->chip.base, gpio->chip.ngpio, pdata->context); if (status < 0) { dev_err(&client->dev, "%s --> %d ", "teardown", status); return status; } } |
15fae37d9
|
415 416 |
return status; } |
adc284755
|
417 418 419 420 421 422 423 |
static void pcf857x_shutdown(struct i2c_client *client) { struct pcf857x *gpio = i2c_get_clientdata(client); /* Drive all the I/O lines high */ gpio->write(gpio->client, BIT(gpio->chip.ngpio) - 1); } |
15fae37d9
|
424 425 426 |
static struct i2c_driver pcf857x_driver = { .driver = { .name = "pcf857x", |
63f57cd45
|
427 |
.of_match_table = of_match_ptr(pcf857x_of_table), |
15fae37d9
|
428 429 430 |
}, .probe = pcf857x_probe, .remove = pcf857x_remove, |
adc284755
|
431 |
.shutdown = pcf857x_shutdown, |
3760f7367
|
432 |
.id_table = pcf857x_id, |
15fae37d9
|
433 434 435 436 437 438 |
}; static int __init pcf857x_init(void) { return i2c_add_driver(&pcf857x_driver); } |
2f8d11971
|
439 440 441 442 |
/* register after i2c postcore initcall and before * subsys initcalls that may rely on these GPIOs */ subsys_initcall(pcf857x_init); |
15fae37d9
|
443 444 445 446 447 448 449 450 451 |
static void __exit pcf857x_exit(void) { i2c_del_driver(&pcf857x_driver); } module_exit(pcf857x_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("David Brownell"); |