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 driver supports the following ACCES devices: PCIe-IDIO-24,
758556204SWilliam Breathitt Gray  * PCIe-IDI-24, PCIe-IDO-24, and PCIe-IDIO-12.
858556204SWilliam Breathitt Gray  */
9*1a200a39SWilliam Breathitt Gray #include <linux/bits.h>
1058556204SWilliam Breathitt Gray #include <linux/device.h>
11*1a200a39SWilliam Breathitt Gray #include <linux/err.h>
12*1a200a39SWilliam Breathitt Gray #include <linux/gpio/regmap.h>
13*1a200a39SWilliam Breathitt Gray #include <linux/irq.h>
1458556204SWilliam Breathitt Gray #include <linux/kernel.h>
1558556204SWilliam Breathitt Gray #include <linux/module.h>
1658556204SWilliam Breathitt Gray #include <linux/pci.h>
17*1a200a39SWilliam Breathitt Gray #include <linux/regmap.h>
1858556204SWilliam Breathitt Gray #include <linux/spinlock.h>
1958556204SWilliam Breathitt Gray #include <linux/types.h>
2058556204SWilliam Breathitt Gray 
2110a2f11dSArnaud de Turckheim /*
2210a2f11dSArnaud de Turckheim  * PLX PEX8311 PCI LCS_INTCSR Interrupt Control/Status
2310a2f11dSArnaud de Turckheim  *
2410a2f11dSArnaud de Turckheim  * Bit: Description
2510a2f11dSArnaud de Turckheim  *   0: Enable Interrupt Sources (Bit 0)
2610a2f11dSArnaud de Turckheim  *   1: Enable Interrupt Sources (Bit 1)
2710a2f11dSArnaud de Turckheim  *   2: Generate Internal PCI Bus Internal SERR# Interrupt
2810a2f11dSArnaud de Turckheim  *   3: Mailbox Interrupt Enable
2910a2f11dSArnaud de Turckheim  *   4: Power Management Interrupt Enable
3010a2f11dSArnaud de Turckheim  *   5: Power Management Interrupt
3110a2f11dSArnaud de Turckheim  *   6: Slave Read Local Data Parity Check Error Enable
3210a2f11dSArnaud de Turckheim  *   7: Slave Read Local Data Parity Check Error Status
3310a2f11dSArnaud de Turckheim  *   8: Internal PCI Wire Interrupt Enable
3410a2f11dSArnaud de Turckheim  *   9: PCI Express Doorbell Interrupt Enable
3510a2f11dSArnaud de Turckheim  *  10: PCI Abort Interrupt Enable
3610a2f11dSArnaud de Turckheim  *  11: Local Interrupt Input Enable
3710a2f11dSArnaud de Turckheim  *  12: Retry Abort Enable
3810a2f11dSArnaud de Turckheim  *  13: PCI Express Doorbell Interrupt Active
3910a2f11dSArnaud de Turckheim  *  14: PCI Abort Interrupt Active
4010a2f11dSArnaud de Turckheim  *  15: Local Interrupt Input Active
4110a2f11dSArnaud de Turckheim  *  16: Local Interrupt Output Enable
4210a2f11dSArnaud de Turckheim  *  17: Local Doorbell Interrupt Enable
4310a2f11dSArnaud de Turckheim  *  18: DMA Channel 0 Interrupt Enable
4410a2f11dSArnaud de Turckheim  *  19: DMA Channel 1 Interrupt Enable
4510a2f11dSArnaud de Turckheim  *  20: Local Doorbell Interrupt Active
4610a2f11dSArnaud de Turckheim  *  21: DMA Channel 0 Interrupt Active
4710a2f11dSArnaud de Turckheim  *  22: DMA Channel 1 Interrupt Active
4810a2f11dSArnaud de Turckheim  *  23: Built-In Self-Test (BIST) Interrupt Active
4910a2f11dSArnaud de Turckheim  *  24: Direct Master was the Bus Master during a Master or Target Abort
5010a2f11dSArnaud de Turckheim  *  25: DMA Channel 0 was the Bus Master during a Master or Target Abort
5110a2f11dSArnaud de Turckheim  *  26: DMA Channel 1 was the Bus Master during a Master or Target Abort
5210a2f11dSArnaud de Turckheim  *  27: Target Abort after internal 256 consecutive Master Retrys
5310a2f11dSArnaud de Turckheim  *  28: PCI Bus wrote data to LCS_MBOX0
5410a2f11dSArnaud de Turckheim  *  29: PCI Bus wrote data to LCS_MBOX1
5510a2f11dSArnaud de Turckheim  *  30: PCI Bus wrote data to LCS_MBOX2
5610a2f11dSArnaud de Turckheim  *  31: PCI Bus wrote data to LCS_MBOX3
5710a2f11dSArnaud de Turckheim  */
5810a2f11dSArnaud de Turckheim #define PLX_PEX8311_PCI_LCS_INTCSR  0x68
5910a2f11dSArnaud de Turckheim #define INTCSR_INTERNAL_PCI_WIRE    BIT(8)
6010a2f11dSArnaud de Turckheim #define INTCSR_LOCAL_INPUT          BIT(11)
61*1a200a39SWilliam Breathitt Gray #define IDIO_24_ENABLE_IRQ          (INTCSR_INTERNAL_PCI_WIRE | INTCSR_LOCAL_INPUT)
6210a2f11dSArnaud de Turckheim 
63*1a200a39SWilliam Breathitt Gray #define IDIO_24_OUT_BASE 0x0
64*1a200a39SWilliam Breathitt Gray #define IDIO_24_TTLCMOS_OUT_REG 0x3
65*1a200a39SWilliam Breathitt Gray #define IDIO_24_IN_BASE 0x4
66*1a200a39SWilliam Breathitt Gray #define IDIO_24_TTLCMOS_IN_REG 0x7
67*1a200a39SWilliam Breathitt Gray #define IDIO_24_COS_STATUS_BASE 0x8
68*1a200a39SWilliam Breathitt Gray #define IDIO_24_CONTROL_REG 0xC
69*1a200a39SWilliam Breathitt Gray #define IDIO_24_COS_ENABLE 0xE
70*1a200a39SWilliam Breathitt Gray #define IDIO_24_SOFT_RESET 0xF
71*1a200a39SWilliam Breathitt Gray 
72*1a200a39SWilliam Breathitt Gray #define CONTROL_REG_OUT_MODE BIT(1)
73*1a200a39SWilliam Breathitt Gray 
74*1a200a39SWilliam Breathitt Gray #define COS_ENABLE_RISING BIT(1)
75*1a200a39SWilliam Breathitt Gray #define COS_ENABLE_FALLING BIT(4)
76*1a200a39SWilliam Breathitt Gray #define COS_ENABLE_BOTH (COS_ENABLE_RISING | COS_ENABLE_FALLING)
77*1a200a39SWilliam Breathitt Gray 
78*1a200a39SWilliam Breathitt Gray static const struct regmap_config pex8311_intcsr_regmap_config = {
79*1a200a39SWilliam Breathitt Gray 	.name = "pex8311_intcsr",
80*1a200a39SWilliam Breathitt Gray 	.reg_bits = 32,
81*1a200a39SWilliam Breathitt Gray 	.reg_stride = 1,
82*1a200a39SWilliam Breathitt Gray 	.reg_base = PLX_PEX8311_PCI_LCS_INTCSR,
83*1a200a39SWilliam Breathitt Gray 	.val_bits = 32,
84*1a200a39SWilliam Breathitt Gray 	.io_port = true,
85*1a200a39SWilliam Breathitt Gray };
86*1a200a39SWilliam Breathitt Gray 
87*1a200a39SWilliam Breathitt Gray static const struct regmap_range idio_24_wr_ranges[] = {
88*1a200a39SWilliam Breathitt Gray 	regmap_reg_range(0x0, 0x3), regmap_reg_range(0x8, 0xC),
89*1a200a39SWilliam Breathitt Gray 	regmap_reg_range(0xE, 0xF),
90*1a200a39SWilliam Breathitt Gray };
91*1a200a39SWilliam Breathitt Gray static const struct regmap_range idio_24_rd_ranges[] = {
92*1a200a39SWilliam Breathitt Gray 	regmap_reg_range(0x0, 0xC), regmap_reg_range(0xE, 0xF),
93*1a200a39SWilliam Breathitt Gray };
94*1a200a39SWilliam Breathitt Gray static const struct regmap_range idio_24_volatile_ranges[] = {
95*1a200a39SWilliam Breathitt Gray 	regmap_reg_range(0x4, 0xB), regmap_reg_range(0xF, 0xF),
96*1a200a39SWilliam Breathitt Gray };
97*1a200a39SWilliam Breathitt Gray static const struct regmap_access_table idio_24_wr_table = {
98*1a200a39SWilliam Breathitt Gray 	.yes_ranges = idio_24_wr_ranges,
99*1a200a39SWilliam Breathitt Gray 	.n_yes_ranges = ARRAY_SIZE(idio_24_wr_ranges),
100*1a200a39SWilliam Breathitt Gray };
101*1a200a39SWilliam Breathitt Gray static const struct regmap_access_table idio_24_rd_table = {
102*1a200a39SWilliam Breathitt Gray 	.yes_ranges = idio_24_rd_ranges,
103*1a200a39SWilliam Breathitt Gray 	.n_yes_ranges = ARRAY_SIZE(idio_24_rd_ranges),
104*1a200a39SWilliam Breathitt Gray };
105*1a200a39SWilliam Breathitt Gray static const struct regmap_access_table idio_24_volatile_table = {
106*1a200a39SWilliam Breathitt Gray 	.yes_ranges = idio_24_volatile_ranges,
107*1a200a39SWilliam Breathitt Gray 	.n_yes_ranges = ARRAY_SIZE(idio_24_volatile_ranges),
108*1a200a39SWilliam Breathitt Gray };
109*1a200a39SWilliam Breathitt Gray 
110*1a200a39SWilliam Breathitt Gray static const struct regmap_config idio_24_regmap_config = {
111*1a200a39SWilliam Breathitt Gray 	.reg_bits = 8,
112*1a200a39SWilliam Breathitt Gray 	.reg_stride = 1,
113*1a200a39SWilliam Breathitt Gray 	.val_bits = 8,
114*1a200a39SWilliam Breathitt Gray 	.io_port = true,
115*1a200a39SWilliam Breathitt Gray 	.wr_table = &idio_24_wr_table,
116*1a200a39SWilliam Breathitt Gray 	.rd_table = &idio_24_rd_table,
117*1a200a39SWilliam Breathitt Gray 	.volatile_table = &idio_24_volatile_table,
118*1a200a39SWilliam Breathitt Gray 	.cache_type = REGCACHE_FLAT,
119*1a200a39SWilliam Breathitt Gray 	.use_raw_spinlock = true,
120*1a200a39SWilliam Breathitt Gray };
121*1a200a39SWilliam Breathitt Gray 
122*1a200a39SWilliam Breathitt Gray #define IDIO_24_NGPIO_PER_REG 8
123*1a200a39SWilliam Breathitt Gray #define IDIO_24_REGMAP_IRQ(_id)						\
124*1a200a39SWilliam Breathitt Gray 	[24 + _id] = {							\
125*1a200a39SWilliam Breathitt Gray 		.reg_offset = (_id) / IDIO_24_NGPIO_PER_REG,		\
126*1a200a39SWilliam Breathitt Gray 		.mask = BIT((_id) % IDIO_24_NGPIO_PER_REG),		\
127*1a200a39SWilliam Breathitt Gray 		.type = { .types_supported = IRQ_TYPE_EDGE_BOTH },	\
128*1a200a39SWilliam Breathitt Gray 	}
129*1a200a39SWilliam Breathitt Gray #define IDIO_24_IIN_IRQ(_id) IDIO_24_REGMAP_IRQ(_id)
130*1a200a39SWilliam Breathitt Gray #define IDIO_24_TTL_IRQ(_id) IDIO_24_REGMAP_IRQ(24 + _id)
131*1a200a39SWilliam Breathitt Gray 
132*1a200a39SWilliam Breathitt Gray static const struct regmap_irq idio_24_regmap_irqs[] = {
133*1a200a39SWilliam Breathitt Gray 	IDIO_24_IIN_IRQ(0), IDIO_24_IIN_IRQ(1), IDIO_24_IIN_IRQ(2), /* IIN 0-2 */
134*1a200a39SWilliam Breathitt Gray 	IDIO_24_IIN_IRQ(3), IDIO_24_IIN_IRQ(4), IDIO_24_IIN_IRQ(5), /* IIN 3-5 */
135*1a200a39SWilliam Breathitt Gray 	IDIO_24_IIN_IRQ(6), IDIO_24_IIN_IRQ(7), IDIO_24_IIN_IRQ(8), /* IIN 6-8 */
136*1a200a39SWilliam Breathitt Gray 	IDIO_24_IIN_IRQ(9), IDIO_24_IIN_IRQ(10), IDIO_24_IIN_IRQ(11), /* IIN 9-11 */
137*1a200a39SWilliam Breathitt Gray 	IDIO_24_IIN_IRQ(12), IDIO_24_IIN_IRQ(13), IDIO_24_IIN_IRQ(14), /* IIN 12-14 */
138*1a200a39SWilliam Breathitt Gray 	IDIO_24_IIN_IRQ(15), IDIO_24_IIN_IRQ(16), IDIO_24_IIN_IRQ(17), /* IIN 15-17 */
139*1a200a39SWilliam Breathitt Gray 	IDIO_24_IIN_IRQ(18), IDIO_24_IIN_IRQ(19), IDIO_24_IIN_IRQ(20), /* IIN 18-20 */
140*1a200a39SWilliam Breathitt Gray 	IDIO_24_IIN_IRQ(21), IDIO_24_IIN_IRQ(22), IDIO_24_IIN_IRQ(23), /* IIN 21-23 */
141*1a200a39SWilliam Breathitt Gray 	IDIO_24_TTL_IRQ(0), IDIO_24_TTL_IRQ(1), IDIO_24_TTL_IRQ(2), /* TTL 0-2 */
142*1a200a39SWilliam Breathitt Gray 	IDIO_24_TTL_IRQ(3), IDIO_24_TTL_IRQ(4), IDIO_24_TTL_IRQ(5), /* TTL 3-5 */
143*1a200a39SWilliam Breathitt Gray 	IDIO_24_TTL_IRQ(6), IDIO_24_TTL_IRQ(7), /* TTL 6-7 */
14458556204SWilliam Breathitt Gray };
14558556204SWilliam Breathitt Gray 
14658556204SWilliam Breathitt Gray /**
14758556204SWilliam Breathitt Gray  * struct idio_24_gpio - GPIO device private data structure
148*1a200a39SWilliam Breathitt Gray  * @map:	regmap for the device
14958556204SWilliam Breathitt Gray  * @lock:	synchronization lock to prevent I/O race conditions
150*1a200a39SWilliam Breathitt Gray  * @irq_type:	type configuration for IRQs
15158556204SWilliam Breathitt Gray  */
15258556204SWilliam Breathitt Gray struct idio_24_gpio {
153*1a200a39SWilliam Breathitt Gray 	struct regmap *map;
15458556204SWilliam Breathitt Gray 	raw_spinlock_t lock;
155*1a200a39SWilliam Breathitt Gray 	u8 irq_type;
15658556204SWilliam Breathitt Gray };
15758556204SWilliam Breathitt Gray 
idio_24_handle_mask_sync(const int index,const unsigned int mask_buf_def,const unsigned int mask_buf,void * const irq_drv_data)158*1a200a39SWilliam Breathitt Gray static int idio_24_handle_mask_sync(const int index, const unsigned int mask_buf_def,
159*1a200a39SWilliam Breathitt Gray 				    const unsigned int mask_buf, void *const irq_drv_data)
16058556204SWilliam Breathitt Gray {
161*1a200a39SWilliam Breathitt Gray 	const unsigned int type_mask = COS_ENABLE_BOTH << index;
162*1a200a39SWilliam Breathitt Gray 	struct idio_24_gpio *const idio24gpio = irq_drv_data;
163*1a200a39SWilliam Breathitt Gray 	u8 type;
164*1a200a39SWilliam Breathitt Gray 	int ret;
16558556204SWilliam Breathitt Gray 
166*1a200a39SWilliam Breathitt Gray 	raw_spin_lock(&idio24gpio->lock);
16758556204SWilliam Breathitt Gray 
168*1a200a39SWilliam Breathitt Gray 	/* if all are masked, then disable interrupts, else set to type */
169*1a200a39SWilliam Breathitt Gray 	type = (mask_buf == mask_buf_def) ? ~type_mask : idio24gpio->irq_type;
17058556204SWilliam Breathitt Gray 
171*1a200a39SWilliam Breathitt Gray 	ret = regmap_update_bits(idio24gpio->map, IDIO_24_COS_ENABLE, type_mask, type);
172e42615ecSMatti Vaittinen 
173*1a200a39SWilliam Breathitt Gray 	raw_spin_unlock(&idio24gpio->lock);
174*1a200a39SWilliam Breathitt Gray 
175*1a200a39SWilliam Breathitt Gray 	return ret;
17658556204SWilliam Breathitt Gray }
17758556204SWilliam Breathitt Gray 
idio_24_set_type_config(unsigned int ** const buf,const unsigned int type,const struct regmap_irq * const irq_data,const int idx,void * const irq_drv_data)178*1a200a39SWilliam Breathitt Gray static int idio_24_set_type_config(unsigned int **const buf, const unsigned int type,
179*1a200a39SWilliam Breathitt Gray 				   const struct regmap_irq *const irq_data, const int idx,
180*1a200a39SWilliam Breathitt Gray 				   void *const irq_drv_data)
18158556204SWilliam Breathitt Gray {
182*1a200a39SWilliam Breathitt Gray 	const unsigned int offset = irq_data->reg_offset;
183*1a200a39SWilliam Breathitt Gray 	const unsigned int rising = COS_ENABLE_RISING << offset;
184*1a200a39SWilliam Breathitt Gray 	const unsigned int falling = COS_ENABLE_FALLING << offset;
185*1a200a39SWilliam Breathitt Gray 	const unsigned int mask = COS_ENABLE_BOTH << offset;
186*1a200a39SWilliam Breathitt Gray 	struct idio_24_gpio *const idio24gpio = irq_drv_data;
187*1a200a39SWilliam Breathitt Gray 	unsigned int new;
188*1a200a39SWilliam Breathitt Gray 	unsigned int cos_enable;
189*1a200a39SWilliam Breathitt Gray 	int ret;
19058556204SWilliam Breathitt Gray 
191*1a200a39SWilliam Breathitt Gray 	switch (type) {
192*1a200a39SWilliam Breathitt Gray 	case IRQ_TYPE_EDGE_RISING:
193*1a200a39SWilliam Breathitt Gray 		new = rising;
194*1a200a39SWilliam Breathitt Gray 		break;
195*1a200a39SWilliam Breathitt Gray 	case IRQ_TYPE_EDGE_FALLING:
196*1a200a39SWilliam Breathitt Gray 		new = falling;
197*1a200a39SWilliam Breathitt Gray 		break;
198*1a200a39SWilliam Breathitt Gray 	case IRQ_TYPE_EDGE_BOTH:
199*1a200a39SWilliam Breathitt Gray 		new = mask;
200*1a200a39SWilliam Breathitt Gray 		break;
201*1a200a39SWilliam Breathitt Gray 	default:
20258556204SWilliam Breathitt Gray 		return -EINVAL;
203*1a200a39SWilliam Breathitt Gray 	}
20458556204SWilliam Breathitt Gray 
205*1a200a39SWilliam Breathitt Gray 	raw_spin_lock(&idio24gpio->lock);
206*1a200a39SWilliam Breathitt Gray 
207*1a200a39SWilliam Breathitt Gray 	/* replace old bitmap with new bitmap */
208*1a200a39SWilliam Breathitt Gray 	idio24gpio->irq_type = (idio24gpio->irq_type & ~mask) | (new & mask);
209*1a200a39SWilliam Breathitt Gray 
210*1a200a39SWilliam Breathitt Gray 	ret = regmap_read(idio24gpio->map, IDIO_24_COS_ENABLE, &cos_enable);
211*1a200a39SWilliam Breathitt Gray 	if (ret)
212*1a200a39SWilliam Breathitt Gray 		goto exit_unlock;
213*1a200a39SWilliam Breathitt Gray 
214*1a200a39SWilliam Breathitt Gray 	/* if COS is currently enabled then update the edge type */
215*1a200a39SWilliam Breathitt Gray 	if (cos_enable & mask) {
216*1a200a39SWilliam Breathitt Gray 		ret = regmap_update_bits(idio24gpio->map, IDIO_24_COS_ENABLE, mask,
217*1a200a39SWilliam Breathitt Gray 					 idio24gpio->irq_type);
218*1a200a39SWilliam Breathitt Gray 		if (ret)
219*1a200a39SWilliam Breathitt Gray 			goto exit_unlock;
220*1a200a39SWilliam Breathitt Gray 	}
221*1a200a39SWilliam Breathitt Gray 
222*1a200a39SWilliam Breathitt Gray exit_unlock:
223*1a200a39SWilliam Breathitt Gray 	raw_spin_unlock(&idio24gpio->lock);
224*1a200a39SWilliam Breathitt Gray 
225*1a200a39SWilliam Breathitt Gray 	return ret;
226*1a200a39SWilliam Breathitt Gray }
227*1a200a39SWilliam Breathitt Gray 
idio_24_reg_mask_xlate(struct gpio_regmap * const gpio,const unsigned int base,const unsigned int offset,unsigned int * const reg,unsigned int * const mask)228*1a200a39SWilliam Breathitt Gray static int idio_24_reg_mask_xlate(struct gpio_regmap *const gpio, const unsigned int base,
229*1a200a39SWilliam Breathitt Gray 				  const unsigned int offset, unsigned int *const reg,
230*1a200a39SWilliam Breathitt Gray 				  unsigned int *const mask)
231*1a200a39SWilliam Breathitt Gray {
232*1a200a39SWilliam Breathitt Gray 	const unsigned int out_stride = offset / IDIO_24_NGPIO_PER_REG;
233*1a200a39SWilliam Breathitt Gray 	const unsigned int in_stride = (offset - 24) / IDIO_24_NGPIO_PER_REG;
234*1a200a39SWilliam Breathitt Gray 	struct regmap *const map = gpio_regmap_get_drvdata(gpio);
235*1a200a39SWilliam Breathitt Gray 	int err;
236*1a200a39SWilliam Breathitt Gray 	unsigned int ctrl_reg;
237*1a200a39SWilliam Breathitt Gray 
238*1a200a39SWilliam Breathitt Gray 	switch (base) {
239*1a200a39SWilliam Breathitt Gray 	case IDIO_24_OUT_BASE:
240*1a200a39SWilliam Breathitt Gray 		*mask = BIT(offset % IDIO_24_NGPIO_PER_REG);
241*1a200a39SWilliam Breathitt Gray 
242*1a200a39SWilliam Breathitt Gray 		/* FET Outputs */
243*1a200a39SWilliam Breathitt Gray 		if (offset < 24) {
244*1a200a39SWilliam Breathitt Gray 			*reg = IDIO_24_OUT_BASE + out_stride;
24558556204SWilliam Breathitt Gray 			return 0;
24658556204SWilliam Breathitt Gray 		}
24758556204SWilliam Breathitt Gray 
248*1a200a39SWilliam Breathitt Gray 		/* Isolated Inputs */
249*1a200a39SWilliam Breathitt Gray 		if (offset < 48) {
250*1a200a39SWilliam Breathitt Gray 			*reg = IDIO_24_IN_BASE + in_stride;
251*1a200a39SWilliam Breathitt Gray 			return 0;
252*1a200a39SWilliam Breathitt Gray 		}
25358556204SWilliam Breathitt Gray 
254*1a200a39SWilliam Breathitt Gray 		err = regmap_read(map, IDIO_24_CONTROL_REG, &ctrl_reg);
255*1a200a39SWilliam Breathitt Gray 		if (err)
256*1a200a39SWilliam Breathitt Gray 			return err;
25758556204SWilliam Breathitt Gray 
258*1a200a39SWilliam Breathitt Gray 		/* TTL/CMOS Outputs */
259*1a200a39SWilliam Breathitt Gray 		if (ctrl_reg & CONTROL_REG_OUT_MODE) {
260*1a200a39SWilliam Breathitt Gray 			*reg = IDIO_24_TTLCMOS_OUT_REG;
261*1a200a39SWilliam Breathitt Gray 			return 0;
262*1a200a39SWilliam Breathitt Gray 		}
26358556204SWilliam Breathitt Gray 
264*1a200a39SWilliam Breathitt Gray 		/* TTL/CMOS Inputs */
265*1a200a39SWilliam Breathitt Gray 		*reg = IDIO_24_TTLCMOS_IN_REG;
266*1a200a39SWilliam Breathitt Gray 		return 0;
267*1a200a39SWilliam Breathitt Gray 	case IDIO_24_CONTROL_REG:
268*1a200a39SWilliam Breathitt Gray 		/* We can only set direction for TTL/CMOS lines */
269*1a200a39SWilliam Breathitt Gray 		if (offset < 48)
270*1a200a39SWilliam Breathitt Gray 			return -EOPNOTSUPP;
27158556204SWilliam Breathitt Gray 
272*1a200a39SWilliam Breathitt Gray 		*reg = IDIO_24_CONTROL_REG;
273*1a200a39SWilliam Breathitt Gray 		*mask = CONTROL_REG_OUT_MODE;
274*1a200a39SWilliam Breathitt Gray 		return 0;
275*1a200a39SWilliam Breathitt Gray 	default:
276*1a200a39SWilliam Breathitt Gray 		/* Should never reach this path */
277*1a200a39SWilliam Breathitt Gray 		return -EINVAL;
278*1a200a39SWilliam Breathitt Gray 	}
27958556204SWilliam Breathitt Gray }
28058556204SWilliam Breathitt Gray 
28158556204SWilliam Breathitt Gray #define IDIO_24_NGPIO 56
28258556204SWilliam Breathitt Gray static const char *idio_24_names[IDIO_24_NGPIO] = {
28358556204SWilliam Breathitt Gray 	"OUT0", "OUT1", "OUT2", "OUT3", "OUT4", "OUT5", "OUT6", "OUT7",
28458556204SWilliam Breathitt Gray 	"OUT8", "OUT9", "OUT10", "OUT11", "OUT12", "OUT13", "OUT14", "OUT15",
28558556204SWilliam Breathitt Gray 	"OUT16", "OUT17", "OUT18", "OUT19", "OUT20", "OUT21", "OUT22", "OUT23",
28658556204SWilliam Breathitt Gray 	"IIN0", "IIN1", "IIN2", "IIN3", "IIN4", "IIN5", "IIN6", "IIN7",
28758556204SWilliam Breathitt Gray 	"IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15",
28858556204SWilliam Breathitt Gray 	"IIN16", "IIN17", "IIN18", "IIN19", "IIN20", "IIN21", "IIN22", "IIN23",
28958556204SWilliam Breathitt Gray 	"TTL0", "TTL1", "TTL2", "TTL3", "TTL4", "TTL5", "TTL6", "TTL7"
29058556204SWilliam Breathitt Gray };
29158556204SWilliam Breathitt Gray 
idio_24_probe(struct pci_dev * pdev,const struct pci_device_id * id)29258556204SWilliam Breathitt Gray static int idio_24_probe(struct pci_dev *pdev, const struct pci_device_id *id)
29358556204SWilliam Breathitt Gray {
29458556204SWilliam Breathitt Gray 	struct device *const dev = &pdev->dev;
29558556204SWilliam Breathitt Gray 	struct idio_24_gpio *idio24gpio;
29658556204SWilliam Breathitt Gray 	int err;
29710a2f11dSArnaud de Turckheim 	const size_t pci_plx_bar_index = 1;
29858556204SWilliam Breathitt Gray 	const size_t pci_bar_index = 2;
29958556204SWilliam Breathitt Gray 	const char *const name = pci_name(pdev);
300*1a200a39SWilliam Breathitt Gray 	struct gpio_regmap_config gpio_config = {};
301*1a200a39SWilliam Breathitt Gray 	void __iomem *pex8311_regs;
302*1a200a39SWilliam Breathitt Gray 	void __iomem *idio_24_regs;
303*1a200a39SWilliam Breathitt Gray 	struct regmap *intcsr_map;
304*1a200a39SWilliam Breathitt Gray 	struct regmap_irq_chip *chip;
305*1a200a39SWilliam Breathitt Gray 	struct regmap_irq_chip_data *chip_data;
30658556204SWilliam Breathitt Gray 
30758556204SWilliam Breathitt Gray 	err = pcim_enable_device(pdev);
30858556204SWilliam Breathitt Gray 	if (err) {
30958556204SWilliam Breathitt Gray 		dev_err(dev, "Failed to enable PCI device (%d)\n", err);
31058556204SWilliam Breathitt Gray 		return err;
31158556204SWilliam Breathitt Gray 	}
31258556204SWilliam Breathitt Gray 
31310a2f11dSArnaud de Turckheim 	err = pcim_iomap_regions(pdev, BIT(pci_plx_bar_index) | BIT(pci_bar_index), name);
31458556204SWilliam Breathitt Gray 	if (err) {
31558556204SWilliam Breathitt Gray 		dev_err(dev, "Unable to map PCI I/O addresses (%d)\n", err);
31658556204SWilliam Breathitt Gray 		return err;
31758556204SWilliam Breathitt Gray 	}
31858556204SWilliam Breathitt Gray 
319*1a200a39SWilliam Breathitt Gray 	pex8311_regs = pcim_iomap_table(pdev)[pci_plx_bar_index];
320*1a200a39SWilliam Breathitt Gray 	idio_24_regs = pcim_iomap_table(pdev)[pci_bar_index];
32158556204SWilliam Breathitt Gray 
322*1a200a39SWilliam Breathitt Gray 	intcsr_map = devm_regmap_init_mmio(dev, pex8311_regs, &pex8311_intcsr_regmap_config);
323*1a200a39SWilliam Breathitt Gray 	if (IS_ERR(intcsr_map))
324*1a200a39SWilliam Breathitt Gray 		return dev_err_probe(dev, PTR_ERR(intcsr_map),
325*1a200a39SWilliam Breathitt Gray 				     "Unable to initialize PEX8311 register map\n");
32658556204SWilliam Breathitt Gray 
327*1a200a39SWilliam Breathitt Gray 	idio24gpio = devm_kzalloc(dev, sizeof(*idio24gpio), GFP_KERNEL);
328*1a200a39SWilliam Breathitt Gray 	if (!idio24gpio)
329*1a200a39SWilliam Breathitt Gray 		return -ENOMEM;
330*1a200a39SWilliam Breathitt Gray 
331*1a200a39SWilliam Breathitt Gray 	idio24gpio->map = devm_regmap_init_mmio(dev, idio_24_regs, &idio_24_regmap_config);
332*1a200a39SWilliam Breathitt Gray 	if (IS_ERR(idio24gpio->map))
333*1a200a39SWilliam Breathitt Gray 		return dev_err_probe(dev, PTR_ERR(idio24gpio->map),
334*1a200a39SWilliam Breathitt Gray 				     "Unable to initialize register map\n");
335866e863eSLinus Walleij 
33658556204SWilliam Breathitt Gray 	raw_spin_lock_init(&idio24gpio->lock);
33758556204SWilliam Breathitt Gray 
338*1a200a39SWilliam Breathitt Gray 	/* Initialize all IRQ type configuration to IRQ_TYPE_EDGE_BOTH */
339*1a200a39SWilliam Breathitt Gray 	idio24gpio->irq_type = GENMASK(7, 0);
340*1a200a39SWilliam Breathitt Gray 
341*1a200a39SWilliam Breathitt Gray 	chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
342*1a200a39SWilliam Breathitt Gray 	if (!chip)
343*1a200a39SWilliam Breathitt Gray 		return -ENOMEM;
344*1a200a39SWilliam Breathitt Gray 
345*1a200a39SWilliam Breathitt Gray 	chip->name = name;
346*1a200a39SWilliam Breathitt Gray 	chip->status_base = IDIO_24_COS_STATUS_BASE;
347*1a200a39SWilliam Breathitt Gray 	chip->mask_base = IDIO_24_COS_ENABLE;
348*1a200a39SWilliam Breathitt Gray 	chip->ack_base = IDIO_24_COS_STATUS_BASE;
349*1a200a39SWilliam Breathitt Gray 	chip->num_regs = 4;
350*1a200a39SWilliam Breathitt Gray 	chip->irqs = idio_24_regmap_irqs;
351*1a200a39SWilliam Breathitt Gray 	chip->num_irqs = ARRAY_SIZE(idio_24_regmap_irqs);
352*1a200a39SWilliam Breathitt Gray 	chip->handle_mask_sync = idio_24_handle_mask_sync;
353*1a200a39SWilliam Breathitt Gray 	chip->set_type_config = idio_24_set_type_config;
354*1a200a39SWilliam Breathitt Gray 	chip->irq_drv_data = idio24gpio;
355*1a200a39SWilliam Breathitt Gray 
35658556204SWilliam Breathitt Gray 	/* Software board reset */
357*1a200a39SWilliam Breathitt Gray 	err = regmap_write(idio24gpio->map, IDIO_24_SOFT_RESET, 0);
358*1a200a39SWilliam Breathitt Gray 	if (err)
359*1a200a39SWilliam Breathitt Gray 		return err;
36010a2f11dSArnaud de Turckheim 	/*
36110a2f11dSArnaud de Turckheim 	 * enable PLX PEX8311 internal PCI wire interrupt and local interrupt
36210a2f11dSArnaud de Turckheim 	 * input
36310a2f11dSArnaud de Turckheim 	 */
364*1a200a39SWilliam Breathitt Gray 	err = regmap_update_bits(intcsr_map, 0x0, IDIO_24_ENABLE_IRQ, IDIO_24_ENABLE_IRQ);
365*1a200a39SWilliam Breathitt Gray 	if (err)
36658556204SWilliam Breathitt Gray 		return err;
36758556204SWilliam Breathitt Gray 
368*1a200a39SWilliam Breathitt Gray 	err = devm_regmap_add_irq_chip(dev, idio24gpio->map, pdev->irq, 0, 0, chip, &chip_data);
369*1a200a39SWilliam Breathitt Gray 	if (err)
370*1a200a39SWilliam Breathitt Gray 		return dev_err_probe(dev, err, "IRQ registration failed\n");
37158556204SWilliam Breathitt Gray 
372*1a200a39SWilliam Breathitt Gray 	gpio_config.parent = dev;
373*1a200a39SWilliam Breathitt Gray 	gpio_config.regmap = idio24gpio->map;
374*1a200a39SWilliam Breathitt Gray 	gpio_config.ngpio = IDIO_24_NGPIO;
375*1a200a39SWilliam Breathitt Gray 	gpio_config.names = idio_24_names;
376*1a200a39SWilliam Breathitt Gray 	gpio_config.reg_dat_base = GPIO_REGMAP_ADDR(IDIO_24_OUT_BASE);
377*1a200a39SWilliam Breathitt Gray 	gpio_config.reg_set_base = GPIO_REGMAP_ADDR(IDIO_24_OUT_BASE);
378*1a200a39SWilliam Breathitt Gray 	gpio_config.reg_dir_out_base = GPIO_REGMAP_ADDR(IDIO_24_CONTROL_REG);
379*1a200a39SWilliam Breathitt Gray 	gpio_config.ngpio_per_reg = IDIO_24_NGPIO_PER_REG;
380*1a200a39SWilliam Breathitt Gray 	gpio_config.irq_domain = regmap_irq_get_domain(chip_data);
381*1a200a39SWilliam Breathitt Gray 	gpio_config.reg_mask_xlate = idio_24_reg_mask_xlate;
382*1a200a39SWilliam Breathitt Gray 	gpio_config.drvdata = idio24gpio->map;
383*1a200a39SWilliam Breathitt Gray 
384*1a200a39SWilliam Breathitt Gray 	return PTR_ERR_OR_ZERO(devm_gpio_regmap_register(dev, &gpio_config));
38558556204SWilliam Breathitt Gray }
38658556204SWilliam Breathitt Gray 
38758556204SWilliam Breathitt Gray static const struct pci_device_id idio_24_pci_dev_id[] = {
38858556204SWilliam Breathitt Gray 	{ PCI_DEVICE(0x494F, 0x0FD0) }, { PCI_DEVICE(0x494F, 0x0BD0) },
38958556204SWilliam Breathitt Gray 	{ PCI_DEVICE(0x494F, 0x07D0) }, { PCI_DEVICE(0x494F, 0x0FC0) },
39058556204SWilliam Breathitt Gray 	{ 0 }
39158556204SWilliam Breathitt Gray };
39258556204SWilliam Breathitt Gray MODULE_DEVICE_TABLE(pci, idio_24_pci_dev_id);
39358556204SWilliam Breathitt Gray 
39458556204SWilliam Breathitt Gray static struct pci_driver idio_24_driver = {
39558556204SWilliam Breathitt Gray 	.name = "pcie-idio-24",
39658556204SWilliam Breathitt Gray 	.id_table = idio_24_pci_dev_id,
39758556204SWilliam Breathitt Gray 	.probe = idio_24_probe
39858556204SWilliam Breathitt Gray };
39958556204SWilliam Breathitt Gray 
40058556204SWilliam Breathitt Gray module_pci_driver(idio_24_driver);
40158556204SWilliam Breathitt Gray 
40258556204SWilliam Breathitt Gray MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
40358556204SWilliam Breathitt Gray MODULE_DESCRIPTION("ACCES PCIe-IDIO-24 GPIO driver");
40458556204SWilliam Breathitt Gray MODULE_LICENSE("GPL v2");
405