2 * mcp23s08.c - SPI gpio expander driver
5 #include <linux/kernel.h>
6 #include <linux/device.h>
7 #include <linux/workqueue.h>
8 #include <linux/mutex.h>
9 #include <linux/gpio.h>
10 #include <linux/spi/spi.h>
11 #include <linux/spi/mcp23s08.h>
12 #include <linux/slab.h>
15 /* Registers are all 8 bits wide.
17 * The mcp23s17 has twice as many bits, and can be configured to work
18 * with either 16 bit registers or with two adjacent 8 bit banks.
20 * Also, there are I2C versions of both chips.
22 #define MCP_IODIR 0x00 /* init/reset: all ones */
24 #define MCP_GPINTEN 0x02
25 #define MCP_DEFVAL 0x03
26 #define MCP_INTCON 0x04
27 #define MCP_IOCON 0x05
28 # define IOCON_SEQOP (1 << 5)
29 # define IOCON_HAEN (1 << 3)
30 # define IOCON_ODR (1 << 2)
31 # define IOCON_INTPOL (1 << 1)
34 #define MCP_INTCAP 0x08
39 struct spi_device
*spi
;
43 /* lock protects the cached values */
46 struct gpio_chip chip
;
48 struct work_struct work
;
51 /* A given spi_device can represent up to four mcp23s08 chips
52 * sharing the same chipselect but using different addresses
53 * (e.g. chips #0 and #3 might be populated, but not #1 or $2).
54 * Driver data holds all the per-chip data.
56 struct mcp23s08_driver_data
{
58 struct mcp23s08
*mcp
[4];
59 struct mcp23s08 chip
[];
62 static int mcp23s08_read(struct mcp23s08
*mcp
, unsigned reg
)
67 tx
[0] = mcp
->addr
| 0x01;
69 status
= spi_write_then_read(mcp
->spi
, tx
, sizeof tx
, rx
, sizeof rx
);
70 return (status
< 0) ? status
: rx
[0];
73 static int mcp23s08_write(struct mcp23s08
*mcp
, unsigned reg
, u8 val
)
80 return spi_write_then_read(mcp
->spi
, tx
, sizeof tx
, NULL
, 0);
84 mcp23s08_read_regs(struct mcp23s08
*mcp
, unsigned reg
, u8
*vals
, unsigned n
)
88 if ((n
+ reg
) > sizeof mcp
->cache
)
90 tx
[0] = mcp
->addr
| 0x01;
92 return spi_write_then_read(mcp
->spi
, tx
, sizeof tx
, vals
, n
);
95 /*----------------------------------------------------------------------*/
97 static int mcp23s08_direction_input(struct gpio_chip
*chip
, unsigned offset
)
99 struct mcp23s08
*mcp
= container_of(chip
, struct mcp23s08
, chip
);
102 mutex_lock(&mcp
->lock
);
103 mcp
->cache
[MCP_IODIR
] |= (1 << offset
);
104 status
= mcp23s08_write(mcp
, MCP_IODIR
, mcp
->cache
[MCP_IODIR
]);
105 mutex_unlock(&mcp
->lock
);
109 static int mcp23s08_get(struct gpio_chip
*chip
, unsigned offset
)
111 struct mcp23s08
*mcp
= container_of(chip
, struct mcp23s08
, chip
);
114 mutex_lock(&mcp
->lock
);
116 /* REVISIT reading this clears any IRQ ... */
117 status
= mcp23s08_read(mcp
, MCP_GPIO
);
121 mcp
->cache
[MCP_GPIO
] = status
;
122 status
= !!(status
& (1 << offset
));
124 mutex_unlock(&mcp
->lock
);
128 static int __mcp23s08_set(struct mcp23s08
*mcp
, unsigned mask
, int value
)
130 u8 olat
= mcp
->cache
[MCP_OLAT
];
136 mcp
->cache
[MCP_OLAT
] = olat
;
137 return mcp23s08_write(mcp
, MCP_OLAT
, olat
);
140 static void mcp23s08_set(struct gpio_chip
*chip
, unsigned offset
, int value
)
142 struct mcp23s08
*mcp
= container_of(chip
, struct mcp23s08
, chip
);
143 u8 mask
= 1 << offset
;
145 mutex_lock(&mcp
->lock
);
146 __mcp23s08_set(mcp
, mask
, value
);
147 mutex_unlock(&mcp
->lock
);
151 mcp23s08_direction_output(struct gpio_chip
*chip
, unsigned offset
, int value
)
153 struct mcp23s08
*mcp
= container_of(chip
, struct mcp23s08
, chip
);
154 u8 mask
= 1 << offset
;
157 mutex_lock(&mcp
->lock
);
158 status
= __mcp23s08_set(mcp
, mask
, value
);
160 mcp
->cache
[MCP_IODIR
] &= ~mask
;
161 status
= mcp23s08_write(mcp
, MCP_IODIR
, mcp
->cache
[MCP_IODIR
]);
163 mutex_unlock(&mcp
->lock
);
167 /*----------------------------------------------------------------------*/
169 #ifdef CONFIG_DEBUG_FS
171 #include <linux/seq_file.h>
174 * This shows more info than the generic gpio dump code:
175 * pullups, deglitching, open drain drive.
177 static void mcp23s08_dbg_show(struct seq_file
*s
, struct gpio_chip
*chip
)
179 struct mcp23s08
*mcp
;
184 mcp
= container_of(chip
, struct mcp23s08
, chip
);
186 /* NOTE: we only handle one bank for now ... */
187 bank
= '0' + ((mcp
->addr
>> 1) & 0x3);
189 mutex_lock(&mcp
->lock
);
190 t
= mcp23s08_read_regs(mcp
, 0, mcp
->cache
, sizeof mcp
->cache
);
192 seq_printf(s
, " I/O ERROR %d\n", t
);
196 for (t
= 0, mask
= 1; t
< 8; t
++, mask
<<= 1) {
199 label
= gpiochip_is_requested(chip
, t
);
203 seq_printf(s
, " gpio-%-3d P%c.%d (%-12s) %s %s %s",
204 chip
->base
+ t
, bank
, t
, label
,
205 (mcp
->cache
[MCP_IODIR
] & mask
) ? "in " : "out",
206 (mcp
->cache
[MCP_GPIO
] & mask
) ? "hi" : "lo",
207 (mcp
->cache
[MCP_GPPU
] & mask
) ? " " : "up");
208 /* NOTE: ignoring the irq-related registers */
212 mutex_unlock(&mcp
->lock
);
216 #define mcp23s08_dbg_show NULL
219 /*----------------------------------------------------------------------*/
221 static int mcp23s08_probe_one(struct spi_device
*spi
, unsigned addr
,
222 unsigned base
, unsigned pullups
)
224 struct mcp23s08_driver_data
*data
= spi_get_drvdata(spi
);
225 struct mcp23s08
*mcp
= data
->mcp
[addr
];
229 mutex_init(&mcp
->lock
);
232 mcp
->addr
= 0x40 | (addr
<< 1);
234 mcp
->chip
.label
= "mcp23s08",
236 mcp
->chip
.direction_input
= mcp23s08_direction_input
;
237 mcp
->chip
.get
= mcp23s08_get
;
238 mcp
->chip
.direction_output
= mcp23s08_direction_output
;
239 mcp
->chip
.set
= mcp23s08_set
;
240 mcp
->chip
.dbg_show
= mcp23s08_dbg_show
;
242 mcp
->chip
.base
= base
;
244 mcp
->chip
.can_sleep
= 1;
245 mcp
->chip
.dev
= &spi
->dev
;
246 mcp
->chip
.owner
= THIS_MODULE
;
248 /* verify MCP_IOCON.SEQOP = 0, so sequential reads work,
249 * and MCP_IOCON.HAEN = 1, so we work with all chips.
251 status
= mcp23s08_read(mcp
, MCP_IOCON
);
254 if ((status
& IOCON_SEQOP
) || !(status
& IOCON_HAEN
)) {
255 status
&= ~IOCON_SEQOP
;
256 status
|= IOCON_HAEN
;
257 status
= mcp23s08_write(mcp
, MCP_IOCON
, (u8
) status
);
262 /* configure ~100K pullups */
263 status
= mcp23s08_write(mcp
, MCP_GPPU
, pullups
);
267 status
= mcp23s08_read_regs(mcp
, 0, mcp
->cache
, sizeof mcp
->cache
);
271 /* disable inverter on input */
272 if (mcp
->cache
[MCP_IPOL
] != 0) {
273 mcp
->cache
[MCP_IPOL
] = 0;
278 if (mcp
->cache
[MCP_GPINTEN
] != 0) {
279 mcp
->cache
[MCP_GPINTEN
] = 0;
288 memcpy(&tx
[2], &mcp
->cache
[MCP_IPOL
], sizeof(tx
) - 2);
289 status
= spi_write_then_read(mcp
->spi
, tx
, sizeof tx
, NULL
, 0);
294 status
= gpiochip_add(&mcp
->chip
);
297 dev_dbg(&spi
->dev
, "can't setup chip %d, --> %d\n",
302 static int mcp23s08_probe(struct spi_device
*spi
)
304 struct mcp23s08_platform_data
*pdata
;
307 struct mcp23s08_driver_data
*data
;
311 pdata
= spi
->dev
.platform_data
;
312 if (!pdata
|| !gpio_is_valid(pdata
->base
)) {
313 dev_dbg(&spi
->dev
, "invalid or missing platform data\n");
317 for (addr
= 0; addr
< 4; addr
++) {
318 if (!pdata
->chip
[addr
].is_present
)
325 data
= kzalloc(sizeof *data
+ chips
* sizeof(struct mcp23s08
),
329 spi_set_drvdata(spi
, data
);
332 for (addr
= 0; addr
< 4; addr
++) {
333 if (!pdata
->chip
[addr
].is_present
)
336 data
->mcp
[addr
] = &data
->chip
[chips
];
337 status
= mcp23s08_probe_one(spi
, addr
, base
,
338 pdata
->chip
[addr
].pullups
);
343 data
->ngpio
= base
- pdata
->base
;
345 /* NOTE: these chips have a relatively sane IRQ framework, with
346 * per-signal masking and level/edge triggering. It's not yet
351 status
= pdata
->setup(spi
,
352 pdata
->base
, data
->ngpio
,
355 dev_dbg(&spi
->dev
, "setup --> %d\n", status
);
361 for (addr
= 0; addr
< 4; addr
++) {
364 if (!data
->mcp
[addr
])
366 tmp
= gpiochip_remove(&data
->mcp
[addr
]->chip
);
368 dev_err(&spi
->dev
, "%s --> %d\n", "remove", tmp
);
374 static int mcp23s08_remove(struct spi_device
*spi
)
376 struct mcp23s08_driver_data
*data
= spi_get_drvdata(spi
);
377 struct mcp23s08_platform_data
*pdata
= spi
->dev
.platform_data
;
381 if (pdata
->teardown
) {
382 status
= pdata
->teardown(spi
,
383 pdata
->base
, data
->ngpio
,
386 dev_err(&spi
->dev
, "%s --> %d\n", "teardown", status
);
391 for (addr
= 0; addr
< 4; addr
++) {
394 if (!data
->mcp
[addr
])
397 tmp
= gpiochip_remove(&data
->mcp
[addr
]->chip
);
399 dev_err(&spi
->dev
, "%s --> %d\n", "remove", tmp
);
408 static struct spi_driver mcp23s08_driver
= {
409 .probe
= mcp23s08_probe
,
410 .remove
= mcp23s08_remove
,
413 .owner
= THIS_MODULE
,
417 /*----------------------------------------------------------------------*/
419 static int __init
mcp23s08_init(void)
421 return spi_register_driver(&mcp23s08_driver
);
423 /* register after spi postcore initcall and before
424 * subsys initcalls that may rely on these GPIOs
426 subsys_initcall(mcp23s08_init
);
428 static void __exit
mcp23s08_exit(void)
430 spi_unregister_driver(&mcp23s08_driver
);
432 module_exit(mcp23s08_exit
);
434 MODULE_LICENSE("GPL");
435 MODULE_ALIAS("spi:mcp23s08");