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>
10 #include <linux/spi/spi.h>
11 #include <linux/spi/mcp23s08.h>
16 /* Registers are all 8 bits wide.
18 * The mcp23s17 has twice as many bits, and can be configured to work
19 * with either 16 bit registers or with two adjacent 8 bit banks.
21 * Also, there are I2C versions of both chips.
23 #define MCP_IODIR 0x00 /* init/reset: all ones */
25 #define MCP_GPINTEN 0x02
26 #define MCP_DEFVAL 0x03
27 #define MCP_INTCON 0x04
28 #define MCP_IOCON 0x05
29 # define IOCON_SEQOP (1 << 5)
30 # define IOCON_HAEN (1 << 3)
31 # define IOCON_ODR (1 << 2)
32 # define IOCON_INTPOL (1 << 1)
35 #define MCP_INTCAP 0x08
40 struct spi_device
*spi
;
43 /* lock protects the cached values */
47 struct gpio_chip chip
;
49 struct work_struct work
;
52 static int mcp23s08_read(struct mcp23s08
*mcp
, unsigned reg
)
57 tx
[0] = mcp
->addr
| 0x01;
59 status
= spi_write_then_read(mcp
->spi
, tx
, sizeof tx
, rx
, sizeof rx
);
60 return (status
< 0) ? status
: rx
[0];
63 static int mcp23s08_write(struct mcp23s08
*mcp
, unsigned reg
, u8 val
)
70 return spi_write_then_read(mcp
->spi
, tx
, sizeof tx
, NULL
, 0);
74 mcp23s08_read_regs(struct mcp23s08
*mcp
, unsigned reg
, u8
*vals
, unsigned n
)
78 if ((n
+ reg
) > sizeof mcp
->cache
)
80 tx
[0] = mcp
->addr
| 0x01;
82 return spi_write_then_read(mcp
->spi
, tx
, sizeof tx
, vals
, n
);
85 /*----------------------------------------------------------------------*/
87 static int mcp23s08_direction_input(struct gpio_chip
*chip
, unsigned offset
)
89 struct mcp23s08
*mcp
= container_of(chip
, struct mcp23s08
, chip
);
92 mutex_lock(&mcp
->lock
);
93 mcp
->cache
[MCP_IODIR
] |= (1 << offset
);
94 status
= mcp23s08_write(mcp
, MCP_IODIR
, mcp
->cache
[MCP_IODIR
]);
95 mutex_unlock(&mcp
->lock
);
99 static int mcp23s08_get(struct gpio_chip
*chip
, unsigned offset
)
101 struct mcp23s08
*mcp
= container_of(chip
, struct mcp23s08
, chip
);
104 mutex_lock(&mcp
->lock
);
106 /* REVISIT reading this clears any IRQ ... */
107 status
= mcp23s08_read(mcp
, MCP_GPIO
);
111 mcp
->cache
[MCP_GPIO
] = status
;
112 status
= !!(status
& (1 << offset
));
114 mutex_unlock(&mcp
->lock
);
118 static int __mcp23s08_set(struct mcp23s08
*mcp
, unsigned mask
, int value
)
120 u8 olat
= mcp
->cache
[MCP_OLAT
];
126 mcp
->cache
[MCP_OLAT
] = olat
;
127 return mcp23s08_write(mcp
, MCP_OLAT
, olat
);
130 static void mcp23s08_set(struct gpio_chip
*chip
, unsigned offset
, int value
)
132 struct mcp23s08
*mcp
= container_of(chip
, struct mcp23s08
, chip
);
133 u8 mask
= 1 << offset
;
135 mutex_lock(&mcp
->lock
);
136 __mcp23s08_set(mcp
, mask
, value
);
137 mutex_unlock(&mcp
->lock
);
141 mcp23s08_direction_output(struct gpio_chip
*chip
, unsigned offset
, int value
)
143 struct mcp23s08
*mcp
= container_of(chip
, struct mcp23s08
, chip
);
144 u8 mask
= 1 << offset
;
147 mutex_lock(&mcp
->lock
);
148 status
= __mcp23s08_set(mcp
, mask
, value
);
150 mcp
->cache
[MCP_IODIR
] &= ~mask
;
151 status
= mcp23s08_write(mcp
, MCP_IODIR
, mcp
->cache
[MCP_IODIR
]);
153 mutex_unlock(&mcp
->lock
);
157 /*----------------------------------------------------------------------*/
159 #ifdef CONFIG_DEBUG_FS
161 #include <linux/seq_file.h>
164 * This shows more info than the generic gpio dump code:
165 * pullups, deglitching, open drain drive.
167 static void mcp23s08_dbg_show(struct seq_file
*s
, struct gpio_chip
*chip
)
169 struct mcp23s08
*mcp
;
174 mcp
= container_of(chip
, struct mcp23s08
, chip
);
176 /* NOTE: we only handle one bank for now ... */
177 bank
= '0' + ((mcp
->addr
>> 1) & 0x3);
179 mutex_lock(&mcp
->lock
);
180 t
= mcp23s08_read_regs(mcp
, 0, mcp
->cache
, sizeof mcp
->cache
);
182 seq_printf(s
, " I/O ERROR %d\n", t
);
186 for (t
= 0, mask
= 1; t
< 8; t
++, mask
<<= 1) {
189 label
= gpiochip_is_requested(chip
, t
);
193 seq_printf(s
, " gpio-%-3d P%c.%d (%-12s) %s %s %s",
194 chip
->base
+ t
, bank
, t
, label
,
195 (mcp
->cache
[MCP_IODIR
] & mask
) ? "in " : "out",
196 (mcp
->cache
[MCP_GPIO
] & mask
) ? "hi" : "lo",
197 (mcp
->cache
[MCP_GPPU
] & mask
) ? " " : "up");
198 /* NOTE: ignoring the irq-related registers */
202 mutex_unlock(&mcp
->lock
);
206 #define mcp23s08_dbg_show NULL
209 /*----------------------------------------------------------------------*/
211 static int mcp23s08_probe(struct spi_device
*spi
)
213 struct mcp23s08
*mcp
;
214 struct mcp23s08_platform_data
*pdata
;
218 pdata
= spi
->dev
.platform_data
;
219 if (!pdata
|| pdata
->slave
> 3 || !pdata
->base
)
222 mcp
= kzalloc(sizeof *mcp
, GFP_KERNEL
);
226 mutex_init(&mcp
->lock
);
229 mcp
->addr
= 0x40 | (pdata
->slave
<< 1);
231 mcp
->chip
.label
= "mcp23s08",
233 mcp
->chip
.direction_input
= mcp23s08_direction_input
;
234 mcp
->chip
.get
= mcp23s08_get
;
235 mcp
->chip
.direction_output
= mcp23s08_direction_output
;
236 mcp
->chip
.set
= mcp23s08_set
;
237 mcp
->chip
.dbg_show
= mcp23s08_dbg_show
;
239 mcp
->chip
.base
= pdata
->base
;
241 mcp
->chip
.can_sleep
= 1;
242 mcp
->chip
.owner
= THIS_MODULE
;
244 spi_set_drvdata(spi
, mcp
);
246 /* verify MCP_IOCON.SEQOP = 0, so sequential reads work */
247 status
= mcp23s08_read(mcp
, MCP_IOCON
);
250 if (status
& IOCON_SEQOP
) {
251 status
&= ~IOCON_SEQOP
;
252 status
= mcp23s08_write(mcp
, MCP_IOCON
, (u8
) status
);
257 /* configure ~100K pullups */
258 status
= mcp23s08_write(mcp
, MCP_GPPU
, pdata
->pullups
);
262 status
= mcp23s08_read_regs(mcp
, 0, mcp
->cache
, sizeof mcp
->cache
);
266 /* disable inverter on input */
267 if (mcp
->cache
[MCP_IPOL
] != 0) {
268 mcp
->cache
[MCP_IPOL
] = 0;
273 if (mcp
->cache
[MCP_GPINTEN
] != 0) {
274 mcp
->cache
[MCP_GPINTEN
] = 0;
283 memcpy(&tx
[2], &mcp
->cache
[MCP_IPOL
], sizeof(tx
) - 2);
284 status
= spi_write_then_read(mcp
->spi
, tx
, sizeof tx
, NULL
, 0);
286 /* FIXME check status... */
289 status
= gpiochip_add(&mcp
->chip
);
291 /* NOTE: these chips have a relatively sane IRQ framework, with
292 * per-signal masking and level/edge triggering. It's not yet
297 status
= pdata
->setup(spi
, mcp
->chip
.base
,
298 mcp
->chip
.ngpio
, pdata
->context
);
300 dev_dbg(&spi
->dev
, "setup --> %d\n", status
);
310 static int mcp23s08_remove(struct spi_device
*spi
)
312 struct mcp23s08
*mcp
= spi_get_drvdata(spi
);
313 struct mcp23s08_platform_data
*pdata
= spi
->dev
.platform_data
;
316 if (pdata
->teardown
) {
317 status
= pdata
->teardown(spi
,
318 mcp
->chip
.base
, mcp
->chip
.ngpio
,
321 dev_err(&spi
->dev
, "%s --> %d\n", "teardown", status
);
326 status
= gpiochip_remove(&mcp
->chip
);
330 dev_err(&spi
->dev
, "%s --> %d\n", "remove", status
);
334 static struct spi_driver mcp23s08_driver
= {
335 .probe
= mcp23s08_probe
,
336 .remove
= mcp23s08_remove
,
339 .owner
= THIS_MODULE
,
343 /*----------------------------------------------------------------------*/
345 static int __init
mcp23s08_init(void)
347 return spi_register_driver(&mcp23s08_driver
);
349 module_init(mcp23s08_init
);
351 static void __exit
mcp23s08_exit(void)
353 spi_unregister_driver(&mcp23s08_driver
);
355 module_exit(mcp23s08_exit
);
357 MODULE_LICENSE("GPL");