1 // SPDX-License-Identifier: GPL-2.0-only
3 * GPIO driver for the ACCES PCIe-IDIO-24 family
4 * Copyright (C) 2018 William Breathitt Gray
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.
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.
15 * This driver supports the following ACCES devices: PCIe-IDIO-24,
16 * PCIe-IDI-24, PCIe-IDO-24, and PCIe-IDIO-12.
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>
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
43 * @in8_15: Read: Isolated Inputs 8-15
45 * @in16_23: Read: Isolated Inputs 16-23
47 * @ttl_in0_7: Read: TTL/CMOS Inputs 0-7
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
61 * @cos_enable: Read: COS Enable
63 * @soft_reset: Read: IRQ Output Pin Status
64 * Write: Software Board Reset
66 struct idio_24_gpio_reg
{
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
93 struct gpio_chip chip
;
95 struct idio_24_gpio_reg __iomem
*reg
;
96 unsigned long irq_mask
;
99 static int idio_24_gpio_get_direction(struct gpio_chip
*chip
,
102 struct idio_24_gpio
*const idio24gpio
= gpiochip_get_data(chip
);
103 const unsigned long out_mode_mask
= BIT(1);
107 return GPIO_LINE_DIRECTION_OUT
;
109 /* Isolated Inputs */
111 return GPIO_LINE_DIRECTION_IN
;
114 /* OUT MODE = 1 when TTL/CMOS Output Mode is set */
115 if (ioread8(&idio24gpio
->reg
->ctl
) & out_mode_mask
)
116 return GPIO_LINE_DIRECTION_OUT
;
118 return GPIO_LINE_DIRECTION_IN
;
121 static int idio_24_gpio_direction_input(struct gpio_chip
*chip
,
124 struct idio_24_gpio
*const idio24gpio
= gpiochip_get_data(chip
);
126 unsigned int ctl_state
;
127 const unsigned long out_mode_mask
= BIT(1);
131 raw_spin_lock_irqsave(&idio24gpio
->lock
, flags
);
133 /* Clear TTL/CMOS Output Mode */
134 ctl_state
= ioread8(&idio24gpio
->reg
->ctl
) & ~out_mode_mask
;
135 iowrite8(ctl_state
, &idio24gpio
->reg
->ctl
);
137 raw_spin_unlock_irqrestore(&idio24gpio
->lock
, flags
);
143 static int idio_24_gpio_direction_output(struct gpio_chip
*chip
,
144 unsigned int offset
, int value
)
146 struct idio_24_gpio
*const idio24gpio
= gpiochip_get_data(chip
);
148 unsigned int ctl_state
;
149 const unsigned long out_mode_mask
= BIT(1);
153 raw_spin_lock_irqsave(&idio24gpio
->lock
, flags
);
155 /* Set TTL/CMOS Output Mode */
156 ctl_state
= ioread8(&idio24gpio
->reg
->ctl
) | out_mode_mask
;
157 iowrite8(ctl_state
, &idio24gpio
->reg
->ctl
);
159 raw_spin_unlock_irqrestore(&idio24gpio
->lock
, flags
);
162 chip
->set(chip
, offset
, value
);
166 static int idio_24_gpio_get(struct gpio_chip
*chip
, unsigned int offset
)
168 struct idio_24_gpio
*const idio24gpio
= gpiochip_get_data(chip
);
169 const unsigned long offset_mask
= BIT(offset
% 8);
170 const unsigned long out_mode_mask
= BIT(1);
174 return !!(ioread8(&idio24gpio
->reg
->out0_7
) & offset_mask
);
177 return !!(ioread8(&idio24gpio
->reg
->out8_15
) & offset_mask
);
180 return !!(ioread8(&idio24gpio
->reg
->out16_23
) & offset_mask
);
182 /* Isolated Inputs */
184 return !!(ioread8(&idio24gpio
->reg
->in0_7
) & offset_mask
);
187 return !!(ioread8(&idio24gpio
->reg
->in8_15
) & offset_mask
);
190 return !!(ioread8(&idio24gpio
->reg
->in16_23
) & offset_mask
);
192 /* TTL/CMOS Outputs */
193 if (ioread8(&idio24gpio
->reg
->ctl
) & out_mode_mask
)
194 return !!(ioread8(&idio24gpio
->reg
->ttl_out0_7
) & offset_mask
);
196 /* TTL/CMOS Inputs */
197 return !!(ioread8(&idio24gpio
->reg
->ttl_in0_7
) & offset_mask
);
200 static int idio_24_gpio_get_multiple(struct gpio_chip
*chip
,
201 unsigned long *mask
, unsigned long *bits
)
203 struct idio_24_gpio
*const idio24gpio
= gpiochip_get_data(chip
);
204 unsigned long offset
;
205 unsigned long gpio_mask
;
206 void __iomem
*ports
[] = {
207 &idio24gpio
->reg
->out0_7
, &idio24gpio
->reg
->out8_15
,
208 &idio24gpio
->reg
->out16_23
, &idio24gpio
->reg
->in0_7
,
209 &idio24gpio
->reg
->in8_15
, &idio24gpio
->reg
->in16_23
,
212 unsigned long port_state
;
213 const unsigned long out_mode_mask
= BIT(1);
215 /* clear bits array to a clean slate */
216 bitmap_zero(bits
, chip
->ngpio
);
218 for_each_set_clump8(offset
, gpio_mask
, mask
, ARRAY_SIZE(ports
) * 8) {
221 /* read bits from current gpio port (port 6 is TTL GPIO) */
223 port_state
= ioread8(ports
[index
]);
224 else if (ioread8(&idio24gpio
->reg
->ctl
) & out_mode_mask
)
225 port_state
= ioread8(&idio24gpio
->reg
->ttl_out0_7
);
227 port_state
= ioread8(&idio24gpio
->reg
->ttl_in0_7
);
229 port_state
&= gpio_mask
;
231 bitmap_set_value8(bits
, port_state
, offset
);
237 static void idio_24_gpio_set(struct gpio_chip
*chip
, unsigned int offset
,
240 struct idio_24_gpio
*const idio24gpio
= gpiochip_get_data(chip
);
241 const unsigned long out_mode_mask
= BIT(1);
243 const unsigned int mask
= BIT(offset
% 8);
245 unsigned int out_state
;
247 /* Isolated Inputs */
248 if (offset
> 23 && offset
< 48)
251 /* TTL/CMOS Inputs */
252 if (offset
> 47 && !(ioread8(&idio24gpio
->reg
->ctl
) & out_mode_mask
))
255 /* TTL/CMOS Outputs */
257 base
= &idio24gpio
->reg
->ttl_out0_7
;
259 else if (offset
> 15)
260 base
= &idio24gpio
->reg
->out16_23
;
262 base
= &idio24gpio
->reg
->out8_15
;
264 base
= &idio24gpio
->reg
->out0_7
;
266 raw_spin_lock_irqsave(&idio24gpio
->lock
, flags
);
269 out_state
= ioread8(base
) | mask
;
271 out_state
= ioread8(base
) & ~mask
;
273 iowrite8(out_state
, base
);
275 raw_spin_unlock_irqrestore(&idio24gpio
->lock
, flags
);
278 static void idio_24_gpio_set_multiple(struct gpio_chip
*chip
,
279 unsigned long *mask
, unsigned long *bits
)
281 struct idio_24_gpio
*const idio24gpio
= gpiochip_get_data(chip
);
282 unsigned long offset
;
283 unsigned long gpio_mask
;
284 void __iomem
*ports
[] = {
285 &idio24gpio
->reg
->out0_7
, &idio24gpio
->reg
->out8_15
,
286 &idio24gpio
->reg
->out16_23
289 unsigned long bitmask
;
291 unsigned long out_state
;
292 const unsigned long out_mode_mask
= BIT(1);
294 for_each_set_clump8(offset
, gpio_mask
, mask
, ARRAY_SIZE(ports
) * 8) {
297 bitmask
= bitmap_get_value8(bits
, offset
) & gpio_mask
;
299 raw_spin_lock_irqsave(&idio24gpio
->lock
, flags
);
301 /* read bits from current gpio port (port 6 is TTL GPIO) */
303 out_state
= ioread8(ports
[index
]);
304 } else if (ioread8(&idio24gpio
->reg
->ctl
) & out_mode_mask
) {
305 out_state
= ioread8(&idio24gpio
->reg
->ttl_out0_7
);
307 /* skip TTL GPIO if set for input */
308 raw_spin_unlock_irqrestore(&idio24gpio
->lock
, flags
);
312 /* set requested bit states */
313 out_state
&= ~gpio_mask
;
314 out_state
|= bitmask
;
316 /* write bits for current gpio port (port 6 is TTL GPIO) */
318 iowrite8(out_state
, ports
[index
]);
320 iowrite8(out_state
, &idio24gpio
->reg
->ttl_out0_7
);
322 raw_spin_unlock_irqrestore(&idio24gpio
->lock
, flags
);
326 static void idio_24_irq_ack(struct irq_data
*data
)
330 static void idio_24_irq_mask(struct irq_data
*data
)
332 struct gpio_chip
*const chip
= irq_data_get_irq_chip_data(data
);
333 struct idio_24_gpio
*const idio24gpio
= gpiochip_get_data(chip
);
335 const unsigned long bit_offset
= irqd_to_hwirq(data
) - 24;
336 unsigned char new_irq_mask
;
337 const unsigned long bank_offset
= bit_offset
/8 * 8;
338 unsigned char cos_enable_state
;
340 raw_spin_lock_irqsave(&idio24gpio
->lock
, flags
);
342 idio24gpio
->irq_mask
&= BIT(bit_offset
);
343 new_irq_mask
= idio24gpio
->irq_mask
>> bank_offset
;
346 cos_enable_state
= ioread8(&idio24gpio
->reg
->cos_enable
);
348 /* Disable Rising Edge detection */
349 cos_enable_state
&= ~BIT(bank_offset
);
350 /* Disable Falling Edge detection */
351 cos_enable_state
&= ~BIT(bank_offset
+ 4);
353 iowrite8(cos_enable_state
, &idio24gpio
->reg
->cos_enable
);
356 raw_spin_unlock_irqrestore(&idio24gpio
->lock
, flags
);
359 static void idio_24_irq_unmask(struct irq_data
*data
)
361 struct gpio_chip
*const chip
= irq_data_get_irq_chip_data(data
);
362 struct idio_24_gpio
*const idio24gpio
= gpiochip_get_data(chip
);
364 unsigned char prev_irq_mask
;
365 const unsigned long bit_offset
= irqd_to_hwirq(data
) - 24;
366 const unsigned long bank_offset
= bit_offset
/8 * 8;
367 unsigned char cos_enable_state
;
369 raw_spin_lock_irqsave(&idio24gpio
->lock
, flags
);
371 prev_irq_mask
= idio24gpio
->irq_mask
>> bank_offset
;
372 idio24gpio
->irq_mask
|= BIT(bit_offset
);
374 if (!prev_irq_mask
) {
375 cos_enable_state
= ioread8(&idio24gpio
->reg
->cos_enable
);
377 /* Enable Rising Edge detection */
378 cos_enable_state
|= BIT(bank_offset
);
379 /* Enable Falling Edge detection */
380 cos_enable_state
|= BIT(bank_offset
+ 4);
382 iowrite8(cos_enable_state
, &idio24gpio
->reg
->cos_enable
);
385 raw_spin_unlock_irqrestore(&idio24gpio
->lock
, flags
);
388 static int idio_24_irq_set_type(struct irq_data
*data
, unsigned int flow_type
)
390 /* The only valid irq types are none and both-edges */
391 if (flow_type
!= IRQ_TYPE_NONE
&&
392 (flow_type
& IRQ_TYPE_EDGE_BOTH
) != IRQ_TYPE_EDGE_BOTH
)
398 static struct irq_chip idio_24_irqchip
= {
399 .name
= "pcie-idio-24",
400 .irq_ack
= idio_24_irq_ack
,
401 .irq_mask
= idio_24_irq_mask
,
402 .irq_unmask
= idio_24_irq_unmask
,
403 .irq_set_type
= idio_24_irq_set_type
406 static irqreturn_t
idio_24_irq_handler(int irq
, void *dev_id
)
408 struct idio_24_gpio
*const idio24gpio
= dev_id
;
409 unsigned long irq_status
;
410 struct gpio_chip
*const chip
= &idio24gpio
->chip
;
411 unsigned long irq_mask
;
414 raw_spin_lock(&idio24gpio
->lock
);
416 /* Read Change-Of-State status */
417 irq_status
= ioread32(&idio24gpio
->reg
->cos0_7
);
419 raw_spin_unlock(&idio24gpio
->lock
);
421 /* Make sure our device generated IRQ */
425 /* Handle only unmasked IRQ */
426 irq_mask
= idio24gpio
->irq_mask
& irq_status
;
428 for_each_set_bit(gpio
, &irq_mask
, chip
->ngpio
- 24)
429 generic_handle_irq(irq_find_mapping(chip
->irq
.domain
,
432 raw_spin_lock(&idio24gpio
->lock
);
434 /* Clear Change-Of-State status */
435 iowrite32(irq_status
, &idio24gpio
->reg
->cos0_7
);
437 raw_spin_unlock(&idio24gpio
->lock
);
442 #define IDIO_24_NGPIO 56
443 static const char *idio_24_names
[IDIO_24_NGPIO
] = {
444 "OUT0", "OUT1", "OUT2", "OUT3", "OUT4", "OUT5", "OUT6", "OUT7",
445 "OUT8", "OUT9", "OUT10", "OUT11", "OUT12", "OUT13", "OUT14", "OUT15",
446 "OUT16", "OUT17", "OUT18", "OUT19", "OUT20", "OUT21", "OUT22", "OUT23",
447 "IIN0", "IIN1", "IIN2", "IIN3", "IIN4", "IIN5", "IIN6", "IIN7",
448 "IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15",
449 "IIN16", "IIN17", "IIN18", "IIN19", "IIN20", "IIN21", "IIN22", "IIN23",
450 "TTL0", "TTL1", "TTL2", "TTL3", "TTL4", "TTL5", "TTL6", "TTL7"
453 static int idio_24_probe(struct pci_dev
*pdev
, const struct pci_device_id
*id
)
455 struct device
*const dev
= &pdev
->dev
;
456 struct idio_24_gpio
*idio24gpio
;
458 const size_t pci_bar_index
= 2;
459 const char *const name
= pci_name(pdev
);
461 idio24gpio
= devm_kzalloc(dev
, sizeof(*idio24gpio
), GFP_KERNEL
);
465 err
= pcim_enable_device(pdev
);
467 dev_err(dev
, "Failed to enable PCI device (%d)\n", err
);
471 err
= pcim_iomap_regions(pdev
, BIT(pci_bar_index
), name
);
473 dev_err(dev
, "Unable to map PCI I/O addresses (%d)\n", err
);
477 idio24gpio
->reg
= pcim_iomap_table(pdev
)[pci_bar_index
];
479 idio24gpio
->chip
.label
= name
;
480 idio24gpio
->chip
.parent
= dev
;
481 idio24gpio
->chip
.owner
= THIS_MODULE
;
482 idio24gpio
->chip
.base
= -1;
483 idio24gpio
->chip
.ngpio
= IDIO_24_NGPIO
;
484 idio24gpio
->chip
.names
= idio_24_names
;
485 idio24gpio
->chip
.get_direction
= idio_24_gpio_get_direction
;
486 idio24gpio
->chip
.direction_input
= idio_24_gpio_direction_input
;
487 idio24gpio
->chip
.direction_output
= idio_24_gpio_direction_output
;
488 idio24gpio
->chip
.get
= idio_24_gpio_get
;
489 idio24gpio
->chip
.get_multiple
= idio_24_gpio_get_multiple
;
490 idio24gpio
->chip
.set
= idio_24_gpio_set
;
491 idio24gpio
->chip
.set_multiple
= idio_24_gpio_set_multiple
;
493 raw_spin_lock_init(&idio24gpio
->lock
);
495 /* Software board reset */
496 iowrite8(0, &idio24gpio
->reg
->soft_reset
);
498 err
= devm_gpiochip_add_data(dev
, &idio24gpio
->chip
, idio24gpio
);
500 dev_err(dev
, "GPIO registering failed (%d)\n", err
);
504 err
= gpiochip_irqchip_add(&idio24gpio
->chip
, &idio_24_irqchip
, 0,
505 handle_edge_irq
, IRQ_TYPE_NONE
);
507 dev_err(dev
, "Could not add irqchip (%d)\n", err
);
511 err
= devm_request_irq(dev
, pdev
->irq
, idio_24_irq_handler
, IRQF_SHARED
,
514 dev_err(dev
, "IRQ handler registering failed (%d)\n", err
);
521 static const struct pci_device_id idio_24_pci_dev_id
[] = {
522 { PCI_DEVICE(0x494F, 0x0FD0) }, { PCI_DEVICE(0x494F, 0x0BD0) },
523 { PCI_DEVICE(0x494F, 0x07D0) }, { PCI_DEVICE(0x494F, 0x0FC0) },
526 MODULE_DEVICE_TABLE(pci
, idio_24_pci_dev_id
);
528 static struct pci_driver idio_24_driver
= {
529 .name
= "pcie-idio-24",
530 .id_table
= idio_24_pci_dev_id
,
531 .probe
= idio_24_probe
534 module_pci_driver(idio_24_driver
);
536 MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
537 MODULE_DESCRIPTION("ACCES PCIe-IDIO-24 GPIO driver");
538 MODULE_LICENSE("GPL v2");