11802d0beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 202e74fc0SWilliam Breathitt Gray /* 302e74fc0SWilliam Breathitt Gray * GPIO driver for the ACCES PCI-IDIO-16 402e74fc0SWilliam Breathitt Gray * Copyright (C) 2017 William Breathitt Gray 502e74fc0SWilliam Breathitt Gray */ 6810ebfc5SWilliam Breathitt Gray #include <linux/bitmap.h> 702e74fc0SWilliam Breathitt Gray #include <linux/bitops.h> 802e74fc0SWilliam Breathitt Gray #include <linux/device.h> 902e74fc0SWilliam Breathitt Gray #include <linux/errno.h> 1002e74fc0SWilliam Breathitt Gray #include <linux/gpio/driver.h> 1102e74fc0SWilliam Breathitt Gray #include <linux/interrupt.h> 1202e74fc0SWilliam Breathitt Gray #include <linux/irqdesc.h> 1302e74fc0SWilliam Breathitt Gray #include <linux/kernel.h> 1402e74fc0SWilliam Breathitt Gray #include <linux/module.h> 1502e74fc0SWilliam Breathitt Gray #include <linux/pci.h> 1602e74fc0SWilliam Breathitt Gray #include <linux/spinlock.h> 1702e74fc0SWilliam Breathitt Gray #include <linux/types.h> 1802e74fc0SWilliam Breathitt Gray 1902e74fc0SWilliam Breathitt Gray /** 2002e74fc0SWilliam Breathitt Gray * struct idio_16_gpio_reg - GPIO device registers structure 2102e74fc0SWilliam Breathitt Gray * @out0_7: Read: FET Drive Outputs 0-7 2202e74fc0SWilliam Breathitt Gray * Write: FET Drive Outputs 0-7 2302e74fc0SWilliam Breathitt Gray * @in0_7: Read: Isolated Inputs 0-7 2402e74fc0SWilliam Breathitt Gray * Write: Clear Interrupt 2502e74fc0SWilliam Breathitt Gray * @irq_ctl: Read: Enable IRQ 2602e74fc0SWilliam Breathitt Gray * Write: Disable IRQ 2702e74fc0SWilliam Breathitt Gray * @filter_ctl: Read: Activate Input Filters 0-15 2802e74fc0SWilliam Breathitt Gray * Write: Deactivate Input Filters 0-15 2902e74fc0SWilliam Breathitt Gray * @out8_15: Read: FET Drive Outputs 8-15 3002e74fc0SWilliam Breathitt Gray * Write: FET Drive Outputs 8-15 3102e74fc0SWilliam Breathitt Gray * @in8_15: Read: Isolated Inputs 8-15 3202e74fc0SWilliam Breathitt Gray * Write: Unused 3302e74fc0SWilliam Breathitt Gray * @irq_status: Read: Interrupt status 3402e74fc0SWilliam Breathitt Gray * Write: Unused 3502e74fc0SWilliam Breathitt Gray */ 3602e74fc0SWilliam Breathitt Gray struct idio_16_gpio_reg { 3702e74fc0SWilliam Breathitt Gray u8 out0_7; 3802e74fc0SWilliam Breathitt Gray u8 in0_7; 3902e74fc0SWilliam Breathitt Gray u8 irq_ctl; 4002e74fc0SWilliam Breathitt Gray u8 filter_ctl; 4102e74fc0SWilliam Breathitt Gray u8 out8_15; 4202e74fc0SWilliam Breathitt Gray u8 in8_15; 4302e74fc0SWilliam Breathitt Gray u8 irq_status; 4402e74fc0SWilliam Breathitt Gray }; 4502e74fc0SWilliam Breathitt Gray 4602e74fc0SWilliam Breathitt Gray /** 4702e74fc0SWilliam Breathitt Gray * struct idio_16_gpio - GPIO device private data structure 4802e74fc0SWilliam Breathitt Gray * @chip: instance of the gpio_chip 4902e74fc0SWilliam Breathitt Gray * @lock: synchronization lock to prevent I/O race conditions 5002e74fc0SWilliam Breathitt Gray * @reg: I/O address offset for the GPIO device registers 5102e74fc0SWilliam Breathitt Gray * @irq_mask: I/O bits affected by interrupts 5202e74fc0SWilliam Breathitt Gray */ 5302e74fc0SWilliam Breathitt Gray struct idio_16_gpio { 5402e74fc0SWilliam Breathitt Gray struct gpio_chip chip; 55ea38ce08SJulia Cartwright raw_spinlock_t lock; 5602e74fc0SWilliam Breathitt Gray struct idio_16_gpio_reg __iomem *reg; 5702e74fc0SWilliam Breathitt Gray unsigned long irq_mask; 5802e74fc0SWilliam Breathitt Gray }; 5902e74fc0SWilliam Breathitt Gray 6002e74fc0SWilliam Breathitt Gray static int idio_16_gpio_get_direction(struct gpio_chip *chip, 6102e74fc0SWilliam Breathitt Gray unsigned int offset) 6202e74fc0SWilliam Breathitt Gray { 6302e74fc0SWilliam Breathitt Gray if (offset > 15) 6402e74fc0SWilliam Breathitt Gray return 1; 6502e74fc0SWilliam Breathitt Gray 6602e74fc0SWilliam Breathitt Gray return 0; 6702e74fc0SWilliam Breathitt Gray } 6802e74fc0SWilliam Breathitt Gray 6902e74fc0SWilliam Breathitt Gray static int idio_16_gpio_direction_input(struct gpio_chip *chip, 7002e74fc0SWilliam Breathitt Gray unsigned int offset) 7102e74fc0SWilliam Breathitt Gray { 7202e74fc0SWilliam Breathitt Gray return 0; 7302e74fc0SWilliam Breathitt Gray } 7402e74fc0SWilliam Breathitt Gray 7502e74fc0SWilliam Breathitt Gray static int idio_16_gpio_direction_output(struct gpio_chip *chip, 7602e74fc0SWilliam Breathitt Gray unsigned int offset, int value) 7702e74fc0SWilliam Breathitt Gray { 7802e74fc0SWilliam Breathitt Gray chip->set(chip, offset, value); 7902e74fc0SWilliam Breathitt Gray return 0; 8002e74fc0SWilliam Breathitt Gray } 8102e74fc0SWilliam Breathitt Gray 8202e74fc0SWilliam Breathitt Gray static int idio_16_gpio_get(struct gpio_chip *chip, unsigned int offset) 8302e74fc0SWilliam Breathitt Gray { 8402e74fc0SWilliam Breathitt Gray struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip); 8502e74fc0SWilliam Breathitt Gray unsigned long mask = BIT(offset); 8602e74fc0SWilliam Breathitt Gray 8702e74fc0SWilliam Breathitt Gray if (offset < 8) 8802e74fc0SWilliam Breathitt Gray return !!(ioread8(&idio16gpio->reg->out0_7) & mask); 8902e74fc0SWilliam Breathitt Gray 9002e74fc0SWilliam Breathitt Gray if (offset < 16) 9102e74fc0SWilliam Breathitt Gray return !!(ioread8(&idio16gpio->reg->out8_15) & (mask >> 8)); 9202e74fc0SWilliam Breathitt Gray 9302e74fc0SWilliam Breathitt Gray if (offset < 24) 9402e74fc0SWilliam Breathitt Gray return !!(ioread8(&idio16gpio->reg->in0_7) & (mask >> 16)); 9502e74fc0SWilliam Breathitt Gray 9602e74fc0SWilliam Breathitt Gray return !!(ioread8(&idio16gpio->reg->in8_15) & (mask >> 24)); 9702e74fc0SWilliam Breathitt Gray } 9802e74fc0SWilliam Breathitt Gray 99810ebfc5SWilliam Breathitt Gray static int idio_16_gpio_get_multiple(struct gpio_chip *chip, 100810ebfc5SWilliam Breathitt Gray unsigned long *mask, unsigned long *bits) 101810ebfc5SWilliam Breathitt Gray { 102810ebfc5SWilliam Breathitt Gray struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip); 103810ebfc5SWilliam Breathitt Gray size_t i; 104810ebfc5SWilliam Breathitt Gray const unsigned int gpio_reg_size = 8; 105810ebfc5SWilliam Breathitt Gray unsigned int bits_offset; 106810ebfc5SWilliam Breathitt Gray size_t word_index; 107810ebfc5SWilliam Breathitt Gray unsigned int word_offset; 108810ebfc5SWilliam Breathitt Gray unsigned long word_mask; 109810ebfc5SWilliam Breathitt Gray const unsigned long port_mask = GENMASK(gpio_reg_size - 1, 0); 110810ebfc5SWilliam Breathitt Gray unsigned long port_state; 111aaf96e51SWilliam Breathitt Gray void __iomem *ports[] = { 112aaf96e51SWilliam Breathitt Gray &idio16gpio->reg->out0_7, &idio16gpio->reg->out8_15, 113aaf96e51SWilliam Breathitt Gray &idio16gpio->reg->in0_7, &idio16gpio->reg->in8_15, 114810ebfc5SWilliam Breathitt Gray }; 115810ebfc5SWilliam Breathitt Gray 116810ebfc5SWilliam Breathitt Gray /* clear bits array to a clean slate */ 117810ebfc5SWilliam Breathitt Gray bitmap_zero(bits, chip->ngpio); 118810ebfc5SWilliam Breathitt Gray 119810ebfc5SWilliam Breathitt Gray /* get bits are evaluated a gpio port register at a time */ 120810ebfc5SWilliam Breathitt Gray for (i = 0; i < ARRAY_SIZE(ports); i++) { 121810ebfc5SWilliam Breathitt Gray /* gpio offset in bits array */ 122810ebfc5SWilliam Breathitt Gray bits_offset = i * gpio_reg_size; 123810ebfc5SWilliam Breathitt Gray 124810ebfc5SWilliam Breathitt Gray /* word index for bits array */ 125810ebfc5SWilliam Breathitt Gray word_index = BIT_WORD(bits_offset); 126810ebfc5SWilliam Breathitt Gray 127810ebfc5SWilliam Breathitt Gray /* gpio offset within current word of bits array */ 128810ebfc5SWilliam Breathitt Gray word_offset = bits_offset % BITS_PER_LONG; 129810ebfc5SWilliam Breathitt Gray 130810ebfc5SWilliam Breathitt Gray /* mask of get bits for current gpio within current word */ 131810ebfc5SWilliam Breathitt Gray word_mask = mask[word_index] & (port_mask << word_offset); 132810ebfc5SWilliam Breathitt Gray if (!word_mask) { 133810ebfc5SWilliam Breathitt Gray /* no get bits in this port so skip to next one */ 134810ebfc5SWilliam Breathitt Gray continue; 135810ebfc5SWilliam Breathitt Gray } 136810ebfc5SWilliam Breathitt Gray 137810ebfc5SWilliam Breathitt Gray /* read bits from current gpio port */ 138aaf96e51SWilliam Breathitt Gray port_state = ioread8(ports[i]); 139810ebfc5SWilliam Breathitt Gray 140810ebfc5SWilliam Breathitt Gray /* store acquired bits at respective bits array offset */ 141f837bf6aSWilliam Breathitt Gray bits[word_index] |= (port_state << word_offset) & word_mask; 142810ebfc5SWilliam Breathitt Gray } 143810ebfc5SWilliam Breathitt Gray 144810ebfc5SWilliam Breathitt Gray return 0; 145810ebfc5SWilliam Breathitt Gray } 146810ebfc5SWilliam Breathitt Gray 14702e74fc0SWilliam Breathitt Gray static void idio_16_gpio_set(struct gpio_chip *chip, unsigned int offset, 14802e74fc0SWilliam Breathitt Gray int value) 14902e74fc0SWilliam Breathitt Gray { 15002e74fc0SWilliam Breathitt Gray struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip); 15102e74fc0SWilliam Breathitt Gray unsigned int mask = BIT(offset); 15202e74fc0SWilliam Breathitt Gray void __iomem *base; 15302e74fc0SWilliam Breathitt Gray unsigned long flags; 15402e74fc0SWilliam Breathitt Gray unsigned int out_state; 15502e74fc0SWilliam Breathitt Gray 15602e74fc0SWilliam Breathitt Gray if (offset > 15) 15702e74fc0SWilliam Breathitt Gray return; 15802e74fc0SWilliam Breathitt Gray 15902e74fc0SWilliam Breathitt Gray if (offset > 7) { 16002e74fc0SWilliam Breathitt Gray mask >>= 8; 16102e74fc0SWilliam Breathitt Gray base = &idio16gpio->reg->out8_15; 16202e74fc0SWilliam Breathitt Gray } else 16302e74fc0SWilliam Breathitt Gray base = &idio16gpio->reg->out0_7; 16402e74fc0SWilliam Breathitt Gray 165ea38ce08SJulia Cartwright raw_spin_lock_irqsave(&idio16gpio->lock, flags); 16602e74fc0SWilliam Breathitt Gray 16702e74fc0SWilliam Breathitt Gray if (value) 16802e74fc0SWilliam Breathitt Gray out_state = ioread8(base) | mask; 16902e74fc0SWilliam Breathitt Gray else 17002e74fc0SWilliam Breathitt Gray out_state = ioread8(base) & ~mask; 17102e74fc0SWilliam Breathitt Gray 17202e74fc0SWilliam Breathitt Gray iowrite8(out_state, base); 17302e74fc0SWilliam Breathitt Gray 174ea38ce08SJulia Cartwright raw_spin_unlock_irqrestore(&idio16gpio->lock, flags); 17502e74fc0SWilliam Breathitt Gray } 17602e74fc0SWilliam Breathitt Gray 17702e74fc0SWilliam Breathitt Gray static void idio_16_gpio_set_multiple(struct gpio_chip *chip, 17802e74fc0SWilliam Breathitt Gray unsigned long *mask, unsigned long *bits) 17902e74fc0SWilliam Breathitt Gray { 18002e74fc0SWilliam Breathitt Gray struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip); 18102e74fc0SWilliam Breathitt Gray unsigned long flags; 18202e74fc0SWilliam Breathitt Gray unsigned int out_state; 18302e74fc0SWilliam Breathitt Gray 184ea38ce08SJulia Cartwright raw_spin_lock_irqsave(&idio16gpio->lock, flags); 18502e74fc0SWilliam Breathitt Gray 18602e74fc0SWilliam Breathitt Gray /* process output lines 0-7 */ 18702e74fc0SWilliam Breathitt Gray if (*mask & 0xFF) { 18802e74fc0SWilliam Breathitt Gray out_state = ioread8(&idio16gpio->reg->out0_7) & ~*mask; 18902e74fc0SWilliam Breathitt Gray out_state |= *mask & *bits; 19002e74fc0SWilliam Breathitt Gray iowrite8(out_state, &idio16gpio->reg->out0_7); 19102e74fc0SWilliam Breathitt Gray } 19202e74fc0SWilliam Breathitt Gray 19302e74fc0SWilliam Breathitt Gray /* shift to next output line word */ 19402e74fc0SWilliam Breathitt Gray *mask >>= 8; 19502e74fc0SWilliam Breathitt Gray 19602e74fc0SWilliam Breathitt Gray /* process output lines 8-15 */ 19702e74fc0SWilliam Breathitt Gray if (*mask & 0xFF) { 19802e74fc0SWilliam Breathitt Gray *bits >>= 8; 19902e74fc0SWilliam Breathitt Gray out_state = ioread8(&idio16gpio->reg->out8_15) & ~*mask; 20002e74fc0SWilliam Breathitt Gray out_state |= *mask & *bits; 20102e74fc0SWilliam Breathitt Gray iowrite8(out_state, &idio16gpio->reg->out8_15); 20202e74fc0SWilliam Breathitt Gray } 20302e74fc0SWilliam Breathitt Gray 204ea38ce08SJulia Cartwright raw_spin_unlock_irqrestore(&idio16gpio->lock, flags); 20502e74fc0SWilliam Breathitt Gray } 20602e74fc0SWilliam Breathitt Gray 20702e74fc0SWilliam Breathitt Gray static void idio_16_irq_ack(struct irq_data *data) 20802e74fc0SWilliam Breathitt Gray { 20902e74fc0SWilliam Breathitt Gray } 21002e74fc0SWilliam Breathitt Gray 21102e74fc0SWilliam Breathitt Gray static void idio_16_irq_mask(struct irq_data *data) 21202e74fc0SWilliam Breathitt Gray { 21302e74fc0SWilliam Breathitt Gray struct gpio_chip *chip = irq_data_get_irq_chip_data(data); 21402e74fc0SWilliam Breathitt Gray struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip); 21502e74fc0SWilliam Breathitt Gray const unsigned long mask = BIT(irqd_to_hwirq(data)); 21602e74fc0SWilliam Breathitt Gray unsigned long flags; 21702e74fc0SWilliam Breathitt Gray 21802e74fc0SWilliam Breathitt Gray idio16gpio->irq_mask &= ~mask; 21902e74fc0SWilliam Breathitt Gray 22002e74fc0SWilliam Breathitt Gray if (!idio16gpio->irq_mask) { 221ea38ce08SJulia Cartwright raw_spin_lock_irqsave(&idio16gpio->lock, flags); 22202e74fc0SWilliam Breathitt Gray 22302e74fc0SWilliam Breathitt Gray iowrite8(0, &idio16gpio->reg->irq_ctl); 22402e74fc0SWilliam Breathitt Gray 225ea38ce08SJulia Cartwright raw_spin_unlock_irqrestore(&idio16gpio->lock, flags); 22602e74fc0SWilliam Breathitt Gray } 22702e74fc0SWilliam Breathitt Gray } 22802e74fc0SWilliam Breathitt Gray 22902e74fc0SWilliam Breathitt Gray static void idio_16_irq_unmask(struct irq_data *data) 23002e74fc0SWilliam Breathitt Gray { 23102e74fc0SWilliam Breathitt Gray struct gpio_chip *chip = irq_data_get_irq_chip_data(data); 23202e74fc0SWilliam Breathitt Gray struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip); 23302e74fc0SWilliam Breathitt Gray const unsigned long mask = BIT(irqd_to_hwirq(data)); 23402e74fc0SWilliam Breathitt Gray const unsigned long prev_irq_mask = idio16gpio->irq_mask; 23502e74fc0SWilliam Breathitt Gray unsigned long flags; 23602e74fc0SWilliam Breathitt Gray 23702e74fc0SWilliam Breathitt Gray idio16gpio->irq_mask |= mask; 23802e74fc0SWilliam Breathitt Gray 23902e74fc0SWilliam Breathitt Gray if (!prev_irq_mask) { 240ea38ce08SJulia Cartwright raw_spin_lock_irqsave(&idio16gpio->lock, flags); 24102e74fc0SWilliam Breathitt Gray 24202e74fc0SWilliam Breathitt Gray ioread8(&idio16gpio->reg->irq_ctl); 24302e74fc0SWilliam Breathitt Gray 244ea38ce08SJulia Cartwright raw_spin_unlock_irqrestore(&idio16gpio->lock, flags); 24502e74fc0SWilliam Breathitt Gray } 24602e74fc0SWilliam Breathitt Gray } 24702e74fc0SWilliam Breathitt Gray 24802e74fc0SWilliam Breathitt Gray static int idio_16_irq_set_type(struct irq_data *data, unsigned int flow_type) 24902e74fc0SWilliam Breathitt Gray { 25002e74fc0SWilliam Breathitt Gray /* The only valid irq types are none and both-edges */ 25102e74fc0SWilliam Breathitt Gray if (flow_type != IRQ_TYPE_NONE && 25202e74fc0SWilliam Breathitt Gray (flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH) 25302e74fc0SWilliam Breathitt Gray return -EINVAL; 25402e74fc0SWilliam Breathitt Gray 25502e74fc0SWilliam Breathitt Gray return 0; 25602e74fc0SWilliam Breathitt Gray } 25702e74fc0SWilliam Breathitt Gray 25802e74fc0SWilliam Breathitt Gray static struct irq_chip idio_16_irqchip = { 25902e74fc0SWilliam Breathitt Gray .name = "pci-idio-16", 26002e74fc0SWilliam Breathitt Gray .irq_ack = idio_16_irq_ack, 26102e74fc0SWilliam Breathitt Gray .irq_mask = idio_16_irq_mask, 26202e74fc0SWilliam Breathitt Gray .irq_unmask = idio_16_irq_unmask, 26302e74fc0SWilliam Breathitt Gray .irq_set_type = idio_16_irq_set_type 26402e74fc0SWilliam Breathitt Gray }; 26502e74fc0SWilliam Breathitt Gray 26602e74fc0SWilliam Breathitt Gray static irqreturn_t idio_16_irq_handler(int irq, void *dev_id) 26702e74fc0SWilliam Breathitt Gray { 26802e74fc0SWilliam Breathitt Gray struct idio_16_gpio *const idio16gpio = dev_id; 26902e74fc0SWilliam Breathitt Gray unsigned int irq_status; 27002e74fc0SWilliam Breathitt Gray struct gpio_chip *const chip = &idio16gpio->chip; 27102e74fc0SWilliam Breathitt Gray int gpio; 27202e74fc0SWilliam Breathitt Gray 273ea38ce08SJulia Cartwright raw_spin_lock(&idio16gpio->lock); 27402e74fc0SWilliam Breathitt Gray 27502e74fc0SWilliam Breathitt Gray irq_status = ioread8(&idio16gpio->reg->irq_status); 27602e74fc0SWilliam Breathitt Gray 277ea38ce08SJulia Cartwright raw_spin_unlock(&idio16gpio->lock); 27802e74fc0SWilliam Breathitt Gray 27902e74fc0SWilliam Breathitt Gray /* Make sure our device generated IRQ */ 28002e74fc0SWilliam Breathitt Gray if (!(irq_status & 0x3) || !(irq_status & 0x4)) 28102e74fc0SWilliam Breathitt Gray return IRQ_NONE; 28202e74fc0SWilliam Breathitt Gray 28302e74fc0SWilliam Breathitt Gray for_each_set_bit(gpio, &idio16gpio->irq_mask, chip->ngpio) 284f0fbe7bcSThierry Reding generic_handle_irq(irq_find_mapping(chip->irq.domain, gpio)); 28502e74fc0SWilliam Breathitt Gray 286ea38ce08SJulia Cartwright raw_spin_lock(&idio16gpio->lock); 28702e74fc0SWilliam Breathitt Gray 28802e74fc0SWilliam Breathitt Gray /* Clear interrupt */ 28902e74fc0SWilliam Breathitt Gray iowrite8(0, &idio16gpio->reg->in0_7); 29002e74fc0SWilliam Breathitt Gray 291ea38ce08SJulia Cartwright raw_spin_unlock(&idio16gpio->lock); 29202e74fc0SWilliam Breathitt Gray 29302e74fc0SWilliam Breathitt Gray return IRQ_HANDLED; 29402e74fc0SWilliam Breathitt Gray } 29502e74fc0SWilliam Breathitt Gray 29602e74fc0SWilliam Breathitt Gray #define IDIO_16_NGPIO 32 29702e74fc0SWilliam Breathitt Gray static const char *idio_16_names[IDIO_16_NGPIO] = { 29802e74fc0SWilliam Breathitt Gray "OUT0", "OUT1", "OUT2", "OUT3", "OUT4", "OUT5", "OUT6", "OUT7", 29902e74fc0SWilliam Breathitt Gray "OUT8", "OUT9", "OUT10", "OUT11", "OUT12", "OUT13", "OUT14", "OUT15", 30002e74fc0SWilliam Breathitt Gray "IIN0", "IIN1", "IIN2", "IIN3", "IIN4", "IIN5", "IIN6", "IIN7", 30102e74fc0SWilliam Breathitt Gray "IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15" 30202e74fc0SWilliam Breathitt Gray }; 30302e74fc0SWilliam Breathitt Gray 30402e74fc0SWilliam Breathitt Gray static int idio_16_probe(struct pci_dev *pdev, const struct pci_device_id *id) 30502e74fc0SWilliam Breathitt Gray { 30602e74fc0SWilliam Breathitt Gray struct device *const dev = &pdev->dev; 30702e74fc0SWilliam Breathitt Gray struct idio_16_gpio *idio16gpio; 30802e74fc0SWilliam Breathitt Gray int err; 309deab2b05SWilliam Breathitt Gray const size_t pci_bar_index = 2; 31002e74fc0SWilliam Breathitt Gray const char *const name = pci_name(pdev); 31102e74fc0SWilliam Breathitt Gray 31202e74fc0SWilliam Breathitt Gray idio16gpio = devm_kzalloc(dev, sizeof(*idio16gpio), GFP_KERNEL); 31302e74fc0SWilliam Breathitt Gray if (!idio16gpio) 31402e74fc0SWilliam Breathitt Gray return -ENOMEM; 31502e74fc0SWilliam Breathitt Gray 31602e74fc0SWilliam Breathitt Gray err = pcim_enable_device(pdev); 31702e74fc0SWilliam Breathitt Gray if (err) { 31802e74fc0SWilliam Breathitt Gray dev_err(dev, "Failed to enable PCI device (%d)\n", err); 31902e74fc0SWilliam Breathitt Gray return err; 32002e74fc0SWilliam Breathitt Gray } 32102e74fc0SWilliam Breathitt Gray 322deab2b05SWilliam Breathitt Gray err = pcim_iomap_regions(pdev, BIT(pci_bar_index), name); 32302e74fc0SWilliam Breathitt Gray if (err) { 32402e74fc0SWilliam Breathitt Gray dev_err(dev, "Unable to map PCI I/O addresses (%d)\n", err); 32502e74fc0SWilliam Breathitt Gray return err; 32602e74fc0SWilliam Breathitt Gray } 32702e74fc0SWilliam Breathitt Gray 328deab2b05SWilliam Breathitt Gray idio16gpio->reg = pcim_iomap_table(pdev)[pci_bar_index]; 32902e74fc0SWilliam Breathitt Gray 33002e74fc0SWilliam Breathitt Gray /* Deactivate input filters */ 33102e74fc0SWilliam Breathitt Gray iowrite8(0, &idio16gpio->reg->filter_ctl); 33202e74fc0SWilliam Breathitt Gray 33302e74fc0SWilliam Breathitt Gray idio16gpio->chip.label = name; 33402e74fc0SWilliam Breathitt Gray idio16gpio->chip.parent = dev; 33502e74fc0SWilliam Breathitt Gray idio16gpio->chip.owner = THIS_MODULE; 33602e74fc0SWilliam Breathitt Gray idio16gpio->chip.base = -1; 33702e74fc0SWilliam Breathitt Gray idio16gpio->chip.ngpio = IDIO_16_NGPIO; 33802e74fc0SWilliam Breathitt Gray idio16gpio->chip.names = idio_16_names; 33902e74fc0SWilliam Breathitt Gray idio16gpio->chip.get_direction = idio_16_gpio_get_direction; 34002e74fc0SWilliam Breathitt Gray idio16gpio->chip.direction_input = idio_16_gpio_direction_input; 34102e74fc0SWilliam Breathitt Gray idio16gpio->chip.direction_output = idio_16_gpio_direction_output; 34202e74fc0SWilliam Breathitt Gray idio16gpio->chip.get = idio_16_gpio_get; 343810ebfc5SWilliam Breathitt Gray idio16gpio->chip.get_multiple = idio_16_gpio_get_multiple; 34402e74fc0SWilliam Breathitt Gray idio16gpio->chip.set = idio_16_gpio_set; 34502e74fc0SWilliam Breathitt Gray idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple; 34602e74fc0SWilliam Breathitt Gray 347ea38ce08SJulia Cartwright raw_spin_lock_init(&idio16gpio->lock); 34802e74fc0SWilliam Breathitt Gray 34902e74fc0SWilliam Breathitt Gray err = devm_gpiochip_add_data(dev, &idio16gpio->chip, idio16gpio); 35002e74fc0SWilliam Breathitt Gray if (err) { 35102e74fc0SWilliam Breathitt Gray dev_err(dev, "GPIO registering failed (%d)\n", err); 35202e74fc0SWilliam Breathitt Gray return err; 35302e74fc0SWilliam Breathitt Gray } 35402e74fc0SWilliam Breathitt Gray 35502e74fc0SWilliam Breathitt Gray /* Disable IRQ by default and clear any pending interrupt */ 35602e74fc0SWilliam Breathitt Gray iowrite8(0, &idio16gpio->reg->irq_ctl); 35702e74fc0SWilliam Breathitt Gray iowrite8(0, &idio16gpio->reg->in0_7); 35802e74fc0SWilliam Breathitt Gray 35902e74fc0SWilliam Breathitt Gray err = gpiochip_irqchip_add(&idio16gpio->chip, &idio_16_irqchip, 0, 36002e74fc0SWilliam Breathitt Gray handle_edge_irq, IRQ_TYPE_NONE); 36102e74fc0SWilliam Breathitt Gray if (err) { 36202e74fc0SWilliam Breathitt Gray dev_err(dev, "Could not add irqchip (%d)\n", err); 36302e74fc0SWilliam Breathitt Gray return err; 36402e74fc0SWilliam Breathitt Gray } 36502e74fc0SWilliam Breathitt Gray 36602e74fc0SWilliam Breathitt Gray err = devm_request_irq(dev, pdev->irq, idio_16_irq_handler, IRQF_SHARED, 36702e74fc0SWilliam Breathitt Gray name, idio16gpio); 36802e74fc0SWilliam Breathitt Gray if (err) { 36902e74fc0SWilliam Breathitt Gray dev_err(dev, "IRQ handler registering failed (%d)\n", err); 37002e74fc0SWilliam Breathitt Gray return err; 37102e74fc0SWilliam Breathitt Gray } 37202e74fc0SWilliam Breathitt Gray 37302e74fc0SWilliam Breathitt Gray return 0; 37402e74fc0SWilliam Breathitt Gray } 37502e74fc0SWilliam Breathitt Gray 37602e74fc0SWilliam Breathitt Gray static const struct pci_device_id idio_16_pci_dev_id[] = { 377fd254a23SWilliam Breathitt Gray { PCI_DEVICE(0x494F, 0x0DC8) }, { 0 } 37802e74fc0SWilliam Breathitt Gray }; 37902e74fc0SWilliam Breathitt Gray MODULE_DEVICE_TABLE(pci, idio_16_pci_dev_id); 38002e74fc0SWilliam Breathitt Gray 38102e74fc0SWilliam Breathitt Gray static struct pci_driver idio_16_driver = { 38202e74fc0SWilliam Breathitt Gray .name = "pci-idio-16", 38302e74fc0SWilliam Breathitt Gray .id_table = idio_16_pci_dev_id, 38402e74fc0SWilliam Breathitt Gray .probe = idio_16_probe 38502e74fc0SWilliam Breathitt Gray }; 38602e74fc0SWilliam Breathitt Gray 38702e74fc0SWilliam Breathitt Gray module_pci_driver(idio_16_driver); 38802e74fc0SWilliam Breathitt Gray 38902e74fc0SWilliam Breathitt Gray MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>"); 39002e74fc0SWilliam Breathitt Gray MODULE_DESCRIPTION("ACCES PCI-IDIO-16 GPIO driver"); 39102e74fc0SWilliam Breathitt Gray MODULE_LICENSE("GPL v2"); 392