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;
268deab2b05SWilliam Breathitt Gray 	const size_t pci_bar_index = 2;
26902e74fc0SWilliam Breathitt Gray 	const char *const name = pci_name(pdev);
27002e74fc0SWilliam Breathitt Gray 
27102e74fc0SWilliam Breathitt Gray 	idio16gpio = devm_kzalloc(dev, sizeof(*idio16gpio), GFP_KERNEL);
27202e74fc0SWilliam Breathitt Gray 	if (!idio16gpio)
27302e74fc0SWilliam Breathitt Gray 		return -ENOMEM;
27402e74fc0SWilliam Breathitt Gray 
27502e74fc0SWilliam Breathitt Gray 	err = pcim_enable_device(pdev);
27602e74fc0SWilliam Breathitt Gray 	if (err) {
27702e74fc0SWilliam Breathitt Gray 		dev_err(dev, "Failed to enable PCI device (%d)\n", err);
27802e74fc0SWilliam Breathitt Gray 		return err;
27902e74fc0SWilliam Breathitt Gray 	}
28002e74fc0SWilliam Breathitt Gray 
281deab2b05SWilliam Breathitt Gray 	err = pcim_iomap_regions(pdev, BIT(pci_bar_index), name);
28202e74fc0SWilliam Breathitt Gray 	if (err) {
28302e74fc0SWilliam Breathitt Gray 		dev_err(dev, "Unable to map PCI I/O addresses (%d)\n", err);
28402e74fc0SWilliam Breathitt Gray 		return err;
28502e74fc0SWilliam Breathitt Gray 	}
28602e74fc0SWilliam Breathitt Gray 
287deab2b05SWilliam Breathitt Gray 	idio16gpio->reg = pcim_iomap_table(pdev)[pci_bar_index];
28802e74fc0SWilliam Breathitt Gray 
28902e74fc0SWilliam Breathitt Gray 	/* Deactivate input filters */
29002e74fc0SWilliam Breathitt Gray 	iowrite8(0, &idio16gpio->reg->filter_ctl);
29102e74fc0SWilliam Breathitt Gray 
29202e74fc0SWilliam Breathitt Gray 	idio16gpio->chip.label = name;
29302e74fc0SWilliam Breathitt Gray 	idio16gpio->chip.parent = dev;
29402e74fc0SWilliam Breathitt Gray 	idio16gpio->chip.owner = THIS_MODULE;
29502e74fc0SWilliam Breathitt Gray 	idio16gpio->chip.base = -1;
29602e74fc0SWilliam Breathitt Gray 	idio16gpio->chip.ngpio = IDIO_16_NGPIO;
29702e74fc0SWilliam Breathitt Gray 	idio16gpio->chip.names = idio_16_names;
29802e74fc0SWilliam Breathitt Gray 	idio16gpio->chip.get_direction = idio_16_gpio_get_direction;
29902e74fc0SWilliam Breathitt Gray 	idio16gpio->chip.direction_input = idio_16_gpio_direction_input;
30002e74fc0SWilliam Breathitt Gray 	idio16gpio->chip.direction_output = idio_16_gpio_direction_output;
30102e74fc0SWilliam Breathitt Gray 	idio16gpio->chip.get = idio_16_gpio_get;
30202e74fc0SWilliam Breathitt Gray 	idio16gpio->chip.set = idio_16_gpio_set;
30302e74fc0SWilliam Breathitt Gray 	idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple;
30402e74fc0SWilliam Breathitt Gray 
30502e74fc0SWilliam Breathitt Gray 	spin_lock_init(&idio16gpio->lock);
30602e74fc0SWilliam Breathitt Gray 
30702e74fc0SWilliam Breathitt Gray 	err = devm_gpiochip_add_data(dev, &idio16gpio->chip, idio16gpio);
30802e74fc0SWilliam Breathitt Gray 	if (err) {
30902e74fc0SWilliam Breathitt Gray 		dev_err(dev, "GPIO registering failed (%d)\n", err);
31002e74fc0SWilliam Breathitt Gray 		return err;
31102e74fc0SWilliam Breathitt Gray 	}
31202e74fc0SWilliam Breathitt Gray 
31302e74fc0SWilliam Breathitt Gray 	/* Disable IRQ by default and clear any pending interrupt */
31402e74fc0SWilliam Breathitt Gray 	iowrite8(0, &idio16gpio->reg->irq_ctl);
31502e74fc0SWilliam Breathitt Gray 	iowrite8(0, &idio16gpio->reg->in0_7);
31602e74fc0SWilliam Breathitt Gray 
31702e74fc0SWilliam Breathitt Gray 	err = gpiochip_irqchip_add(&idio16gpio->chip, &idio_16_irqchip, 0,
31802e74fc0SWilliam Breathitt Gray 		handle_edge_irq, IRQ_TYPE_NONE);
31902e74fc0SWilliam Breathitt Gray 	if (err) {
32002e74fc0SWilliam Breathitt Gray 		dev_err(dev, "Could not add irqchip (%d)\n", err);
32102e74fc0SWilliam Breathitt Gray 		return err;
32202e74fc0SWilliam Breathitt Gray 	}
32302e74fc0SWilliam Breathitt Gray 
32402e74fc0SWilliam Breathitt Gray 	err = devm_request_irq(dev, pdev->irq, idio_16_irq_handler, IRQF_SHARED,
32502e74fc0SWilliam Breathitt Gray 		name, idio16gpio);
32602e74fc0SWilliam Breathitt Gray 	if (err) {
32702e74fc0SWilliam Breathitt Gray 		dev_err(dev, "IRQ handler registering failed (%d)\n", err);
32802e74fc0SWilliam Breathitt Gray 		return err;
32902e74fc0SWilliam Breathitt Gray 	}
33002e74fc0SWilliam Breathitt Gray 
33102e74fc0SWilliam Breathitt Gray 	return 0;
33202e74fc0SWilliam Breathitt Gray }
33302e74fc0SWilliam Breathitt Gray 
33402e74fc0SWilliam Breathitt Gray static const struct pci_device_id idio_16_pci_dev_id[] = {
335fd254a23SWilliam Breathitt Gray 	{ PCI_DEVICE(0x494F, 0x0DC8) }, { 0 }
33602e74fc0SWilliam Breathitt Gray };
33702e74fc0SWilliam Breathitt Gray MODULE_DEVICE_TABLE(pci, idio_16_pci_dev_id);
33802e74fc0SWilliam Breathitt Gray 
33902e74fc0SWilliam Breathitt Gray static struct pci_driver idio_16_driver = {
34002e74fc0SWilliam Breathitt Gray 	.name = "pci-idio-16",
34102e74fc0SWilliam Breathitt Gray 	.id_table = idio_16_pci_dev_id,
34202e74fc0SWilliam Breathitt Gray 	.probe = idio_16_probe
34302e74fc0SWilliam Breathitt Gray };
34402e74fc0SWilliam Breathitt Gray 
34502e74fc0SWilliam Breathitt Gray module_pci_driver(idio_16_driver);
34602e74fc0SWilliam Breathitt Gray 
34702e74fc0SWilliam Breathitt Gray MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
34802e74fc0SWilliam Breathitt Gray MODULE_DESCRIPTION("ACCES PCI-IDIO-16 GPIO driver");
34902e74fc0SWilliam Breathitt Gray MODULE_LICENSE("GPL v2");
350