158556204SWilliam Breathitt Gray // SPDX-License-Identifier: GPL-2.0-only
258556204SWilliam Breathitt Gray /*
358556204SWilliam Breathitt Gray  * GPIO driver for the ACCES PCIe-IDIO-24 family
458556204SWilliam Breathitt Gray  * Copyright (C) 2018 William Breathitt Gray
558556204SWilliam Breathitt Gray  *
658556204SWilliam Breathitt Gray  * This program is free software; you can redistribute it and/or modify
758556204SWilliam Breathitt Gray  * it under the terms of the GNU General Public License, version 2, as
858556204SWilliam Breathitt Gray  * published by the Free Software Foundation.
958556204SWilliam Breathitt Gray  *
1058556204SWilliam Breathitt Gray  * This program is distributed in the hope that it will be useful, but
1158556204SWilliam Breathitt Gray  * WITHOUT ANY WARRANTY; without even the implied warranty of
1258556204SWilliam Breathitt Gray  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1358556204SWilliam Breathitt Gray  * General Public License for more details.
1458556204SWilliam Breathitt Gray  *
1558556204SWilliam Breathitt Gray  * This driver supports the following ACCES devices: PCIe-IDIO-24,
1658556204SWilliam Breathitt Gray  * PCIe-IDI-24, PCIe-IDO-24, and PCIe-IDIO-12.
1758556204SWilliam Breathitt Gray  */
1858556204SWilliam Breathitt Gray #include <linux/bitops.h>
1958556204SWilliam Breathitt Gray #include <linux/device.h>
2058556204SWilliam Breathitt Gray #include <linux/errno.h>
2158556204SWilliam Breathitt Gray #include <linux/gpio/driver.h>
2258556204SWilliam Breathitt Gray #include <linux/interrupt.h>
2358556204SWilliam Breathitt Gray #include <linux/irqdesc.h>
2458556204SWilliam Breathitt Gray #include <linux/kernel.h>
2558556204SWilliam Breathitt Gray #include <linux/module.h>
2658556204SWilliam Breathitt Gray #include <linux/pci.h>
2758556204SWilliam Breathitt Gray #include <linux/spinlock.h>
2858556204SWilliam Breathitt Gray #include <linux/types.h>
2958556204SWilliam Breathitt Gray 
3058556204SWilliam Breathitt Gray /**
3158556204SWilliam Breathitt Gray  * struct idio_24_gpio_reg - GPIO device registers structure
3258556204SWilliam Breathitt Gray  * @out0_7:	Read: FET Outputs 0-7
3358556204SWilliam Breathitt Gray  *		Write: FET Outputs 0-7
3458556204SWilliam Breathitt Gray  * @out8_15:	Read: FET Outputs 8-15
3558556204SWilliam Breathitt Gray  *		Write: FET Outputs 8-15
3658556204SWilliam Breathitt Gray  * @out16_23:	Read: FET Outputs 16-23
3758556204SWilliam Breathitt Gray  *		Write: FET Outputs 16-23
3858556204SWilliam Breathitt Gray  * @ttl_out0_7:	Read: TTL/CMOS Outputs 0-7
3958556204SWilliam Breathitt Gray  *		Write: TTL/CMOS Outputs 0-7
4058556204SWilliam Breathitt Gray  * @in0_7:	Read: Isolated Inputs 0-7
4158556204SWilliam Breathitt Gray  *		Write: Reserved
4258556204SWilliam Breathitt Gray  * @in8_15:	Read: Isolated Inputs 8-15
4358556204SWilliam Breathitt Gray  *		Write: Reserved
4458556204SWilliam Breathitt Gray  * @in16_23:	Read: Isolated Inputs 16-23
4558556204SWilliam Breathitt Gray  *		Write: Reserved
4658556204SWilliam Breathitt Gray  * @ttl_in0_7:	Read: TTL/CMOS Inputs 0-7
4758556204SWilliam Breathitt Gray  *		Write: Reserved
4858556204SWilliam Breathitt Gray  * @cos0_7:	Read: COS Status Inputs 0-7
4958556204SWilliam Breathitt Gray  *		Write: COS Clear Inputs 0-7
5058556204SWilliam Breathitt Gray  * @cos8_15:	Read: COS Status Inputs 8-15
5158556204SWilliam Breathitt Gray  *		Write: COS Clear Inputs 8-15
5258556204SWilliam Breathitt Gray  * @cos16_23:	Read: COS Status Inputs 16-23
5358556204SWilliam Breathitt Gray  *		Write: COS Clear Inputs 16-23
5458556204SWilliam Breathitt Gray  * @cos_ttl0_7:	Read: COS Status TTL/CMOS 0-7
5558556204SWilliam Breathitt Gray  *		Write: COS Clear TTL/CMOS 0-7
5658556204SWilliam Breathitt Gray  * @ctl:	Read: Control Register
5758556204SWilliam Breathitt Gray  *		Write: Control Register
5858556204SWilliam Breathitt Gray  * @reserved:	Read: Reserved
5958556204SWilliam Breathitt Gray  *		Write: Reserved
6058556204SWilliam Breathitt Gray  * @cos_enable:	Read: COS Enable
6158556204SWilliam Breathitt Gray  *		Write: COS Enable
6258556204SWilliam Breathitt Gray  * @soft_reset:	Read: IRQ Output Pin Status
6358556204SWilliam Breathitt Gray  *		Write: Software Board Reset
6458556204SWilliam Breathitt Gray  */
6558556204SWilliam Breathitt Gray struct idio_24_gpio_reg {
6658556204SWilliam Breathitt Gray 	u8 out0_7;
6758556204SWilliam Breathitt Gray 	u8 out8_15;
6858556204SWilliam Breathitt Gray 	u8 out16_23;
6958556204SWilliam Breathitt Gray 	u8 ttl_out0_7;
7058556204SWilliam Breathitt Gray 	u8 in0_7;
7158556204SWilliam Breathitt Gray 	u8 in8_15;
7258556204SWilliam Breathitt Gray 	u8 in16_23;
7358556204SWilliam Breathitt Gray 	u8 ttl_in0_7;
7458556204SWilliam Breathitt Gray 	u8 cos0_7;
7558556204SWilliam Breathitt Gray 	u8 cos8_15;
7658556204SWilliam Breathitt Gray 	u8 cos16_23;
7758556204SWilliam Breathitt Gray 	u8 cos_ttl0_7;
7858556204SWilliam Breathitt Gray 	u8 ctl;
7958556204SWilliam Breathitt Gray 	u8 reserved;
8058556204SWilliam Breathitt Gray 	u8 cos_enable;
8158556204SWilliam Breathitt Gray 	u8 soft_reset;
8258556204SWilliam Breathitt Gray };
8358556204SWilliam Breathitt Gray 
8458556204SWilliam Breathitt Gray /**
8558556204SWilliam Breathitt Gray  * struct idio_24_gpio - GPIO device private data structure
8658556204SWilliam Breathitt Gray  * @chip:	instance of the gpio_chip
8758556204SWilliam Breathitt Gray  * @lock:	synchronization lock to prevent I/O race conditions
8858556204SWilliam Breathitt Gray  * @reg:	I/O address offset for the GPIO device registers
8958556204SWilliam Breathitt Gray  * @irq_mask:	I/O bits affected by interrupts
9058556204SWilliam Breathitt Gray  */
9158556204SWilliam Breathitt Gray struct idio_24_gpio {
9258556204SWilliam Breathitt Gray 	struct gpio_chip chip;
9358556204SWilliam Breathitt Gray 	raw_spinlock_t lock;
9458556204SWilliam Breathitt Gray 	struct idio_24_gpio_reg __iomem *reg;
9558556204SWilliam Breathitt Gray 	unsigned long irq_mask;
9658556204SWilliam Breathitt Gray };
9758556204SWilliam Breathitt Gray 
9858556204SWilliam Breathitt Gray static int idio_24_gpio_get_direction(struct gpio_chip *chip,
9958556204SWilliam Breathitt Gray 	unsigned int offset)
10058556204SWilliam Breathitt Gray {
10158556204SWilliam Breathitt Gray 	struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
10258556204SWilliam Breathitt Gray 	const unsigned long out_mode_mask = BIT(1);
10358556204SWilliam Breathitt Gray 
10458556204SWilliam Breathitt Gray 	/* FET Outputs */
10558556204SWilliam Breathitt Gray 	if (offset < 24)
10658556204SWilliam Breathitt Gray 		return 0;
10758556204SWilliam Breathitt Gray 
10858556204SWilliam Breathitt Gray 	/* Isolated Inputs */
10958556204SWilliam Breathitt Gray 	if (offset < 48)
11058556204SWilliam Breathitt Gray 		return 1;
11158556204SWilliam Breathitt Gray 
11258556204SWilliam Breathitt Gray 	/* TTL/CMOS I/O */
11358556204SWilliam Breathitt Gray 	/* OUT MODE = 1 when TTL/CMOS Output Mode is set */
11458556204SWilliam Breathitt Gray 	return !(ioread8(&idio24gpio->reg->ctl) & out_mode_mask);
11558556204SWilliam Breathitt Gray }
11658556204SWilliam Breathitt Gray 
11758556204SWilliam Breathitt Gray static int idio_24_gpio_direction_input(struct gpio_chip *chip,
11858556204SWilliam Breathitt Gray 	unsigned int offset)
11958556204SWilliam Breathitt Gray {
12058556204SWilliam Breathitt Gray 	struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
12158556204SWilliam Breathitt Gray 	unsigned long flags;
12258556204SWilliam Breathitt Gray 	unsigned int ctl_state;
12358556204SWilliam Breathitt Gray 	const unsigned long out_mode_mask = BIT(1);
12458556204SWilliam Breathitt Gray 
12558556204SWilliam Breathitt Gray 	/* TTL/CMOS I/O */
12658556204SWilliam Breathitt Gray 	if (offset > 47) {
12758556204SWilliam Breathitt Gray 		raw_spin_lock_irqsave(&idio24gpio->lock, flags);
12858556204SWilliam Breathitt Gray 
12958556204SWilliam Breathitt Gray 		/* Clear TTL/CMOS Output Mode */
13058556204SWilliam Breathitt Gray 		ctl_state = ioread8(&idio24gpio->reg->ctl) & ~out_mode_mask;
13158556204SWilliam Breathitt Gray 		iowrite8(ctl_state, &idio24gpio->reg->ctl);
13258556204SWilliam Breathitt Gray 
13358556204SWilliam Breathitt Gray 		raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
13458556204SWilliam Breathitt Gray 	}
13558556204SWilliam Breathitt Gray 
13658556204SWilliam Breathitt Gray 	return 0;
13758556204SWilliam Breathitt Gray }
13858556204SWilliam Breathitt Gray 
13958556204SWilliam Breathitt Gray static int idio_24_gpio_direction_output(struct gpio_chip *chip,
14058556204SWilliam Breathitt Gray 	unsigned int offset, int value)
14158556204SWilliam Breathitt Gray {
14258556204SWilliam Breathitt Gray 	struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
14358556204SWilliam Breathitt Gray 	unsigned long flags;
14458556204SWilliam Breathitt Gray 	unsigned int ctl_state;
14558556204SWilliam Breathitt Gray 	const unsigned long out_mode_mask = BIT(1);
14658556204SWilliam Breathitt Gray 
14758556204SWilliam Breathitt Gray 	/* TTL/CMOS I/O */
14858556204SWilliam Breathitt Gray 	if (offset > 47) {
14958556204SWilliam Breathitt Gray 		raw_spin_lock_irqsave(&idio24gpio->lock, flags);
15058556204SWilliam Breathitt Gray 
15158556204SWilliam Breathitt Gray 		/* Set TTL/CMOS Output Mode */
15258556204SWilliam Breathitt Gray 		ctl_state = ioread8(&idio24gpio->reg->ctl) | out_mode_mask;
15358556204SWilliam Breathitt Gray 		iowrite8(ctl_state, &idio24gpio->reg->ctl);
15458556204SWilliam Breathitt Gray 
15558556204SWilliam Breathitt Gray 		raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
15658556204SWilliam Breathitt Gray 	}
15758556204SWilliam Breathitt Gray 
15858556204SWilliam Breathitt Gray 	chip->set(chip, offset, value);
15958556204SWilliam Breathitt Gray 	return 0;
16058556204SWilliam Breathitt Gray }
16158556204SWilliam Breathitt Gray 
16258556204SWilliam Breathitt Gray static int idio_24_gpio_get(struct gpio_chip *chip, unsigned int offset)
16358556204SWilliam Breathitt Gray {
16458556204SWilliam Breathitt Gray 	struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
16558556204SWilliam Breathitt Gray 	const unsigned long offset_mask = BIT(offset % 8);
16658556204SWilliam Breathitt Gray 	const unsigned long out_mode_mask = BIT(1);
16758556204SWilliam Breathitt Gray 
16858556204SWilliam Breathitt Gray 	/* FET Outputs */
16958556204SWilliam Breathitt Gray 	if (offset < 8)
17058556204SWilliam Breathitt Gray 		return !!(ioread8(&idio24gpio->reg->out0_7) & offset_mask);
17158556204SWilliam Breathitt Gray 
17258556204SWilliam Breathitt Gray 	if (offset < 16)
17358556204SWilliam Breathitt Gray 		return !!(ioread8(&idio24gpio->reg->out8_15) & offset_mask);
17458556204SWilliam Breathitt Gray 
17558556204SWilliam Breathitt Gray 	if (offset < 24)
17658556204SWilliam Breathitt Gray 		return !!(ioread8(&idio24gpio->reg->out16_23) & offset_mask);
17758556204SWilliam Breathitt Gray 
17858556204SWilliam Breathitt Gray 	/* Isolated Inputs */
17958556204SWilliam Breathitt Gray 	if (offset < 32)
18058556204SWilliam Breathitt Gray 		return !!(ioread8(&idio24gpio->reg->in0_7) & offset_mask);
18158556204SWilliam Breathitt Gray 
18258556204SWilliam Breathitt Gray 	if (offset < 40)
18358556204SWilliam Breathitt Gray 		return !!(ioread8(&idio24gpio->reg->in8_15) & offset_mask);
18458556204SWilliam Breathitt Gray 
18558556204SWilliam Breathitt Gray 	if (offset < 48)
18658556204SWilliam Breathitt Gray 		return !!(ioread8(&idio24gpio->reg->in16_23) & offset_mask);
18758556204SWilliam Breathitt Gray 
18858556204SWilliam Breathitt Gray 	/* TTL/CMOS Outputs */
18958556204SWilliam Breathitt Gray 	if (ioread8(&idio24gpio->reg->ctl) & out_mode_mask)
19058556204SWilliam Breathitt Gray 		return !!(ioread8(&idio24gpio->reg->ttl_out0_7) & offset_mask);
19158556204SWilliam Breathitt Gray 
19258556204SWilliam Breathitt Gray 	/* TTL/CMOS Inputs */
19358556204SWilliam Breathitt Gray 	return !!(ioread8(&idio24gpio->reg->ttl_in0_7) & offset_mask);
19458556204SWilliam Breathitt Gray }
19558556204SWilliam Breathitt Gray 
19658556204SWilliam Breathitt Gray static void idio_24_gpio_set(struct gpio_chip *chip, unsigned int offset,
19758556204SWilliam Breathitt Gray 	int value)
19858556204SWilliam Breathitt Gray {
19958556204SWilliam Breathitt Gray 	struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
20058556204SWilliam Breathitt Gray 	const unsigned long out_mode_mask = BIT(1);
20158556204SWilliam Breathitt Gray 	void __iomem *base;
20258556204SWilliam Breathitt Gray 	const unsigned int mask = BIT(offset % 8);
20358556204SWilliam Breathitt Gray 	unsigned long flags;
20458556204SWilliam Breathitt Gray 	unsigned int out_state;
20558556204SWilliam Breathitt Gray 
20658556204SWilliam Breathitt Gray 	/* Isolated Inputs */
20758556204SWilliam Breathitt Gray 	if (offset > 23 && offset < 48)
20858556204SWilliam Breathitt Gray 		return;
20958556204SWilliam Breathitt Gray 
21058556204SWilliam Breathitt Gray 	/* TTL/CMOS Inputs */
21158556204SWilliam Breathitt Gray 	if (offset > 47 && !(ioread8(&idio24gpio->reg->ctl) & out_mode_mask))
21258556204SWilliam Breathitt Gray 		return;
21358556204SWilliam Breathitt Gray 
21458556204SWilliam Breathitt Gray 	/* TTL/CMOS Outputs */
21558556204SWilliam Breathitt Gray 	if (offset > 47)
21658556204SWilliam Breathitt Gray 		base = &idio24gpio->reg->ttl_out0_7;
21758556204SWilliam Breathitt Gray 	/* FET Outputs */
21858556204SWilliam Breathitt Gray 	else if (offset > 15)
21958556204SWilliam Breathitt Gray 		base = &idio24gpio->reg->out16_23;
22058556204SWilliam Breathitt Gray 	else if (offset > 7)
22158556204SWilliam Breathitt Gray 		base = &idio24gpio->reg->out8_15;
22258556204SWilliam Breathitt Gray 	else
22358556204SWilliam Breathitt Gray 		base = &idio24gpio->reg->out0_7;
22458556204SWilliam Breathitt Gray 
22558556204SWilliam Breathitt Gray 	raw_spin_lock_irqsave(&idio24gpio->lock, flags);
22658556204SWilliam Breathitt Gray 
22758556204SWilliam Breathitt Gray 	if (value)
22858556204SWilliam Breathitt Gray 		out_state = ioread8(base) | mask;
22958556204SWilliam Breathitt Gray 	else
23058556204SWilliam Breathitt Gray 		out_state = ioread8(base) & ~mask;
23158556204SWilliam Breathitt Gray 
23258556204SWilliam Breathitt Gray 	iowrite8(out_state, base);
23358556204SWilliam Breathitt Gray 
23458556204SWilliam Breathitt Gray 	raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
23558556204SWilliam Breathitt Gray }
23658556204SWilliam Breathitt Gray 
23758556204SWilliam Breathitt Gray static void idio_24_irq_ack(struct irq_data *data)
23858556204SWilliam Breathitt Gray {
23958556204SWilliam Breathitt Gray }
24058556204SWilliam Breathitt Gray 
24158556204SWilliam Breathitt Gray static void idio_24_irq_mask(struct irq_data *data)
24258556204SWilliam Breathitt Gray {
24358556204SWilliam Breathitt Gray 	struct gpio_chip *const chip = irq_data_get_irq_chip_data(data);
24458556204SWilliam Breathitt Gray 	struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
24558556204SWilliam Breathitt Gray 	unsigned long flags;
24658556204SWilliam Breathitt Gray 	const unsigned long bit_offset = irqd_to_hwirq(data) - 24;
24758556204SWilliam Breathitt Gray 	unsigned char new_irq_mask;
24858556204SWilliam Breathitt Gray 	const unsigned long bank_offset = bit_offset/8 * 8;
24958556204SWilliam Breathitt Gray 	unsigned char cos_enable_state;
25058556204SWilliam Breathitt Gray 
25158556204SWilliam Breathitt Gray 	raw_spin_lock_irqsave(&idio24gpio->lock, flags);
25258556204SWilliam Breathitt Gray 
25358556204SWilliam Breathitt Gray 	idio24gpio->irq_mask &= BIT(bit_offset);
25458556204SWilliam Breathitt Gray 	new_irq_mask = idio24gpio->irq_mask >> bank_offset;
25558556204SWilliam Breathitt Gray 
25658556204SWilliam Breathitt Gray 	if (!new_irq_mask) {
25758556204SWilliam Breathitt Gray 		cos_enable_state = ioread8(&idio24gpio->reg->cos_enable);
25858556204SWilliam Breathitt Gray 
25958556204SWilliam Breathitt Gray 		/* Disable Rising Edge detection */
26058556204SWilliam Breathitt Gray 		cos_enable_state &= ~BIT(bank_offset);
26158556204SWilliam Breathitt Gray 		/* Disable Falling Edge detection */
26258556204SWilliam Breathitt Gray 		cos_enable_state &= ~BIT(bank_offset + 4);
26358556204SWilliam Breathitt Gray 
26458556204SWilliam Breathitt Gray 		iowrite8(cos_enable_state, &idio24gpio->reg->cos_enable);
26558556204SWilliam Breathitt Gray 	}
26658556204SWilliam Breathitt Gray 
26758556204SWilliam Breathitt Gray 	raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
26858556204SWilliam Breathitt Gray }
26958556204SWilliam Breathitt Gray 
27058556204SWilliam Breathitt Gray static void idio_24_irq_unmask(struct irq_data *data)
27158556204SWilliam Breathitt Gray {
27258556204SWilliam Breathitt Gray 	struct gpio_chip *const chip = irq_data_get_irq_chip_data(data);
27358556204SWilliam Breathitt Gray 	struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
27458556204SWilliam Breathitt Gray 	unsigned long flags;
27558556204SWilliam Breathitt Gray 	unsigned char prev_irq_mask;
27658556204SWilliam Breathitt Gray 	const unsigned long bit_offset = irqd_to_hwirq(data) - 24;
27758556204SWilliam Breathitt Gray 	const unsigned long bank_offset = bit_offset/8 * 8;
27858556204SWilliam Breathitt Gray 	unsigned char cos_enable_state;
27958556204SWilliam Breathitt Gray 
28058556204SWilliam Breathitt Gray 	raw_spin_lock_irqsave(&idio24gpio->lock, flags);
28158556204SWilliam Breathitt Gray 
28258556204SWilliam Breathitt Gray 	prev_irq_mask = idio24gpio->irq_mask >> bank_offset;
28358556204SWilliam Breathitt Gray 	idio24gpio->irq_mask |= BIT(bit_offset);
28458556204SWilliam Breathitt Gray 
28558556204SWilliam Breathitt Gray 	if (!prev_irq_mask) {
28658556204SWilliam Breathitt Gray 		cos_enable_state = ioread8(&idio24gpio->reg->cos_enable);
28758556204SWilliam Breathitt Gray 
28858556204SWilliam Breathitt Gray 		/* Enable Rising Edge detection */
28958556204SWilliam Breathitt Gray 		cos_enable_state |= BIT(bank_offset);
29058556204SWilliam Breathitt Gray 		/* Enable Falling Edge detection */
29158556204SWilliam Breathitt Gray 		cos_enable_state |= BIT(bank_offset + 4);
29258556204SWilliam Breathitt Gray 
29358556204SWilliam Breathitt Gray 		iowrite8(cos_enable_state, &idio24gpio->reg->cos_enable);
29458556204SWilliam Breathitt Gray 	}
29558556204SWilliam Breathitt Gray 
29658556204SWilliam Breathitt Gray 	raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
29758556204SWilliam Breathitt Gray }
29858556204SWilliam Breathitt Gray 
29958556204SWilliam Breathitt Gray static int idio_24_irq_set_type(struct irq_data *data, unsigned int flow_type)
30058556204SWilliam Breathitt Gray {
30158556204SWilliam Breathitt Gray 	/* The only valid irq types are none and both-edges */
30258556204SWilliam Breathitt Gray 	if (flow_type != IRQ_TYPE_NONE &&
30358556204SWilliam Breathitt Gray 		(flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH)
30458556204SWilliam Breathitt Gray 		return -EINVAL;
30558556204SWilliam Breathitt Gray 
30658556204SWilliam Breathitt Gray 	return 0;
30758556204SWilliam Breathitt Gray }
30858556204SWilliam Breathitt Gray 
30958556204SWilliam Breathitt Gray static struct irq_chip idio_24_irqchip = {
31058556204SWilliam Breathitt Gray 	.name = "pcie-idio-24",
31158556204SWilliam Breathitt Gray 	.irq_ack = idio_24_irq_ack,
31258556204SWilliam Breathitt Gray 	.irq_mask = idio_24_irq_mask,
31358556204SWilliam Breathitt Gray 	.irq_unmask = idio_24_irq_unmask,
31458556204SWilliam Breathitt Gray 	.irq_set_type = idio_24_irq_set_type
31558556204SWilliam Breathitt Gray };
31658556204SWilliam Breathitt Gray 
31758556204SWilliam Breathitt Gray static irqreturn_t idio_24_irq_handler(int irq, void *dev_id)
31858556204SWilliam Breathitt Gray {
31958556204SWilliam Breathitt Gray 	struct idio_24_gpio *const idio24gpio = dev_id;
32058556204SWilliam Breathitt Gray 	unsigned long irq_status;
32158556204SWilliam Breathitt Gray 	struct gpio_chip *const chip = &idio24gpio->chip;
32258556204SWilliam Breathitt Gray 	unsigned long irq_mask;
32358556204SWilliam Breathitt Gray 	int gpio;
32458556204SWilliam Breathitt Gray 
32558556204SWilliam Breathitt Gray 	raw_spin_lock(&idio24gpio->lock);
32658556204SWilliam Breathitt Gray 
32758556204SWilliam Breathitt Gray 	/* Read Change-Of-State status */
32858556204SWilliam Breathitt Gray 	irq_status = ioread32(&idio24gpio->reg->cos0_7);
32958556204SWilliam Breathitt Gray 
33058556204SWilliam Breathitt Gray 	raw_spin_unlock(&idio24gpio->lock);
33158556204SWilliam Breathitt Gray 
33258556204SWilliam Breathitt Gray 	/* Make sure our device generated IRQ */
33358556204SWilliam Breathitt Gray 	if (!irq_status)
33458556204SWilliam Breathitt Gray 		return IRQ_NONE;
33558556204SWilliam Breathitt Gray 
33658556204SWilliam Breathitt Gray 	/* Handle only unmasked IRQ */
33758556204SWilliam Breathitt Gray 	irq_mask = idio24gpio->irq_mask & irq_status;
33858556204SWilliam Breathitt Gray 
33958556204SWilliam Breathitt Gray 	for_each_set_bit(gpio, &irq_mask, chip->ngpio - 24)
34058556204SWilliam Breathitt Gray 		generic_handle_irq(irq_find_mapping(chip->irq.domain,
34158556204SWilliam Breathitt Gray 			gpio + 24));
34258556204SWilliam Breathitt Gray 
34358556204SWilliam Breathitt Gray 	raw_spin_lock(&idio24gpio->lock);
34458556204SWilliam Breathitt Gray 
34558556204SWilliam Breathitt Gray 	/* Clear Change-Of-State status */
34658556204SWilliam Breathitt Gray 	iowrite32(irq_status, &idio24gpio->reg->cos0_7);
34758556204SWilliam Breathitt Gray 
34858556204SWilliam Breathitt Gray 	raw_spin_unlock(&idio24gpio->lock);
34958556204SWilliam Breathitt Gray 
35058556204SWilliam Breathitt Gray 	return IRQ_HANDLED;
35158556204SWilliam Breathitt Gray }
35258556204SWilliam Breathitt Gray 
35358556204SWilliam Breathitt Gray #define IDIO_24_NGPIO 56
35458556204SWilliam Breathitt Gray static const char *idio_24_names[IDIO_24_NGPIO] = {
35558556204SWilliam Breathitt Gray 	"OUT0", "OUT1", "OUT2", "OUT3", "OUT4", "OUT5", "OUT6", "OUT7",
35658556204SWilliam Breathitt Gray 	"OUT8", "OUT9", "OUT10", "OUT11", "OUT12", "OUT13", "OUT14", "OUT15",
35758556204SWilliam Breathitt Gray 	"OUT16", "OUT17", "OUT18", "OUT19", "OUT20", "OUT21", "OUT22", "OUT23",
35858556204SWilliam Breathitt Gray 	"IIN0", "IIN1", "IIN2", "IIN3", "IIN4", "IIN5", "IIN6", "IIN7",
35958556204SWilliam Breathitt Gray 	"IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15",
36058556204SWilliam Breathitt Gray 	"IIN16", "IIN17", "IIN18", "IIN19", "IIN20", "IIN21", "IIN22", "IIN23",
36158556204SWilliam Breathitt Gray 	"TTL0", "TTL1", "TTL2", "TTL3", "TTL4", "TTL5", "TTL6", "TTL7"
36258556204SWilliam Breathitt Gray };
36358556204SWilliam Breathitt Gray 
36458556204SWilliam Breathitt Gray static int idio_24_probe(struct pci_dev *pdev, const struct pci_device_id *id)
36558556204SWilliam Breathitt Gray {
36658556204SWilliam Breathitt Gray 	struct device *const dev = &pdev->dev;
36758556204SWilliam Breathitt Gray 	struct idio_24_gpio *idio24gpio;
36858556204SWilliam Breathitt Gray 	int err;
36958556204SWilliam Breathitt Gray 	const size_t pci_bar_index = 2;
37058556204SWilliam Breathitt Gray 	const char *const name = pci_name(pdev);
37158556204SWilliam Breathitt Gray 
37258556204SWilliam Breathitt Gray 	idio24gpio = devm_kzalloc(dev, sizeof(*idio24gpio), GFP_KERNEL);
37358556204SWilliam Breathitt Gray 	if (!idio24gpio)
37458556204SWilliam Breathitt Gray 		return -ENOMEM;
37558556204SWilliam Breathitt Gray 
37658556204SWilliam Breathitt Gray 	err = pcim_enable_device(pdev);
37758556204SWilliam Breathitt Gray 	if (err) {
37858556204SWilliam Breathitt Gray 		dev_err(dev, "Failed to enable PCI device (%d)\n", err);
37958556204SWilliam Breathitt Gray 		return err;
38058556204SWilliam Breathitt Gray 	}
38158556204SWilliam Breathitt Gray 
38258556204SWilliam Breathitt Gray 	err = pcim_iomap_regions(pdev, BIT(pci_bar_index), name);
38358556204SWilliam Breathitt Gray 	if (err) {
38458556204SWilliam Breathitt Gray 		dev_err(dev, "Unable to map PCI I/O addresses (%d)\n", err);
38558556204SWilliam Breathitt Gray 		return err;
38658556204SWilliam Breathitt Gray 	}
38758556204SWilliam Breathitt Gray 
38858556204SWilliam Breathitt Gray 	idio24gpio->reg = pcim_iomap_table(pdev)[pci_bar_index];
38958556204SWilliam Breathitt Gray 
39058556204SWilliam Breathitt Gray 	idio24gpio->chip.label = name;
39158556204SWilliam Breathitt Gray 	idio24gpio->chip.parent = dev;
39258556204SWilliam Breathitt Gray 	idio24gpio->chip.owner = THIS_MODULE;
39358556204SWilliam Breathitt Gray 	idio24gpio->chip.base = -1;
39458556204SWilliam Breathitt Gray 	idio24gpio->chip.ngpio = IDIO_24_NGPIO;
39558556204SWilliam Breathitt Gray 	idio24gpio->chip.names = idio_24_names;
39658556204SWilliam Breathitt Gray 	idio24gpio->chip.get_direction = idio_24_gpio_get_direction;
39758556204SWilliam Breathitt Gray 	idio24gpio->chip.direction_input = idio_24_gpio_direction_input;
39858556204SWilliam Breathitt Gray 	idio24gpio->chip.direction_output = idio_24_gpio_direction_output;
39958556204SWilliam Breathitt Gray 	idio24gpio->chip.get = idio_24_gpio_get;
40058556204SWilliam Breathitt Gray 	idio24gpio->chip.set = idio_24_gpio_set;
40158556204SWilliam Breathitt Gray 
40258556204SWilliam Breathitt Gray 	raw_spin_lock_init(&idio24gpio->lock);
40358556204SWilliam Breathitt Gray 
40458556204SWilliam Breathitt Gray 	/* Software board reset */
40558556204SWilliam Breathitt Gray 	iowrite8(0, &idio24gpio->reg->soft_reset);
40658556204SWilliam Breathitt Gray 
40758556204SWilliam Breathitt Gray 	err = devm_gpiochip_add_data(dev, &idio24gpio->chip, idio24gpio);
40858556204SWilliam Breathitt Gray 	if (err) {
40958556204SWilliam Breathitt Gray 		dev_err(dev, "GPIO registering failed (%d)\n", err);
41058556204SWilliam Breathitt Gray 		return err;
41158556204SWilliam Breathitt Gray 	}
41258556204SWilliam Breathitt Gray 
41358556204SWilliam Breathitt Gray 	err = gpiochip_irqchip_add(&idio24gpio->chip, &idio_24_irqchip, 0,
41458556204SWilliam Breathitt Gray 		handle_edge_irq, IRQ_TYPE_NONE);
41558556204SWilliam Breathitt Gray 	if (err) {
41658556204SWilliam Breathitt Gray 		dev_err(dev, "Could not add irqchip (%d)\n", err);
41758556204SWilliam Breathitt Gray 		return err;
41858556204SWilliam Breathitt Gray 	}
41958556204SWilliam Breathitt Gray 
42058556204SWilliam Breathitt Gray 	err = devm_request_irq(dev, pdev->irq, idio_24_irq_handler, IRQF_SHARED,
42158556204SWilliam Breathitt Gray 		name, idio24gpio);
42258556204SWilliam Breathitt Gray 	if (err) {
42358556204SWilliam Breathitt Gray 		dev_err(dev, "IRQ handler registering failed (%d)\n", err);
42458556204SWilliam Breathitt Gray 		return err;
42558556204SWilliam Breathitt Gray 	}
42658556204SWilliam Breathitt Gray 
42758556204SWilliam Breathitt Gray 	return 0;
42858556204SWilliam Breathitt Gray }
42958556204SWilliam Breathitt Gray 
43058556204SWilliam Breathitt Gray static const struct pci_device_id idio_24_pci_dev_id[] = {
43158556204SWilliam Breathitt Gray 	{ PCI_DEVICE(0x494F, 0x0FD0) }, { PCI_DEVICE(0x494F, 0x0BD0) },
43258556204SWilliam Breathitt Gray 	{ PCI_DEVICE(0x494F, 0x07D0) }, { PCI_DEVICE(0x494F, 0x0FC0) },
43358556204SWilliam Breathitt Gray 	{ 0 }
43458556204SWilliam Breathitt Gray };
43558556204SWilliam Breathitt Gray MODULE_DEVICE_TABLE(pci, idio_24_pci_dev_id);
43658556204SWilliam Breathitt Gray 
43758556204SWilliam Breathitt Gray static struct pci_driver idio_24_driver = {
43858556204SWilliam Breathitt Gray 	.name = "pcie-idio-24",
43958556204SWilliam Breathitt Gray 	.id_table = idio_24_pci_dev_id,
44058556204SWilliam Breathitt Gray 	.probe = idio_24_probe
44158556204SWilliam Breathitt Gray };
44258556204SWilliam Breathitt Gray 
44358556204SWilliam Breathitt Gray module_pci_driver(idio_24_driver);
44458556204SWilliam Breathitt Gray 
44558556204SWilliam Breathitt Gray MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
44658556204SWilliam Breathitt Gray MODULE_DESCRIPTION("ACCES PCIe-IDIO-24 GPIO driver");
44758556204SWilliam Breathitt Gray MODULE_LICENSE("GPL v2");
448