linux/drivers/gpio/gpio-mcp23s08.c
<<
>>
Prefs
   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#if IS_ENABLED(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#if IS_ENABLED(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#if IS_ENABLED(CONFIG_I2C)
 477
 478static int 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 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         = 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");
 725
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.