~ubuntu-branches/ubuntu/precise/linux-ti-omap4/precise

« back to all changes in this revision

Viewing changes to drivers/gpio/mcp23s08.c

  • Committer: Bazaar Package Importer
  • Author(s): Paolo Pisati
  • Date: 2011-06-29 15:23:51 UTC
  • mfrom: (26.1.1 natty-proposed)
  • Revision ID: james.westby@ubuntu.com-20110629152351-xs96tm303d95rpbk
Tags: 3.0.0-1200.2
* Rebased against 3.0.0-6.7
* BSP from TI based on 3.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
10
10
#include <linux/spi/spi.h>
11
11
#include <linux/spi/mcp23s08.h>
12
12
#include <linux/slab.h>
 
13
#include <asm/byteorder.h>
13
14
 
 
15
/**
 
16
 * MCP types supported by driver
 
17
 */
 
18
#define MCP_TYPE_S08    0
 
19
#define MCP_TYPE_S17    1
14
20
 
15
21
/* Registers are all 8 bits wide.
16
22
 *
35
41
#define MCP_GPIO        0x09
36
42
#define MCP_OLAT        0x0a
37
43
 
 
44
struct mcp23s08;
 
45
 
 
46
struct mcp23s08_ops {
 
47
        int     (*read)(struct mcp23s08 *mcp, unsigned reg);
 
48
        int     (*write)(struct mcp23s08 *mcp, unsigned reg, unsigned val);
 
49
        int     (*read_regs)(struct mcp23s08 *mcp, unsigned reg,
 
50
                             u16 *vals, unsigned n);
 
51
};
 
52
 
38
53
struct mcp23s08 {
39
54
        struct spi_device       *spi;
40
55
        u8                      addr;
41
56
 
42
 
        u8                      cache[11];
 
57
        u16                     cache[11];
43
58
        /* lock protects the cached values */
44
59
        struct mutex            lock;
45
60
 
46
61
        struct gpio_chip        chip;
47
62
 
48
63
        struct work_struct      work;
 
64
 
 
65
        const struct mcp23s08_ops       *ops;
49
66
};
50
67
 
51
 
/* A given spi_device can represent up to four mcp23s08 chips
 
68
/* A given spi_device can represent up to eight mcp23sxx chips
52
69
 * sharing the same chipselect but using different addresses
53
70
 * (e.g. chips #0 and #3 might be populated, but not #1 or $2).
54
71
 * Driver data holds all the per-chip data.
55
72
 */
56
73
struct mcp23s08_driver_data {
57
74
        unsigned                ngpio;
58
 
        struct mcp23s08         *mcp[4];
 
75
        struct mcp23s08         *mcp[8];
59
76
        struct mcp23s08         chip[];
60
77
};
61
78
 
70
87
        return (status < 0) ? status : rx[0];
71
88
}
72
89
 
73
 
static int mcp23s08_write(struct mcp23s08 *mcp, unsigned reg, u8 val)
 
90
static int mcp23s08_write(struct mcp23s08 *mcp, unsigned reg, unsigned val)
74
91
{
75
92
        u8      tx[3];
76
93
 
81
98
}
82
99
 
83
100
static int
84
 
mcp23s08_read_regs(struct mcp23s08 *mcp, unsigned reg, u8 *vals, unsigned n)
 
101
mcp23s08_read_regs(struct mcp23s08 *mcp, unsigned reg, u16 *vals, unsigned n)
 
102
{
 
103
        u8      tx[2], *tmp;
 
104
        int     status;
 
105
 
 
106
        if ((n + reg) > sizeof mcp->cache)
 
107
                return -EINVAL;
 
108
        tx[0] = mcp->addr | 0x01;
 
109
        tx[1] = reg;
 
110
 
 
111
        tmp = (u8 *)vals;
 
112
        status = spi_write_then_read(mcp->spi, tx, sizeof tx, tmp, n);
 
113
        if (status >= 0) {
 
114
                while (n--)
 
115
                        vals[n] = tmp[n]; /* expand to 16bit */
 
116
        }
 
117
        return status;
 
118
}
 
119
 
 
120
static int mcp23s17_read(struct mcp23s08 *mcp, unsigned reg)
 
121
{
 
122
        u8      tx[2], rx[2];
 
123
        int     status;
 
124
 
 
125
        tx[0] = mcp->addr | 0x01;
 
126
        tx[1] = reg << 1;
 
127
        status = spi_write_then_read(mcp->spi, tx, sizeof tx, rx, sizeof rx);
 
128
        return (status < 0) ? status : (rx[0] | (rx[1] << 8));
 
129
}
 
130
 
 
131
static int mcp23s17_write(struct mcp23s08 *mcp, unsigned reg, unsigned val)
 
