xref: /openbmc/linux/drivers/gpio/gpio-pcie-idio-24.c (revision 58556204662812f4beec1bc8ee7685884037e0a4)
1*58556204SWilliam Breathitt Gray // SPDX-License-Identifier: GPL-2.0-only
2*58556204SWilliam Breathitt Gray /*
3*58556204SWilliam Breathitt Gray  * GPIO driver for the ACCES PCIe-IDIO-24 family
4*58556204SWilliam Breathitt Gray  * Copyright (C) 2018 William Breathitt Gray
5*58556204SWilliam Breathitt Gray  *
6*58556204SWilliam Breathitt Gray  * This program is free software; you can redistribute it and/or modify
7*58556204SWilliam Breathitt Gray  * it under the terms of the GNU General Public License, version 2, as
8*58556204SWilliam Breathitt Gray  * published by the Free Software Foundation.
9*58556204SWilliam Breathitt Gray  *
10*58556204SWilliam Breathitt Gray  * This program is distributed in the hope that it will be useful, but
11*58556204SWilliam Breathitt Gray  * WITHOUT ANY WARRANTY; without even the implied warranty of
12*58556204SWilliam Breathitt Gray  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13*58556204SWilliam Breathitt Gray  * General Public License for more details.
14*58556204SWilliam Breathitt Gray  *
15*58556204SWilliam Breathitt Gray  * This driver supports the following ACCES devices: PCIe-IDIO-24,
16*58556204SWilliam Breathitt Gray  * PCIe-IDI-24, PCIe-IDO-24, and PCIe-IDIO-12.
17*58556204SWilliam Breathitt Gray  */
18*58556204SWilliam Breathitt Gray #include <linux/bitops.h>
19*58556204SWilliam Breathitt Gray #include <linux/device.h>
20*58556204SWilliam Breathitt Gray #include <linux/errno.h>
21*58556204SWilliam Breathitt Gray #include <linux/gpio/driver.h>
22*58556204SWilliam Breathitt Gray #include <linux/interrupt.h>
23*58556204SWilliam Breathitt Gray #include <linux/irqdesc.h>
24*58556204SWilliam Breathitt Gray #include <linux/kernel.h>
25*58556204SWilliam Breathitt Gray #include <linux/module.h>
26*58556204SWilliam Breathitt Gray #include <linux/pci.h>
27*58556204SWilliam Breathitt Gray #include <linux/spinlock.h>
28*58556204SWilliam Breathitt Gray #include <linux/types.h>
29*58556204SWilliam Breathitt Gray 
30*58556204SWilliam Breathitt Gray /**
31*58556204SWilliam Breathitt Gray  * struct idio_24_gpio_reg - GPIO device registers structure
32*58556204SWilliam Breathitt Gray  * @out0_7:	Read: FET Outputs 0-7
33*58556204SWilliam Breathitt Gray  *		Write: FET Outputs 0-7
34*58556204SWilliam Breathitt Gray  * @out8_15:	Read: FET Outputs 8-15
35*58556204SWilliam Breathitt Gray  *		Write: FET Outputs 8-15
36*58556204SWilliam Breathitt Gray  * @out16_23:	Read: FET Outputs 16-23
37*58556204SWilliam Breathitt Gray  *		Write: FET Outputs 16-23
38*58556204SWilliam Breathitt Gray  * @ttl_out0_7:	Read: TTL/CMOS Outputs 0-7
39*58556204SWilliam Breathitt Gray  *		Write: TTL/CMOS Outputs 0-7
40*58556204SWilliam Breathitt Gray  * @in0_7:	Read: Isolated Inputs 0-7
41*58556204SWilliam Breathitt Gray  *		Write: Reserved
42*58556204SWilliam Breathitt Gray  * @in8_15:	Read: Isolated Inputs 8-15
43*58556204SWilliam Breathitt Gray  *		Write: Reserved
44*58556204SWilliam Breathitt Gray  * @in16_23:	Read: Isolated Inputs 16-23
45*58556204SWilliam Breathitt Gray  *		Write: Reserved
46*58556204SWilliam Breathitt Gray  * @ttl_in0_7:	Read: TTL/CMOS Inputs 0-7
47*58556204SWilliam Breathitt Gray  *		Write: Reserved
48*58556204SWilliam Breathitt Gray  * @cos0_7:	Read: COS Status Inputs 0-7
49*58556204SWilliam Breathitt Gray  *		Write: COS Clear Inputs 0-7
50*58556204SWilliam Breathitt Gray  * @cos8_15:	Read: COS Status Inputs 8-15
51*58556204SWilliam Breathitt Gray  *		Write: COS Clear Inputs 8-15
52*58556204SWilliam Breathitt Gray  * @cos16_23:	Read: COS Status Inputs 16-23
53*58556204SWilliam Breathitt Gray  *		Write: COS Clear Inputs 16-23
54*58556204SWilliam Breathitt Gray  * @cos_ttl0_7:	Read: COS Status TTL/CMOS 0-7
55*58556204SWilliam Breathitt Gray  *		Write: COS Clear TTL/CMOS 0-7
56*58556204SWilliam Breathitt Gray  * @ctl:	Read: Control Register
57*58556204SWilliam Breathitt Gray  *		Write: Control Register
58*58556204SWilliam Breathitt Gray  * @reserved:	Read: Reserved
59*58556204SWilliam Breathitt Gray  *		Write: Reserved
60*58556204SWilliam Breathitt Gray  * @cos_enable:	Read: COS Enable
61*58556204SWilliam Breathitt Gray  *		Write: COS Enable
62*58556204SWilliam Breathitt Gray  * @soft_reset:	Read: IRQ Output Pin Status
63*58556204SWilliam Breathitt Gray  *		Write: Software Board Reset
64*58556204SWilliam Breathitt Gray  */
65*58556204SWilliam Breathitt Gray struct idio_24_gpio_reg {
66*58556204SWilliam Breathitt Gray 	u8 out0_7;
67*58556204SWilliam Breathitt Gray 	u8 out8_15;
68*58556204SWilliam Breathitt Gray 	u8 out16_23;
69*58556204SWilliam Breathitt Gray 	u8 ttl_out0_7;
70*58556204SWilliam Breathitt Gray 	u8 in0_7;
71*58556204SWilliam Breathitt Gray 	u8 in8_15;
72*58556204SWilliam Breathitt Gray 	u8 in16_23;
73*58556204SWilliam Breathitt Gray 	u8 ttl_in0_7;
74*58556204SWilliam Breathitt Gray 	u8 cos0_7;
75*58556204SWilliam Breathitt Gray 	u8 cos8_15;
76*58556204SWilliam Breathitt Gray 	u8 cos16_23;
77*58556204SWilliam Breathitt Gray 	u8 cos_ttl0_7;
78*58556204SWilliam Breathitt Gray 	u8 ctl;
79*58556204SWilliam Breathitt Gray 	u8 reserved;
80*58556204SWilliam Breathitt Gray 	u8 cos_enable;
81*58556204SWilliam Breathitt Gray 	u8 soft_reset;
82*58556204SWilliam Breathitt Gray };
83*58556204SWilliam Breathitt Gray 
84*58556204SWilliam Breathitt Gray /**
85*58556204SWilliam Breathitt Gray  * struct idio_24_gpio - GPIO device private data structure
86*58556204SWilliam Breathitt Gray  * @chip:	instance of the gpio_chip
87*58556204SWilliam Breathitt Gray  * @lock:	synchronization lock to prevent I/O race conditions
88*58556204SWilliam Breathitt Gray  * @reg:	I/O address offset for the GPIO device registers
89*58556204SWilliam Breathitt Gray  * @irq_mask:	I/O bits affected by interrupts
90*58556204SWilliam Breathitt Gray  */
91*58556204SWilliam Breathitt Gray struct idio_24_gpio {
92*58556204SWilliam Breathitt Gray 	struct gpio_chip chip;
93*58556204SWilliam Breathitt Gray 	raw_spinlock_t lock;
94*58556204SWilliam Breathitt Gray 	struct idio_24_gpio_reg __iomem *reg;
95*58556204SWilliam Breathitt Gray 	unsigned long irq_mask;
96*58556204SWilliam Breathitt Gray };
97*58556204SWilliam Breathitt Gray 
98*58556204SWilliam Breathitt Gray static int idio_24_gpio_get_direction(struct gpio_chip *chip,
99*58556204SWilliam Breathitt Gray 	unsigned int offset)
100*58556204SWilliam Breathitt Gray {
101*58556204SWilliam Breathitt Gray 	struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
102*58556204SWilliam Breathitt Gray 	const unsigned long out_mode_mask = BIT(1);
103*58556204SWilliam Breathitt Gray 
104*58556204SWilliam Breathitt Gray 	/* FET Outputs */
105*58556204SWilliam Breathitt Gray 	if (offset < 24)
106*58556204SWilliam Breathitt Gray 		return 0;
107*58556204SWilliam Breathitt Gray 
108*58556204SWilliam Breathitt Gray 	/* Isolated Inputs */
109*58556204SWilliam Breathitt Gray 	if (offset < 48)
110*58556204SWilliam Breathitt Gray 		return 1;
111*58556204SWilliam Breathitt Gray 
112*58556204SWilliam Breathitt Gray 	/* TTL/CMOS I/O */
113*58556204SWilliam Breathitt Gray 	/* OUT MODE = 1 when TTL/CMOS Output Mode is set */
114*58556204SWilliam Breathitt Gray 	return !(ioread8(&idio24gpio->reg->ctl) & out_mode_mask);
115*58556204SWilliam Breathitt Gray }
116*58556204SWilliam Breathitt Gray 
117*58556204SWilliam Breathitt Gray static int idio_24_gpio_direction_input(struct gpio_chip *chip,
118*58556204SWilliam Breathitt Gray 	unsigned int offset)
119*58556204SWilliam Breathitt Gray {
120*58556204SWilliam Breathitt Gray 	struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
121*58556204SWilliam Breathitt Gray 	unsigned long flags;
122*58556204SWilliam Breathitt Gray 	unsigned int ctl_state;
123*58556204SWilliam Breathitt Gray 	const unsigned long out_mode_mask = BIT(1);
124*58556204SWilliam Breathitt Gray 
125*58556204SWilliam Breathitt Gray 	/* TTL/CMOS I/O */
126*58556204SWilliam Breathitt Gray 	if (offset > 47) {
127*58556204SWilliam Breathitt Gray 		raw_spin_lock_irqsave(&idio24gpio->lock, flags);
128*58556204SWilliam Breathitt Gray 
129*58556204SWilliam Breathitt Gray 		/* Clear TTL/CMOS Output Mode */
130*58556204SWilliam Breathitt Gray 		ctl_state = ioread8(&idio24gpio->reg->ctl) & ~out_mode_mask;
131*58556204SWilliam Breathitt Gray 		iowrite8(ctl_state, &idio24gpio->reg->ctl);
132*58556204SWilliam Breathitt Gray 
133*58556204SWilliam Breathitt Gray 		raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
134*58556204SWilliam Breathitt Gray 	}
135*58556204SWilliam Breathitt Gray 
136*58556204SWilliam Breathitt Gray 	return 0;
137*58556204SWilliam Breathitt Gray }
138*58556204SWilliam Breathitt Gray 
139*58556204SWilliam Breathitt Gray static int idio_24_gpio_direction_output(struct gpio_chip *chip,
140*58556204SWilliam Breathitt Gray 	unsigned int offset, int value)
141*58556204SWilliam Breathitt Gray {
142*58556204SWilliam Breathitt Gray 	struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
143*58556204SWilliam Breathitt Gray 	unsigned long flags;
144*58556204SWilliam Breathitt Gray 	unsigned int ctl_state;
145*58556204SWilliam Breathitt Gray 	const unsigned long out_mode_mask = BIT(1);
146*58556204SWilliam Breathitt Gray 
147*58556204SWilliam Breathitt Gray 	/* TTL/CMOS I/O */
148*58556204SWilliam Breathitt Gray 	if (offset > 47) {
149*58556204SWilliam Breathitt Gray 		raw_spin_lock_irqsave(&idio24gpio->lock, flags);
150*58556204SWilliam Breathitt Gray 
151*58556204SWilliam Breathitt Gray 		/* Set TTL/CMOS Output Mode */
152*58556204SWilliam Breathitt Gray 		ctl_state = ioread8(&idio24gpio->reg->ctl) | out_mode_mask;
153*58556204SWilliam Breathitt Gray 		iowrite8(ctl_state, &idio24gpio->reg->ctl);
154*58556204SWilliam Breathitt Gray 
155*58556204SWilliam Breathitt Gray 		raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
156*58556204SWilliam Breathitt Gray 	}
157*58556204SWilliam Breathitt Gray 
158*58556204SWilliam Breathitt Gray 	chip->set(chip, offset, value);
159*58556204SWilliam Breathitt Gray 	return 0;
160*58556204SWilliam Breathitt Gray }
161*58556204SWilliam Breathitt Gray 
162*58556204SWilliam Breathitt Gray static int idio_24_gpio_get(struct gpio_chip *chip, unsigned int offset)
163*58556204SWilliam Breathitt Gray {
164*58556204SWilliam Breathitt Gray 	struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
165*58556204SWilliam Breathitt Gray 	const unsigned long offset_mask = BIT(offset % 8);
166*58556204SWilliam Breathitt Gray 	const unsigned long out_mode_mask = BIT(1);
167*58556204SWilliam Breathitt Gray 
168*58556204SWilliam Breathitt Gray 	/* FET Outputs */
169*58556204SWilliam Breathitt Gray 	if (offset < 8)
170*58556204SWilliam Breathitt Gray 		return !!(ioread8(&idio24gpio->reg->out0_7) & offset_mask);
171*58556204SWilliam Breathitt Gray 
172*58556204SWilliam Breathitt Gray 	if (offset < 16)
173*58556204SWilliam Breathitt Gray 		return !!(ioread8(&idio24gpio->reg->out8_15) & offset_mask);
174*58556204SWilliam Breathitt Gray 
175*58556204SWilliam Breathitt Gray 	if (offset < 24)
176*58556204SWilliam Breathitt Gray 		return !!(ioread8(&idio24gpio->reg->out16_23) & offset_mask);
177*58556204SWilliam Breathitt Gray 
178*58556204SWilliam Breathitt Gray 	/* Isolated Inputs */
179*58556204SWilliam Breathitt Gray 	if (offset < 32)
180*58556204SWilliam Breathitt Gray 		return !!(ioread8(&idio24gpio->reg->in0_7) & offset_mask);
181*58556204SWilliam Breathitt Gray 
182*58556204SWilliam Breathitt Gray 	if (offset < 40)
183*58556204SWilliam Breathitt Gray 		return !!(ioread8(&idio24gpio->reg->in8_15) & offset_mask);
184*58556204SWilliam Breathitt Gray 
185*58556204SWilliam Breathitt Gray 	if (offset < 48)
186*58556204SWilliam Breathitt Gray 		return !!(ioread8(&idio24gpio->reg->in16_23) & offset_mask);
187*58556204SWilliam Breathitt Gray 
188*58556204SWilliam Breathitt Gray 	/* TTL/CMOS Outputs */
189*58556204SWilliam Breathitt Gray 	if (ioread8(&idio24gpio->reg->ctl) & out_mode_mask)
190*58556204SWilliam Breathitt Gray 		return !!(ioread8(&idio24gpio->reg->ttl_out0_7) & offset_mask);
191*58556204SWilliam Breathitt Gray 
192*58556204SWilliam Breathitt Gray 	/* TTL/CMOS Inputs */
193*58556204SWilliam Breathitt Gray 	return !!(ioread8(&idio24gpio->reg->ttl_in0_7) & offset_mask);
194*58556204SWilliam Breathitt Gray }
195*58556204SWilliam Breathitt Gray 
196*58556204SWilliam Breathitt Gray static void idio_24_gpio_set(struct gpio_chip *chip, unsigned int offset,
197*58556204SWilliam Breathitt Gray 	int value)
198*58556204SWilliam Breathitt Gray {
199*58556204SWilliam Breathitt Gray 	struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
200*58556204SWilliam Breathitt Gray 	const unsigned long out_mode_mask = BIT(1);
201*58556204SWilliam Breathitt Gray 	void __iomem *base;
202*58556204SWilliam Breathitt Gray 	const unsigned int mask = BIT(offset % 8);
203*58556204SWilliam Breathitt Gray 	unsigned long flags;
204*58556204SWilliam Breathitt Gray 	unsigned int out_state;
205*58556204SWilliam Breathitt Gray 
206*58556204SWilliam Breathitt Gray 	/* Isolated Inputs */
207*58556204SWilliam Breathitt Gray 	if (offset > 23 && offset < 48)
208*58556204SWilliam Breathitt Gray 		return;
209*58556204SWilliam Breathitt Gray 
210*58556204SWilliam Breathitt Gray 	/* TTL/CMOS Inputs */
211*58556204SWilliam Breathitt Gray 	if (offset > 47 && !(ioread8(&idio24gpio->reg->ctl) & out_mode_mask))
212*58556204SWilliam Breathitt Gray 		return;
213*58556204SWilliam Breathitt Gray 
214*58556204SWilliam Breathitt Gray 	/* TTL/CMOS Outputs */
215*58556204SWilliam Breathitt Gray 	if (offset > 47)
216*58556204SWilliam Breathitt Gray 		base = &idio24gpio->reg->ttl_out0_7;
217*58556204SWilliam Breathitt Gray 	/* FET Outputs */
218*58556204SWilliam Breathitt Gray 	else if (offset > 15)
219*58556204SWilliam Breathitt Gray 		base = &idio24gpio->reg->out16_23;
220*58556204SWilliam Breathitt Gray 	else if (offset > 7)
221*58556204SWilliam Breathitt Gray 		base = &idio24gpio->reg->out8_15;
222*58556204SWilliam Breathitt Gray 	else
223*58556204SWilliam Breathitt Gray 		base = &idio24gpio->reg->out0_7;
224*58556204SWilliam Breathitt Gray 
225*58556204SWilliam Breathitt Gray 	raw_spin_lock_irqsave(&idio24gpio->lock, flags);
226*58556204SWilliam Breathitt Gray 
227*58556204SWilliam Breathitt Gray 	if (value)
228*58556204SWilliam Breathitt Gray 		out_state = ioread8(base) | mask;
229*58556204SWilliam Breathitt Gray 	else
230*58556204SWilliam Breathitt Gray 		out_state = ioread8(base) & ~mask;
231*58556204SWilliam Breathitt Gray 
232*58556204SWilliam Breathitt Gray 	iowrite8(out_state, base);
233*58556204SWilliam Breathitt Gray 
234*58556204SWilliam Breathitt Gray 	raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
235*58556204SWilliam Breathitt Gray }
236*58556204SWilliam Breathitt Gray 
237*58556204SWilliam Breathitt Gray static void idio_24_irq_ack(struct irq_data *data)
238*58556204SWilliam Breathitt Gray {
239*58556204SWilliam Breathitt Gray }
240*58556204SWilliam Breathitt Gray 
241*58556204SWilliam Breathitt Gray static void idio_24_irq_mask(struct irq_data *data)
242*58556204SWilliam Breathitt Gray {
243*58556204SWilliam Breathitt Gray 	struct gpio_chip *const chip = irq_data_get_irq_chip_data(data);
244*58556204SWilliam Breathitt Gray 	struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
245*58556204SWilliam Breathitt Gray 	unsigned long flags;
246*58556204SWilliam Breathitt Gray 	const unsigned long bit_offset = irqd_to_hwirq(data) - 24;
247*58556204SWilliam Breathitt Gray 	unsigned char new_irq_mask;
248*58556204SWilliam Breathitt Gray 	const unsigned long bank_offset = bit_offset/8 * 8;
249*58556204SWilliam Breathitt Gray 	unsigned char cos_enable_state;
250*58556204SWilliam Breathitt Gray 
251*58556204SWilliam Breathitt Gray 	raw_spin_lock_irqsave(&idio24gpio->lock, flags);
252*58556204SWilliam Breathitt Gray 
253*58556204SWilliam Breathitt Gray 	idio24gpio->irq_mask &= BIT(bit_offset);
254*58556204SWilliam Breathitt Gray 	new_irq_mask = idio24gpio->irq_mask >> bank_offset;
255*58556204SWilliam Breathitt Gray 
256*58556204SWilliam Breathitt Gray 	if (!new_irq_mask) {
257*58556204SWilliam Breathitt Gray 		cos_enable_state = ioread8(&idio24gpio->reg->cos_enable);
258*58556204SWilliam Breathitt Gray 
259*58556204SWilliam Breathitt Gray 		/* Disable Rising Edge detection */
260*58556204SWilliam Breathitt Gray 		cos_enable_state &= ~BIT(bank_offset);
261*58556204SWilliam Breathitt Gray 		/* Disable Falling Edge detection */
262*58556204SWilliam Breathitt Gray 		cos_enable_state &= ~BIT(bank_offset + 4);
263*58556204SWilliam Breathitt Gray 
264*58556204SWilliam Breathitt Gray 		iowrite8(cos_enable_state, &idio24gpio->reg->cos_enable);
265*58556204SWilliam Breathitt Gray 	}
266*58556204SWilliam Breathitt Gray 
267*58556204SWilliam Breathitt Gray 	raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
268*58556204SWilliam Breathitt Gray }
269*58556204SWilliam Breathitt Gray 
270*58556204SWilliam Breathitt Gray static void idio_24_irq_unmask(struct irq_data *data)
271*58556204SWilliam Breathitt Gray {
272*58556204SWilliam Breathitt Gray 	struct gpio_chip *const chip = irq_data_get_irq_chip_data(data);
273*58556204SWilliam Breathitt Gray 	struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
274*58556204SWilliam Breathitt Gray 	unsigned long flags;
275*58556204SWilliam Breathitt Gray 	unsigned char prev_irq_mask;
276*58556204SWilliam Breathitt Gray 	const unsigned long bit_offset = irqd_to_hwirq(data) - 24;
277*58556204SWilliam Breathitt Gray 	const unsigned long bank_offset = bit_offset/8 * 8;
278*58556204SWilliam Breathitt Gray 	unsigned char cos_enable_state;
279*58556204SWilliam Breathitt Gray 
280*58556204SWilliam Breathitt Gray 	raw_spin_lock_irqsave(&idio24gpio->lock, flags);
281*58556204SWilliam Breathitt Gray 
282*58556204SWilliam Breathitt Gray 	prev_irq_mask = idio24gpio->irq_mask >> bank_offset;
283*58556204SWilliam Breathitt Gray 	idio24gpio->irq_mask |= BIT(bit_offset);
284*58556204SWilliam Breathitt Gray 
285*58556204SWilliam Breathitt Gray 	if (!prev_irq_mask) {
286*58556204SWilliam Breathitt Gray 		cos_enable_state = ioread8(&idio24gpio->reg->cos_enable);
287*58556204SWilliam Breathitt Gray 
288*58556204SWilliam Breathitt Gray 		/* Enable Rising Edge detection */
289*58556204SWilliam Breathitt Gray 		cos_enable_state |= BIT(bank_offset);
290*58556204SWilliam Breathitt Gray 		/* Enable Falling Edge detection */
291*58556204SWilliam Breathitt Gray 		cos_enable_state |= BIT(bank_offset + 4);
292*58556204SWilliam Breathitt Gray 
293*58556204SWilliam Breathitt Gray 		iowrite8(cos_enable_state, &idio24gpio->reg->cos_enable);
294*58556204SWilliam Breathitt Gray 	}
295*58556204SWilliam Breathitt Gray 
296*58556204SWilliam Breathitt Gray 	raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
297*58556204SWilliam Breathitt Gray }
298*58556204SWilliam Breathitt Gray 
299*58556204SWilliam Breathitt Gray static int idio_24_irq_set_type(struct irq_data *data, unsigned int flow_type)
300*58556204SWilliam Breathitt Gray {
301*58556204SWilliam Breathitt Gray 	/* The only valid irq types are none and both-edges */
302*58556204SWilliam Breathitt Gray 	if (flow_type != IRQ_TYPE_NONE &&
303*58556204SWilliam Breathitt Gray 		(flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH)
304*58556204SWilliam Breathitt Gray 		return -EINVAL;
305*58556204SWilliam Breathitt Gray 
306*58556204SWilliam Breathitt Gray 	return 0;
307*58556204SWilliam Breathitt Gray }
308*58556204SWilliam Breathitt Gray 
309*58556204SWilliam Breathitt Gray static struct irq_chip idio_24_irqchip = {
310*58556204SWilliam Breathitt Gray 	.name = "pcie-idio-24",
311*58556204SWilliam Breathitt Gray 	.irq_ack = idio_24_irq_ack,
312*58556204SWilliam Breathitt Gray 	.irq_mask = idio_24_irq_mask,
313*58556204SWilliam Breathitt Gray 	.irq_unmask = idio_24_irq_unmask,
314*58556204SWilliam Breathitt Gray 	.irq_set_type = idio_24_irq_set_type
315*58556204SWilliam Breathitt Gray };
316*58556204SWilliam Breathitt Gray 
317*58556204SWilliam Breathitt Gray static irqreturn_t idio_24_irq_handler(int irq, void *dev_id)
318*58556204SWilliam Breathitt Gray {
319*58556204SWilliam Breathitt Gray 	struct idio_24_gpio *const idio24gpio = dev_id;
320*58556204SWilliam Breathitt Gray 	unsigned long irq_status;
321*58556204SWilliam Breathitt Gray 	struct gpio_chip *const chip = &idio24gpio->chip;
322*58556204SWilliam Breathitt Gray 	unsigned long irq_mask;
323*58556204SWilliam Breathitt Gray 	int gpio;
324*58556204SWilliam Breathitt Gray 
325*58556204SWilliam Breathitt Gray 	raw_spin_lock(&idio24gpio->lock);
326*58556204SWilliam Breathitt Gray 
327*58556204SWilliam Breathitt Gray 	/* Read Change-Of-State status */
328*58556204SWilliam Breathitt Gray 	irq_status = ioread32(&idio24gpio->reg->cos0_7);
329*58556204SWilliam Breathitt Gray 
330*58556204SWilliam Breathitt Gray 	raw_spin_unlock(&idio24gpio->lock);
331*58556204SWilliam Breathitt Gray 
332*58556204SWilliam Breathitt Gray 	/* Make sure our device generated IRQ */
333*58556204SWilliam Breathitt Gray 	if (!irq_status)
334*58556204SWilliam Breathitt Gray 		return IRQ_NONE;
335*58556204SWilliam Breathitt Gray 
336*58556204SWilliam Breathitt Gray 	/* Handle only unmasked IRQ */
337*58556204SWilliam Breathitt Gray 	irq_mask = idio24gpio->irq_mask & irq_status;
338*58556204SWilliam Breathitt Gray 
339*58556204SWilliam Breathitt Gray 	for_each_set_bit(gpio, &irq_mask, chip->ngpio - 24)
340*58556204SWilliam Breathitt Gray 		generic_handle_irq(irq_find_mapping(chip->irq.domain,
341*58556204SWilliam Breathitt Gray 			gpio + 24));
342*58556204SWilliam Breathitt Gray 
343*58556204SWilliam Breathitt Gray 	raw_spin_lock(&idio24gpio->lock);
344*58556204SWilliam Breathitt Gray 
345*58556204SWilliam Breathitt Gray 	/* Clear Change-Of-State status */
346*58556204SWilliam Breathitt Gray 	iowrite32(irq_status, &idio24gpio->reg->cos0_7);
347*58556204SWilliam Breathitt Gray 
348*58556204SWilliam Breathitt Gray 	raw_spin_unlock(&idio24gpio->lock);
349*58556204SWilliam Breathitt Gray 
350*58556204SWilliam Breathitt Gray 	return IRQ_HANDLED;
351*58556204SWilliam Breathitt Gray }
352*58556204SWilliam Breathitt Gray 
353*58556204SWilliam Breathitt Gray #define IDIO_24_NGPIO 56
354*58556204SWilliam Breathitt Gray static const char *idio_24_names[IDIO_24_NGPIO] = {
355*58556204SWilliam Breathitt Gray 	"OUT0", "OUT1", "OUT2", "OUT3", "OUT4", "OUT5", "OUT6", "OUT7",
356*58556204SWilliam Breathitt Gray 	"OUT8", "OUT9", "OUT10", "OUT11", "OUT12", "OUT13", "OUT14", "OUT15",
357*58556204SWilliam Breathitt Gray 	"OUT16", "OUT17", "OUT18", "OUT19", "OUT20", "OUT21", "OUT22", "OUT23",
358*58556204SWilliam Breathitt Gray 	"IIN0", "IIN1", "IIN2", "IIN3", "IIN4", "IIN5", "IIN6", "IIN7",
359*58556204SWilliam Breathitt Gray 	"IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15",
360*58556204SWilliam Breathitt Gray 	"IIN16", "IIN17", "IIN18", "IIN19", "IIN20", "IIN21", "IIN22", "IIN23",
361*58556204SWilliam Breathitt Gray 	"TTL0", "TTL1", "TTL2", "TTL3", "TTL4", "TTL5", "TTL6", "TTL7"
362*58556204SWilliam Breathitt Gray };
363*58556204SWilliam Breathitt Gray 
364*58556204SWilliam Breathitt Gray static int idio_24_probe(struct pci_dev *pdev, const struct pci_device_id *id)
365*58556204SWilliam Breathitt Gray {
366*58556204SWilliam Breathitt Gray 	struct device *const dev = &pdev->dev;
367*58556204SWilliam Breathitt Gray 	struct idio_24_gpio *idio24gpio;
368*58556204SWilliam Breathitt Gray 	int err;
369*58556204SWilliam Breathitt Gray 	const size_t pci_bar_index = 2;
370*58556204SWilliam Breathitt Gray 	const char *const name = pci_name(pdev);
371*58556204SWilliam Breathitt Gray 
372*58556204SWilliam Breathitt Gray 	idio24gpio = devm_kzalloc(dev, sizeof(*idio24gpio), GFP_KERNEL);
373*58556204SWilliam Breathitt Gray 	if (!idio24gpio)
374*58556204SWilliam Breathitt Gray 		return -ENOMEM;
375*58556204SWilliam Breathitt Gray 
376*58556204SWilliam Breathitt Gray 	err = pcim_enable_device(pdev);
377*58556204SWilliam Breathitt Gray 	if (err) {
378*58556204SWilliam Breathitt Gray 		dev_err(dev, "Failed to enable PCI device (%d)\n", err);
379*58556204SWilliam Breathitt Gray 		return err;
380*58556204SWilliam Breathitt Gray 	}
381*58556204SWilliam Breathitt Gray 
382*58556204SWilliam Breathitt Gray 	err = pcim_iomap_regions(pdev, BIT(pci_bar_index), name);
383*58556204SWilliam Breathitt Gray 	if (err) {
384*58556204SWilliam Breathitt Gray 		dev_err(dev, "Unable to map PCI I/O addresses (%d)\n", err);
385*58556204SWilliam Breathitt Gray 		return err;
386*58556204SWilliam Breathitt Gray 	}
387*58556204SWilliam Breathitt Gray 
388*58556204SWilliam Breathitt Gray 	idio24gpio->reg = pcim_iomap_table(pdev)[pci_bar_index];
389*58556204SWilliam Breathitt Gray 
390*58556204SWilliam Breathitt Gray 	idio24gpio->chip.label = name;
391*58556204SWilliam Breathitt Gray 	idio24gpio->chip.parent = dev;
392*58556204SWilliam Breathitt Gray 	idio24gpio->chip.owner = THIS_MODULE;
393*58556204SWilliam Breathitt Gray 	idio24gpio->chip.base = -1;
394*58556204SWilliam Breathitt Gray 	idio24gpio->chip.ngpio = IDIO_24_NGPIO;
395*58556204SWilliam Breathitt Gray 	idio24gpio->chip.names = idio_24_names;
396*58556204SWilliam Breathitt Gray 	idio24gpio->chip.get_direction = idio_24_gpio_get_direction;
397*58556204SWilliam Breathitt Gray 	idio24gpio->chip.direction_input = idio_24_gpio_direction_input;
398*58556204SWilliam Breathitt Gray 	idio24gpio->chip.direction_output = idio_24_gpio_direction_output;
399*58556204SWilliam Breathitt Gray 	idio24gpio->chip.get = idio_24_gpio_get;
400*58556204SWilliam Breathitt Gray 	idio24gpio->chip.set = idio_24_gpio_set;
401*58556204SWilliam Breathitt Gray 
402*58556204SWilliam Breathitt Gray 	raw_spin_lock_init(&idio24gpio->lock);
403*58556204SWilliam Breathitt Gray 
404*58556204SWilliam Breathitt Gray 	/* Software board reset */
405*58556204SWilliam Breathitt Gray 	iowrite8(0, &idio24gpio->reg->soft_reset);
406*58556204SWilliam Breathitt Gray 
407*58556204SWilliam Breathitt Gray 	err = devm_gpiochip_add_data(dev, &idio24gpio->chip, idio24gpio);
408*58556204SWilliam Breathitt Gray 	if (err) {
409*58556204SWilliam Breathitt Gray 		dev_err(dev, "GPIO registering failed (%d)\n", err);
410*58556204SWilliam Breathitt Gray 		return err;
411*58556204SWilliam Breathitt Gray 	}
412*58556204SWilliam Breathitt Gray 
413*58556204SWilliam Breathitt Gray 	err = gpiochip_irqchip_add(&idio24gpio->chip, &idio_24_irqchip, 0,
414*58556204SWilliam Breathitt Gray 		handle_edge_irq, IRQ_TYPE_NONE);
415*58556204SWilliam Breathitt Gray 	if (err) {
416*58556204SWilliam Breathitt Gray 		dev_err(dev, "Could not add irqchip (%d)\n", err);
417*58556204SWilliam Breathitt Gray 		return err;
418*58556204SWilliam Breathitt Gray 	}
419*58556204SWilliam Breathitt Gray 
420*58556204SWilliam Breathitt Gray 	err = devm_request_irq(dev, pdev->irq, idio_24_irq_handler, IRQF_SHARED,
421*58556204SWilliam Breathitt Gray 		name, idio24gpio);
422*58556204SWilliam Breathitt Gray 	if (err) {
423*58556204SWilliam Breathitt Gray 		dev_err(dev, "IRQ handler registering failed (%d)\n", err);
424*58556204SWilliam Breathitt Gray 		return err;
425*58556204SWilliam Breathitt Gray 	}
426*58556204SWilliam Breathitt Gray 
427*58556204SWilliam Breathitt Gray 	return 0;
428*58556204SWilliam Breathitt Gray }
429*58556204SWilliam Breathitt Gray 
430*58556204SWilliam Breathitt Gray static const struct pci_device_id idio_24_pci_dev_id[] = {
431*58556204SWilliam Breathitt Gray 	{ PCI_DEVICE(0x494F, 0x0FD0) }, { PCI_DEVICE(0x494F, 0x0BD0) },
432*58556204SWilliam Breathitt Gray 	{ PCI_DEVICE(0x494F, 0x07D0) }, { PCI_DEVICE(0x494F, 0x0FC0) },
433*58556204SWilliam Breathitt Gray 	{ 0 }
434*58556204SWilliam Breathitt Gray };
435*58556204SWilliam Breathitt Gray MODULE_DEVICE_TABLE(pci, idio_24_pci_dev_id);
436*58556204SWilliam Breathitt Gray 
437*58556204SWilliam Breathitt Gray static struct pci_driver idio_24_driver = {
438*58556204SWilliam Breathitt Gray 	.name = "pcie-idio-24",
439*58556204SWilliam Breathitt Gray 	.id_table = idio_24_pci_dev_id,
440*58556204SWilliam Breathitt Gray 	.probe = idio_24_probe
441*58556204SWilliam Breathitt Gray };
442*58556204SWilliam Breathitt Gray 
443*58556204SWilliam Breathitt Gray module_pci_driver(idio_24_driver);
444*58556204SWilliam Breathitt Gray 
445*58556204SWilliam Breathitt Gray MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
446*58556204SWilliam Breathitt Gray MODULE_DESCRIPTION("ACCES PCIe-IDIO-24 GPIO driver");
447*58556204SWilliam Breathitt Gray MODULE_LICENSE("GPL v2");
448