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