Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.2-rc6 724 lines 16 kB view raw
1/* 2 * MCP23S08 SPI/GPIO gpio expander driver 3 */ 4 5#include <linux/kernel.h> 6#include <linux/device.h> 7#include <linux/mutex.h> 8#include <linux/module.h> 9#include <linux/gpio.h> 10#include <linux/i2c.h> 11#include <linux/spi/spi.h> 12#include <linux/spi/mcp23s08.h> 13#include <linux/slab.h> 14#include <asm/byteorder.h> 15 16/** 17 * MCP types supported by driver 18 */ 19#define MCP_TYPE_S08 0 20#define MCP_TYPE_S17 1 21#define MCP_TYPE_008 2 22#define MCP_TYPE_017 3 23 24/* Registers are all 8 bits wide. 25 * 26 * The mcp23s17 has twice as many bits, and can be configured to work 27 * with either 16 bit registers or with two adjacent 8 bit banks. 28 */ 29#define MCP_IODIR 0x00 /* init/reset: all ones */ 30#define MCP_IPOL 0x01 31#define MCP_GPINTEN 0x02 32#define MCP_DEFVAL 0x03 33#define MCP_INTCON 0x04 34#define MCP_IOCON 0x05 35# define IOCON_SEQOP (1 << 5) 36# define IOCON_HAEN (1 << 3) 37# define IOCON_ODR (1 << 2) 38# define IOCON_INTPOL (1 << 1) 39#define MCP_GPPU 0x06 40#define MCP_INTF 0x07 41#define MCP_INTCAP 0x08 42#define MCP_GPIO 0x09 43#define MCP_OLAT 0x0a 44 45struct mcp23s08; 46 47struct mcp23s08_ops { 48 int (*read)(struct mcp23s08 *mcp, unsigned reg); 49 int (*write)(struct mcp23s08 *mcp, unsigned reg, unsigned val); 50 int (*read_regs)(struct mcp23s08 *mcp, unsigned reg, 51 u16 *vals, unsigned n); 52}; 53 54struct mcp23s08 { 55 u8 addr; 56 57 u16 cache[11]; 58 /* lock protects the cached values */ 59 struct mutex lock; 60 61 struct gpio_chip chip; 62 63 const struct mcp23s08_ops *ops; 64 void *data; /* ops specific data */ 65}; 66 67/* A given spi_device can represent up to eight mcp23sxx chips 68 * sharing the same chipselect but using different addresses 69 * (e.g. chips #0 and #3 might be populated, but not #1 or $2). 70 * Driver data holds all the per-chip data. 71 */ 72struct mcp23s08_driver_data { 73 unsigned ngpio; 74 struct mcp23s08 *mcp[8]; 75 struct mcp23s08 chip[]; 76}; 77 78/*----------------------------------------------------------------------*/ 79 80#ifdef CONFIG_I2C 81 82static int mcp23008_read(struct mcp23s08 *mcp, unsigned reg) 83{ 84 return i2c_smbus_read_byte_data(mcp->data, reg); 85} 86 87static int mcp23008_write(struct mcp23s08 *mcp, unsigned reg, unsigned val) 88{ 89 return i2c_smbus_write_byte_data(mcp->data, reg, val); 90} 91 92static int 93mcp23008_read_regs(struct mcp23s08 *mcp, unsigned reg, u16 *vals, unsigned n) 94{ 95 while (n--) { 96 int ret = mcp23008_read(mcp, reg++); 97 if (ret < 0) 98 return ret; 99 *vals++ = ret; 100 } 101 102 return 0; 103} 104 105static int mcp23017_read(struct mcp23s08 *mcp, unsigned reg) 106{ 107 return i2c_smbus_read_word_data(mcp->data, reg << 1); 108} 109 110static int mcp23017_write(struct mcp23s08 *mcp, unsigned reg, unsigned val) 111{ 112 return i2c_smbus_write_word_data(mcp->data, reg << 1, val); 113} 114 115static int 116mcp23017_read_regs(struct mcp23s08 *mcp, unsigned reg, u16 *vals, unsigned n) 117{ 118 while (n--) { 119 int ret = mcp23017_read(mcp, reg++); 120 if (ret < 0) 121 return ret; 122 *vals++ = ret; 123 } 124 125 return 0; 126} 127 128static const struct mcp23s08_ops mcp23008_ops = { 129 .read = mcp23008_read, 130 .write = mcp23008_write, 131 .read_regs = mcp23008_read_regs, 132}; 133 134static const struct mcp23s08_ops mcp23017_ops = { 135 .read = mcp23017_read, 136 .write = mcp23017_write, 137 .read_regs = mcp23017_read_regs, 138}; 139 140#endif /* CONFIG_I2C */ 141 142/*----------------------------------------------------------------------*/ 143 144#ifdef CONFIG_SPI_MASTER 145 146static int mcp23s08_read(struct mcp23s08 *mcp, unsigned reg) 147{ 148 u8 tx[2], rx[1]; 149 int status; 150 151 tx[0] = mcp->addr | 0x01; 152 tx[1] = reg; 153 status = spi_write_then_read(mcp->data, tx, sizeof tx, rx, sizeof rx); 154 return (status < 0) ? status : rx[0]; 155} 156 157static int mcp23s08_write(struct mcp23s08 *mcp, unsigned reg, unsigned val) 158{ 159 u8 tx[3]; 160 161 tx[0] = mcp->addr; 162 tx[1] = reg; 163 tx[2] = val; 164 return spi_write_then_read(mcp->data, tx, sizeof tx, NULL, 0); 165} 166 167static int 168mcp23s08_read_regs(struct mcp23s08 *mcp, unsigned reg, u16 *vals, unsigned n) 169{ 170 u8 tx[2], *tmp; 171 int status; 172 173 if ((n + reg) > sizeof mcp->cache) 174 return -EINVAL; 175 tx[0] = mcp->addr | 0x01; 176 tx[1] = reg; 177 178 tmp = (u8 *)vals; 179 status = spi_write_then_read(mcp->data, tx, sizeof tx, tmp, n); 180 if (status >= 0) { 181 while (n--) 182 vals[n] = tmp[n]; /* expand to 16bit */ 183 } 184 return status; 185} 186 187static int mcp23s17_read(struct mcp23s08 *mcp, unsigned reg) 188{ 189 u8 tx[2], rx[2]; 190 int status; 191 192 tx[0] = mcp->addr | 0x01; 193 tx[1] = reg << 1; 194 status = spi_write_then_read(mcp->data, tx, sizeof tx, rx, sizeof rx); 195 return (status < 0) ? status : (rx[0] | (rx[1] << 8)); 196} 197 198static int mcp23s17_write(struct mcp23s08 *mcp, unsigned reg, unsigned val) 199{ 200 u8 tx[4]; 201 202 tx[0] = mcp->addr; 203 tx[1] = reg << 1; 204 tx[2] = val; 205 tx[3] = val >> 8; 206 return spi_write_then_read(mcp->data, tx, sizeof tx, NULL, 0); 207} 208 209static int 210mcp23s17_read_regs(struct mcp23s08 *mcp, unsigned reg, u16 *vals, unsigned n) 211{ 212 u8 tx[2]; 213 int status; 214 215 if ((n + reg) > sizeof mcp->cache) 216 return -EINVAL; 217 tx[0] = mcp->addr | 0x01; 218 tx[1] = reg << 1; 219 220 status = spi_write_then_read(mcp->data, tx, sizeof tx, 221 (u8 *)vals, n * 2); 222 if (status >= 0) { 223 while (n--) 224 vals[n] = __le16_to_cpu((__le16)vals[n]); 225 } 226 227 return status; 228} 229 230static const struct mcp23s08_ops mcp23s08_ops = { 231 .read = mcp23s08_read, 232 .write = mcp23s08_write, 233 .read_regs = mcp23s08_read_regs, 234}; 235 236static const struct mcp23s08_ops mcp23s17_ops = { 237 .read = mcp23s17_read, 238 .write = mcp23s17_write, 239 .read_regs = mcp23s17_read_regs, 240}; 241 242#endif /* CONFIG_SPI_MASTER */ 243 244/*----------------------------------------------------------------------*/ 245 246static int mcp23s08_direction_input(struct gpio_chip *chip, unsigned offset) 247{ 248 struct mcp23s08 *mcp = container_of(chip, struct mcp23s08, chip); 249 int status; 250 251 mutex_lock(&mcp->lock); 252 mcp->cache[MCP_IODIR] |= (1 << offset); 253 status = mcp->ops->write(mcp, MCP_IODIR, mcp->cache[MCP_IODIR]); 254 mutex_unlock(&mcp->lock); 255 return status; 256} 257 258static int mcp23s08_get(struct gpio_chip *chip, unsigned offset) 259{ 260 struct mcp23s08 *mcp = container_of(chip, struct mcp23s08, chip); 261 int status; 262 263 mutex_lock(&mcp->lock); 264 265 /* REVISIT reading this clears any IRQ ... */ 266 status = mcp->ops->read(mcp, MCP_GPIO); 267 if (status < 0) 268 status = 0; 269 else { 270 mcp->cache[MCP_GPIO] = status; 271 status = !!(status & (1 << offset)); 272 } 273 mutex_unlock(&mcp->lock); 274 return status; 275} 276 277static int __mcp23s08_set(struct mcp23s08 *mcp, unsigned mask, int value) 278{ 279 unsigned olat = mcp->cache[MCP_OLAT]; 280 281 if (value) 282 olat |= mask; 283 else 284 olat &= ~mask; 285 mcp->cache[MCP_OLAT] = olat; 286 return mcp->ops->write(mcp, MCP_OLAT, olat); 287} 288 289static void mcp23s08_set(struct gpio_chip *chip, unsigned offset, int value) 290{ 291 struct mcp23s08 *mcp = container_of(chip, struct mcp23s08, chip); 292 unsigned mask = 1 << offset; 293 294 mutex_lock(&mcp->lock); 295 __mcp23s08_set(mcp, mask, value); 296 mutex_unlock(&mcp->lock); 297} 298 299static int 300mcp23s08_direction_output(struct gpio_chip *chip, unsigned offset, int value) 301{ 302 struct mcp23s08 *mcp = container_of(chip, struct mcp23s08, chip); 303 unsigned mask = 1 << offset; 304 int status; 305 306 mutex_lock(&mcp->lock); 307 status = __mcp23s08_set(mcp, mask, value); 308 if (status == 0) { 309 mcp->cache[MCP_IODIR] &= ~mask; 310 status = mcp->ops->write(mcp, MCP_IODIR, mcp->cache[MCP_IODIR]); 311 } 312 mutex_unlock(&mcp->lock); 313 return status; 314} 315 316/*----------------------------------------------------------------------*/ 317 318#ifdef CONFIG_DEBUG_FS 319 320#include <linux/seq_file.h> 321 322/* 323 * This shows more info than the generic gpio dump code: 324 * pullups, deglitching, open drain drive. 325 */ 326static void mcp23s08_dbg_show(struct seq_file *s, struct gpio_chip *chip) 327{ 328 struct mcp23s08 *mcp; 329 char bank; 330 int t; 331 unsigned mask; 332 333 mcp = container_of(chip, struct mcp23s08, chip); 334 335 /* NOTE: we only handle one bank for now ... */ 336 bank = '0' + ((mcp->addr >> 1) & 0x7); 337 338 mutex_lock(&mcp->lock); 339 t = mcp->ops->read_regs(mcp, 0, mcp->cache, ARRAY_SIZE(mcp->cache)); 340 if (t < 0) { 341 seq_printf(s, " I/O ERROR %d\n", t); 342 goto done; 343 } 344 345 for (t = 0, mask = 1; t < chip->ngpio; t++, mask <<= 1) { 346 const char *label; 347 348 label = gpiochip_is_requested(chip, t); 349 if (!label) 350 continue; 351 352 seq_printf(s, " gpio-%-3d P%c.%d (%-12s) %s %s %s", 353 chip->base + t, bank, t, label, 354 (mcp->cache[MCP_IODIR] & mask) ? "in " : "out", 355 (mcp->cache[MCP_GPIO] & mask) ? "hi" : "lo", 356 (mcp->cache[MCP_GPPU] & mask) ? " " : "up"); 357 /* NOTE: ignoring the irq-related registers */ 358 seq_printf(s, "\n"); 359 } 360done: 361 mutex_unlock(&mcp->lock); 362} 363 364#else 365#define mcp23s08_dbg_show NULL 366#endif 367 368/*----------------------------------------------------------------------*/ 369 370static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, 371 void *data, unsigned addr, 372 unsigned type, unsigned base, unsigned pullups) 373{ 374 int status; 375 376 mutex_init(&mcp->lock); 377 378 mcp->data = data; 379 mcp->addr = addr; 380 381 mcp->chip.direction_input = mcp23s08_direction_input; 382 mcp->chip.get = mcp23s08_get; 383 mcp->chip.direction_output = mcp23s08_direction_output; 384 mcp->chip.set = mcp23s08_set; 385 mcp->chip.dbg_show = mcp23s08_dbg_show; 386 387 switch (type) { 388#ifdef CONFIG_SPI_MASTER 389 case MCP_TYPE_S08: 390 mcp->ops = &mcp23s08_ops; 391 mcp->chip.ngpio = 8; 392 mcp->chip.label = "mcp23s08"; 393 break; 394 395 case MCP_TYPE_S17: 396 mcp->ops = &mcp23s17_ops; 397 mcp->chip.ngpio = 16; 398 mcp->chip.label = "mcp23s17"; 399 break; 400#endif /* CONFIG_SPI_MASTER */ 401 402#ifdef CONFIG_I2C 403 case MCP_TYPE_008: 404 mcp->ops = &mcp23008_ops; 405 mcp->chip.ngpio = 8; 406 mcp->chip.label = "mcp23008"; 407 break; 408 409 case MCP_TYPE_017: 410 mcp->ops = &mcp23017_ops; 411 mcp->chip.ngpio = 16; 412 mcp->chip.label = "mcp23017"; 413 break; 414#endif /* CONFIG_I2C */ 415 416 default: 417 dev_err(dev, "invalid device type (%d)\n", type); 418 return -EINVAL; 419 } 420 421 mcp->chip.base = base; 422 mcp->chip.can_sleep = 1; 423 mcp->chip.dev = dev; 424 mcp->chip.owner = THIS_MODULE; 425 426 /* verify MCP_IOCON.SEQOP = 0, so sequential reads work, 427 * and MCP_IOCON.HAEN = 1, so we work with all chips. 428 */ 429 status = mcp->ops->read(mcp, MCP_IOCON); 430 if (status < 0) 431 goto fail; 432 if ((status & IOCON_SEQOP) || !(status & IOCON_HAEN)) { 433 /* mcp23s17 has IOCON twice, make sure they are in sync */ 434 status &= ~(IOCON_SEQOP | (IOCON_SEQOP << 8)); 435 status |= IOCON_HAEN | (IOCON_HAEN << 8); 436 status = mcp->ops->write(mcp, MCP_IOCON, status); 437 if (status < 0) 438 goto fail; 439 } 440 441 /* configure ~100K pullups */ 442 status = mcp->ops->write(mcp, MCP_GPPU, pullups); 443 if (status < 0) 444 goto fail; 445 446 status = mcp->ops->read_regs(mcp, 0, mcp->cache, ARRAY_SIZE(mcp->cache)); 447 if (status < 0) 448 goto fail; 449 450 /* disable inverter on input */ 451 if (mcp->cache[MCP_IPOL] != 0) { 452 mcp->cache[MCP_IPOL] = 0; 453 status = mcp->ops->write(mcp, MCP_IPOL, 0); 454 if (status < 0) 455 goto fail; 456 } 457 458 /* disable irqs */ 459 if (mcp->cache[MCP_GPINTEN] != 0) { 460 mcp->cache[MCP_GPINTEN] = 0; 461 status = mcp->ops->write(mcp, MCP_GPINTEN, 0); 462 if (status < 0) 463 goto fail; 464 } 465 466 status = gpiochip_add(&mcp->chip); 467fail: 468 if (status < 0) 469 dev_dbg(dev, "can't setup chip %d, --> %d\n", 470 addr, status); 471 return status; 472} 473 474/*----------------------------------------------------------------------*/ 475 476#ifdef CONFIG_I2C 477 478static int __devinit mcp230xx_probe(struct i2c_client *client, 479 const struct i2c_device_id *id) 480{ 481 struct mcp23s08_platform_data *pdata; 482 struct mcp23s08 *mcp; 483 int status; 484 485 pdata = client->dev.platform_data; 486 if (!pdata || !gpio_is_valid(pdata->base)) { 487 dev_dbg(&client->dev, "invalid or missing platform data\n"); 488 return -EINVAL; 489 } 490 491 mcp = kzalloc(sizeof *mcp, GFP_KERNEL); 492 if (!mcp) 493 return -ENOMEM; 494 495 status = mcp23s08_probe_one(mcp, &client->dev, client, client->addr, 496 id->driver_data, pdata->base, 497 pdata->chip[0].pullups); 498 if (status) 499 goto fail; 500 501 i2c_set_clientdata(client, mcp); 502 503 return 0; 504 505fail: 506 kfree(mcp); 507 508 return status; 509} 510 511static int __devexit mcp230xx_remove(struct i2c_client *client) 512{ 513 struct mcp23s08 *mcp = i2c_get_clientdata(client); 514 int status; 515 516 status = gpiochip_remove(&mcp->chip); 517 if (status == 0) 518 kfree(mcp); 519 520 return status; 521} 522 523static const struct i2c_device_id mcp230xx_id[] = { 524 { "mcp23008", MCP_TYPE_008 }, 525 { "mcp23017", MCP_TYPE_017 }, 526 { }, 527}; 528MODULE_DEVICE_TABLE(i2c, mcp230xx_id); 529 530static struct i2c_driver mcp230xx_driver = { 531 .driver = { 532 .name = "mcp230xx", 533 .owner = THIS_MODULE, 534 }, 535 .probe = mcp230xx_probe, 536 .remove = __devexit_p(mcp230xx_remove), 537 .id_table = mcp230xx_id, 538}; 539 540static int __init mcp23s08_i2c_init(void) 541{ 542 return i2c_add_driver(&mcp230xx_driver); 543} 544 545static void mcp23s08_i2c_exit(void) 546{ 547 i2c_del_driver(&mcp230xx_driver); 548} 549 550#else 551 552static int __init mcp23s08_i2c_init(void) { return 0; } 553static void mcp23s08_i2c_exit(void) { } 554 555#endif /* CONFIG_I2C */ 556 557/*----------------------------------------------------------------------*/ 558 559#ifdef CONFIG_SPI_MASTER 560 561static int mcp23s08_probe(struct spi_device *spi) 562{ 563 struct mcp23s08_platform_data *pdata; 564 unsigned addr; 565 unsigned chips = 0; 566 struct mcp23s08_driver_data *data; 567 int status, type; 568 unsigned base; 569 570 type = spi_get_device_id(spi)->driver_data; 571 572 pdata = spi->dev.platform_data; 573 if (!pdata || !gpio_is_valid(pdata->base)) { 574 dev_dbg(&spi->dev, "invalid or missing platform data\n"); 575 return -EINVAL; 576 } 577 578 for (addr = 0; addr < ARRAY_SIZE(pdata->chip); addr++) { 579 if (!pdata->chip[addr].is_present) 580 continue; 581 chips++; 582 if ((type == MCP_TYPE_S08) && (addr > 3)) { 583 dev_err(&spi->dev, 584 "mcp23s08 only supports address 0..3\n"); 585 return -EINVAL; 586 } 587 } 588 if (!chips) 589 return -ENODEV; 590 591 data = kzalloc(sizeof *data + chips * sizeof(struct mcp23s08), 592 GFP_KERNEL); 593 if (!data) 594 return -ENOMEM; 595 spi_set_drvdata(spi, data); 596 597 base = pdata->base; 598 for (addr = 0; addr < ARRAY_SIZE(pdata->chip); addr++) { 599 if (!pdata->chip[addr].is_present) 600 continue; 601 chips--; 602 data->mcp[addr] = &data->chip[chips]; 603 status = mcp23s08_probe_one(data->mcp[addr], &spi->dev, spi, 604 0x40 | (addr << 1), type, base, 605 pdata->chip[addr].pullups); 606 if (status < 0) 607 goto fail; 608 609 base += (type == MCP_TYPE_S17) ? 16 : 8; 610 } 611 data->ngpio = base - pdata->base; 612 613 /* NOTE: these chips have a relatively sane IRQ framework, with 614 * per-signal masking and level/edge triggering. It's not yet 615 * handled here... 616 */ 617 618 return 0; 619 620fail: 621 for (addr = 0; addr < ARRAY_SIZE(data->mcp); addr++) { 622 int tmp; 623 624 if (!data->mcp[addr]) 625 continue; 626 tmp = gpiochip_remove(&data->mcp[addr]->chip); 627 if (tmp < 0) 628 dev_err(&spi->dev, "%s --> %d\n", "remove", tmp); 629 } 630 kfree(data); 631 return status; 632} 633 634static int mcp23s08_remove(struct spi_device *spi) 635{ 636 struct mcp23s08_driver_data *data = spi_get_drvdata(spi); 637 unsigned addr; 638 int status = 0; 639 640 for (addr = 0; addr < ARRAY_SIZE(data->mcp); addr++) { 641 int tmp; 642 643 if (!data->mcp[addr]) 644 continue; 645 646 tmp = gpiochip_remove(&data->mcp[addr]->chip); 647 if (tmp < 0) { 648 dev_err(&spi->dev, "%s --> %d\n", "remove", tmp); 649 status = tmp; 650 } 651 } 652 if (status == 0) 653 kfree(data); 654 return status; 655} 656 657static const struct spi_device_id mcp23s08_ids[] = { 658 { "mcp23s08", MCP_TYPE_S08 }, 659 { "mcp23s17", MCP_TYPE_S17 }, 660 { }, 661}; 662MODULE_DEVICE_TABLE(spi, mcp23s08_ids); 663 664static struct spi_driver mcp23s08_driver = { 665 .probe = mcp23s08_probe, 666 .remove = mcp23s08_remove, 667 .id_table = mcp23s08_ids, 668 .driver = { 669 .name = "mcp23s08", 670 .owner = THIS_MODULE, 671 }, 672}; 673 674static int __init mcp23s08_spi_init(void) 675{ 676 return spi_register_driver(&mcp23s08_driver); 677} 678 679static void mcp23s08_spi_exit(void) 680{ 681 spi_unregister_driver(&mcp23s08_driver); 682} 683 684#else 685 686static int __init mcp23s08_spi_init(void) { return 0; } 687static void mcp23s08_spi_exit(void) { } 688 689#endif /* CONFIG_SPI_MASTER */ 690 691/*----------------------------------------------------------------------*/ 692 693static int __init mcp23s08_init(void) 694{ 695 int ret; 696 697 ret = mcp23s08_spi_init(); 698 if (ret) 699 goto spi_fail; 700 701 ret = mcp23s08_i2c_init(); 702 if (ret) 703 goto i2c_fail; 704 705 return 0; 706 707 i2c_fail: 708 mcp23s08_spi_exit(); 709 spi_fail: 710 return ret; 711} 712/* register after spi/i2c postcore initcall and before 713 * subsys initcalls that may rely on these GPIOs 714 */ 715subsys_initcall(mcp23s08_init); 716 717static void __exit mcp23s08_exit(void) 718{ 719 mcp23s08_spi_exit(); 720 mcp23s08_i2c_exit(); 721} 722module_exit(mcp23s08_exit); 723 724MODULE_LICENSE("GPL");