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/bitops.h>
19 #include <linux/device.h>
20 #include <linux/errno.h>
21 #include <linux/gpio/driver.h>
22 #include <linux/interrupt.h>
23 #include <linux/irqdesc.h>
24 #include <linux/kernel.h>
25 #include <linux/module.h>
26 #include <linux/pci.h>
27 #include <linux/spinlock.h>
28 #include <linux/types.h>
31 * struct idio_24_gpio_reg - GPIO device registers structure
32 * @out0_7: Read: FET Outputs 0-7
33 * Write: FET Outputs 0-7
34 * @out8_15: Read: FET Outputs 8-15
35 * Write: FET Outputs 8-15
36 * @out16_23: Read: FET Outputs 16-23
37 * Write: FET Outputs 16-23
38 * @ttl_out0_7: Read: TTL/CMOS Outputs 0-7
39 * Write: TTL/CMOS Outputs 0-7
40 * @in0_7: Read: Isolated Inputs 0-7
42 * @in8_15: Read: Isolated Inputs 8-15
44 * @in16_23: Read: Isolated Inputs 16-23
46 * @ttl_in0_7: Read: TTL/CMOS Inputs 0-7
48 * @cos0_7: Read: COS Status Inputs 0-7
49 * Write: COS Clear Inputs 0-7
50 * @cos8_15: Read: COS Status Inputs 8-15
51 * Write: COS Clear Inputs 8-15
52 * @cos16_23: Read: COS Status Inputs 16-23
53 * Write: COS Clear Inputs 16-23
54 * @cos_ttl0_7: Read: COS Status TTL/CMOS 0-7
55 * Write: COS Clear TTL/CMOS 0-7
56 * @ctl: Read: Control Register
57 * Write: Control Register
58 * @reserved: Read: Reserved
60 * @cos_enable: Read: COS Enable
62 * @soft_reset: Read: IRQ Output Pin Status
63 * Write: Software Board Reset
65 struct idio_24_gpio_reg
{
85 * struct idio_24_gpio - GPIO device private data structure
86 * @chip: instance of the gpio_chip
87 * @lock: synchronization lock to prevent I/O race conditions
88 * @reg: I/O address offset for the GPIO device registers
89 * @irq_mask: I/O bits affected by interrupts
92 struct gpio_chip chip
;
94 struct idio_24_gpio_reg __iomem
*reg
;
95 unsigned long irq_mask
;
98 static int idio_24_gpio_get_direction(struct gpio_chip
*chip
,
101 struct idio_24_gpio
*const idio24gpio
= gpiochip_get_data(chip
);
102 const unsigned long out_mode_mask
= BIT(1);
108 /* Isolated Inputs */
113 /* OUT MODE = 1 when TTL/CMOS Output Mode is set */
114 return !(ioread8(&idio24gpio
->reg
->ctl
) & out_mode_mask
);
117 static int idio_24_gpio_direction_input(struct gpio_chip
*chip
,
120 struct idio_24_gpio
*const idio24gpio
= gpiochip_get_data(chip
);
122 unsigned int ctl_state
;
123 const unsigned long out_mode_mask
= BIT(1);
127 raw_spin_lock_irqsave(&idio24gpio
->lock
, flags
);
129 /* Clear TTL/CMOS Output Mode */
130 ctl_state
= ioread8(&idio24gpio
->reg
->ctl
) & ~out_mode_mask
;
131 iowrite8(ctl_state
, &idio24gpio
->reg
->ctl
);
133 raw_spin_unlock_irqrestore(&idio24gpio
->lock
, flags
);
139 static int idio_24_gpio_direction_output(struct gpio_chip
*chip
,
140 unsigned int offset
, int value
)
142 struct idio_24_gpio
*const idio24gpio
= gpiochip_get_data(chip
);
144 unsigned int ctl_state
;
145 const unsigned long out_mode_mask
= BIT(1);
149 raw_spin_lock_irqsave(&idio24gpio
->lock
, flags
);
151 /* Set TTL/CMOS Output Mode */
152 ctl_state
= ioread8(&idio24gpio
->reg
->ctl
) | out_mode_mask
;
153 iowrite8(ctl_state
, &idio24gpio
->reg
->ctl
);
155 raw_spin_unlock_irqrestore(&idio24gpio
->lock
, flags
);
158 chip
->set(chip
, offset
, value
);
162 static int idio_24_gpio_get(struct gpio_chip
*chip
, unsigned int offset
)
164 struct idio_24_gpio
*const idio24gpio
= gpiochip_get_data(chip
);
165 const unsigned long offset_mask
= BIT(offset
% 8);
166 const unsigned long out_mode_mask
= BIT(1);
170 return !!(ioread8(&idio24gpio
->reg
->out0_7
) & offset_mask
);
173 return !!(ioread8(&idio24gpio
->reg
->out8_15
) & offset_mask
);
176 return !!(ioread8(&idio24gpio
->reg
->out16_23
) & offset_mask
);
178 /* Isolated Inputs */
180 return !!(ioread8(&idio24gpio
->reg
->in0_7
) & offset_mask
);
183 return !!(ioread8(&idio24gpio
->reg
->in8_15
) & offset_mask
);
186 return !!(ioread8(&idio24gpio
->reg
->in16_23
) & offset_mask
);
188 /* TTL/CMOS Outputs */
189 if (ioread8(&idio24gpio
->reg
->ctl
) & out_mode_mask
)
190 return !!(ioread8(&idio24gpio
->reg
->ttl_out0_7
) & offset_mask
);
192 /* TTL/CMOS Inputs */
193 return !!(ioread8(&idio24gpio
->reg
->ttl_in0_7
) & offset_mask
);
196 static void idio_24_gpio_set(struct gpio_chip
*chip
, unsigned int offset
,
199 struct idio_24_gpio
*const idio24gpio
= gpiochip_get_data(chip
);
200 const unsigned long out_mode_mask
= BIT(1);
202 const unsigned int mask
= BIT(offset
% 8);
204 unsigned int out_state
;
206 /* Isolated Inputs */
207 if (offset
> 23 && offset
< 48)
210 /* TTL/CMOS Inputs */
211 if (offset
> 47 && !(ioread8(&idio24gpio
->reg
->ctl
) & out_mode_mask
))
214 /* TTL/CMOS Outputs */
216 base
= &idio24gpio
->reg
->ttl_out0_7
;
218 else if (offset
> 15)
219 base
= &idio24gpio
->reg
->out16_23
;
221 base
= &idio24gpio
->reg
->out8_15
;
223 base
= &idio24gpio
->reg
->out0_7
;
225 raw_spin_lock_irqsave(&idio24gpio
->lock
, flags
);
228 out_state
= ioread8(base
) | mask
;
230 out_state
= ioread8(base
) & ~mask
;
232 iowrite8(out_state
, base
);
234 raw_spin_unlock_irqrestore(&idio24gpio
->lock
, flags
);
237 static void idio_24_irq_ack(struct irq_data
*data
)
241 static void idio_24_irq_mask(struct irq_data
*data
)
243 struct gpio_chip
*const chip
= irq_data_get_irq_chip_data(data
);
244 struct idio_24_gpio
*const idio24gpio
= gpiochip_get_data(chip
);
246 const unsigned long bit_offset
= irqd_to_hwirq(data
) - 24;
247 unsigned char new_irq_mask
;
248 const unsigned long bank_offset
= bit_offset
/8 * 8;
249 unsigned char cos_enable_state
;
251 raw_spin_lock_irqsave(&idio24gpio
->lock
, flags
);
253 idio24gpio
->irq_mask
&= BIT(bit_offset
);
254 new_irq_mask
= idio24gpio
->irq_mask
>> bank_offset
;
257 cos_enable_state
= ioread8(&idio24gpio
->reg
->cos_enable
);
259 /* Disable Rising Edge detection */
260 cos_enable_state
&= ~BIT(bank_offset
);
261 /* Disable Falling Edge detection */
262 cos_enable_state
&= ~BIT(bank_offset
+ 4);
264 iowrite8(cos_enable_state
, &idio24gpio
->reg
->cos_enable
);
267 raw_spin_unlock_irqrestore(&idio24gpio
->lock
, flags
);
270 static void idio_24_irq_unmask(struct irq_data
*data
)
272 struct gpio_chip
*const chip
= irq_data_get_irq_chip_data(data
);
273 struct idio_24_gpio
*const idio24gpio
= gpiochip_get_data(chip
);
275 unsigned char prev_irq_mask
;
276 const unsigned long bit_offset
= irqd_to_hwirq(data
) - 24;
277 const unsigned long bank_offset
= bit_offset
/8 * 8;
278 unsigned char cos_enable_state
;
280 raw_spin_lock_irqsave(&idio24gpio
->lock
, flags
);
282 prev_irq_mask
= idio24gpio
->irq_mask
>> bank_offset
;
283 idio24gpio
->irq_mask
|= BIT(bit_offset
);
285 if (!prev_irq_mask
) {
286 cos_enable_state
= ioread8(&idio24gpio
->reg
->cos_enable
);
288 /* Enable Rising Edge detection */
289 cos_enable_state
|= BIT(bank_offset
);
290 /* Enable Falling Edge detection */
291 cos_enable_state
|= BIT(bank_offset
+ 4);
293 iowrite8(cos_enable_state
, &idio24gpio
->reg
->cos_enable
);
296 raw_spin_unlock_irqrestore(&idio24gpio
->lock
, flags
);
299 static int idio_24_irq_set_type(struct irq_data
*data
, unsigned int flow_type
)
301 /* The only valid irq types are none and both-edges */
302 if (flow_type
!= IRQ_TYPE_NONE
&&
303 (flow_type
& IRQ_TYPE_EDGE_BOTH
) != IRQ_TYPE_EDGE_BOTH
)
309 static struct irq_chip idio_24_irqchip
= {
310 .name
= "pcie-idio-24",
311 .irq_ack
= idio_24_irq_ack
,
312 .irq_mask
= idio_24_irq_mask
,
313 .irq_unmask
= idio_24_irq_unmask
,
314 .irq_set_type
= idio_24_irq_set_type
317 static irqreturn_t
idio_24_irq_handler(int irq
, void *dev_id
)
319 struct idio_24_gpio
*const idio24gpio
= dev_id
;
320 unsigned long irq_status
;
321 struct gpio_chip
*const chip
= &idio24gpio
->chip
;
322 unsigned long irq_mask
;
325 raw_spin_lock(&idio24gpio
->lock
);
327 /* Read Change-Of-State status */
328 irq_status
= ioread32(&idio24gpio
->reg
->cos0_7
);
330 raw_spin_unlock(&idio24gpio
->lock
);
332 /* Make sure our device generated IRQ */
336 /* Handle only unmasked IRQ */
337 irq_mask
= idio24gpio
->irq_mask
& irq_status
;
339 for_each_set_bit(gpio
, &irq_mask
, chip
->ngpio
- 24)
340 generic_handle_irq(irq_find_mapping(chip
->irq
.domain
,
343 raw_spin_lock(&idio24gpio
->lock
);
345 /* Clear Change-Of-State status */
346 iowrite32(irq_status
, &idio24gpio
->reg
->cos0_7
);
348 raw_spin_unlock(&idio24gpio
->lock
);
353 #define IDIO_24_NGPIO 56
354 static const char *idio_24_names
[IDIO_24_NGPIO
] = {
355 "OUT0", "OUT1", "OUT2", "OUT3", "OUT4", "OUT5", "OUT6", "OUT7",
356 "OUT8", "OUT9", "OUT10", "OUT11", "OUT12", "OUT13", "OUT14", "OUT15",
357 "OUT16", "OUT17", "OUT18", "OUT19", "OUT20", "OUT21", "OUT22", "OUT23",
358 "IIN0", "IIN1", "IIN2", "IIN3", "IIN4", "IIN5", "IIN6", "IIN7",
359 "IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15",
360 "IIN16", "IIN17", "IIN18", "IIN19", "IIN20", "IIN21", "IIN22", "IIN23",
361 "TTL0", "TTL1", "TTL2", "TTL3", "TTL4", "TTL5", "TTL6", "TTL7"
364 static int idio_24_probe(struct pci_dev
*pdev
, const struct pci_device_id
*id
)
366 struct device
*const dev
= &pdev
->dev
;
367 struct idio_24_gpio
*idio24gpio
;
369 const size_t pci_bar_index
= 2;
370 const char *const name
= pci_name(pdev
);
372 idio24gpio
= devm_kzalloc(dev
, sizeof(*idio24gpio
), GFP_KERNEL
);
376 err
= pcim_enable_device(pdev
);
378 dev_err(dev
, "Failed to enable PCI device (%d)\n", err
);
382 err
= pcim_iomap_regions(pdev
, BIT(pci_bar_index
), name
);
384 dev_err(dev
, "Unable to map PCI I/O addresses (%d)\n", err
);
388 idio24gpio
->reg
= pcim_iomap_table(pdev
)[pci_bar_index
];
390 idio24gpio
->chip
.label
= name
;
391 idio24gpio
->chip
.parent
= dev
;
392 idio24gpio
->chip
.owner
= THIS_MODULE
;
393 idio24gpio
->chip
.base
= -1;
394 idio24gpio
->chip
.ngpio
= IDIO_24_NGPIO
;
395 idio24gpio
->chip
.names
= idio_24_names
;
396 idio24gpio
->chip
.get_direction
= idio_24_gpio_get_direction
;
397 idio24gpio
->chip
.direction_input
= idio_24_gpio_direction_input
;
398 idio24gpio
->chip
.direction_output
= idio_24_gpio_direction_output
;
399 idio24gpio
->chip
.get
= idio_24_gpio_get
;
400 idio24gpio
->chip
.set
= idio_24_gpio_set
;
402 raw_spin_lock_init(&idio24gpio
->lock
);
404 /* Software board reset */
405 iowrite8(0, &idio24gpio
->reg
->soft_reset
);
407 err
= devm_gpiochip_add_data(dev
, &idio24gpio
->chip
, idio24gpio
);
409 dev_err(dev
, "GPIO registering failed (%d)\n", err
);
413 err
= gpiochip_irqchip_add(&idio24gpio
->chip
, &idio_24_irqchip
, 0,
414 handle_edge_irq
, IRQ_TYPE_NONE
);
416 dev_err(dev
, "Could not add irqchip (%d)\n", err
);
420 err
= devm_request_irq(dev
, pdev
->irq
, idio_24_irq_handler
, IRQF_SHARED
,
423 dev_err(dev
, "IRQ handler registering failed (%d)\n", err
);
430 static const struct pci_device_id idio_24_pci_dev_id
[] = {
431 { PCI_DEVICE(0x494F, 0x0FD0) }, { PCI_DEVICE(0x494F, 0x0BD0) },
432 { PCI_DEVICE(0x494F, 0x07D0) }, { PCI_DEVICE(0x494F, 0x0FC0) },
435 MODULE_DEVICE_TABLE(pci
, idio_24_pci_dev_id
);
437 static struct pci_driver idio_24_driver
= {
438 .name
= "pcie-idio-24",
439 .id_table
= idio_24_pci_dev_id
,
440 .probe
= idio_24_probe
443 module_pci_driver(idio_24_driver
);
445 MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
446 MODULE_DESCRIPTION("ACCES PCIe-IDIO-24 GPIO driver");
447 MODULE_LICENSE("GPL v2");