132
{
 
133
        u8      tx[4];
 
134
 
 
135
        tx[0] = mcp->addr;
 
136
        tx[1] = reg << 1;
 
137
        tx[2] = val;
 
138
        tx[3] = val >> 8;
 
139
        return spi_write_then_read(mcp->spi, tx, sizeof tx, NULL, 0);
 
140
}
 
141
 
 
142
static int
 
143
mcp23s17_read_regs(struct mcp23s08 *mcp, unsigned reg, u16 *vals, unsigned n)
85
144
{
86
145
        u8      tx[2];
 
146
        int     status;
87
147
 
88
148
        if ((n + reg) > sizeof mcp->cache)
89
149
                return -EINVAL;
90
150
        tx[0] = mcp->addr | 0x01;
91
 
        tx[1] = reg;
92
 
        return spi_write_then_read(mcp->spi, tx, sizeof tx, vals, n);
 
151
        tx[1] = reg << 1;
 
152
 
 
153
        status = spi_write_then_read(mcp->spi, tx, sizeof tx,
 
154
                                     (u8 *)vals, n * 2);
 
155
        if (status >= 0) {
 
156
                while (n--)
 
157
                        vals[n] = __le16_to_cpu((__le16)vals[n]);
 
158
        }
 
159
 
 
160
        return status;
93
161
}
94
162
 
 
163
static const struct mcp23s08_ops mcp23s08_ops = {
 
164
        .read           = mcp23s08_read,
 
165
        .write          = mcp23s08_write,
 
166
        .read_regs      = mcp23s08_read_regs,
 
167
};
 
168
 
 
169
static const struct mcp23s08_ops mcp23s17_ops = {
 
170
        .read           = mcp23s17_read,
 
171
        .write          = mcp23s17_write,
 
172
        .read_regs      = mcp23s17_read_regs,
 
173
};
 
174
 
 
175
 
95
176
/*----------------------------------------------------------------------*/
96
177
 
97
178
static int mcp23s08_direction_input(struct gpio_chip *chip, unsigned offset)
101
182
 
102
183
        mutex_lock(&mcp->lock);
103
184
        mcp->cache[MCP_IODIR] |= (1 << offset);
104
 
        status = mcp23s08_write(mcp, MCP_IODIR, mcp->cache[MCP_IODIR]);
 
185
        status = mcp->ops->write(mcp, MCP_IODIR, mcp->cache[MCP_IODIR]);
105
186
        mutex_unlock(&mcp->lock);
106
187
        return status;
107
188
}
114
195
        mutex_lock(&mcp->lock);
115
196
 
116
197
        /* REVISIT reading this clears any IRQ ... */
117
 
        status = mcp23s08_read(mcp, MCP_GPIO);
 
198
        status = mcp->ops->read(mcp, MCP_GPIO);
118
199
        if (status < 0)
119
200
                status = 0;
