xref: /linux/drivers/gpio/gpio-pcie-idio-24.c (revision 18f90d372cf35b387663f1567de701e5393f6eb5)
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  */
66 struct 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  */
92 struct 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 
99 static 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 
118 static 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 
140 static 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 
163 static 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 
197 static 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 
252 static 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 
293 static 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 
352 static void idio_24_irq_ack(struct irq_data *data)
353 {
354 }
355 
356 static 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 
385 static 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 
414 static 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 
424 static 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 
432 static 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
469 static 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 
479 static 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 
547 static 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 };
552 MODULE_DEVICE_TABLE(pci, idio_24_pci_dev_id);
553 
554 static 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 
560 module_pci_driver(idio_24_driver);
561 
562 MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
563 MODULE_DESCRIPTION("ACCES PCIe-IDIO-24 GPIO driver");
564 MODULE_LICENSE("GPL v2");
565