aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpio
diff options
context:
space:
mode:
authorPeter Korsgaard <jacmet@sunsite.dk>2011-07-15 04:25:32 -0400
committerGrant Likely <grant.likely@secretlab.ca>2011-07-15 15:54:18 -0400
commit752ad5e82dfd83851e44a2b9da8761994cd7e61c (patch)
treede338b98720ac3a37f18b2db868a85e2b8cfe726 /drivers/gpio
parentd62b98f305a6b0d32fbdc72ac6ba3d4f4768adeb (diff)
mcp23s08: add i2c support
Add i2c bindings for the mcp230xx devices. This is quite a lot simpler than the spi one as there's no funky sub addressing done (one struct i2c_client per struct gpio_chip). The mcp23s08_platform_data structure is reused for i2c, even though only a single mcp23s08_chip_info structure is needed. To use, simply fill out a platform_data structure and pass it in i2c_board_info, E.G.: static const struct mcp23s08_platform_data mcp23017_data = { .chip[0] = { .pullups = 0x00ff, }, .base = 240, }; static struct i2c_board_info __initdata i2c_devs[] = { { I2C_BOARD_INFO("mcp23017", 0x20), .platform_data = &smartview_mcp23017_data, }, ... }; Signed-off-by: Peter Korsgaard <jacmet@sunsite.dk> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Diffstat (limited to 'drivers/gpio')
-rw-r--r--drivers/gpio/Kconfig7
-rw-r--r--drivers/gpio/gpio-mcp23s08.c192
2 files changed, 191 insertions, 8 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 47eae6ea5dd2..363498697c2c 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -412,10 +412,11 @@ config GPIO_MAX7301
412 GPIO driver for Maxim MAX7301 SPI-based GPIO expander. 412 GPIO driver for Maxim MAX7301 SPI-based GPIO expander.
413 413
414config GPIO_MCP23S08 414config GPIO_MCP23S08
415 tristate "Microchip MCP23Sxx I/O expander" 415 tristate "Microchip MCP23xxx I/O expander"
416 depends on SPI_MASTER 416 depends on SPI_MASTER || I2C
417 help 417 help
418 SPI driver for Microchip MCP23S08/MPC23S17 I/O expanders. 418 SPI/I2C driver for Microchip MCP23S08/MCP23S17/MCP23008/MCP23017
419 I/O expanders.
419 This provides a GPIO interface supporting inputs and outputs. 420 This provides a GPIO interface supporting inputs and outputs.
420 421
421config GPIO_MC33880 422config GPIO_MC33880
diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c
index 7b78f940868e..1ef46e6c2a2a 100644
--- a/drivers/gpio/gpio-mcp23s08.c
+++ b/drivers/gpio/gpio-mcp23s08.c
@@ -1,11 +1,12 @@
1/* 1/*
2 * MCP23S08 SPI gpio expander driver 2 * MCP23S08 SPI/GPIO gpio expander driver
3 */ 3 */
4 4
5#include <linux/kernel.h> 5#include <linux/kernel.h>
6#include <linux/device.h> 6#include <linux/device.h>
7#include <linux/mutex.h> 7#include <linux/mutex.h>
8#include <linux/gpio.h> 8#include <linux/gpio.h>
9#include <linux/i2c.h>
9#include <linux/spi/spi.h> 10#include <linux/spi/spi.h>
10#include <linux/spi/mcp23s08.h> 11#include <linux/spi/mcp23s08.h>
11#include <linux/slab.h> 12#include <linux/slab.h>
@@ -16,13 +17,13 @@
16 */ 17 */
17#define MCP_TYPE_S08 0 18#define MCP_TYPE_S08 0
18#define MCP_TYPE_S17 1 19#define MCP_TYPE_S17 1
20#define MCP_TYPE_008 2
21#define MCP_TYPE_017 3
19 22
20/* Registers are all 8 bits wide. 23/* Registers are all 8 bits wide.
21 * 24 *
22 * The mcp23s17 has twice as many bits, and can be configured to work 25 * The mcp23s17 has twice as many bits, and can be configured to work
23 * with either 16 bit registers or with two adjacent 8 bit banks. 26 * with either 16 bit registers or with two adjacent 8 bit banks.
24 *
25 * Also, there are I2C versions of both chips.
26 */ 27 */
27#define MCP_IODIR 0x00 /* init/reset: all ones */ 28#define MCP_IODIR 0x00 /* init/reset: all ones */
28#define MCP_IPOL 0x01 29#define MCP_IPOL 0x01
@@ -73,6 +74,72 @@ struct mcp23s08_driver_data {
73 struct mcp23s08 chip[]; 74 struct mcp23s08 chip[];
74}; 75};
75 76
77/*----------------------------------------------------------------------*/
78
79#ifdef CONFIG_I2C
80
81static int mcp23008_read(struct mcp23s08 *mcp, unsigned reg)
82{
83 return i2c_smbus_read_byte_data(mcp->data, reg);
84}
85
86static int mcp23008_write(struct mcp23s08 *mcp, unsigned reg, unsigned val)
87{
88 return i2c_smbus_write_byte_data(mcp->data, reg, val);
89}
90
91static int
92mcp23008_read_regs(struct mcp23s08 *mcp, unsigned reg, u16 *vals, unsigned n)
93{
94 while (n--) {
95 int ret = mcp23008_read(mcp, reg++);
96 if (ret < 0)
97 return ret;
98 *vals++ = ret;
99 }
100
101 return 0;
102}
103
104static int mcp23017_read(struct mcp23s08 *mcp, unsigned reg)
105{
106 return i2c_smbus_read_word_data(mcp->data, reg << 1);
107}
108
109static int mcp23017_write(struct mcp23s08 *mcp, unsigned reg, unsigned val)
110{
111 return i2c_smbus_write_word_data(mcp->data, reg << 1, val);
112}
113
114static int
115mcp23017_read_regs(struct mcp23s08 *mcp, unsigned reg, u16 *vals, unsigned n)
116{
117 while (n--) {
118 int ret = mcp23017_read(mcp, reg++);
119 if (ret < 0)
120 return ret;
121 *vals++ = ret;
122 }
123
124 return 0;
125}
126
127static const struct mcp23s08_ops mcp23008_ops = {
128 .read = mcp23008_read,
129 .write = mcp23008_write,
130 .read_regs = mcp23008_read_regs,
131};
132
133static const struct mcp23s08_ops mcp23017_ops = {
134 .read = mcp23017_read,
135 .write = mcp23017_write,
136 .read_regs = mcp23017_read_regs,
137};
138
139#endif /* CONFIG_I2C */
140
141/*----------------------------------------------------------------------*/
142
76#ifdef CONFIG_SPI_MASTER 143#ifdef CONFIG_SPI_MASTER
77 144
78static int mcp23s08_read(struct mcp23s08 *mcp, unsigned reg) 145static int mcp23s08_read(struct mcp23s08 *mcp, unsigned reg)
@@ -331,6 +398,20 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
331 break; 398 break;
332#endif /* CONFIG_SPI_MASTER */ 399#endif /* CONFIG_SPI_MASTER */
333 400
401#ifdef CONFIG_I2C
402 case MCP_TYPE_008:
403 mcp->ops = &mcp23008_ops;
404 mcp->chip.ngpio = 8;
405 mcp->chip.label = "mcp23008";
406 break;
407
408 case MCP_TYPE_017:
409 mcp->ops = &mcp23017_ops;
410 mcp->chip.ngpio = 16;
411 mcp->chip.label = "mcp23017";
412 break;
413#endif /* CONFIG_I2C */
414
334 default: 415 default:
335 dev_err(dev, "invalid device type (%d)\n", type); 416 dev_err(dev, "invalid device type (%d)\n", type);
336 return -EINVAL; 417 return -EINVAL;
@@ -389,6 +470,91 @@ fail:
389 return status; 470 return status;
390} 471}
391 472
473/*----------------------------------------------------------------------*/
474
475#ifdef CONFIG_I2C
476
477static int __devinit mcp230xx_probe(struct i2c_client *client,
478 const struct i2c_device_id *id)
479{
480 struct mcp23s08_platform_data *pdata;
481 struct mcp23s08 *mcp;
482 int status;
483
484 pdata = client->dev.platform_data;
485 if (!pdata || !gpio_is_valid(pdata->base)) {
486 dev_dbg(&client->dev, "invalid or missing platform data\n");
487 return -EINVAL;
488 }
489
490 mcp = kzalloc(sizeof *mcp, GFP_KERNEL);
491 if (!mcp)
492 return -ENOMEM;
493
494 status = mcp23s08_probe_one(mcp, &client->dev, client, client->addr,
495 id->driver_data, pdata->base,
496 pdata->chip[0].pullups);
497 if (status)
498 goto fail;
499
500 i2c_set_clientdata(client, mcp);
501
502 return 0;
503
504fail:
505 kfree(mcp);
506
507 return status;
508}
509
510static int __devexit mcp230xx_remove(struct i2c_client *client)
511{
512 struct mcp23s08 *mcp = i2c_get_clientdata(client);
513 int status;
514
515 status = gpiochip_remove(&mcp->chip);
516 if (status == 0)
517 kfree(mcp);
518
519 return status;
520}
521
522static const struct i2c_device_id mcp230xx_id[] = {
523 { "mcp23008", MCP_TYPE_008 },
524 { "mcp23017", MCP_TYPE_017 },
525 { },
526};
527MODULE_DEVICE_TABLE(i2c, mcp230xx_id);
528
529static struct i2c_driver mcp230xx_driver = {
530 .driver = {
531 .name = "mcp230xx",
532 .owner = THIS_MODULE,
533 },
534 .probe = mcp230xx_probe,
535 .remove = __devexit_p(mcp230xx_remove),
536 .id_table = mcp230xx_id,
537};
538
539static int __init mcp23s08_i2c_init(void)
540{
541 return i2c_add_driver(&mcp230xx_driver);
542}
543
544static void mcp23s08_i2c_exit(void)
545{
546 i2c_del_driver(&mcp230xx_driver);
547}
548
549#else
550
551static int __init mcp23s08_i2c_init(void) { return 0; }
552static void mcp23s08_i2c_exit(void) { }
553
554#endif /* CONFIG_I2C */
555
556/*----------------------------------------------------------------------*/
557
392#ifdef CONFIG_SPI_MASTER 558#ifdef CONFIG_SPI_MASTER
393 559
394static int mcp23s08_probe(struct spi_device *spi) 560static int mcp23s08_probe(struct spi_device *spi)
@@ -525,9 +691,24 @@ static void mcp23s08_spi_exit(void) { }
525 691
526static int __init mcp23s08_init(void) 692static int __init mcp23s08_init(void)
527{ 693{
528 return mcp23s08_spi_init(); 694 int ret;
695
696 ret = mcp23s08_spi_init();
697 if (ret)
698 goto spi_fail;
699
700 ret = mcp23s08_i2c_init();
701 if (ret)
702 goto i2c_fail;
703
704 return 0;
705
706 i2c_fail:
707 mcp23s08_spi_exit();
708 spi_fail:
709 return ret;
529} 710}
530/* register after spi postcore initcall and before 711/* register after spi/i2c postcore initcall and before
531 * subsys initcalls that may rely on these GPIOs 712 * subsys initcalls that may rely on these GPIOs
532 */ 713 */
533subsys_initcall(mcp23s08_init); 714subsys_initcall(mcp23s08_init);
@@ -535,6 +716,7 @@ subsys_initcall(mcp23s08_init);
535static void __exit mcp23s08_exit(void) 716static void __exit mcp23s08_exit(void)
536{ 717{
537 mcp23s08_spi_exit(); 718 mcp23s08_spi_exit();
719 mcp23s08_i2c_exit();
538} 720}
539module_exit(mcp23s08_exit); 721module_exit(mcp23s08_exit);
540 722