2 * GPIO driver for the ACCES PCI-IDIO-16
3 * Copyright (C) 2017 William Breathitt Gray
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License, version 2, as
7 * published by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 #include <linux/bitmap.h>
15 #include <linux/bitops.h>
16 #include <linux/device.h>
17 #include <linux/errno.h>
18 #include <linux/gpio/driver.h>
19 #include <linux/interrupt.h>
20 #include <linux/irqdesc.h>
21 #include <linux/kernel.h>
22 #include <linux/module.h>
23 #include <linux/pci.h>
24 #include <linux/spinlock.h>
25 #include <linux/types.h>
28 * struct idio_16_gpio_reg - GPIO device registers structure
29 * @out0_7: Read: FET Drive Outputs 0-7
30 * Write: FET Drive Outputs 0-7
31 * @in0_7: Read: Isolated Inputs 0-7
32 * Write: Clear Interrupt
33 * @irq_ctl: Read: Enable IRQ
35 * @filter_ctl: Read: Activate Input Filters 0-15
36 * Write: Deactivate Input Filters 0-15
37 * @out8_15: Read: FET Drive Outputs 8-15
38 * Write: FET Drive Outputs 8-15
39 * @in8_15: Read: Isolated Inputs 8-15
41 * @irq_status: Read: Interrupt status
44 struct idio_16_gpio_reg
{
55 * struct idio_16_gpio - GPIO device private data structure
56 * @chip: instance of the gpio_chip
57 * @lock: synchronization lock to prevent I/O race conditions
58 * @reg: I/O address offset for the GPIO device registers
59 * @irq_mask: I/O bits affected by interrupts
62 struct gpio_chip chip
;
64 struct idio_16_gpio_reg __iomem
*reg
;
65 unsigned long irq_mask
;
68 static int idio_16_gpio_get_direction(struct gpio_chip
*chip
,
77 static int idio_16_gpio_direction_input(struct gpio_chip
*chip
,
83 static int idio_16_gpio_direction_output(struct gpio_chip
*chip
,
84 unsigned int offset
, int value
)
86 chip
->set(chip
, offset
, value
);
90 static int idio_16_gpio_get(struct gpio_chip
*chip
, unsigned int offset
)
92 struct idio_16_gpio
*const idio16gpio
= gpiochip_get_data(chip
);
93 unsigned long mask
= BIT(offset
);
96 return !!(ioread8(&idio16gpio
->reg
->out0_7
) & mask
);
99 return !!(ioread8(&idio16gpio
->reg
->out8_15
) & (mask
>> 8));
102 return !!(ioread8(&idio16gpio
->reg
->in0_7
) & (mask
>> 16));
104 return !!(ioread8(&idio16gpio
->reg
->in8_15
) & (mask
>> 24));
107 static int idio_16_gpio_get_multiple(struct gpio_chip
*chip
,
108 unsigned long *mask
, unsigned long *bits
)
110 struct idio_16_gpio
*const idio16gpio
= gpiochip_get_data(chip
);
112 const unsigned int gpio_reg_size
= 8;
113 unsigned int bits_offset
;
115 unsigned int word_offset
;
116 unsigned long word_mask
;
117 const unsigned long port_mask
= GENMASK(gpio_reg_size
- 1, 0);
118 unsigned long port_state
;
119 void __iomem
*ports
[] = {
120 &idio16gpio
->reg
->out0_7
, &idio16gpio
->reg
->out8_15
,
121 &idio16gpio
->reg
->in0_7
, &idio16gpio
->reg
->in8_15
,
124 /* clear bits array to a clean slate */
125 bitmap_zero(bits
, chip
->ngpio
);
127 /* get bits are evaluated a gpio port register at a time */
128 for (i
= 0; i
< ARRAY_SIZE(ports
); i
++) {
129 /* gpio offset in bits array */
130 bits_offset
= i
* gpio_reg_size
;
132 /* word index for bits array */
133 word_index
= BIT_WORD(bits_offset
);
135 /* gpio offset within current word of bits array */
136 word_offset
= bits_offset
% BITS_PER_LONG
;
138 /* mask of get bits for current gpio within current word */
139 word_mask
= mask
[word_index
] & (port_mask
<< word_offset
);
141 /* no get bits in this port so skip to next one */
145 /* read bits from current gpio port */
146 port_state
= ioread8(ports
[i
]);
148 /* store acquired bits at respective bits array offset */
149 bits
[word_index
] |= port_state
<< word_offset
;
155 static void idio_16_gpio_set(struct gpio_chip
*chip
, unsigned int offset
,
158 struct idio_16_gpio
*const idio16gpio
= gpiochip_get_data(chip
);
159 unsigned int mask
= BIT(offset
);
162 unsigned int out_state
;
169 base
= &idio16gpio
->reg
->out8_15
;
171 base
= &idio16gpio
->reg
->out0_7
;
173 raw_spin_lock_irqsave(&idio16gpio
->lock
, flags
);
176 out_state
= ioread8(base
) | mask
;
178 out_state
= ioread8(base
) & ~mask
;
180 iowrite8(out_state
, base
);
182 raw_spin_unlock_irqrestore(&idio16gpio
->lock
, flags
);
185 static void idio_16_gpio_set_multiple(struct gpio_chip
*chip
,
186 unsigned long *mask
, unsigned long *bits
)
188 struct idio_16_gpio
*const idio16gpio
= gpiochip_get_data(chip
);
190 unsigned int out_state
;
192 raw_spin_lock_irqsave(&idio16gpio
->lock
, flags
);
194 /* process output lines 0-7 */
196 out_state
= ioread8(&idio16gpio
->reg
->out0_7
) & ~*mask
;
197 out_state
|= *mask
& *bits
;
198 iowrite8(out_state
, &idio16gpio
->reg
->out0_7
);
201 /* shift to next output line word */
204 /* process output lines 8-15 */
207 out_state
= ioread8(&idio16gpio
->reg
->out8_15
) & ~*mask
;
208 out_state
|= *mask
& *bits
;
209 iowrite8(out_state
, &idio16gpio
->reg
->out8_15
);
212 raw_spin_unlock_irqrestore(&idio16gpio
->lock
, flags
);
215 static void idio_16_irq_ack(struct irq_data
*data
)
219 static void idio_16_irq_mask(struct irq_data
*data
)
221 struct gpio_chip
*chip
= irq_data_get_irq_chip_data(data
);
222 struct idio_16_gpio
*const idio16gpio
= gpiochip_get_data(chip
);
223 const unsigned long mask
= BIT(irqd_to_hwirq(data
));
226 idio16gpio
->irq_mask
&= ~mask
;
228 if (!idio16gpio
->irq_mask
) {
229 raw_spin_lock_irqsave(&idio16gpio
->lock
, flags
);
231 iowrite8(0, &idio16gpio
->reg
->irq_ctl
);
233 raw_spin_unlock_irqrestore(&idio16gpio
->lock
, flags
);
237 static void idio_16_irq_unmask(struct irq_data
*data
)
239 struct gpio_chip
*chip
= irq_data_get_irq_chip_data(data
);
240 struct idio_16_gpio
*const idio16gpio
= gpiochip_get_data(chip
);
241 const unsigned long mask
= BIT(irqd_to_hwirq(data
));
242 const unsigned long prev_irq_mask
= idio16gpio
->irq_mask
;
245 idio16gpio
->irq_mask
|= mask
;
247 if (!prev_irq_mask
) {
248 raw_spin_lock_irqsave(&idio16gpio
->lock
, flags
);
250 ioread8(&idio16gpio
->reg
->irq_ctl
);
252 raw_spin_unlock_irqrestore(&idio16gpio
->lock
, flags
);
256 static int idio_16_irq_set_type(struct irq_data
*data
, unsigned int flow_type
)
258 /* The only valid irq types are none and both-edges */
259 if (flow_type
!= IRQ_TYPE_NONE
&&
260 (flow_type
& IRQ_TYPE_EDGE_BOTH
) != IRQ_TYPE_EDGE_BOTH
)
266 static struct irq_chip idio_16_irqchip
= {
267 .name
= "pci-idio-16",
268 .irq_ack
= idio_16_irq_ack
,
269 .irq_mask
= idio_16_irq_mask
,
270 .irq_unmask
= idio_16_irq_unmask
,
271 .irq_set_type
= idio_16_irq_set_type
274 static irqreturn_t
idio_16_irq_handler(int irq
, void *dev_id
)
276 struct idio_16_gpio
*const idio16gpio
= dev_id
;
277 unsigned int irq_status
;
278 struct gpio_chip
*const chip
= &idio16gpio
->chip
;
281 raw_spin_lock(&idio16gpio
->lock
);
283 irq_status
= ioread8(&idio16gpio
->reg
->irq_status
);
285 raw_spin_unlock(&idio16gpio
->lock
);
287 /* Make sure our device generated IRQ */
288 if (!(irq_status
& 0x3) || !(irq_status
& 0x4))
291 for_each_set_bit(gpio
, &idio16gpio
->irq_mask
, chip
->ngpio
)
292 generic_handle_irq(irq_find_mapping(chip
->irq
.domain
, gpio
));
294 raw_spin_lock(&idio16gpio
->lock
);
296 /* Clear interrupt */
297 iowrite8(0, &idio16gpio
->reg
->in0_7
);
299 raw_spin_unlock(&idio16gpio
->lock
);
304 #define IDIO_16_NGPIO 32
305 static const char *idio_16_names
[IDIO_16_NGPIO
] = {
306 "OUT0", "OUT1", "OUT2", "OUT3", "OUT4", "OUT5", "OUT6", "OUT7",
307 "OUT8", "OUT9", "OUT10", "OUT11", "OUT12", "OUT13", "OUT14", "OUT15",
308 "IIN0", "IIN1", "IIN2", "IIN3", "IIN4", "IIN5", "IIN6", "IIN7",
309 "IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15"
312 static int idio_16_probe(struct pci_dev
*pdev
, const struct pci_device_id
*id
)
314 struct device
*const dev
= &pdev
->dev
;
315 struct idio_16_gpio
*idio16gpio
;
317 const size_t pci_bar_index
= 2;
318 const char *const name
= pci_name(pdev
);
320 idio16gpio
= devm_kzalloc(dev
, sizeof(*idio16gpio
), GFP_KERNEL
);
324 err
= pcim_enable_device(pdev
);
326 dev_err(dev
, "Failed to enable PCI device (%d)\n", err
);
330 err
= pcim_iomap_regions(pdev
, BIT(pci_bar_index
), name
);
332 dev_err(dev
, "Unable to map PCI I/O addresses (%d)\n", err
);
336 idio16gpio
->reg
= pcim_iomap_table(pdev
)[pci_bar_index
];
338 /* Deactivate input filters */
339 iowrite8(0, &idio16gpio
->reg
->filter_ctl
);
341 idio16gpio
->chip
.label
= name
;
342 idio16gpio
->chip
.parent
= dev
;
343 idio16gpio
->chip
.owner
= THIS_MODULE
;
344 idio16gpio
->chip
.base
= -1;
345 idio16gpio
->chip
.ngpio
= IDIO_16_NGPIO
;
346 idio16gpio
->chip
.names
= idio_16_names
;
347 idio16gpio
->chip
.get_direction
= idio_16_gpio_get_direction
;
348 idio16gpio
->chip
.direction_input
= idio_16_gpio_direction_input
;
349 idio16gpio
->chip
.direction_output
= idio_16_gpio_direction_output
;
350 idio16gpio
->chip
.get
= idio_16_gpio_get
;
351 idio16gpio
->chip
.get_multiple
= idio_16_gpio_get_multiple
;
352 idio16gpio
->chip
.set
= idio_16_gpio_set
;
353 idio16gpio
->chip
.set_multiple
= idio_16_gpio_set_multiple
;
355 raw_spin_lock_init(&idio16gpio
->lock
);
357 err
= devm_gpiochip_add_data(dev
, &idio16gpio
->chip
, idio16gpio
);
359 dev_err(dev
, "GPIO registering failed (%d)\n", err
);
363 /* Disable IRQ by default and clear any pending interrupt */
364 iowrite8(0, &idio16gpio
->reg
->irq_ctl
);
365 iowrite8(0, &idio16gpio
->reg
->in0_7
);
367 err
= gpiochip_irqchip_add(&idio16gpio
->chip
, &idio_16_irqchip
, 0,
368 handle_edge_irq
, IRQ_TYPE_NONE
);
370 dev_err(dev
, "Could not add irqchip (%d)\n", err
);
374 err
= devm_request_irq(dev
, pdev
->irq
, idio_16_irq_handler
, IRQF_SHARED
,
377 dev_err(dev
, "IRQ handler registering failed (%d)\n", err
);
384 static const struct pci_device_id idio_16_pci_dev_id
[] = {
385 { PCI_DEVICE(0x494F, 0x0DC8) }, { 0 }
387 MODULE_DEVICE_TABLE(pci
, idio_16_pci_dev_id
);
389 static struct pci_driver idio_16_driver
= {
390 .name
= "pci-idio-16",
391 .id_table
= idio_16_pci_dev_id
,
392 .probe
= idio_16_probe
395 module_pci_driver(idio_16_driver
);
397 MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
398 MODULE_DESCRIPTION("ACCES PCI-IDIO-16 GPIO driver");
399 MODULE_LICENSE("GPL v2");