linux/drivers/gpio/gpio-pcie-idio-24.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * GPIO driver for the ACCES PCIe-IDIO-24 family
   4 * Copyright (C) 2018 William Breathitt Gray
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License, version 2, as
   8 * published by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope that it will be useful, but
  11 * WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13 * General Public License for more details.
  14 *
  15 * This driver supports the following ACCES devices: PCIe-IDIO-24,
  16 * PCIe-IDI-24, PCIe-IDO-24, and PCIe-IDIO-12.
  17 */
  18#include <linux/bitmap.h>
  19#include <linux/bitops.h>
  20#include <linux/device.h>
  21#include <linux/errno.h>
  22#include <linux/gpio/driver.h>
  23#include <linux/interrupt.h>
  24#include <linux/irqdesc.h>
  25#include <linux/kernel.h>
  26#include <linux/module.h>
  27#include <linux/pci.h>
  28#include <linux/spinlock.h>
  29#include <linux/types.h>
  30
  31/**
  32 * struct idio_24_gpio_reg - GPIO device registers structure
  33 * @out0_7:     Read: FET Outputs 0-7
  34 *              Write: FET Outputs 0-7
  35 * @out8_15:    Read: FET Outputs 8-15
  36 *              Write: FET Outputs 8-15
  37 * @out16_23:   Read: FET Outputs 16-23
  38 *              Write: FET Outputs 16-23
  39 * @ttl_out0_7: Read: TTL/CMOS Outputs 0-7
  40 *              Write: TTL/CMOS Outputs 0-7
  41 * @in0_7:      Read: Isolated Inputs 0-7
  42 *              Write: Reserved
  43 * @in8_15:     Read: Isolated Inputs 8-15
  44 *              Write: Reserved
  45 * @in16_23:    Read: Isolated Inputs 16-23
  46 *              Write: Reserved
  47 * @ttl_in0_7:  Read: TTL/CMOS Inputs 0-7
  48 *              Write: Reserved
  49 * @cos0_7:     Read: COS Status Inputs 0-7
  50 *              Write: COS Clear Inputs 0-7
  51 * @cos8_15:    Read: COS Status Inputs 8-15
  52 *              Write: COS Clear Inputs 8-15
  53 * @cos16_23:   Read: COS Status Inputs 16-23
  54 *              Write: COS Clear Inputs 16-23
  55 * @cos_ttl0_7: Read: COS Status TTL/CMOS 0-7
  56 *              Write: COS Clear TTL/CMOS 0-7
  57 * @ctl:        Read: Control Register
  58 *              Write: Control Register
  59 * @reserved:   Read: Reserved
  60 *              Write: Reserved
  61 * @cos_enable: Read: COS Enable
  62 *              Write: COS Enable
  63 * @soft_reset: Read: IRQ Output Pin Status
  64 *              Write: Software Board Reset
  65 */
  66struct idio_24_gpio_reg {
  67        u8 out0_7;
  68        u8 out8_15;
  69        u8 out16_23;
  70        u8 ttl_out0_7;
  71        u8 in0_7;
  72        u8 in8_15;
  73        u8 in16_23;
  74        u8 ttl_in0_7;
  75        u8 cos0_7;
  76        u8 cos8_15;
  77        u8 cos16_23;
  78        u8 cos_ttl0_7;
  79        u8 ctl;
  80        u8 reserved;
  81        u8 cos_enable;
  82        u8 soft_reset;
  83};
  84
  85/**
  86 * struct idio_24_gpio - GPIO device private data structure
  87 * @chip:       instance of the gpio_chip
  88 * @lock:       synchronization lock to prevent I/O race conditions
  89 * @reg:        I/O address offset for the GPIO device registers
  90 * @irq_mask:   I/O bits affected by interrupts
  91 */
  92struct idio_24_gpio {
  93        struct gpio_chip chip;
  94        raw_spinlock_t lock;
  95        struct idio_24_gpio_reg __iomem *reg;
  96        unsigned long irq_mask;
  97};
  98
  99static int idio_24_gpio_get_direction(struct gpio_chip *chip,
 100        unsigned int offset)
 101{
 102        struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
 103        const unsigned long out_mode_mask = BIT(1);
 104
 105        /* FET Outputs */
 106        if (offset < 24)
 107                return 0;
 108
 109        /* Isolated Inputs */
 110        if (offset < 48)
 111                return 1;
 112
 113        /* TTL/CMOS I/O */
 114        /* OUT MODE = 1 when TTL/CMOS Output Mode is set */
 115        return !(ioread8(&idio24gpio->reg->ctl) & out_mode_mask);
 116}
 117
 118static int idio_24_gpio_direction_input(struct gpio_chip *chip,
 119        unsigned int offset)
 120{
 121        struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
 122        unsigned long flags;
 123        unsigned int ctl_state;
 124        const unsigned long out_mode_mask = BIT(1);
 125
 126        /* TTL/CMOS I/O */
 127        if (offset > 47) {
 128                raw_spin_lock_irqsave(&idio24gpio->lock, flags);
 129
 130                /* Clear TTL/CMOS Output Mode */
 131                ctl_state = ioread8(&idio24gpio->reg->ctl) & ~out_mode_mask;
 132                iowrite8(ctl_state, &idio24gpio->reg->ctl);
 133
 134                raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
 135        }
 136
 137        return 0;
 138}
 139
 140static int idio_24_gpio_direction_output(struct gpio_chip *chip,
 141        unsigned int offset, int value)
 142{
 143        struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
 144        unsigned long flags;
 145        unsigned int ctl_state;
 146        const unsigned long out_mode_mask = BIT(1);
 147
 148        /* TTL/CMOS I/O */
 149        if (offset > 47) {
 150                raw_spin_lock_irqsave(&idio24gpio->lock, flags);
 151
 152                /* Set TTL/CMOS Output Mode */
 153                ctl_state = ioread8(&idio24gpio->reg->ctl) | out_mode_mask;
 154                iowrite8(ctl_state, &idio24gpio->reg->ctl);
 155
 156                raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
 157        }
 158
 159        chip->set(chip, offset, value);
 160        return 0;
 161}
 162
 163static int idio_24_gpio_get(struct gpio_chip *chip, unsigned int offset)
 164{
 165        struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
 166        const unsigned long offset_mask = BIT(offset % 8);
 167        const unsigned long out_mode_mask = BIT(1);
 168
 169        /* FET Outputs */
 170        if (offset < 8)
 171                return !!(ioread8(&idio24gpio->reg->out0_7) & offset_mask);
 172
 173        if (offset < 16)
 174                return !!(ioread8(&idio24gpio->reg->out8_15) & offset_mask);
 175
 176        if (offset < 24)
 177                return !!(ioread8(&idio24gpio->reg->out16_23) & offset_mask);
 178
 179        /* Isolated Inputs */
 180        if (offset < 32)
 181                return !!(ioread8(&idio24gpio->reg->in0_7) & offset_mask);
 182
 183        if (offset < 40)
 184                return !!(ioread8(&idio24gpio->reg->in8_15) & offset_mask);
 185
 186        if (offset < 48)
 187                return !!(ioread8(&idio24gpio->reg->in16_23) & offset_mask);
 188
 189        /* TTL/CMOS Outputs */
 190        if (ioread8(&idio24gpio->reg->ctl) & out_mode_mask)
 191                return !!(ioread8(&idio24gpio->reg->ttl_out0_7) & offset_mask);
 192
 193        /* TTL/CMOS Inputs */
 194        return !!(ioread8(&idio24gpio->reg->ttl_in0_7) & offset_mask);
 195}
 196
 197static int idio_24_gpio_get_multiple(struct gpio_chip *chip,
 198        unsigned long *mask, unsigned long *bits)
 199{
 200        struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
 201        size_t i;
 202        const unsigned int gpio_reg_size = 8;
 203        unsigned int bits_offset;
 204        size_t word_index;
 205        unsigned int word_offset;
 206        unsigned long word_mask;
 207        const unsigned long port_mask = GENMASK(gpio_reg_size - 1, 0);
 208        unsigned long port_state;
 209        void __iomem *ports[] = {
 210                &idio24gpio->reg->out0_7, &idio24gpio->reg->out8_15,
 211                &idio24gpio->reg->out16_23, &idio24gpio->reg->in0_7,
 212                &idio24gpio->reg->in8_15, &idio24gpio->reg->in16_23,
 213        };
 214        const unsigned long out_mode_mask = BIT(1);
 215
 216        /* clear bits array to a clean slate */
 217        bitmap_zero(bits, chip->ngpio);
 218
 219        /* get bits are evaluated a gpio port register at a time */
 220        for (i = 0; i < ARRAY_SIZE(ports) + 1; i++) {
 221                /* gpio offset in bits array */
 222                bits_offset = i * gpio_reg_size;
 223
 224                /* word index for bits array */
 225                word_index = BIT_WORD(bits_offset);
 226
 227                /* gpio offset within current word of bits array */
 228                word_offset = bits_offset % BITS_PER_LONG;
 229
 230                /* mask of get bits for current gpio within current word */
 231                word_mask = mask[word_index] & (port_mask << word_offset);
 232                if (!word_mask) {
 233                        /* no get bits in this port so skip to next one */
 234                        continue;
 235                }
 236
 237                /* read bits from current gpio port (port 6 is TTL GPIO) */
 238                if (i < 6)
 239                        port_state = ioread8(ports[i]);
 240                else if (ioread8(&idio24gpio->reg->ctl) & out_mode_mask)
 241                        port_state = ioread8(&idio24gpio->reg->ttl_out0_7);
 242                else
 243                        port_state = ioread8(&idio24gpio->reg->ttl_in0_7);
 244
 245                /* store acquired bits at respective bits array offset */
 246                bits[word_index] |= port_state << word_offset;
 247        }
 248
 249        return 0;
 250}
 251
 252static void idio_24_gpio_set(struct gpio_chip *chip, unsigned int offset,
 253        int value)
 254{
 255        struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
 256        const unsigned long out_mode_mask = BIT(1);
 257        void __iomem *base;
 258        const unsigned int mask = BIT(offset % 8);
 259        unsigned long flags;
 260        unsigned int out_state;
 261
 262        /* Isolated Inputs */
 263        if (offset > 23 && offset < 48)
 264                return;
 265
 266        /* TTL/CMOS Inputs */
 267        if (offset > 47 && !(ioread8(&idio24gpio->reg->ctl) & out_mode_mask))
 268                return;
 269
 270        /* TTL/CMOS Outputs */
 271        if (offset > 47)
 272                base = &idio24gpio->reg->ttl_out0_7;
 273        /* FET Outputs */
 274        else if (offset > 15)
 275                base = &idio24gpio->reg->out16_23;
 276        else if (offset > 7)
 277                base = &idio24gpio->reg->out8_15;
 278        else
 279                base = &idio24gpio->reg->out0_7;
 280
 281        raw_spin_lock_irqsave(&idio24gpio->lock, flags);
 282
 283        if (value)
 284                out_state = ioread8(base) | mask;
 285        else
 286                out_state = ioread8(base) & ~mask;
 287
 288        iowrite8(out_state, base);
 289
 290        raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
 291}
 292
 293static void idio_24_gpio_set_multiple(struct gpio_chip *chip,
 294        unsigned long *mask, unsigned long *bits)
 295{
 296        struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
 297        size_t i;
 298        unsigned long bits_offset;
 299        unsigned long gpio_mask;
 300        const unsigned int gpio_reg_size = 8;
 301        const unsigned long port_mask = GENMASK(gpio_reg_size, 0);
 302        unsigned long flags;
 303        unsigned int out_state;
 304        void __iomem *ports[] = {
 305                &idio24gpio->reg->out0_7, &idio24gpio->reg->out8_15,
 306                &idio24gpio->reg->out16_23
 307        };
 308        const unsigned long out_mode_mask = BIT(1);
 309        const unsigned int ttl_offset = 48;
 310        const size_t ttl_i = BIT_WORD(ttl_offset);
 311        const unsigned int word_offset = ttl_offset % BITS_PER_LONG;
 312        const unsigned long ttl_mask = (mask[ttl_i] >> word_offset) & port_mask;
 313        const unsigned long ttl_bits = (bits[ttl_i] >> word_offset) & ttl_mask;
 314
 315        /* set bits are processed a gpio port register at a time */
 316        for (i = 0; i < ARRAY_SIZE(ports); i++) {
 317                /* gpio offset in bits array */
 318                bits_offset = i * gpio_reg_size;
 319
 320                /* check if any set bits for current port */
 321                gpio_mask = (*mask >> bits_offset) & port_mask;
 322                if (!gpio_mask) {
 323                        /* no set bits for this port so move on to next port */
 324                        continue;
 325                }
 326
 327                raw_spin_lock_irqsave(&idio24gpio->lock, flags);
 328
 329                /* process output lines */
 330                out_state = ioread8(ports[i]) & ~gpio_mask;
 331                out_state |= (*bits >> bits_offset) & gpio_mask;
 332                iowrite8(out_state, ports[i]);
 333
 334                raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
 335        }
 336
 337        /* check if setting TTL lines and if they are in output mode */
 338        if (!ttl_mask || !(ioread8(&idio24gpio->reg->ctl) & out_mode_mask))
 339                return;
 340
 341        /* handle TTL output */
 342        raw_spin_lock_irqsave(&idio24gpio->lock, flags);
 343
 344        /* process output lines */
 345        out_state = ioread8(&idio24gpio->reg->ttl_out0_7) & ~ttl_mask;
 346        out_state |= ttl_bits;
 347        iowrite8(out_state, &idio24gpio->reg->ttl_out0_7);
 348
 349        raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
 350}
 351
 352static void idio_24_irq_ack(struct irq_data *data)
 353{
 354}
 355
 356static void idio_24_irq_mask(struct irq_data *data)
 357{
 358        struct gpio_chip *const chip = irq_data_get_irq_chip_data(data);
 359        struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
 360        unsigned long flags;
 361        const unsigned long bit_offset = irqd_to_hwirq(data) - 24;
 362        unsigned char new_irq_mask;
 363        const unsigned long bank_offset = bit_offset/8 * 8;
 364        unsigned char cos_enable_state;
 365
 366        raw_spin_lock_irqsave(&idio24gpio->lock, flags);
 367
 368        idio24gpio->irq_mask &= BIT(bit_offset);
 369        new_irq_mask = idio24gpio->irq_mask >> bank_offset;
 370
 371        if (!new_irq_mask) {
 372                cos_enable_state = ioread8(&idio24gpio->reg->cos_enable);
 373
 374                /* Disable Rising Edge detection */
 375                cos_enable_state &= ~BIT(bank_offset);
 376                /* Disable Falling Edge detection */
 377                cos_enable_state &= ~BIT(bank_offset + 4);
 378
 379                iowrite8(cos_enable_state, &idio24gpio->reg->cos_enable);
 380        }
 381
 382        raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
 383}
 384
 385static void idio_24_irq_unmask(struct irq_data *data)
 386{
 387        struct gpio_chip *const chip = irq_data_get_irq_chip_data(data);
 388        struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
 389        unsigned long flags;
 390        unsigned char prev_irq_mask;
 391        const unsigned long bit_offset = irqd_to_hwirq(data) - 24;
 392        const unsigned long bank_offset = bit_offset/8 * 8;
 393        unsigned char cos_enable_state;
 394
 395        raw_spin_lock_irqsave(&idio24gpio->lock, flags);
 396
 397        prev_irq_mask = idio24gpio->irq_mask >> bank_offset;
 398        idio24gpio->irq_mask |= BIT(bit_offset);
 399
 400        if (!prev_irq_mask) {
 401                cos_enable_state = ioread8(&idio24gpio->reg->cos_enable);
 402
 403                /* Enable Rising Edge detection */
 404                cos_enable_state |= BIT(bank_offset);
 405                /* Enable Falling Edge detection */
 406                cos_enable_state |= BIT(bank_offset + 4);
 407
 408                iowrite8(cos_enable_state, &idio24gpio->reg->cos_enable);
 409        }
 410
 411        raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
 412}
 413
 414static int idio_24_irq_set_type(struct irq_data *data, unsigned int flow_type)
 415{
 416        /* The only valid irq types are none and both-edges */
 417        if (flow_type != IRQ_TYPE_NONE &&
 418                (flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH)
 419                return -EINVAL;
 420
 421        return 0;
 422}
 423
 424static struct irq_chip idio_24_irqchip = {
 425        .name = "pcie-idio-24",
 426        .irq_ack = idio_24_irq_ack,
 427        .irq_mask = idio_24_irq_mask,
 428        .irq_unmask = idio_24_irq_unmask,
 429        .irq_set_type = idio_24_irq_set_type
 430};
 431
 432static irqreturn_t idio_24_irq_handler(int irq, void *dev_id)
 433{
 434        struct idio_24_gpio *const idio24gpio = dev_id;
 435        unsigned long irq_status;
 436        struct gpio_chip *const chip = &idio24gpio->chip;
 437        unsigned long irq_mask;
 438        int gpio;
 439
 440        raw_spin_lock(&idio24gpio->lock);
 441
 442        /* Read Change-Of-State status */
 443        irq_status = ioread32(&idio24gpio->reg->cos0_7);
 444
 445        raw_spin_unlock(&idio24gpio->lock);
 446
 447        /* Make sure our device generated IRQ */
 448        if (!irq_status)
 449                return IRQ_NONE;
 450
 451        /* Handle only unmasked IRQ */
 452        irq_mask = idio24gpio->irq_mask & irq_status;
 453
 454        for_each_set_bit(gpio, &irq_mask, chip->ngpio - 24)
 455                generic_handle_irq(irq_find_mapping(chip->irq.domain,
 456                        gpio + 24));
 457
 458        raw_spin_lock(&idio24gpio->lock);
 459
 460        /* Clear Change-Of-State status */
 461        iowrite32(irq_status, &idio24gpio->reg->cos0_7);
 462
 463        raw_spin_unlock(&idio24gpio->lock);
 464
 465        return IRQ_HANDLED;
 466}
 467
 468#define IDIO_24_NGPIO 56
 469static const char *idio_24_names[IDIO_24_NGPIO] = {
 470        "OUT0", "OUT1", "OUT2", "OUT3", "OUT4", "OUT5", "OUT6", "OUT7",
 471        "OUT8", "OUT9", "OUT10", "OUT11", "OUT12", "OUT13", "OUT14", "OUT15",
 472        "OUT16", "OUT17", "OUT18", "OUT19", "OUT20", "OUT21", "OUT22", "OUT23",
 473        "IIN0", "IIN1", "IIN2", "IIN3", "IIN4", "IIN5", "IIN6", "IIN7",
 474        "IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15",
 475        "IIN16", "IIN17", "IIN18", "IIN19", "IIN20", "IIN21", "IIN22", "IIN23",
 476        "TTL0", "TTL1", "TTL2", "TTL3", "TTL4", "TTL5", "TTL6", "TTL7"
 477};
 478
 479static int idio_24_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 480{
 481        struct device *const dev = &pdev->dev;
 482        struct idio_24_gpio *idio24gpio;
 483        int err;
 484        const size_t pci_bar_index = 2;
 485        const char *const name = pci_name(pdev);
 486
 487        idio24gpio = devm_kzalloc(dev, sizeof(*idio24gpio), GFP_KERNEL);
 488        if (!idio24gpio)
 489                return -ENOMEM;
 490
 491        err = pcim_enable_device(pdev);
 492        if (err) {
 493                dev_err(dev, "Failed to enable PCI device (%d)\n", err);
 494                return err;
 495        }
 496
 497        err = pcim_iomap_regions(pdev, BIT(pci_bar_index), name);
 498        if (err) {
 499                dev_err(dev, "Unable to map PCI I/O addresses (%d)\n", err);
 500                return err;
 501        }
 502
 503        idio24gpio->reg = pcim_iomap_table(pdev)[pci_bar_index];
 504
 505        idio24gpio->chip.label = name;
 506        idio24gpio->chip.parent = dev;
 507        idio24gpio->chip.owner = THIS_MODULE;
 508        idio24gpio->chip.base = -1;
 509        idio24gpio->chip.ngpio = IDIO_24_NGPIO;
 510        idio24gpio->chip.names = idio_24_names;
 511        idio24gpio->chip.get_direction = idio_24_gpio_get_direction;
 512        idio24gpio->chip.direction_input = idio_24_gpio_direction_input;
 513        idio24gpio->chip.direction_output = idio_24_gpio_direction_output;
 514        idio24gpio->chip.get = idio_24_gpio_get;
 515        idio24gpio->chip.get_multiple = idio_24_gpio_get_multiple;
 516        idio24gpio->chip.set = idio_24_gpio_set;
 517        idio24gpio->chip.set_multiple = idio_24_gpio_set_multiple;
 518
 519        raw_spin_lock_init(&idio24gpio->lock);
 520
 521        /* Software board reset */
 522        iowrite8(0, &idio24gpio->reg->soft_reset);
 523
 524        err = devm_gpiochip_add_data(dev, &idio24gpio->chip, idio24gpio);
 525        if (err) {
 526                dev_err(dev, "GPIO registering failed (%d)\n", err);
 527                return err;
 528        }
 529
 530        err = gpiochip_irqchip_add(&idio24gpio->chip, &idio_24_irqchip, 0,
 531                handle_edge_irq, IRQ_TYPE_NONE);
 532        if (err) {
 533                dev_err(dev, "Could not add irqchip (%d)\n", err);
 534                return err;
 535        }
 536
 537        err = devm_request_irq(dev, pdev->irq, idio_24_irq_handler, IRQF_SHARED,
 538                name, idio24gpio);
 539        if (err) {
 540                dev_err(dev, "IRQ handler registering failed (%d)\n", err);
 541                return err;
 542        }
 543
 544        return 0;
 545}
 546
 547static const struct pci_device_id idio_24_pci_dev_id[] = {
 548        { PCI_DEVICE(0x494F, 0x0FD0) }, { PCI_DEVICE(0x494F, 0x0BD0) },
 549        { PCI_DEVICE(0x494F, 0x07D0) }, { PCI_DEVICE(0x494F, 0x0FC0) },
 550        { 0 }
 551};
 552MODULE_DEVICE_TABLE(pci, idio_24_pci_dev_id);
 553
 554static struct pci_driver idio_24_driver = {
 555        .name = "pcie-idio-24",
 556        .id_table = idio_24_pci_dev_id,
 557        .probe = idio_24_probe
 558};
 559
 560module_pci_driver(idio_24_driver);
 561
 562MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
 563MODULE_DESCRIPTION("ACCES PCIe-IDIO-24 GPIO driver");
 564MODULE_LICENSE("GPL v2");
 565