102e74fc0SWilliam Breathitt Gray /* 202e74fc0SWilliam Breathitt Gray * GPIO driver for the ACCES PCI-IDIO-16 302e74fc0SWilliam Breathitt Gray * Copyright (C) 2017 William Breathitt Gray 402e74fc0SWilliam Breathitt Gray * 502e74fc0SWilliam Breathitt Gray * This program is free software; you can redistribute it and/or modify 602e74fc0SWilliam Breathitt Gray * it under the terms of the GNU General Public License, version 2, as 702e74fc0SWilliam Breathitt Gray * published by the Free Software Foundation. 802e74fc0SWilliam Breathitt Gray * 902e74fc0SWilliam Breathitt Gray * This program is distributed in the hope that it will be useful, but 1002e74fc0SWilliam Breathitt Gray * WITHOUT ANY WARRANTY; without even the implied warranty of 1102e74fc0SWilliam Breathitt Gray * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1202e74fc0SWilliam Breathitt Gray * General Public License for more details. 1302e74fc0SWilliam Breathitt Gray */ 1402e74fc0SWilliam Breathitt Gray #include <linux/bitops.h> 1502e74fc0SWilliam Breathitt Gray #include <linux/device.h> 1602e74fc0SWilliam Breathitt Gray #include <linux/errno.h> 1702e74fc0SWilliam Breathitt Gray #include <linux/gpio/driver.h> 1802e74fc0SWilliam Breathitt Gray #include <linux/interrupt.h> 1902e74fc0SWilliam Breathitt Gray #include <linux/irqdesc.h> 2002e74fc0SWilliam Breathitt Gray #include <linux/kernel.h> 2102e74fc0SWilliam Breathitt Gray #include <linux/module.h> 2202e74fc0SWilliam Breathitt Gray #include <linux/pci.h> 2302e74fc0SWilliam Breathitt Gray #include <linux/spinlock.h> 2402e74fc0SWilliam Breathitt Gray #include <linux/types.h> 2502e74fc0SWilliam Breathitt Gray 2602e74fc0SWilliam Breathitt Gray /** 2702e74fc0SWilliam Breathitt Gray * struct idio_16_gpio_reg - GPIO device registers structure 2802e74fc0SWilliam Breathitt Gray * @out0_7: Read: FET Drive Outputs 0-7 2902e74fc0SWilliam Breathitt Gray * Write: FET Drive Outputs 0-7 3002e74fc0SWilliam Breathitt Gray * @in0_7: Read: Isolated Inputs 0-7 3102e74fc0SWilliam Breathitt Gray * Write: Clear Interrupt 3202e74fc0SWilliam Breathitt Gray * @irq_ctl: Read: Enable IRQ 3302e74fc0SWilliam Breathitt Gray * Write: Disable IRQ 3402e74fc0SWilliam Breathitt Gray * @filter_ctl: Read: Activate Input Filters 0-15 3502e74fc0SWilliam Breathitt Gray * Write: Deactivate Input Filters 0-15 3602e74fc0SWilliam Breathitt Gray * @out8_15: Read: FET Drive Outputs 8-15 3702e74fc0SWilliam Breathitt Gray * Write: FET Drive Outputs 8-15 3802e74fc0SWilliam Breathitt Gray * @in8_15: Read: Isolated Inputs 8-15 3902e74fc0SWilliam Breathitt Gray * Write: Unused 4002e74fc0SWilliam Breathitt Gray * @irq_status: Read: Interrupt status 4102e74fc0SWilliam Breathitt Gray * Write: Unused 4202e74fc0SWilliam Breathitt Gray */ 4302e74fc0SWilliam Breathitt Gray struct idio_16_gpio_reg { 4402e74fc0SWilliam Breathitt Gray u8 out0_7; 4502e74fc0SWilliam Breathitt Gray u8 in0_7; 4602e74fc0SWilliam Breathitt Gray u8 irq_ctl; 4702e74fc0SWilliam Breathitt Gray u8 filter_ctl; 4802e74fc0SWilliam Breathitt Gray u8 out8_15; 4902e74fc0SWilliam Breathitt Gray u8 in8_15; 5002e74fc0SWilliam Breathitt Gray u8 irq_status; 5102e74fc0SWilliam Breathitt Gray }; 5202e74fc0SWilliam Breathitt Gray 5302e74fc0SWilliam Breathitt Gray /** 5402e74fc0SWilliam Breathitt Gray * struct idio_16_gpio - GPIO device private data structure 5502e74fc0SWilliam Breathitt Gray * @chip: instance of the gpio_chip 5602e74fc0SWilliam Breathitt Gray * @lock: synchronization lock to prevent I/O race conditions 5702e74fc0SWilliam Breathitt Gray * @reg: I/O address offset for the GPIO device registers 5802e74fc0SWilliam Breathitt Gray * @irq_mask: I/O bits affected by interrupts 5902e74fc0SWilliam Breathitt Gray */ 6002e74fc0SWilliam Breathitt Gray struct idio_16_gpio { 6102e74fc0SWilliam Breathitt Gray struct gpio_chip chip; 6202e74fc0SWilliam Breathitt Gray spinlock_t lock; 6302e74fc0SWilliam Breathitt Gray struct idio_16_gpio_reg __iomem *reg; 6402e74fc0SWilliam Breathitt Gray unsigned long irq_mask; 6502e74fc0SWilliam Breathitt Gray }; 6602e74fc0SWilliam Breathitt Gray 6702e74fc0SWilliam Breathitt Gray static int idio_16_gpio_get_direction(struct gpio_chip *chip, 6802e74fc0SWilliam Breathitt Gray unsigned int offset) 6902e74fc0SWilliam Breathitt Gray { 7002e74fc0SWilliam Breathitt Gray if (offset > 15) 7102e74fc0SWilliam Breathitt Gray return 1; 7202e74fc0SWilliam Breathitt Gray 7302e74fc0SWilliam Breathitt Gray return 0; 7402e74fc0SWilliam Breathitt Gray } 7502e74fc0SWilliam Breathitt Gray 7602e74fc0SWilliam Breathitt Gray static int idio_16_gpio_direction_input(struct gpio_chip *chip, 7702e74fc0SWilliam Breathitt Gray unsigned int offset) 7802e74fc0SWilliam Breathitt Gray { 7902e74fc0SWilliam Breathitt Gray return 0; 8002e74fc0SWilliam Breathitt Gray } 8102e74fc0SWilliam Breathitt Gray 8202e74fc0SWilliam Breathitt Gray static int idio_16_gpio_direction_output(struct gpio_chip *chip, 8302e74fc0SWilliam Breathitt Gray unsigned int offset, int value) 8402e74fc0SWilliam Breathitt Gray { 8502e74fc0SWilliam Breathitt Gray chip->set(chip, offset, value); 8602e74fc0SWilliam Breathitt Gray return 0; 8702e74fc0SWilliam Breathitt Gray } 8802e74fc0SWilliam Breathitt Gray 8902e74fc0SWilliam Breathitt Gray static int idio_16_gpio_get(struct gpio_chip *chip, unsigned int offset) 9002e74fc0SWilliam Breathitt Gray { 9102e74fc0SWilliam Breathitt Gray struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip); 9202e74fc0SWilliam Breathitt Gray unsigned long mask = BIT(offset); 9302e74fc0SWilliam Breathitt Gray 9402e74fc0SWilliam Breathitt Gray if (offset < 8) 9502e74fc0SWilliam Breathitt Gray return !!(ioread8(&idio16gpio->reg->out0_7) & mask); 9602e74fc0SWilliam Breathitt Gray 9702e74fc0SWilliam Breathitt Gray if (offset < 16) 9802e74fc0SWilliam Breathitt Gray return !!(ioread8(&idio16gpio->reg->out8_15) & (mask >> 8)); 9902e74fc0SWilliam Breathitt Gray 10002e74fc0SWilliam Breathitt Gray if (offset < 24) 10102e74fc0SWilliam Breathitt Gray return !!(ioread8(&idio16gpio->reg->in0_7) & (mask >> 16)); 10202e74fc0SWilliam Breathitt Gray 10302e74fc0SWilliam Breathitt Gray return !!(ioread8(&idio16gpio->reg->in8_15) & (mask >> 24)); 10402e74fc0SWilliam Breathitt Gray } 10502e74fc0SWilliam Breathitt Gray 10602e74fc0SWilliam Breathitt Gray static void idio_16_gpio_set(struct gpio_chip *chip, unsigned int offset, 10702e74fc0SWilliam Breathitt Gray int value) 10802e74fc0SWilliam Breathitt Gray { 10902e74fc0SWilliam Breathitt Gray struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip); 11002e74fc0SWilliam Breathitt Gray unsigned int mask = BIT(offset); 11102e74fc0SWilliam Breathitt Gray void __iomem *base; 11202e74fc0SWilliam Breathitt Gray unsigned long flags; 11302e74fc0SWilliam Breathitt Gray unsigned int out_state; 11402e74fc0SWilliam Breathitt Gray 11502e74fc0SWilliam Breathitt Gray if (offset > 15) 11602e74fc0SWilliam Breathitt Gray return; 11702e74fc0SWilliam Breathitt Gray 11802e74fc0SWilliam Breathitt Gray if (offset > 7) { 11902e74fc0SWilliam Breathitt Gray mask >>= 8; 12002e74fc0SWilliam Breathitt Gray base = &idio16gpio->reg->out8_15; 12102e74fc0SWilliam Breathitt Gray } else 12202e74fc0SWilliam Breathitt Gray base = &idio16gpio->reg->out0_7; 12302e74fc0SWilliam Breathitt Gray 12402e74fc0SWilliam Breathitt Gray spin_lock_irqsave(&idio16gpio->lock, flags); 12502e74fc0SWilliam Breathitt Gray 12602e74fc0SWilliam Breathitt Gray if (value) 12702e74fc0SWilliam Breathitt Gray out_state = ioread8(base) | mask; 12802e74fc0SWilliam Breathitt Gray else 12902e74fc0SWilliam Breathitt Gray out_state = ioread8(base) & ~mask; 13002e74fc0SWilliam Breathitt Gray 13102e74fc0SWilliam Breathitt Gray iowrite8(out_state, base); 13202e74fc0SWilliam Breathitt Gray 13302e74fc0SWilliam Breathitt Gray spin_unlock_irqrestore(&idio16gpio->lock, flags); 13402e74fc0SWilliam Breathitt Gray } 13502e74fc0SWilliam Breathitt Gray 13602e74fc0SWilliam Breathitt Gray static void idio_16_gpio_set_multiple(struct gpio_chip *chip, 13702e74fc0SWilliam Breathitt Gray unsigned long *mask, unsigned long *bits) 13802e74fc0SWilliam Breathitt Gray { 13902e74fc0SWilliam Breathitt Gray struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip); 14002e74fc0SWilliam Breathitt Gray unsigned long flags; 14102e74fc0SWilliam Breathitt Gray unsigned int out_state; 14202e74fc0SWilliam Breathitt Gray 14302e74fc0SWilliam Breathitt Gray spin_lock_irqsave(&idio16gpio->lock, flags); 14402e74fc0SWilliam Breathitt Gray 14502e74fc0SWilliam Breathitt Gray /* process output lines 0-7 */ 14602e74fc0SWilliam Breathitt Gray if (*mask & 0xFF) { 14702e74fc0SWilliam Breathitt Gray out_state = ioread8(&idio16gpio->reg->out0_7) & ~*mask; 14802e74fc0SWilliam Breathitt Gray out_state |= *mask & *bits; 14902e74fc0SWilliam Breathitt Gray iowrite8(out_state, &idio16gpio->reg->out0_7); 15002e74fc0SWilliam Breathitt Gray } 15102e74fc0SWilliam Breathitt Gray 15202e74fc0SWilliam Breathitt Gray /* shift to next output line word */ 15302e74fc0SWilliam Breathitt Gray *mask >>= 8; 15402e74fc0SWilliam Breathitt Gray 15502e74fc0SWilliam Breathitt Gray /* process output lines 8-15 */ 15602e74fc0SWilliam Breathitt Gray if (*mask & 0xFF) { 15702e74fc0SWilliam Breathitt Gray *bits >>= 8; 15802e74fc0SWilliam Breathitt Gray out_state = ioread8(&idio16gpio->reg->out8_15) & ~*mask; 15902e74fc0SWilliam Breathitt Gray out_state |= *mask & *bits; 16002e74fc0SWilliam Breathitt Gray iowrite8(out_state, &idio16gpio->reg->out8_15); 16102e74fc0SWilliam Breathitt Gray } 16202e74fc0SWilliam Breathitt Gray 16302e74fc0SWilliam Breathitt Gray spin_unlock_irqrestore(&idio16gpio->lock, flags); 16402e74fc0SWilliam Breathitt Gray } 16502e74fc0SWilliam Breathitt Gray 16602e74fc0SWilliam Breathitt Gray static void idio_16_irq_ack(struct irq_data *data) 16702e74fc0SWilliam Breathitt Gray { 16802e74fc0SWilliam Breathitt Gray } 16902e74fc0SWilliam Breathitt Gray 17002e74fc0SWilliam Breathitt Gray static void idio_16_irq_mask(struct irq_data *data) 17102e74fc0SWilliam Breathitt Gray { 17202e74fc0SWilliam Breathitt Gray struct gpio_chip *chip = irq_data_get_irq_chip_data(data); 17302e74fc0SWilliam Breathitt Gray struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip); 17402e74fc0SWilliam Breathitt Gray const unsigned long mask = BIT(irqd_to_hwirq(data)); 17502e74fc0SWilliam Breathitt Gray unsigned long flags; 17602e74fc0SWilliam Breathitt Gray 17702e74fc0SWilliam Breathitt Gray idio16gpio->irq_mask &= ~mask; 17802e74fc0SWilliam Breathitt Gray 17902e74fc0SWilliam Breathitt Gray if (!idio16gpio->irq_mask) { 18002e74fc0SWilliam Breathitt Gray spin_lock_irqsave(&idio16gpio->lock, flags); 18102e74fc0SWilliam Breathitt Gray 18202e74fc0SWilliam Breathitt Gray iowrite8(0, &idio16gpio->reg->irq_ctl); 18302e74fc0SWilliam Breathitt Gray 18402e74fc0SWilliam Breathitt Gray spin_unlock_irqrestore(&idio16gpio->lock, flags); 18502e74fc0SWilliam Breathitt Gray } 18602e74fc0SWilliam Breathitt Gray } 18702e74fc0SWilliam Breathitt Gray 18802e74fc0SWilliam Breathitt Gray static void idio_16_irq_unmask(struct irq_data *data) 18902e74fc0SWilliam Breathitt Gray { 19002e74fc0SWilliam Breathitt Gray struct gpio_chip *chip = irq_data_get_irq_chip_data(data); 19102e74fc0SWilliam Breathitt Gray struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip); 19202e74fc0SWilliam Breathitt Gray const unsigned long mask = BIT(irqd_to_hwirq(data)); 19302e74fc0SWilliam Breathitt Gray const unsigned long prev_irq_mask = idio16gpio->irq_mask; 19402e74fc0SWilliam Breathitt Gray unsigned long flags; 19502e74fc0SWilliam Breathitt Gray 19602e74fc0SWilliam Breathitt Gray idio16gpio->irq_mask |= mask; 19702e74fc0SWilliam Breathitt Gray 19802e74fc0SWilliam Breathitt Gray if (!prev_irq_mask) { 19902e74fc0SWilliam Breathitt Gray spin_lock_irqsave(&idio16gpio->lock, flags); 20002e74fc0SWilliam Breathitt Gray 20102e74fc0SWilliam Breathitt Gray ioread8(&idio16gpio->reg->irq_ctl); 20202e74fc0SWilliam Breathitt Gray 20302e74fc0SWilliam Breathitt Gray spin_unlock_irqrestore(&idio16gpio->lock, flags); 20402e74fc0SWilliam Breathitt Gray } 20502e74fc0SWilliam Breathitt Gray } 20602e74fc0SWilliam Breathitt Gray 20702e74fc0SWilliam Breathitt Gray static int idio_16_irq_set_type(struct irq_data *data, unsigned int flow_type) 20802e74fc0SWilliam Breathitt Gray { 20902e74fc0SWilliam Breathitt Gray /* The only valid irq types are none and both-edges */ 21002e74fc0SWilliam Breathitt Gray if (flow_type != IRQ_TYPE_NONE && 21102e74fc0SWilliam Breathitt Gray (flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH) 21202e74fc0SWilliam Breathitt Gray return -EINVAL; 21302e74fc0SWilliam Breathitt Gray 21402e74fc0SWilliam Breathitt Gray return 0; 21502e74fc0SWilliam Breathitt Gray } 21602e74fc0SWilliam Breathitt Gray 21702e74fc0SWilliam Breathitt Gray static struct irq_chip idio_16_irqchip = { 21802e74fc0SWilliam Breathitt Gray .name = "pci-idio-16", 21902e74fc0SWilliam Breathitt Gray .irq_ack = idio_16_irq_ack, 22002e74fc0SWilliam Breathitt Gray .irq_mask = idio_16_irq_mask, 22102e74fc0SWilliam Breathitt Gray .irq_unmask = idio_16_irq_unmask, 22202e74fc0SWilliam Breathitt Gray .irq_set_type = idio_16_irq_set_type 22302e74fc0SWilliam Breathitt Gray }; 22402e74fc0SWilliam Breathitt Gray 22502e74fc0SWilliam Breathitt Gray static irqreturn_t idio_16_irq_handler(int irq, void *dev_id) 22602e74fc0SWilliam Breathitt Gray { 22702e74fc0SWilliam Breathitt Gray struct idio_16_gpio *const idio16gpio = dev_id; 22802e74fc0SWilliam Breathitt Gray unsigned int irq_status; 22902e74fc0SWilliam Breathitt Gray struct gpio_chip *const chip = &idio16gpio->chip; 23002e74fc0SWilliam Breathitt Gray int gpio; 23102e74fc0SWilliam Breathitt Gray 23202e74fc0SWilliam Breathitt Gray spin_lock(&idio16gpio->lock); 23302e74fc0SWilliam Breathitt Gray 23402e74fc0SWilliam Breathitt Gray irq_status = ioread8(&idio16gpio->reg->irq_status); 23502e74fc0SWilliam Breathitt Gray 23602e74fc0SWilliam Breathitt Gray spin_unlock(&idio16gpio->lock); 23702e74fc0SWilliam Breathitt Gray 23802e74fc0SWilliam Breathitt Gray /* Make sure our device generated IRQ */ 23902e74fc0SWilliam Breathitt Gray if (!(irq_status & 0x3) || !(irq_status & 0x4)) 24002e74fc0SWilliam Breathitt Gray return IRQ_NONE; 24102e74fc0SWilliam Breathitt Gray 24202e74fc0SWilliam Breathitt Gray for_each_set_bit(gpio, &idio16gpio->irq_mask, chip->ngpio) 24302e74fc0SWilliam Breathitt Gray generic_handle_irq(irq_find_mapping(chip->irqdomain, gpio)); 24402e74fc0SWilliam Breathitt Gray 24502e74fc0SWilliam Breathitt Gray spin_lock(&idio16gpio->lock); 24602e74fc0SWilliam Breathitt Gray 24702e74fc0SWilliam Breathitt Gray /* Clear interrupt */ 24802e74fc0SWilliam Breathitt Gray iowrite8(0, &idio16gpio->reg->in0_7); 24902e74fc0SWilliam Breathitt Gray 25002e74fc0SWilliam Breathitt Gray spin_unlock(&idio16gpio->lock); 25102e74fc0SWilliam Breathitt Gray 25202e74fc0SWilliam Breathitt Gray return IRQ_HANDLED; 25302e74fc0SWilliam Breathitt Gray } 25402e74fc0SWilliam Breathitt Gray 25502e74fc0SWilliam Breathitt Gray #define IDIO_16_NGPIO 32 25602e74fc0SWilliam Breathitt Gray static const char *idio_16_names[IDIO_16_NGPIO] = { 25702e74fc0SWilliam Breathitt Gray "OUT0", "OUT1", "OUT2", "OUT3", "OUT4", "OUT5", "OUT6", "OUT7", 25802e74fc0SWilliam Breathitt Gray "OUT8", "OUT9", "OUT10", "OUT11", "OUT12", "OUT13", "OUT14", "OUT15", 25902e74fc0SWilliam Breathitt Gray "IIN0", "IIN1", "IIN2", "IIN3", "IIN4", "IIN5", "IIN6", "IIN7", 26002e74fc0SWilliam Breathitt Gray "IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15" 26102e74fc0SWilliam Breathitt Gray }; 26202e74fc0SWilliam Breathitt Gray 26302e74fc0SWilliam Breathitt Gray static int idio_16_probe(struct pci_dev *pdev, const struct pci_device_id *id) 26402e74fc0SWilliam Breathitt Gray { 26502e74fc0SWilliam Breathitt Gray struct device *const dev = &pdev->dev; 26602e74fc0SWilliam Breathitt Gray struct idio_16_gpio *idio16gpio; 26702e74fc0SWilliam Breathitt Gray int err; 26802e74fc0SWilliam Breathitt Gray const char *const name = pci_name(pdev); 26902e74fc0SWilliam Breathitt Gray 27002e74fc0SWilliam Breathitt Gray idio16gpio = devm_kzalloc(dev, sizeof(*idio16gpio), GFP_KERNEL); 27102e74fc0SWilliam Breathitt Gray if (!idio16gpio) 27202e74fc0SWilliam Breathitt Gray return -ENOMEM; 27302e74fc0SWilliam Breathitt Gray 27402e74fc0SWilliam Breathitt Gray err = pcim_enable_device(pdev); 27502e74fc0SWilliam Breathitt Gray if (err) { 27602e74fc0SWilliam Breathitt Gray dev_err(dev, "Failed to enable PCI device (%d)\n", err); 27702e74fc0SWilliam Breathitt Gray return err; 27802e74fc0SWilliam Breathitt Gray } 27902e74fc0SWilliam Breathitt Gray 28002e74fc0SWilliam Breathitt Gray err = pcim_iomap_regions(pdev, 0x1, name); 28102e74fc0SWilliam Breathitt Gray if (err) { 28202e74fc0SWilliam Breathitt Gray dev_err(dev, "Unable to map PCI I/O addresses (%d)\n", err); 28302e74fc0SWilliam Breathitt Gray return err; 28402e74fc0SWilliam Breathitt Gray } 28502e74fc0SWilliam Breathitt Gray 28602e74fc0SWilliam Breathitt Gray idio16gpio->reg = pcim_iomap_table(pdev)[0]; 28702e74fc0SWilliam Breathitt Gray 28802e74fc0SWilliam Breathitt Gray /* Deactivate input filters */ 28902e74fc0SWilliam Breathitt Gray iowrite8(0, &idio16gpio->reg->filter_ctl); 29002e74fc0SWilliam Breathitt Gray 29102e74fc0SWilliam Breathitt Gray idio16gpio->chip.label = name; 29202e74fc0SWilliam Breathitt Gray idio16gpio->chip.parent = dev; 29302e74fc0SWilliam Breathitt Gray idio16gpio->chip.owner = THIS_MODULE; 29402e74fc0SWilliam Breathitt Gray idio16gpio->chip.base = -1; 29502e74fc0SWilliam Breathitt Gray idio16gpio->chip.ngpio = IDIO_16_NGPIO; 29602e74fc0SWilliam Breathitt Gray idio16gpio->chip.names = idio_16_names; 29702e74fc0SWilliam Breathitt Gray idio16gpio->chip.get_direction = idio_16_gpio_get_direction; 29802e74fc0SWilliam Breathitt Gray idio16gpio->chip.direction_input = idio_16_gpio_direction_input; 29902e74fc0SWilliam Breathitt Gray idio16gpio->chip.direction_output = idio_16_gpio_direction_output; 30002e74fc0SWilliam Breathitt Gray idio16gpio->chip.get = idio_16_gpio_get; 30102e74fc0SWilliam Breathitt Gray idio16gpio->chip.set = idio_16_gpio_set; 30202e74fc0SWilliam Breathitt Gray idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple; 30302e74fc0SWilliam Breathitt Gray 30402e74fc0SWilliam Breathitt Gray spin_lock_init(&idio16gpio->lock); 30502e74fc0SWilliam Breathitt Gray 30602e74fc0SWilliam Breathitt Gray err = devm_gpiochip_add_data(dev, &idio16gpio->chip, idio16gpio); 30702e74fc0SWilliam Breathitt Gray if (err) { 30802e74fc0SWilliam Breathitt Gray dev_err(dev, "GPIO registering failed (%d)\n", err); 30902e74fc0SWilliam Breathitt Gray return err; 31002e74fc0SWilliam Breathitt Gray } 31102e74fc0SWilliam Breathitt Gray 31202e74fc0SWilliam Breathitt Gray /* Disable IRQ by default and clear any pending interrupt */ 31302e74fc0SWilliam Breathitt Gray iowrite8(0, &idio16gpio->reg->irq_ctl); 31402e74fc0SWilliam Breathitt Gray iowrite8(0, &idio16gpio->reg->in0_7); 31502e74fc0SWilliam Breathitt Gray 31602e74fc0SWilliam Breathitt Gray err = gpiochip_irqchip_add(&idio16gpio->chip, &idio_16_irqchip, 0, 31702e74fc0SWilliam Breathitt Gray handle_edge_irq, IRQ_TYPE_NONE); 31802e74fc0SWilliam Breathitt Gray if (err) { 31902e74fc0SWilliam Breathitt Gray dev_err(dev, "Could not add irqchip (%d)\n", err); 32002e74fc0SWilliam Breathitt Gray return err; 32102e74fc0SWilliam Breathitt Gray } 32202e74fc0SWilliam Breathitt Gray 32302e74fc0SWilliam Breathitt Gray err = devm_request_irq(dev, pdev->irq, idio_16_irq_handler, IRQF_SHARED, 32402e74fc0SWilliam Breathitt Gray name, idio16gpio); 32502e74fc0SWilliam Breathitt Gray if (err) { 32602e74fc0SWilliam Breathitt Gray dev_err(dev, "IRQ handler registering failed (%d)\n", err); 32702e74fc0SWilliam Breathitt Gray return err; 32802e74fc0SWilliam Breathitt Gray } 32902e74fc0SWilliam Breathitt Gray 33002e74fc0SWilliam Breathitt Gray return 0; 33102e74fc0SWilliam Breathitt Gray } 33202e74fc0SWilliam Breathitt Gray 33302e74fc0SWilliam Breathitt Gray static const struct pci_device_id idio_16_pci_dev_id[] = { 334fd254a23SWilliam Breathitt Gray { PCI_DEVICE(0x494F, 0x0DC8) }, { 0 } 33502e74fc0SWilliam Breathitt Gray }; 33602e74fc0SWilliam Breathitt Gray MODULE_DEVICE_TABLE(pci, idio_16_pci_dev_id); 33702e74fc0SWilliam Breathitt Gray 33802e74fc0SWilliam Breathitt Gray static struct pci_driver idio_16_driver = { 33902e74fc0SWilliam Breathitt Gray .name = "pci-idio-16", 34002e74fc0SWilliam Breathitt Gray .id_table = idio_16_pci_dev_id, 34102e74fc0SWilliam Breathitt Gray .probe = idio_16_probe 34202e74fc0SWilliam Breathitt Gray }; 34302e74fc0SWilliam Breathitt Gray 34402e74fc0SWilliam Breathitt Gray module_pci_driver(idio_16_driver); 34502e74fc0SWilliam Breathitt Gray 34602e74fc0SWilliam Breathitt Gray MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>"); 34702e74fc0SWilliam Breathitt Gray MODULE_DESCRIPTION("ACCES PCI-IDIO-16 GPIO driver"); 34802e74fc0SWilliam Breathitt Gray MODULE_LICENSE("GPL v2"); 349