Loading...
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * GPIO driver for the ACCES PCIe-IDIO-24 family
4 * Copyright (C) 2018 William Breathitt Gray
5 *
6 * This driver supports the following ACCES devices: PCIe-IDIO-24,
7 * PCIe-IDI-24, PCIe-IDO-24, and PCIe-IDIO-12.
8 */
9#include <linux/bits.h>
10#include <linux/device.h>
11#include <linux/err.h>
12#include <linux/gpio/regmap.h>
13#include <linux/irq.h>
14#include <linux/kernel.h>
15#include <linux/module.h>
16#include <linux/pci.h>
17#include <linux/regmap.h>
18#include <linux/spinlock.h>
19#include <linux/types.h>
20
21/*
22 * PLX PEX8311 PCI LCS_INTCSR Interrupt Control/Status
23 *
24 * Bit: Description
25 * 0: Enable Interrupt Sources (Bit 0)
26 * 1: Enable Interrupt Sources (Bit 1)
27 * 2: Generate Internal PCI Bus Internal SERR# Interrupt
28 * 3: Mailbox Interrupt Enable
29 * 4: Power Management Interrupt Enable
30 * 5: Power Management Interrupt
31 * 6: Slave Read Local Data Parity Check Error Enable
32 * 7: Slave Read Local Data Parity Check Error Status
33 * 8: Internal PCI Wire Interrupt Enable
34 * 9: PCI Express Doorbell Interrupt Enable
35 * 10: PCI Abort Interrupt Enable
36 * 11: Local Interrupt Input Enable
37 * 12: Retry Abort Enable
38 * 13: PCI Express Doorbell Interrupt Active
39 * 14: PCI Abort Interrupt Active
40 * 15: Local Interrupt Input Active
41 * 16: Local Interrupt Output Enable
42 * 17: Local Doorbell Interrupt Enable
43 * 18: DMA Channel 0 Interrupt Enable
44 * 19: DMA Channel 1 Interrupt Enable
45 * 20: Local Doorbell Interrupt Active
46 * 21: DMA Channel 0 Interrupt Active
47 * 22: DMA Channel 1 Interrupt Active
48 * 23: Built-In Self-Test (BIST) Interrupt Active
49 * 24: Direct Master was the Bus Master during a Master or Target Abort
50 * 25: DMA Channel 0 was the Bus Master during a Master or Target Abort
51 * 26: DMA Channel 1 was the Bus Master during a Master or Target Abort
52 * 27: Target Abort after internal 256 consecutive Master Retrys
53 * 28: PCI Bus wrote data to LCS_MBOX0
54 * 29: PCI Bus wrote data to LCS_MBOX1
55 * 30: PCI Bus wrote data to LCS_MBOX2
56 * 31: PCI Bus wrote data to LCS_MBOX3
57 */
58#define PLX_PEX8311_PCI_LCS_INTCSR 0x68
59#define INTCSR_INTERNAL_PCI_WIRE BIT(8)
60#define INTCSR_LOCAL_INPUT BIT(11)
61#define IDIO_24_ENABLE_IRQ (INTCSR_INTERNAL_PCI_WIRE | INTCSR_LOCAL_INPUT)
62
63#define IDIO_24_OUT_BASE 0x0
64#define IDIO_24_TTLCMOS_OUT_REG 0x3
65#define IDIO_24_IN_BASE 0x4
66#define IDIO_24_TTLCMOS_IN_REG 0x7
67#define IDIO_24_COS_STATUS_BASE 0x8
68#define IDIO_24_CONTROL_REG 0xC
69#define IDIO_24_COS_ENABLE 0xE
70#define IDIO_24_SOFT_RESET 0xF
71
72#define CONTROL_REG_OUT_MODE BIT(1)
73
74#define COS_ENABLE_RISING BIT(1)
75#define COS_ENABLE_FALLING BIT(4)
76#define COS_ENABLE_BOTH (COS_ENABLE_RISING | COS_ENABLE_FALLING)
77
78static const struct regmap_config pex8311_intcsr_regmap_config = {
79 .name = "pex8311_intcsr",
80 .reg_bits = 32,
81 .reg_stride = 1,
82 .reg_base = PLX_PEX8311_PCI_LCS_INTCSR,
83 .val_bits = 32,
84 .io_port = true,
85};
86
87static const struct regmap_range idio_24_wr_ranges[] = {
88 regmap_reg_range(0x0, 0x3), regmap_reg_range(0x8, 0xC),
89 regmap_reg_range(0xE, 0xF),
90};
91static const struct regmap_range idio_24_rd_ranges[] = {
92 regmap_reg_range(0x0, 0xC), regmap_reg_range(0xE, 0xF),
93};
94static const struct regmap_range idio_24_volatile_ranges[] = {
95 regmap_reg_range(0x4, 0xB), regmap_reg_range(0xF, 0xF),
96};
97static const struct regmap_access_table idio_24_wr_table = {
98 .yes_ranges = idio_24_wr_ranges,
99 .n_yes_ranges = ARRAY_SIZE(idio_24_wr_ranges),
100};
101static const struct regmap_access_table idio_24_rd_table = {
102 .yes_ranges = idio_24_rd_ranges,
103 .n_yes_ranges = ARRAY_SIZE(idio_24_rd_ranges),
104};
105static const struct regmap_access_table idio_24_volatile_table = {
106 .yes_ranges = idio_24_volatile_ranges,
107 .n_yes_ranges = ARRAY_SIZE(idio_24_volatile_ranges),
108};
109
110static const struct regmap_config idio_24_regmap_config = {
111 .reg_bits = 8,
112 .reg_stride = 1,
113 .val_bits = 8,
114 .io_port = true,
115 .wr_table = &idio_24_wr_table,
116 .rd_table = &idio_24_rd_table,
117 .volatile_table = &idio_24_volatile_table,
118 .cache_type = REGCACHE_FLAT,
119 .use_raw_spinlock = true,
120};
121
122#define IDIO_24_NGPIO_PER_REG 8
123#define IDIO_24_REGMAP_IRQ(_id) \
124 [24 + _id] = { \
125 .reg_offset = (_id) / IDIO_24_NGPIO_PER_REG, \
126 .mask = BIT((_id) % IDIO_24_NGPIO_PER_REG), \
127 .type = { .types_supported = IRQ_TYPE_EDGE_BOTH }, \
128 }
129#define IDIO_24_IIN_IRQ(_id) IDIO_24_REGMAP_IRQ(_id)
130#define IDIO_24_TTL_IRQ(_id) IDIO_24_REGMAP_IRQ(24 + _id)
131
132static const struct regmap_irq idio_24_regmap_irqs[] = {
133 IDIO_24_IIN_IRQ(0), IDIO_24_IIN_IRQ(1), IDIO_24_IIN_IRQ(2), /* IIN 0-2 */
134 IDIO_24_IIN_IRQ(3), IDIO_24_IIN_IRQ(4), IDIO_24_IIN_IRQ(5), /* IIN 3-5 */
135 IDIO_24_IIN_IRQ(6), IDIO_24_IIN_IRQ(7), IDIO_24_IIN_IRQ(8), /* IIN 6-8 */
136 IDIO_24_IIN_IRQ(9), IDIO_24_IIN_IRQ(10), IDIO_24_IIN_IRQ(11), /* IIN 9-11 */
137 IDIO_24_IIN_IRQ(12), IDIO_24_IIN_IRQ(13), IDIO_24_IIN_IRQ(14), /* IIN 12-14 */
138 IDIO_24_IIN_IRQ(15), IDIO_24_IIN_IRQ(16), IDIO_24_IIN_IRQ(17), /* IIN 15-17 */
139 IDIO_24_IIN_IRQ(18), IDIO_24_IIN_IRQ(19), IDIO_24_IIN_IRQ(20), /* IIN 18-20 */
140 IDIO_24_IIN_IRQ(21), IDIO_24_IIN_IRQ(22), IDIO_24_IIN_IRQ(23), /* IIN 21-23 */
141 IDIO_24_TTL_IRQ(0), IDIO_24_TTL_IRQ(1), IDIO_24_TTL_IRQ(2), /* TTL 0-2 */
142 IDIO_24_TTL_IRQ(3), IDIO_24_TTL_IRQ(4), IDIO_24_TTL_IRQ(5), /* TTL 3-5 */
143 IDIO_24_TTL_IRQ(6), IDIO_24_TTL_IRQ(7), /* TTL 6-7 */
144};
145
146/**
147 * struct idio_24_gpio - GPIO device private data structure
148 * @map: regmap for the device
149 * @lock: synchronization lock to prevent I/O race conditions
150 * @irq_type: type configuration for IRQs
151 */
152struct idio_24_gpio {
153 struct regmap *map;
154 raw_spinlock_t lock;
155 u8 irq_type;
156};
157
158static int idio_24_handle_mask_sync(const int index, const unsigned int mask_buf_def,
159 const unsigned int mask_buf, void *const irq_drv_data)
160{
161 const unsigned int type_mask = COS_ENABLE_BOTH << index;
162 struct idio_24_gpio *const idio24gpio = irq_drv_data;
163 u8 type;
164 int ret;
165
166 raw_spin_lock(&idio24gpio->lock);
167
168 /* if all are masked, then disable interrupts, else set to type */
169 type = (mask_buf == mask_buf_def) ? ~type_mask : idio24gpio->irq_type;
170
171 ret = regmap_update_bits(idio24gpio->map, IDIO_24_COS_ENABLE, type_mask, type);
172
173 raw_spin_unlock(&idio24gpio->lock);
174
175 return ret;
176}
177
178static int idio_24_set_type_config(unsigned int **const buf, const unsigned int type,
179 const struct regmap_irq *const irq_data, const int idx,
180 void *const irq_drv_data)
181{
182 const unsigned int offset = irq_data->reg_offset;
183 const unsigned int rising = COS_ENABLE_RISING << offset;
184 const unsigned int falling = COS_ENABLE_FALLING << offset;
185 const unsigned int mask = COS_ENABLE_BOTH << offset;
186 struct idio_24_gpio *const idio24gpio = irq_drv_data;
187 unsigned int new;
188 unsigned int cos_enable;
189 int ret;
190
191 switch (type) {
192 case IRQ_TYPE_EDGE_RISING:
193 new = rising;
194 break;
195 case IRQ_TYPE_EDGE_FALLING:
196 new = falling;
197 break;
198 case IRQ_TYPE_EDGE_BOTH:
199 new = mask;
200 break;
201 default:
202 return -EINVAL;
203 }
204
205 raw_spin_lock(&idio24gpio->lock);
206
207 /* replace old bitmap with new bitmap */
208 idio24gpio->irq_type = (idio24gpio->irq_type & ~mask) | (new & mask);
209
210 ret = regmap_read(idio24gpio->map, IDIO_24_COS_ENABLE, &cos_enable);
211 if (ret)
212 goto exit_unlock;
213
214 /* if COS is currently enabled then update the edge type */
215 if (cos_enable & mask) {
216 ret = regmap_update_bits(idio24gpio->map, IDIO_24_COS_ENABLE, mask,
217 idio24gpio->irq_type);
218 if (ret)
219 goto exit_unlock;
220 }
221
222exit_unlock:
223 raw_spin_unlock(&idio24gpio->lock);
224
225 return ret;
226}
227
228static int idio_24_reg_mask_xlate(struct gpio_regmap *const gpio, const unsigned int base,
229 const unsigned int offset, unsigned int *const reg,
230 unsigned int *const mask)
231{
232 const unsigned int out_stride = offset / IDIO_24_NGPIO_PER_REG;
233 const unsigned int in_stride = (offset - 24) / IDIO_24_NGPIO_PER_REG;
234 struct regmap *const map = gpio_regmap_get_drvdata(gpio);
235 int err;
236 unsigned int ctrl_reg;
237
238 switch (base) {
239 case IDIO_24_OUT_BASE:
240 *mask = BIT(offset % IDIO_24_NGPIO_PER_REG);
241
242 /* FET Outputs */
243 if (offset < 24) {
244 *reg = IDIO_24_OUT_BASE + out_stride;
245 return 0;
246 }
247
248 /* Isolated Inputs */
249 if (offset < 48) {
250 *reg = IDIO_24_IN_BASE + in_stride;
251 return 0;
252 }
253
254 err = regmap_read(map, IDIO_24_CONTROL_REG, &ctrl_reg);
255 if (err)
256 return err;
257
258 /* TTL/CMOS Outputs */
259 if (ctrl_reg & CONTROL_REG_OUT_MODE) {
260 *reg = IDIO_24_TTLCMOS_OUT_REG;
261 return 0;
262 }
263
264 /* TTL/CMOS Inputs */
265 *reg = IDIO_24_TTLCMOS_IN_REG;
266 return 0;
267 case IDIO_24_CONTROL_REG:
268 /* We can only set direction for TTL/CMOS lines */
269 if (offset < 48)
270 return -EOPNOTSUPP;
271
272 *reg = IDIO_24_CONTROL_REG;
273 *mask = CONTROL_REG_OUT_MODE;
274 return 0;
275 default:
276 /* Should never reach this path */
277 return -EINVAL;
278 }
279}
280
281#define IDIO_24_NGPIO 56
282static const char *idio_24_names[IDIO_24_NGPIO] = {
283 "OUT0", "OUT1", "OUT2", "OUT3", "OUT4", "OUT5", "OUT6", "OUT7",
284 "OUT8", "OUT9", "OUT10", "OUT11", "OUT12", "OUT13", "OUT14", "OUT15",
285 "OUT16", "OUT17", "OUT18", "OUT19", "OUT20", "OUT21", "OUT22", "OUT23",
286 "IIN0", "IIN1", "IIN2", "IIN3", "IIN4", "IIN5", "IIN6", "IIN7",
287 "IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15",
288 "IIN16", "IIN17", "IIN18", "IIN19", "IIN20", "IIN21", "IIN22", "IIN23",
289 "TTL0", "TTL1", "TTL2", "TTL3", "TTL4", "TTL5", "TTL6", "TTL7"
290};
291
292static int idio_24_probe(struct pci_dev *pdev, const struct pci_device_id *id)
293{
294 struct device *const dev = &pdev->dev;
295 struct idio_24_gpio *idio24gpio;
296 int err;
297 const size_t pci_plx_bar_index = 1;
298 const size_t pci_bar_index = 2;
299 const char *const name = pci_name(pdev);
300 struct gpio_regmap_config gpio_config = {};
301 void __iomem *pex8311_regs;
302 void __iomem *idio_24_regs;
303 struct regmap *intcsr_map;
304 struct regmap_irq_chip *chip;
305 struct regmap_irq_chip_data *chip_data;
306
307 err = pcim_enable_device(pdev);
308 if (err) {
309 dev_err(dev, "Failed to enable PCI device (%d)\n", err);
310 return err;
311 }
312
313 err = pcim_iomap_regions(pdev, BIT(pci_plx_bar_index) | BIT(pci_bar_index), name);
314 if (err) {
315 dev_err(dev, "Unable to map PCI I/O addresses (%d)\n", err);
316 return err;
317 }
318
319 pex8311_regs = pcim_iomap_table(pdev)[pci_plx_bar_index];
320 idio_24_regs = pcim_iomap_table(pdev)[pci_bar_index];
321
322 intcsr_map = devm_regmap_init_mmio(dev, pex8311_regs, &pex8311_intcsr_regmap_config);
323 if (IS_ERR(intcsr_map))
324 return dev_err_probe(dev, PTR_ERR(intcsr_map),
325 "Unable to initialize PEX8311 register map\n");
326
327 idio24gpio = devm_kzalloc(dev, sizeof(*idio24gpio), GFP_KERNEL);
328 if (!idio24gpio)
329 return -ENOMEM;
330
331 idio24gpio->map = devm_regmap_init_mmio(dev, idio_24_regs, &idio_24_regmap_config);
332 if (IS_ERR(idio24gpio->map))
333 return dev_err_probe(dev, PTR_ERR(idio24gpio->map),
334 "Unable to initialize register map\n");
335
336 raw_spin_lock_init(&idio24gpio->lock);
337
338 /* Initialize all IRQ type configuration to IRQ_TYPE_EDGE_BOTH */
339 idio24gpio->irq_type = GENMASK(7, 0);
340
341 chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
342 if (!chip)
343 return -ENOMEM;
344
345 chip->name = name;
346 chip->status_base = IDIO_24_COS_STATUS_BASE;
347 chip->mask_base = IDIO_24_COS_ENABLE;
348 chip->ack_base = IDIO_24_COS_STATUS_BASE;
349 chip->num_regs = 4;
350 chip->irqs = idio_24_regmap_irqs;
351 chip->num_irqs = ARRAY_SIZE(idio_24_regmap_irqs);
352 chip->handle_mask_sync = idio_24_handle_mask_sync;
353 chip->set_type_config = idio_24_set_type_config;
354 chip->irq_drv_data = idio24gpio;
355
356 /* Software board reset */
357 err = regmap_write(idio24gpio->map, IDIO_24_SOFT_RESET, 0);
358 if (err)
359 return err;
360 /*
361 * enable PLX PEX8311 internal PCI wire interrupt and local interrupt
362 * input
363 */
364 err = regmap_update_bits(intcsr_map, 0x0, IDIO_24_ENABLE_IRQ, IDIO_24_ENABLE_IRQ);
365 if (err)
366 return err;
367
368 err = devm_regmap_add_irq_chip(dev, idio24gpio->map, pdev->irq, 0, 0, chip, &chip_data);
369 if (err)
370 return dev_err_probe(dev, err, "IRQ registration failed\n");
371
372 gpio_config.parent = dev;
373 gpio_config.regmap = idio24gpio->map;
374 gpio_config.ngpio = IDIO_24_NGPIO;
375 gpio_config.names = idio_24_names;
376 gpio_config.reg_dat_base = GPIO_REGMAP_ADDR(IDIO_24_OUT_BASE);
377 gpio_config.reg_set_base = GPIO_REGMAP_ADDR(IDIO_24_OUT_BASE);
378 gpio_config.reg_dir_out_base = GPIO_REGMAP_ADDR(IDIO_24_CONTROL_REG);
379 gpio_config.ngpio_per_reg = IDIO_24_NGPIO_PER_REG;
380 gpio_config.irq_domain = regmap_irq_get_domain(chip_data);
381 gpio_config.reg_mask_xlate = idio_24_reg_mask_xlate;
382 gpio_config.drvdata = idio24gpio->map;
383
384 return PTR_ERR_OR_ZERO(devm_gpio_regmap_register(dev, &gpio_config));
385}
386
387static const struct pci_device_id idio_24_pci_dev_id[] = {
388 { PCI_DEVICE(0x494F, 0x0FD0) }, { PCI_DEVICE(0x494F, 0x0BD0) },
389 { PCI_DEVICE(0x494F, 0x07D0) }, { PCI_DEVICE(0x494F, 0x0FC0) },
390 { 0 }
391};
392MODULE_DEVICE_TABLE(pci, idio_24_pci_dev_id);
393
394static struct pci_driver idio_24_driver = {
395 .name = "pcie-idio-24",
396 .id_table = idio_24_pci_dev_id,
397 .probe = idio_24_probe
398};
399
400module_pci_driver(idio_24_driver);
401
402MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
403MODULE_DESCRIPTION("ACCES PCIe-IDIO-24 GPIO driver");
404MODULE_LICENSE("GPL v2");
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * GPIO driver for the ACCES PCIe-IDIO-24 family
4 * Copyright (C) 2018 William Breathitt Gray
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License, version 2, as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * This driver supports the following ACCES devices: PCIe-IDIO-24,
16 * PCIe-IDI-24, PCIe-IDO-24, and PCIe-IDIO-12.
17 */
18#include <linux/bitmap.h>
19#include <linux/bitops.h>
20#include <linux/device.h>
21#include <linux/errno.h>
22#include <linux/gpio/driver.h>
23#include <linux/interrupt.h>
24#include <linux/irqdesc.h>
25#include <linux/kernel.h>
26#include <linux/module.h>
27#include <linux/pci.h>
28#include <linux/spinlock.h>
29#include <linux/types.h>
30
31/**
32 * struct idio_24_gpio_reg - GPIO device registers structure
33 * @out0_7: Read: FET Outputs 0-7
34 * Write: FET Outputs 0-7
35 * @out8_15: Read: FET Outputs 8-15
36 * Write: FET Outputs 8-15
37 * @out16_23: Read: FET Outputs 16-23
38 * Write: FET Outputs 16-23
39 * @ttl_out0_7: Read: TTL/CMOS Outputs 0-7
40 * Write: TTL/CMOS Outputs 0-7
41 * @in0_7: Read: Isolated Inputs 0-7
42 * Write: Reserved
43 * @in8_15: Read: Isolated Inputs 8-15
44 * Write: Reserved
45 * @in16_23: Read: Isolated Inputs 16-23
46 * Write: Reserved
47 * @ttl_in0_7: Read: TTL/CMOS Inputs 0-7
48 * Write: Reserved
49 * @cos0_7: Read: COS Status Inputs 0-7
50 * Write: COS Clear Inputs 0-7
51 * @cos8_15: Read: COS Status Inputs 8-15
52 * Write: COS Clear Inputs 8-15
53 * @cos16_23: Read: COS Status Inputs 16-23
54 * Write: COS Clear Inputs 16-23
55 * @cos_ttl0_7: Read: COS Status TTL/CMOS 0-7
56 * Write: COS Clear TTL/CMOS 0-7
57 * @ctl: Read: Control Register
58 * Write: Control Register
59 * @reserved: Read: Reserved
60 * Write: Reserved
61 * @cos_enable: Read: COS Enable
62 * Write: COS Enable
63 * @soft_reset: Read: IRQ Output Pin Status
64 * Write: Software Board Reset
65 */
66struct idio_24_gpio_reg {
67 u8 out0_7;
68 u8 out8_15;
69 u8 out16_23;
70 u8 ttl_out0_7;
71 u8 in0_7;
72 u8 in8_15;
73 u8 in16_23;
74 u8 ttl_in0_7;
75 u8 cos0_7;
76 u8 cos8_15;
77 u8 cos16_23;
78 u8 cos_ttl0_7;
79 u8 ctl;
80 u8 reserved;
81 u8 cos_enable;
82 u8 soft_reset;
83};
84
85/**
86 * struct idio_24_gpio - GPIO device private data structure
87 * @chip: instance of the gpio_chip
88 * @lock: synchronization lock to prevent I/O race conditions
89 * @reg: I/O address offset for the GPIO device registers
90 * @irq_mask: I/O bits affected by interrupts
91 */
92struct idio_24_gpio {
93 struct gpio_chip chip;
94 raw_spinlock_t lock;
95 struct idio_24_gpio_reg __iomem *reg;
96 unsigned long irq_mask;
97};
98
99static int idio_24_gpio_get_direction(struct gpio_chip *chip,
100 unsigned int offset)
101{
102 struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
103 const unsigned long out_mode_mask = BIT(1);
104
105 /* FET Outputs */
106 if (offset < 24)
107 return 0;
108
109 /* Isolated Inputs */
110 if (offset < 48)
111 return 1;
112
113 /* TTL/CMOS I/O */
114 /* OUT MODE = 1 when TTL/CMOS Output Mode is set */
115 return !(ioread8(&idio24gpio->reg->ctl) & out_mode_mask);
116}
117
118static int idio_24_gpio_direction_input(struct gpio_chip *chip,
119 unsigned int offset)
120{
121 struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
122 unsigned long flags;
123 unsigned int ctl_state;
124 const unsigned long out_mode_mask = BIT(1);
125
126 /* TTL/CMOS I/O */
127 if (offset > 47) {
128 raw_spin_lock_irqsave(&idio24gpio->lock, flags);
129
130 /* Clear TTL/CMOS Output Mode */
131 ctl_state = ioread8(&idio24gpio->reg->ctl) & ~out_mode_mask;
132 iowrite8(ctl_state, &idio24gpio->reg->ctl);
133
134 raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
135 }
136
137 return 0;
138}
139
140static int idio_24_gpio_direction_output(struct gpio_chip *chip,
141 unsigned int offset, int value)
142{
143 struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
144 unsigned long flags;
145 unsigned int ctl_state;
146 const unsigned long out_mode_mask = BIT(1);
147
148 /* TTL/CMOS I/O */
149 if (offset > 47) {
150 raw_spin_lock_irqsave(&idio24gpio->lock, flags);
151
152 /* Set TTL/CMOS Output Mode */
153 ctl_state = ioread8(&idio24gpio->reg->ctl) | out_mode_mask;
154 iowrite8(ctl_state, &idio24gpio->reg->ctl);
155
156 raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
157 }
158
159 chip->set(chip, offset, value);
160 return 0;
161}
162
163static int idio_24_gpio_get(struct gpio_chip *chip, unsigned int offset)
164{
165 struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
166 const unsigned long offset_mask = BIT(offset % 8);
167 const unsigned long out_mode_mask = BIT(1);
168
169 /* FET Outputs */
170 if (offset < 8)
171 return !!(ioread8(&idio24gpio->reg->out0_7) & offset_mask);
172
173 if (offset < 16)
174 return !!(ioread8(&idio24gpio->reg->out8_15) & offset_mask);
175
176 if (offset < 24)
177 return !!(ioread8(&idio24gpio->reg->out16_23) & offset_mask);
178
179 /* Isolated Inputs */
180 if (offset < 32)
181 return !!(ioread8(&idio24gpio->reg->in0_7) & offset_mask);
182
183 if (offset < 40)
184 return !!(ioread8(&idio24gpio->reg->in8_15) & offset_mask);
185
186 if (offset < 48)
187 return !!(ioread8(&idio24gpio->reg->in16_23) & offset_mask);
188
189 /* TTL/CMOS Outputs */
190 if (ioread8(&idio24gpio->reg->ctl) & out_mode_mask)
191 return !!(ioread8(&idio24gpio->reg->ttl_out0_7) & offset_mask);
192
193 /* TTL/CMOS Inputs */
194 return !!(ioread8(&idio24gpio->reg->ttl_in0_7) & offset_mask);
195}
196
197static int idio_24_gpio_get_multiple(struct gpio_chip *chip,
198 unsigned long *mask, unsigned long *bits)
199{
200 struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
201 size_t i;
202 const unsigned int gpio_reg_size = 8;
203 unsigned int bits_offset;
204 size_t word_index;
205 unsigned int word_offset;
206 unsigned long word_mask;
207 const unsigned long port_mask = GENMASK(gpio_reg_size - 1, 0);
208 unsigned long port_state;
209 void __iomem *ports[] = {
210 &idio24gpio->reg->out0_7, &idio24gpio->reg->out8_15,
211 &idio24gpio->reg->out16_23, &idio24gpio->reg->in0_7,
212 &idio24gpio->reg->in8_15, &idio24gpio->reg->in16_23,
213 };
214 const unsigned long out_mode_mask = BIT(1);
215
216 /* clear bits array to a clean slate */
217 bitmap_zero(bits, chip->ngpio);
218
219 /* get bits are evaluated a gpio port register at a time */
220 for (i = 0; i < ARRAY_SIZE(ports) + 1; i++) {
221 /* gpio offset in bits array */
222 bits_offset = i * gpio_reg_size;
223
224 /* word index for bits array */
225 word_index = BIT_WORD(bits_offset);
226
227 /* gpio offset within current word of bits array */
228 word_offset = bits_offset % BITS_PER_LONG;
229
230 /* mask of get bits for current gpio within current word */
231 word_mask = mask[word_index] & (port_mask << word_offset);
232 if (!word_mask) {
233 /* no get bits in this port so skip to next one */
234 continue;
235 }
236
237 /* read bits from current gpio port (port 6 is TTL GPIO) */
238 if (i < 6)
239 port_state = ioread8(ports[i]);
240 else if (ioread8(&idio24gpio->reg->ctl) & out_mode_mask)
241 port_state = ioread8(&idio24gpio->reg->ttl_out0_7);
242 else
243 port_state = ioread8(&idio24gpio->reg->ttl_in0_7);
244
245 /* store acquired bits at respective bits array offset */
246 bits[word_index] |= (port_state << word_offset) & word_mask;
247 }
248
249 return 0;
250}
251
252static void idio_24_gpio_set(struct gpio_chip *chip, unsigned int offset,
253 int value)
254{
255 struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
256 const unsigned long out_mode_mask = BIT(1);
257 void __iomem *base;
258 const unsigned int mask = BIT(offset % 8);
259 unsigned long flags;
260 unsigned int out_state;
261
262 /* Isolated Inputs */
263 if (offset > 23 && offset < 48)
264 return;
265
266 /* TTL/CMOS Inputs */
267 if (offset > 47 && !(ioread8(&idio24gpio->reg->ctl) & out_mode_mask))
268 return;
269
270 /* TTL/CMOS Outputs */
271 if (offset > 47)
272 base = &idio24gpio->reg->ttl_out0_7;
273 /* FET Outputs */
274 else if (offset > 15)
275 base = &idio24gpio->reg->out16_23;
276 else if (offset > 7)
277 base = &idio24gpio->reg->out8_15;
278 else
279 base = &idio24gpio->reg->out0_7;
280
281 raw_spin_lock_irqsave(&idio24gpio->lock, flags);
282
283 if (value)
284 out_state = ioread8(base) | mask;
285 else
286 out_state = ioread8(base) & ~mask;
287
288 iowrite8(out_state, base);
289
290 raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
291}
292
293static void idio_24_gpio_set_multiple(struct gpio_chip *chip,
294 unsigned long *mask, unsigned long *bits)
295{
296 struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
297 size_t i;
298 unsigned long bits_offset;
299 unsigned long gpio_mask;
300 const unsigned int gpio_reg_size = 8;
301 const unsigned long port_mask = GENMASK(gpio_reg_size, 0);
302 unsigned long flags;
303 unsigned int out_state;
304 void __iomem *ports[] = {
305 &idio24gpio->reg->out0_7, &idio24gpio->reg->out8_15,
306 &idio24gpio->reg->out16_23
307 };
308 const unsigned long out_mode_mask = BIT(1);
309 const unsigned int ttl_offset = 48;
310 const size_t ttl_i = BIT_WORD(ttl_offset);
311 const unsigned int word_offset = ttl_offset % BITS_PER_LONG;
312 const unsigned long ttl_mask = (mask[ttl_i] >> word_offset) & port_mask;
313 const unsigned long ttl_bits = (bits[ttl_i] >> word_offset) & ttl_mask;
314
315 /* set bits are processed a gpio port register at a time */
316 for (i = 0; i < ARRAY_SIZE(ports); i++) {
317 /* gpio offset in bits array */
318 bits_offset = i * gpio_reg_size;
319
320 /* check if any set bits for current port */
321 gpio_mask = (*mask >> bits_offset) & port_mask;
322 if (!gpio_mask) {
323 /* no set bits for this port so move on to next port */
324 continue;
325 }
326
327 raw_spin_lock_irqsave(&idio24gpio->lock, flags);
328
329 /* process output lines */
330 out_state = ioread8(ports[i]) & ~gpio_mask;
331 out_state |= (*bits >> bits_offset) & gpio_mask;
332 iowrite8(out_state, ports[i]);
333
334 raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
335 }
336
337 /* check if setting TTL lines and if they are in output mode */
338 if (!ttl_mask || !(ioread8(&idio24gpio->reg->ctl) & out_mode_mask))
339 return;
340
341 /* handle TTL output */
342 raw_spin_lock_irqsave(&idio24gpio->lock, flags);
343
344 /* process output lines */
345 out_state = ioread8(&idio24gpio->reg->ttl_out0_7) & ~ttl_mask;
346 out_state |= ttl_bits;
347 iowrite8(out_state, &idio24gpio->reg->ttl_out0_7);
348
349 raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
350}
351
352static void idio_24_irq_ack(struct irq_data *data)
353{
354}
355
356static void idio_24_irq_mask(struct irq_data *data)
357{
358 struct gpio_chip *const chip = irq_data_get_irq_chip_data(data);
359 struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
360 unsigned long flags;
361 const unsigned long bit_offset = irqd_to_hwirq(data) - 24;
362 unsigned char new_irq_mask;
363 const unsigned long bank_offset = bit_offset/8 * 8;
364 unsigned char cos_enable_state;
365
366 raw_spin_lock_irqsave(&idio24gpio->lock, flags);
367
368 idio24gpio->irq_mask &= BIT(bit_offset);
369 new_irq_mask = idio24gpio->irq_mask >> bank_offset;
370
371 if (!new_irq_mask) {
372 cos_enable_state = ioread8(&idio24gpio->reg->cos_enable);
373
374 /* Disable Rising Edge detection */
375 cos_enable_state &= ~BIT(bank_offset);
376 /* Disable Falling Edge detection */
377 cos_enable_state &= ~BIT(bank_offset + 4);
378
379 iowrite8(cos_enable_state, &idio24gpio->reg->cos_enable);
380 }
381
382 raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
383}
384
385static void idio_24_irq_unmask(struct irq_data *data)
386{
387 struct gpio_chip *const chip = irq_data_get_irq_chip_data(data);
388 struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
389 unsigned long flags;
390 unsigned char prev_irq_mask;
391 const unsigned long bit_offset = irqd_to_hwirq(data) - 24;
392 const unsigned long bank_offset = bit_offset/8 * 8;
393 unsigned char cos_enable_state;
394
395 raw_spin_lock_irqsave(&idio24gpio->lock, flags);
396
397 prev_irq_mask = idio24gpio->irq_mask >> bank_offset;
398 idio24gpio->irq_mask |= BIT(bit_offset);
399
400 if (!prev_irq_mask) {
401 cos_enable_state = ioread8(&idio24gpio->reg->cos_enable);
402
403 /* Enable Rising Edge detection */
404 cos_enable_state |= BIT(bank_offset);
405 /* Enable Falling Edge detection */
406 cos_enable_state |= BIT(bank_offset + 4);
407
408 iowrite8(cos_enable_state, &idio24gpio->reg->cos_enable);
409 }
410
411 raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
412}
413
414static int idio_24_irq_set_type(struct irq_data *data, unsigned int flow_type)
415{
416 /* The only valid irq types are none and both-edges */
417 if (flow_type != IRQ_TYPE_NONE &&
418 (flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH)
419 return -EINVAL;
420
421 return 0;
422}
423
424static struct irq_chip idio_24_irqchip = {
425 .name = "pcie-idio-24",
426 .irq_ack = idio_24_irq_ack,
427 .irq_mask = idio_24_irq_mask,
428 .irq_unmask = idio_24_irq_unmask,
429 .irq_set_type = idio_24_irq_set_type
430};
431
432static irqreturn_t idio_24_irq_handler(int irq, void *dev_id)
433{
434 struct idio_24_gpio *const idio24gpio = dev_id;
435 unsigned long irq_status;
436 struct gpio_chip *const chip = &idio24gpio->chip;
437 unsigned long irq_mask;
438 int gpio;
439
440 raw_spin_lock(&idio24gpio->lock);
441
442 /* Read Change-Of-State status */
443 irq_status = ioread32(&idio24gpio->reg->cos0_7);
444
445 raw_spin_unlock(&idio24gpio->lock);
446
447 /* Make sure our device generated IRQ */
448 if (!irq_status)
449 return IRQ_NONE;
450
451 /* Handle only unmasked IRQ */
452 irq_mask = idio24gpio->irq_mask & irq_status;
453
454 for_each_set_bit(gpio, &irq_mask, chip->ngpio - 24)
455 generic_handle_irq(irq_find_mapping(chip->irq.domain,
456 gpio + 24));
457
458 raw_spin_lock(&idio24gpio->lock);
459
460 /* Clear Change-Of-State status */
461 iowrite32(irq_status, &idio24gpio->reg->cos0_7);
462
463 raw_spin_unlock(&idio24gpio->lock);
464
465 return IRQ_HANDLED;
466}
467
468#define IDIO_24_NGPIO 56
469static const char *idio_24_names[IDIO_24_NGPIO] = {
470 "OUT0", "OUT1", "OUT2", "OUT3", "OUT4", "OUT5", "OUT6", "OUT7",
471 "OUT8", "OUT9", "OUT10", "OUT11", "OUT12", "OUT13", "OUT14", "OUT15",
472 "OUT16", "OUT17", "OUT18", "OUT19", "OUT20", "OUT21", "OUT22", "OUT23",
473 "IIN0", "IIN1", "IIN2", "IIN3", "IIN4", "IIN5", "IIN6", "IIN7",
474 "IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15",
475 "IIN16", "IIN17", "IIN18", "IIN19", "IIN20", "IIN21", "IIN22", "IIN23",
476 "TTL0", "TTL1", "TTL2", "TTL3", "TTL4", "TTL5", "TTL6", "TTL7"
477};
478
479static int idio_24_probe(struct pci_dev *pdev, const struct pci_device_id *id)
480{
481 struct device *const dev = &pdev->dev;
482 struct idio_24_gpio *idio24gpio;
483 int err;
484 const size_t pci_bar_index = 2;
485 const char *const name = pci_name(pdev);
486
487 idio24gpio = devm_kzalloc(dev, sizeof(*idio24gpio), GFP_KERNEL);
488 if (!idio24gpio)
489 return -ENOMEM;
490
491 err = pcim_enable_device(pdev);
492 if (err) {
493 dev_err(dev, "Failed to enable PCI device (%d)\n", err);
494 return err;
495 }
496
497 err = pcim_iomap_regions(pdev, BIT(pci_bar_index), name);
498 if (err) {
499 dev_err(dev, "Unable to map PCI I/O addresses (%d)\n", err);
500 return err;
501 }
502
503 idio24gpio->reg = pcim_iomap_table(pdev)[pci_bar_index];
504
505 idio24gpio->chip.label = name;
506 idio24gpio->chip.parent = dev;
507 idio24gpio->chip.owner = THIS_MODULE;
508 idio24gpio->chip.base = -1;
509 idio24gpio->chip.ngpio = IDIO_24_NGPIO;
510 idio24gpio->chip.names = idio_24_names;
511 idio24gpio->chip.get_direction = idio_24_gpio_get_direction;
512 idio24gpio->chip.direction_input = idio_24_gpio_direction_input;
513 idio24gpio->chip.direction_output = idio_24_gpio_direction_output;
514 idio24gpio->chip.get = idio_24_gpio_get;
515 idio24gpio->chip.get_multiple = idio_24_gpio_get_multiple;
516 idio24gpio->chip.set = idio_24_gpio_set;
517 idio24gpio->chip.set_multiple = idio_24_gpio_set_multiple;
518
519 raw_spin_lock_init(&idio24gpio->lock);
520
521 /* Software board reset */
522 iowrite8(0, &idio24gpio->reg->soft_reset);
523
524 err = devm_gpiochip_add_data(dev, &idio24gpio->chip, idio24gpio);
525 if (err) {
526 dev_err(dev, "GPIO registering failed (%d)\n", err);
527 return err;
528 }
529
530 err = gpiochip_irqchip_add(&idio24gpio->chip, &idio_24_irqchip, 0,
531 handle_edge_irq, IRQ_TYPE_NONE);
532 if (err) {
533 dev_err(dev, "Could not add irqchip (%d)\n", err);
534 return err;
535 }
536
537 err = devm_request_irq(dev, pdev->irq, idio_24_irq_handler, IRQF_SHARED,
538 name, idio24gpio);
539 if (err) {
540 dev_err(dev, "IRQ handler registering failed (%d)\n", err);
541 return err;
542 }
543
544 return 0;
545}
546
547static const struct pci_device_id idio_24_pci_dev_id[] = {
548 { PCI_DEVICE(0x494F, 0x0FD0) }, { PCI_DEVICE(0x494F, 0x0BD0) },
549 { PCI_DEVICE(0x494F, 0x07D0) }, { PCI_DEVICE(0x494F, 0x0FC0) },
550 { 0 }
551};
552MODULE_DEVICE_TABLE(pci, idio_24_pci_dev_id);
553
554static struct pci_driver idio_24_driver = {
555 .name = "pcie-idio-24",
556 .id_table = idio_24_pci_dev_id,
557 .probe = idio_24_probe
558};
559
560module_pci_driver(idio_24_driver);
561
562MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
563MODULE_DESCRIPTION("ACCES PCIe-IDIO-24 GPIO driver");
564MODULE_LICENSE("GPL v2");