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#include <linux/of.h>
  16#include <linux/of_device.h>
  17
  18/**
  19 * MCP types supported by driver
  20 */
  21#define MCP_TYPE_S08    0
  22#define MCP_TYPE_S17    1
  23#define MCP_TYPE_008    2
  24#define MCP_TYPE_017    3
  25
  26/* Registers are all 8 bits wide.
  27 *
  28 * The mcp23s17 has twice as many bits, and can be configured to work
  29 * with either 16 bit registers or with two adjacent 8 bit banks.
  30 */
  31#define MCP_IODIR       0x00            /* init/reset:  all ones */
  32#define MCP_IPOL        0x01
  33#define MCP_GPINTEN     0x02
  34#define MCP_DEFVAL      0x03
  35#define MCP_INTCON      0x04
  36#define MCP_IOCON       0x05
  37#       define IOCON_SEQOP      (1 << 5)
  38#       define IOCON_HAEN       (1 << 3)
  39#       define IOCON_ODR        (1 << 2)
  40#       define IOCON_INTPOL     (1 << 1)
  41#define MCP_GPPU        0x06
  42#define MCP_INTF        0x07
  43#define MCP_INTCAP      0x08
  44#define MCP_GPIO        0x09
  45#define MCP_OLAT        0x0a
  46
  47struct mcp23s08;
  48
  49struct mcp23s08_ops {
  50        int     (*read)(struct mcp23s08 *mcp, unsigned reg);
  51        int     (*write)(struct mcp23s08 *mcp, unsigned reg, unsigned val);
  52        int     (*read_regs)(struct mcp23s08 *mcp, unsigned reg,
  53                             u16 *vals, unsigned n);
  54};
  55
  56struct mcp23s08 {
  57        u8                      addr;
  58
  59        u16                     cache[11];
  60        /* lock protects the cached values */
  61        struct mutex            lock;
  62
  63        struct gpio_chip        chip;
  64
  65        const struct mcp23s08_ops       *ops;
  66        void                    *data; /* ops specific data */
  67};
  68
  69/* A given spi_device can represent up to eight mcp23sxx chips
  70 * sharing the same chipselect but using different addresses
  71 * (e.g. chips #0 and #3 might be populated, but not #1 or $2).
  72 * Driver data holds all the per-chip data.
  73 */
  74struct mcp23s08_driver_data {
  75        unsigned                ngpio;
  76        struct mcp23s08         *mcp[8];
  77        struct mcp23s08         chip[];
  78};
  79
  80/*----------------------------------------------------------------------*/
  81
  82#if IS_ENABLED(CONFIG_I2C)
  83
  84static int mcp23008_read(struct mcp23s08 *mcp, unsigned reg)
  85{
  86        return i2c_smbus_read_byte_data(mcp->data, reg);
  87}
  88
  89static int mcp23008_write(struct mcp23s08 *mcp, unsigned reg, unsigned val)
  90{
  91        return i2c_smbus_write_byte_data(mcp->data, reg, val);
  92}
  93
  94static int
  95mcp23008_read_regs(struct mcp23s08 *mcp, unsigned reg, u16 *vals, unsigned n)
  96{
  97        while (n--) {
  98                int ret = mcp23008_read(mcp, reg++);
  99                if (ret < 0)
 100                        return ret;
 101                *vals++ = ret;
 102        }
 103
 104        return 0;
 105}
 106
 107static int mcp23017_read(struct mcp23s08 *mcp, unsigned reg)
 108{
 109        return i2c_smbus_read_word_data(mcp->data, reg << 1);
 110}
 111
 112static int mcp23017_write(struct mcp23s08 *mcp, unsigned reg, unsigned val)
 113{
 114        return i2c_smbus_write_word_data(mcp->data, reg << 1, val);
 115}
 116
 117static int
 118mcp23017_read_regs(struct mcp23s08 *mcp, unsigned reg, u16 *vals, unsigned n)
 119{
 120        while (n--) {
 121                int ret = mcp23017_read(mcp, reg++);
 122                if (ret < 0)
 123                        return ret;
 124                *vals++ = ret;
 125        }
 126
 127        return 0;
 128}
 129
 130static const struct mcp23s08_ops mcp23008_ops = {
 131        .read           = mcp23008_read,
 132        .write          = mcp23008_write,
 133        .read_regs      = mcp23008_read_regs,
 134};
 135
 136static const struct mcp23s08_ops mcp23017_ops = {
 137        .read           = mcp23017_read,
 138        .write          = mcp23017_write,
 139        .read_regs      = mcp23017_read_regs,
 140};
 141
 142#endif /* CONFIG_I2C */
 143
 144/*----------------------------------------------------------------------*/
 145
 146#ifdef CONFIG_SPI_MASTER
 147
 148static int mcp23s08_read(struct mcp23s08 *mcp, unsigned reg)
 149{
 150        u8      tx[2], rx[1];
 151        int     status;
 152
 153        tx[0] = mcp->addr | 0x01;
 154        tx[1] = reg;
 155        status = spi_write_then_read(mcp->data, tx, sizeof tx, rx, sizeof rx);
 156        return (status < 0) ? status : rx[0];
 157}
 158
 159static int mcp23s08_write(struct mcp23s08 *mcp, unsigned reg, unsigned val)
 160{
 161        u8      tx[3];
 162
 163        tx[0] = mcp->addr;
 164        tx[1] = reg;
 165        tx[2] = val;
 166        return spi_write_then_read(mcp->data, tx, sizeof tx, NULL, 0);
 167}
 168
 169static int
 170mcp23s08_read_regs(struct mcp23s08 *mcp, unsigned reg, u16 *vals, unsigned n)
 171{
 172        u8      tx[2], *tmp;
 173        int     status;
 174
 175        if ((n + reg) > sizeof mcp->cache)
 176                return -EINVAL;
 177        tx[0] = mcp->addr | 0x01;
 178        tx[1] = reg;
 179
 180        tmp = (u8 *)vals;
 181        status = spi_write_then_read(mcp->data, tx, sizeof tx, tmp, n);
 182        if (status >= 0) {
 183                while (n--)
 184                        vals[n] = tmp[n]; /* expand to 16bit */
 185        }
 186        return status;
 187}
 188
 189static int mcp23s17_read(struct mcp23s08 *mcp, unsigned reg)
 190{
 191        u8      tx[2], rx[2];
 192        int     status;
 193
 194        tx[0] = mcp->addr | 0x01;
 195        tx[1] = reg << 1;
 196        status = spi_write_then_read(mcp->data, tx, sizeof tx, rx, sizeof rx);
 197        return (status < 0) ? status : (rx[0] | (rx[1] << 8));
 198}
 199
 200static int mcp23s17_write(struct mcp23s08 *mcp, unsigned reg, unsigned val)
 201{
 202        u8      tx[4];
 203
 204        tx[0] = mcp->addr;
 205        tx[1] = reg << 1;
 206        tx[2] = val;
 207        tx[3] = val >> 8;
 208        return spi_write_then_read(mcp->data, tx, sizeof tx, NULL, 0);
 209}
 210
 211static int
 212mcp23s17_read_regs(struct mcp23s08 *mcp, unsigned reg, u16 *vals, unsigned n)
 213{
 214        u8      tx[2];
 215        int     status;
 216
 217        if ((n + reg) > sizeof mcp->cache)
 218                return -EINVAL;
 219        tx[0] = mcp->addr | 0x01;
 220        tx[1] = reg << 1;
 221
 222        status = spi_write_then_read(mcp->data, tx, sizeof tx,
 223                                     (u8 *)vals, n * 2);
 224        if (status >= 0) {
 225                while (n--)
 226                        vals[n] = __le16_to_cpu((__le16)vals[n]);
 227        }
 228
 229        return status;
 230}
 231
 232static const struct mcp23s08_ops mcp23s08_ops = {
 233        .read           = mcp23s08_read,
 234        .write          = mcp23s08_write,
 235        .read_regs      = mcp23s08_read_regs,
 236};
 237
 238static const struct mcp23s08_ops mcp23s17_ops = {
 239        .read           = mcp23s17_read,
 240        .write          = mcp23s17_write,
 241        .read_regs      = mcp23s17_read_regs,
 242};
 243
 244#endif /* CONFIG_SPI_MASTER */
 245
 246/*----------------------------------------------------------------------*/
 247
 248static int mcp23s08_direction_input(struct gpio_chip *chip, unsigned offset)
 249{
 250        struct mcp23s08 *mcp = container_of(chip, struct mcp23s08, chip);
 251        int status;
 252
 253        mutex_lock(&mcp->lock);
 254        mcp->cache[MCP_IODIR] |= (1 << offset);
 255        status = mcp->ops->write(mcp, MCP_IODIR, mcp->cache[MCP_IODIR]);
 256        mutex_unlock(&mcp->lock);
 257        return status;
 258}
 259
 260static int mcp23s08_get(struct gpio_chip *chip, unsigned offset)
 261{
 262        struct mcp23s08 *mcp = container_of(chip, struct mcp23s08, chip);
 263        int status;
 264
 265        mutex_lock(&mcp->lock);
 266
 267        /* REVISIT reading this clears any IRQ ... */
 268        status = mcp->ops->read(mcp, MCP_GPIO);
 269        if (status < 0)
 270                status = 0;
 271        else {
 272                mcp->cache[MCP_GPIO] = status;
 273                status = !!(status & (1 << offset));
 274        }
 275        mutex_unlock(&mcp->lock);
 276        return status;
 277}
 278
 279static int __mcp23s08_set(struct mcp23s08 *mcp, unsigned mask, int value)
 280{
 281        unsigned olat = mcp->cache[MCP_OLAT];
 282
 283        if (value)
 284                olat |= mask;
 285        else
 286                olat &= ~mask;
 287        mcp->cache[MCP_OLAT] = olat;
 288        return mcp->ops->write(mcp, MCP_OLAT, olat);
 289}
 290
 291static void mcp23s08_set(struct gpio_chip *chip, unsigned offset, int value)
 292{
 293        struct mcp23s08 *mcp = container_of(chip, struct mcp23s08, chip);
 294        unsigned mask = 1 << offset;
 295
 296        mutex_lock(&mcp->lock);
 297        __mcp23s08_set(mcp, mask, value);
 298        mutex_unlock(&mcp->lock);
 299}
 300
 301static int
 302mcp23s08_direction_output(struct gpio_chip *chip, unsigned offset, int value)
 303{
 304        struct mcp23s08 *mcp = container_of(chip, struct mcp23s08, chip);
 305        unsigned mask = 1 << offset;
 306        int status;
 307
 308        mutex_lock(&mcp->lock);
 309        status = __mcp23s08_set(mcp, mask, value);
 310        if (status == 0) {
 311                mcp->cache[MCP_IODIR] &= ~mask;
 312                status = mcp->ops->write(mcp, MCP_IODIR, mcp->cache[MCP_IODIR]);
 313        }
 314        mutex_unlock(&mcp->lock);
 315        return status;
 316}
 317
 318/*----------------------------------------------------------------------*/
 319
 320#ifdef CONFIG_DEBUG_FS
 321
 322#include <linux/seq_file.h>
 323
 324/*
 325 * This shows more info than the generic gpio dump code:
 326 * pullups, deglitching, open drain drive.
 327 */
 328static void mcp23s08_dbg_show(struct seq_file *s, struct gpio_chip *chip)
 329{
 330        struct mcp23s08 *mcp;
 331        char            bank;
 332        int             t;
 333        unsigned        mask;
 334
 335        mcp = container_of(chip, struct mcp23s08, chip);
 336
 337        /* NOTE: we only handle one bank for now ... */
 338        bank = '0' + ((mcp->addr >> 1) & 0x7);
 339
 340        mutex_lock(&mcp->lock);
 341        t = mcp->ops->read_regs(mcp, 0, mcp->cache, ARRAY_SIZE(mcp->cache));
 342        if (t < 0) {
 343                seq_printf(s, " I/O ERROR %d\n", t);
 344                goto done;
 345        }
 346
 347        for (t = 0, mask = 1; t < chip->ngpio; t++, mask <<= 1) {
 348                const char      *label;
 349
 350                label = gpiochip_is_requested(chip, t);
 351                if (!label)
 352                        continue;
 353
 354                seq_printf(s, " gpio-%-3d P%c.%d (%-12s) %s %s %s",
 355                        chip->base + t, bank, t, label,
 356                        (mcp->cache[MCP_IODIR] & mask) ? "in " : "out",
 357                        (mcp->cache[MCP_GPIO] & mask) ? "hi" : "lo",
 358                        (mcp->cache[MCP_GPPU] & mask) ? "up" : "  ");
 359                /* NOTE:  ignoring the irq-related registers */
 360                seq_printf(s, "\n");
 361        }
 362done:
 363        mutex_unlock(&mcp->lock);
 364}
 365
 366#else
 367#define mcp23s08_dbg_show       NULL
 368#endif
 369
 370/*----------------------------------------------------------------------*/
 371
 372static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
 373                              void *data, unsigned addr,
 374                              unsigned type, unsigned base, unsigned pullups)
 375{
 376        int status;
 377
 378        mutex_init(&mcp->lock);
 379
 380        mcp->data = data;
 381        mcp->addr = addr;
 382
 383        mcp->chip.direction_input = mcp23s08_direction_input;
 384        mcp->chip.get = mcp23s08_get;
 385        mcp->chip.direction_output = mcp23s08_direction_output;
 386        mcp->chip.set = mcp23s08_set;
 387        mcp->chip.dbg_show = mcp23s08_dbg_show;
 388#ifdef CONFIG_OF
 389        mcp->chip.of_gpio_n_cells = 2;
 390        mcp->chip.of_node = dev->of_node;
 391#endif
 392
 393        switch (type) {
 394#ifdef CONFIG_SPI_MASTER
 395        case MCP_TYPE_S08:
 396                mcp->ops = &mcp23s08_ops;
 397                mcp->chip.ngpio = 8;
 398                mcp->chip.label = "mcp23s08";
 399                break;
 400
 401        case MCP_TYPE_S17:
 402                mcp->ops = &mcp23s17_ops;
 403                mcp->chip.ngpio = 16;
 404                mcp->chip.label = "mcp23s17";
 405                break;
 406#endif /* CONFIG_SPI_MASTER */
 407
 408#if IS_ENABLED(CONFIG_I2C)
 409        case MCP_TYPE_008:
 410                mcp->ops = &mcp23008_ops;
 411                mcp->chip.ngpio = 8;
 412                mcp->chip.label = "mcp23008";
 413                break;
 414
 415        case MCP_TYPE_017:
 416                mcp->ops = &mcp23017_ops;
 417                mcp->chip.ngpio = 16;
 418                mcp->chip.label = "mcp23017";
 419                break;
 420#endif /* CONFIG_I2C */
 421
 422        default:
 423                dev_err(dev, "invalid device type (%d)\n", type);
 424                return -EINVAL;
 425        }
 426
 427        mcp->chip.base = base;
 428        mcp->chip.can_sleep = 1;
 429        mcp->chip.dev = dev;
 430        mcp->chip.owner = THIS_MODULE;
 431
 432        /* verify MCP_IOCON.SEQOP = 0, so sequential reads work,
 433         * and MCP_IOCON.HAEN = 1, so we work with all chips.
 434         */
 435        status = mcp->ops->read(mcp, MCP_IOCON);
 436        if (status < 0)
 437                goto fail;
 438        if ((status & IOCON_SEQOP) || !(status & IOCON_HAEN)) {
 439                /* mcp23s17 has IOCON twice, make sure they are in sync */
 440                status &= ~(IOCON_SEQOP | (IOCON_SEQOP << 8));
 441                status |= IOCON_HAEN | (IOCON_HAEN << 8);
 442                status = mcp->ops->write(mcp, MCP_IOCON, status);
 443                if (status < 0)
 444                        goto fail;
 445        }
 446
 447        /* configure ~100K pullups */
 448        status = mcp->ops->write(mcp, MCP_GPPU, pullups);
 449        if (status < 0)
 450                goto fail;
 451
 452        status = mcp->ops->read_regs(mcp, 0, mcp->cache, ARRAY_SIZE(mcp->cache));
 453        if (status < 0)
 454                goto fail;
 455
 456        /* disable inverter on input */
 457        if (mcp->cache[MCP_IPOL] != 0) {
 458                mcp->cache[MCP_IPOL] = 0;
 459                status = mcp->ops->write(mcp, MCP_IPOL, 0);
 460                if (status < 0)
 461                        goto fail;
 462        }
 463
 464        /* disable irqs */
 465        if (mcp->cache[MCP_GPINTEN] != 0) {
 466                mcp->cache[MCP_GPINTEN] = 0;
 467                status = mcp->ops->write(mcp, MCP_GPINTEN, 0);
 468                if (status < 0)
 469                        goto fail;
 470        }
 471
 472        status = gpiochip_add(&mcp->chip);
 473fail:
 474        if (status < 0)
 475                dev_dbg(dev, "can't setup chip %d, --> %d\n",
 476                        addr, status);
 477        return status;
 478}
 479
 480/*----------------------------------------------------------------------*/
 481
 482#ifdef CONFIG_OF
 483#ifdef CONFIG_SPI_MASTER
 484static struct of_device_id mcp23s08_spi_of_match[] = {
 485        {
 486                .compatible = "mcp,mcp23s08", .data = (void *) MCP_TYPE_S08,
 487        },
 488        {
 489                .compatible = "mcp,mcp23s17", .data = (void *) MCP_TYPE_S17,
 490        },
 491        { },
 492};
 493MODULE_DEVICE_TABLE(of, mcp23s08_spi_of_match);
 494#endif
 495
 496#if IS_ENABLED(CONFIG_I2C)
 497static struct of_device_id mcp23s08_i2c_of_match[] = {
 498        {
 499                .compatible = "mcp,mcp23008", .data = (void *) MCP_TYPE_008,
 500        },
 501        {
 502                .compatible = "mcp,mcp23017", .data = (void *) MCP_TYPE_017,
 503        },
 504        { },
 505};
 506MODULE_DEVICE_TABLE(of, mcp23s08_i2c_of_match);
 507#endif
 508#endif /* CONFIG_OF */
 509
 510
 511#if IS_ENABLED(CONFIG_I2C)
 512
 513static int mcp230xx_probe(struct i2c_client *client,
 514                                    const struct i2c_device_id *id)
 515{
 516        struct mcp23s08_platform_data *pdata;
 517        struct mcp23s08 *mcp;
 518        int status, base, pullups;
 519        const struct of_device_id *match;
 520
 521        match = of_match_device(of_match_ptr(mcp23s08_i2c_of_match),
 522                                        &client->dev);
 523        if (match) {
 524                base = -1;
 525                pullups = 0;
 526        } else {
 527                pdata = client->dev.platform_data;
 528                if (!pdata || !gpio_is_valid(pdata->base)) {
 529                        dev_dbg(&client->dev,
 530                                        "invalid or missing platform data\n");
 531                        return -EINVAL;
 532                }
 533                base = pdata->base;
 534                pullups = pdata->chip[0].pullups;
 535        }
 536
 537        mcp = kzalloc(sizeof *mcp, GFP_KERNEL);
 538        if (!mcp)
 539                return -ENOMEM;
 540
 541        status = mcp23s08_probe_one(mcp, &client->dev, client, client->addr,
 542                                    id->driver_data, base, pullups);
 543        if (status)
 544                goto fail;
 545
 546        i2c_set_clientdata(client, mcp);
 547
 548        return 0;
 549
 550fail:
 551        kfree(mcp);
 552
 553        return status;
 554}
 555
 556static int mcp230xx_remove(struct i2c_client *client)
 557{
 558        struct mcp23s08 *mcp = i2c_get_clientdata(client);
 559        int status;
 560
 561        status = gpiochip_remove(&mcp->chip);
 562        if (status == 0)
 563                kfree(mcp);
 564
 565        return status;
 566}
 567
 568static const struct i2c_device_id mcp230xx_id[] = {
 569        { "mcp23008", MCP_TYPE_008 },
 570        { "mcp23017", MCP_TYPE_017 },
 571        { },
 572};
 573MODULE_DEVICE_TABLE(i2c, mcp230xx_id);
 574
 575static struct i2c_driver mcp230xx_driver = {
 576        .driver = {
 577                .name   = "mcp230xx",
 578                .owner  = THIS_MODULE,
 579                .of_match_table = of_match_ptr(mcp23s08_i2c_of_match),
 580        },
 581        .probe          = mcp230xx_probe,
 582        .remove         = mcp230xx_remove,
 583        .id_table       = mcp230xx_id,
 584};
 585
 586static int __init mcp23s08_i2c_init(void)
 587{
 588        return i2c_add_driver(&mcp230xx_driver);
 589}
 590
 591static void mcp23s08_i2c_exit(void)
 592{
 593        i2c_del_driver(&mcp230xx_driver);
 594}
 595
 596#else
 597
 598static int __init mcp23s08_i2c_init(void) { return 0; }
 599static void mcp23s08_i2c_exit(void) { }
 600
 601#endif /* CONFIG_I2C */
 602
 603/*----------------------------------------------------------------------*/
 604
 605#ifdef CONFIG_SPI_MASTER
 606
 607static int mcp23s08_probe(struct spi_device *spi)
 608{
 609        struct mcp23s08_platform_data   *pdata;
 610        unsigned                        addr;
 611        unsigned                        chips = 0;
 612        struct mcp23s08_driver_data     *data;
 613        int                             status, type;
 614        unsigned                        base = -1,
 615                                        ngpio = 0,
 616                                        pullups[ARRAY_SIZE(pdata->chip)];
 617        const struct                    of_device_id *match;
 618        u32                             spi_present_mask = 0;
 619
 620        match = of_match_device(of_match_ptr(mcp23s08_spi_of_match), &spi->dev);
 621        if (match) {
 622                type = (int)match->data;
 623                status = of_property_read_u32(spi->dev.of_node,
 624                                "mcp,spi-present-mask", &spi_present_mask);
 625                if (status) {
 626                        dev_err(&spi->dev, "DT has no spi-present-mask\n");
 627                        return -ENODEV;
 628                }
 629                if ((spi_present_mask <= 0) || (spi_present_mask >= 256)) {
 630                        dev_err(&spi->dev, "invalid spi-present-mask\n");
 631                        return -ENODEV;
 632                }
 633
 634                for (addr = 0; addr < ARRAY_SIZE(pdata->chip); addr++)
 635                        pullups[addr] = 0;
 636        } else {
 637                type = spi_get_device_id(spi)->driver_data;
 638                pdata = spi->dev.platform_data;
 639                if (!pdata || !gpio_is_valid(pdata->base)) {
 640                        dev_dbg(&spi->dev,
 641                                        "invalid or missing platform data\n");
 642                        return -EINVAL;
 643                }
 644
 645                for (addr = 0; addr < ARRAY_SIZE(pdata->chip); addr++) {
 646                        if (!pdata->chip[addr].is_present)
 647                                continue;
 648                        chips++;
 649                        if ((type == MCP_TYPE_S08) && (addr > 3)) {
 650                                dev_err(&spi->dev,
 651                                        "mcp23s08 only supports address 0..3\n");
 652                                return -EINVAL;
 653                        }
 654                        spi_present_mask |= 1 << addr;
 655                        pullups[addr] = pdata->chip[addr].pullups;
 656                }
 657
 658                if (!chips)
 659                        return -ENODEV;
 660
 661                base = pdata->base;
 662        }
 663
 664        data = kzalloc(sizeof *data + chips * sizeof(struct mcp23s08),
 665                        GFP_KERNEL);
 666        if (!data)
 667                return -ENOMEM;
 668        spi_set_drvdata(spi, data);
 669
 670        for (addr = 0; addr < ARRAY_SIZE(pdata->chip); addr++) {
 671                if (!(spi_present_mask & (1 << addr)))
 672                        continue;
 673                chips--;
 674                data->mcp[addr] = &data->chip[chips];
 675                status = mcp23s08_probe_one(data->mcp[addr], &spi->dev, spi,
 676                                            0x40 | (addr << 1), type, base,
 677                                            pullups[addr]);
 678                if (status < 0)
 679                        goto fail;
 680
 681                if (base != -1)
 682                        base += (type == MCP_TYPE_S17) ? 16 : 8;
 683                ngpio += (type == MCP_TYPE_S17) ? 16 : 8;
 684        }
 685        data->ngpio = ngpio;
 686
 687        /* NOTE:  these chips have a relatively sane IRQ framework, with
 688         * per-signal masking and level/edge triggering.  It's not yet
 689         * handled here...
 690         */
 691
 692        return 0;
 693
 694fail:
 695        for (addr = 0; addr < ARRAY_SIZE(data->mcp); addr++) {
 696                int tmp;
 697
 698                if (!data->mcp[addr])
 699                        continue;
 700                tmp = gpiochip_remove(&data->mcp[addr]->chip);
 701                if (tmp < 0)
 702                        dev_err(&spi->dev, "%s --> %d\n", "remove", tmp);
 703        }
 704        kfree(data);
 705        return status;
 706}
 707
 708static int mcp23s08_remove(struct spi_device *spi)
 709{
 710        struct mcp23s08_driver_data     *data = spi_get_drvdata(spi);
 711        unsigned                        addr;
 712        int                             status = 0;
 713
 714        for (addr = 0; addr < ARRAY_SIZE(data->mcp); addr++) {
 715                int tmp;
 716
 717                if (!data->mcp[addr])
 718                        continue;
 719
 720                tmp = gpiochip_remove(&data->mcp[addr]->chip);
 721                if (tmp < 0) {
 722                        dev_err(&spi->dev, "%s --> %d\n", "remove", tmp);
 723                        status = tmp;
 724                }
 725        }
 726        if (status == 0)
 727                kfree(data);
 728        return status;
 729}
 730
 731static const struct spi_device_id mcp23s08_ids[] = {
 732        { "mcp23s08", MCP_TYPE_S08 },
 733        { "mcp23s17", MCP_TYPE_S17 },
 734        { },
 735};
 736MODULE_DEVICE_TABLE(spi, mcp23s08_ids);
 737
 738static struct spi_driver mcp23s08_driver = {
 739        .probe          = mcp23s08_probe,
 740        .remove         = mcp23s08_remove,
 741        .id_table       = mcp23s08_ids,
 742        .driver = {
 743                .name   = "mcp23s08",
 744                .owner  = THIS_MODULE,
 745                .of_match_table = of_match_ptr(mcp23s08_spi_of_match),
 746        },
 747};
 748
 749static int __init mcp23s08_spi_init(void)
 750{
 751        return spi_register_driver(&mcp23s08_driver);
 752}
 753
 754static void mcp23s08_spi_exit(void)
 755{
 756        spi_unregister_driver(&mcp23s08_driver);
 757}
 758
 759#else
 760
 761static int __init mcp23s08_spi_init(void) { return 0; }
 762static void mcp23s08_spi_exit(void) { }
 763
 764#endif /* CONFIG_SPI_MASTER */
 765
 766/*----------------------------------------------------------------------*/
 767
 768static int __init mcp23s08_init(void)
 769{
 770        int ret;
 771
 772        ret = mcp23s08_spi_init();
 773        if (ret)
 774                goto spi_fail;
 775
 776        ret = mcp23s08_i2c_init();
 777        if (ret)
 778                goto i2c_fail;
 779
 780        return 0;
 781
 782 i2c_fail:
 783        mcp23s08_spi_exit();
 784 spi_fail:
 785        return ret;
 786}
 787/* register after spi/i2c postcore initcall and before
 788 * subsys initcalls that may rely on these GPIOs
 789 */
 790subsys_initcall(mcp23s08_init);
 791
 792static void __exit mcp23s08_exit(void)
 793{
 794        mcp23s08_spi_exit();
 795        mcp23s08_i2c_exit();
 796}
 797module_exit(mcp23s08_exit);
 798
 799MODULE_LICENSE("GPL");
 800
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.