120
201
        else {
127
208
 
128
209
static int __mcp23s08_set(struct mcp23s08 *mcp, unsigned mask, int value)
129
210
{
130
 
        u8 olat = mcp->cache[MCP_OLAT];
 
211
        unsigned olat = mcp->cache[MCP_OLAT];
131
212
 
132
213
        if (value)
133
214
                olat |= mask;
134
215
        else
135
216
                olat &= ~mask;
136
217
        mcp->cache[MCP_OLAT] = olat;
137
 
        return mcp23s08_write(mcp, MCP_OLAT, olat);
 
218
        return mcp->ops->write(mcp, MCP_OLAT, olat);
138
219
}
139
220
 
140
221
static void mcp23s08_set(struct gpio_chip *chip, unsigned offset, int value)
141
222
{
142
223
        struct mcp23s08 *mcp = container_of(chip, struct mcp23s08, chip);
143
 
        u8 mask = 1 << offset;
 
224
        unsigned mask = 1 << offset;
144
225
 
145
226
        mutex_lock(&mcp->lock);
146
227
        __mcp23s08_set(mcp, mask, value);
151
232
mcp23s08_direction_output(struct gpio_chip *chip, unsigned offset, int value)
152
233
{
153
234
        struct mcp23s08 *mcp = container_of(chip, struct mcp23s08, chip);
154
 
        u8 mask = 1 << offset;
 
235
        unsigned mask = 1 << offset;
155
236
        int status;
156
237
 
157
238
        mutex_lock(&mcp->lock);
158
239
        status = __mcp23s08_set(mcp, mask, value);
159
240
        if (status == 0) {
160
241
                mcp->cache[MCP_IODIR] &= ~mask;
161
 
                status = mcp23s08_write(mcp, MCP_IODIR, mcp->cache[MCP_IODIR]);
 
242
                status = mcp->ops->write(mcp, MCP_IODIR, mcp->cache[MCP_IODIR]);
162
243
        }
163
244
        mutex_unlock(&mcp->lock);
164
245
        return status;
184
265
        mcp = container_of(chip, struct mcp23s08, chip);
185
266
 
186
267
        /* NOTE: we only handle one bank for now ... */
187
 
        bank = '0' + ((mcp->addr >> 1) & 0x3);
 
268
        bank = '0' + ((mcp->addr >> 1) & 0x7);
188
269
 
189
270
        mutex_lock(&mcp->lock);
190
 
        t = mcp23s08_read_regs(mcp, 0, mcp->cache, sizeof mcp->cache);
 
271
        t = mcp->ops->read_regs(mcp, 0, mcp->cache, ARRAY_SIZE(mcp->cache));
191
272
        if (t < 0) {
192
273
                seq_printf(s, " I/O ERROR %d\n", t);
193
274
                goto done;
194
275
        }
195
276
 
196
 
        for (t = 0, mask = 1; t < 8; t++, mask <<= 1) {
 
277
        for (t = 0, mask = 1; t < chip->ngpio; t++, mask <<= 1) {
197
278
                const char      *label;
198
279
 
199
280
                label = gpiochip_is_requested(chip, t);
219
300
/*----------------------------------------------------------------------*/
220
301
 
221
302
static int mcp23s08_probe_one(struct spi_device *spi, unsigned addr,
222
 
                unsigned base, unsigned pullups)
 
303
                              unsigned type, unsigned base, unsigned pullups)
223
304
{
224
305
        struct mcp23s08_driver_data     *data = spi_get_drvdata(spi);
225
306
        struct mcp23s08                 *mcp = data->mcp[addr];
226
307
        int                             status;
227
 
        int                             do_update = 0;
228
308
 
229
309
        mutex_init(&mcp->lock);
230
310
 
231
311
        mcp->spi = spi;
232
312
        mcp->addr = 0x40 | (addr << 1);
233
313
 
234
 
        mcp->chip.label = "mcp23s08",
235
 
 
236
314
        mcp->chip.direction_input = mcp23s08_direction_input;
237
315
        mcp->chip.get = mcp23s08_get;
238
316
        mcp->chip.direction_output = mcp23s08_direction_output;
239
317
        mcp->chip.set = mcp23s08_set;
240
318
        mcp->chip.dbg_show = mcp23s08_dbg_show;
241
319
 
 
320
        if (type == MCP_TYPE_S17) {
 
321
                mcp->ops = &mcp23s17_ops;
 
322
                mcp->chip.ngpio = 16;
 
323
                mcp->chip.label = "mcp23s17";
 
324
        } else {
 
325
                mcp->ops = &mcp23s08_ops;
 
326
                mcp->chip.ngpio = 8;
 
327
                mcp->chip.label = "mcp23s08";
 
328
        }
242
329
        mcp->chip.base = base;
243
 
        mcp->chip.ngpio = 8;
244
330
        mcp->chip.can_sleep = 1;
245
331
        mcp->chip.dev = &spi->dev;
246
332
        mcp->chip.owner = THIS_MODULE;
248
334
        /* verify MCP_IOCON.SEQOP = 0, so sequential reads work,
249
335
         * and MCP_IOCON.HAEN = 1, so we work with all chips.
250
336
         */
251
 
        status = mcp23s08_read(mcp, MCP_IOCON);
 
337
        status = mcp->ops->read(mcp, MCP_IOCON);
252
338
        if (status < 0)
253
339
                goto fail;
254
340
        if ((status & IOCON_SEQOP) || !(status & IOCON_HAEN)) {
255
 
                status &= ~IOCON_SEQOP;
256
 
                status |= IOCON_HAEN;
257
 
                status = mcp23s08_write(mcp, MCP_IOCON, (u8) status);
 
341
                /* mcp23s17 has IOCON twice, make sure they are in sync */
 
342
                status &= ~(IOCON_SEQOP | (IOCON_SEQOP << 8));
 
343
                status |= IOCON_HAEN | (IOCON_HAEN << 8);
 
344
                status = mcp->ops->write(mcp, MCP_IOCON, status);
258
345
                if (status < 0)
259
346
                        goto fail;
260
347
        }
261
348
 
262
349
        /* configure ~100K pullups */
263
 
        status = mcp23s08_write(mcp, MCP_GPPU, pullups);
 
350
        status = mcp->ops->write(mcp, MCP_GPPU, pullups);
264
351
        if (status < 0)
265
352
                goto fail;
266
353
 
267
 
        status = mcp23s08_read_regs(mcp, 0, mcp->cache, sizeof mcp->cache);
 
354
        status = mcp->ops->read_regs(mcp, 0, mcp->cache, ARRAY_SIZE(mcp->cache));
268
355
        if (status < 0)
269
356
                goto fail;
270
357
 
271
358
        /* disable inverter on input */
272
359
        if (mcp->cache[MCP_IPOL] != 0) {
273
360
                mcp->cache[MCP_IPOL] = 0;
274
 
                do_update = 1;
 
361
                status = mcp->ops->write(mcp, MCP_IPOL, 0);
 
362
                if (status < 0)
 
363
                        goto fail;
275
364
        }
276
365
 
277
366
        /* disable irqs */
278
367
        if (mcp->cache[MCP_GPINTEN] != 0) {
279
368
                mcp->cache[MCP_GPINTEN] = 0;
280
 
                do_update = 1;
281
 
        }
282
 
 
283
 
        if (do_update) {
284
 
                u8 tx[4];
285
 
 
286
 
                tx[0] = mcp->addr;
287
 
                tx[1] = MCP_IPOL;
288
 
                memcpy(&tx[2], &mcp->cache[MCP_IPOL], sizeof(tx) - 2);
289
 
                status = spi_write_then_read(mcp->spi, tx, sizeof tx, NULL, 0);
 
369
                status = mcp->ops->write(mcp, MCP_GPINTEN, 0);
290
370
                if (status < 0)
291
371
                        goto fail;
292
372
        }
305
385
        unsigned                        addr;
306
386
        unsigned                        chips = 0;
307
387
        struct mcp23s08_driver_data     *data;
308
 
        int                             status;
 
388
        int                             status, type;
309
389
        unsigned                        base;
310
390
 
 
391
        type = spi_get_device_id(spi)->driver_data;
 
392
 
311
393
        pdata = spi->dev.platform_data;
312
394
        if (!pdata || !gpio_is_valid(pdata->base)) {
313
395
                dev_dbg(&spi->dev, "invalid or missing platform data\n");
314
396
                return -EINVAL;
315
397
        }
316
398
 
317
 
        for (addr = 0; addr < 4; addr++) {
 
399
        for (addr = 0; addr < ARRAY_SIZE(pdata->chip); addr++) {
318
400
                if (!pdata->chip[addr].is_present)
319
401
                        continue;
320
402
                chips++;
 
403
                if ((type == MCP_TYPE_S08) && (addr > 3)) {
 
404
                        dev_err(&spi->dev,
 
405
                                "mcp23s08 only supports address 0..3\n");
 
406
                        return -EINVAL;
 
407
                }
321
408
        }
322
409
        if (!chips)
323
410
                return -ENODEV;
329
416
        spi_set_drvdata(spi, data);
330
417
 
331
418
        base = pdata->base;
332
 
        for (addr = 0; addr < 4; addr++) {
 
419
        for (addr = 0; addr < ARRAY_SIZE(pdata->chip); addr++) {
333
420
                if (!pdata->chip[addr].is_present)
334
421
                        continue;
335
422
                chips--;
336
423
                data->mcp[addr] = &data->chip[chips];
337
 
                status = mcp23s08_probe_one(spi, addr, base,
338
 
                                pdata->chip[addr].pullups);
 
424
                status = mcp23s08_probe_one(spi, addr, type, base,
 
425
                                            pdata->chip[addr].pullups);
339
426
                if (status < 0)
340
427
                        goto fail;
341
 
                base += 8;
 
428
 
 
429
                base += (type == MCP_TYPE_S17) ? 16 : 8;
342
430
        }
343
431
        data->ngpio = base - pdata->base;
344
432
 
358
446
        return 0;
359
447
 
360
448
fail:
361
 
        for (addr = 0; addr < 4; addr++) {
 
449
        for (addr = 0; addr < ARRAY_SIZE(data->mcp); addr++) {
362
450
                int tmp;
363
451
 
364
452
                if (!data->mcp[addr])
388
476
                }
389
477
        }
390
478
 
391
 
        for (addr = 0; addr < 4; addr++) {
 
479
        for (addr = 0; addr < ARRAY_SIZE(data->mcp); addr++) {
392
480
                int tmp;
393
481
 
394
482
                if (!data->mcp[addr])
405
493
        return status;
406
494
}
407
495
 
 
496
static const struct spi_device_id mcp23s08_ids[] = {
 
497
        { "mcp23s08", MCP_TYPE_S08 },
 
498
        { "mcp23s17", MCP_TYPE_S17 },
 
499
        { },
 
500
};
 
501
MODULE_DEVICE_TABLE(spi, mcp23s08_ids);
 
502
 
408
503
static struct spi_driver mcp23s08_driver = {
409
504
        .probe          = mcp23s08_probe,
410
505
        .remove         = mcp23s08_remove,
 
506
        .id_table       = mcp23s08_ids,
411
507
        .driver = {
412
508
                .name   = "mcp23s08",
413
509
                .owner  = THIS_MODULE,
432
528
module_exit(mcp23s08_exit);
433
529
 
434
530
MODULE_LICENSE("GPL");
435
 
MODULE_ALIAS("spi:mcp23s08");