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