Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  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 GPIO_LINE_DIRECTION_OUT;
108
109	/* Isolated Inputs */
110	if (offset < 48)
111		return GPIO_LINE_DIRECTION_IN;
112
113	/* TTL/CMOS I/O */
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;
117
118	return GPIO_LINE_DIRECTION_IN;
119}
120
121static int idio_24_gpio_direction_input(struct gpio_chip *chip,
122	unsigned int offset)
123{
124	struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
125	unsigned long flags;
126	unsigned int ctl_state;
127	const unsigned long out_mode_mask = BIT(1);
128
129	/* TTL/CMOS I/O */
130	if (offset > 47) {
131		raw_spin_lock_irqsave(&idio24gpio->lock, flags);
132
133		/* Clear TTL/CMOS Output Mode */
134		ctl_state = ioread8(&idio24gpio->reg->ctl) & ~out_mode_mask;
135		iowrite8(ctl_state, &idio24gpio->reg->ctl);
136
137		raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
138	}
139
140	return 0;
141}
142
143static int idio_24_gpio_direction_output(struct gpio_chip *chip,
144	unsigned int offset, int value)
145{
146	struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
147	unsigned long flags;
148	unsigned int ctl_state;
149	const unsigned long out_mode_mask = BIT(1);
150
151	/* TTL/CMOS I/O */
152	if (offset > 47) {
153		raw_spin_lock_irqsave(&idio24gpio->lock, flags);
154
155		/* Set TTL/CMOS Output Mode */
156		ctl_state = ioread8(&idio24gpio->reg->ctl) | out_mode_mask;
157		iowrite8(ctl_state, &idio24gpio->reg->ctl);
158
159		raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
160	}
161
162	chip->set(chip, offset, value);
163	return 0;
164}
165
166static int idio_24_gpio_get(struct gpio_chip *chip, unsigned int offset)
167{
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);
171
172	/* FET Outputs */
173	if (offset < 8)
174		return !!(ioread8(&idio24gpio->reg->out0_7) & offset_mask);
175
176	if (offset < 16)
177		return !!(ioread8(&idio24gpio->reg->out8_15) & offset_mask);
178
179	if (offset < 24)
180		return !!(ioread8(&idio24gpio->reg->out16_23) & offset_mask);
181
182	/* Isolated Inputs */
183	if (offset < 32)
184		return !!(ioread8(&idio24gpio->reg->in0_7) & offset_mask);
185
186	if (offset < 40)
187		return !!(ioread8(&idio24gpio->reg->in8_15) & offset_mask);
188
189	if (offset < 48)
190		return !!(ioread8(&idio24gpio->reg->in16_23) & offset_mask);
191
192	/* TTL/CMOS Outputs */
193	if (ioread8(&idio24gpio->reg->ctl) & out_mode_mask)
194		return !!(ioread8(&idio24gpio->reg->ttl_out0_7) & offset_mask);
195
196	/* TTL/CMOS Inputs */
197	return !!(ioread8(&idio24gpio->reg->ttl_in0_7) & offset_mask);
198}
199
200static int idio_24_gpio_get_multiple(struct gpio_chip *chip,
201	unsigned long *mask, unsigned long *bits)
202{
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,
210	};
211	size_t index;
212	unsigned long port_state;
213	const unsigned long out_mode_mask = BIT(1);
214
215	/* clear bits array to a clean slate */
216	bitmap_zero(bits, chip->ngpio);
217
218	for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) {
219		index = offset / 8;
220
221		/* read bits from current gpio port (port 6 is TTL GPIO) */
222		if (index < 6)
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);
226		else
227			port_state = ioread8(&idio24gpio->reg->ttl_in0_7);
228
229		port_state &= gpio_mask;
230
231		bitmap_set_value8(bits, port_state, offset);
232	}
233
234	return 0;
235}
236
237static void idio_24_gpio_set(struct gpio_chip *chip, unsigned int offset,
238	int value)
239{
240	struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
241	const unsigned long out_mode_mask = BIT(1);
242	void __iomem *base;
243	const unsigned int mask = BIT(offset % 8);
244	unsigned long flags;
245	unsigned int out_state;
246
247	/* Isolated Inputs */
248	if (offset > 23 && offset < 48)
249		return;
250
251	/* TTL/CMOS Inputs */
252	if (offset > 47 && !(ioread8(&idio24gpio->reg->ctl) & out_mode_mask))
253		return;
254
255	/* TTL/CMOS Outputs */
256	if (offset > 47)
257		base = &idio24gpio->reg->ttl_out0_7;
258	/* FET Outputs */
259	else if (offset > 15)
260		base = &idio24gpio->reg->out16_23;
261	else if (offset > 7)
262		base = &idio24gpio->reg->out8_15;
263	else
264		base = &idio24gpio->reg->out0_7;
265
266	raw_spin_lock_irqsave(&idio24gpio->lock, flags);
267
268	if (value)
269		out_state = ioread8(base) | mask;
270	else
271		out_state = ioread8(base) & ~mask;
272
273	iowrite8(out_state, base);
274
275	raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
276}
277
278static void idio_24_gpio_set_multiple(struct gpio_chip *chip,
279	unsigned long *mask, unsigned long *bits)
280{
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
287	};
288	size_t index;
289	unsigned long bitmask;
290	unsigned long flags;
291	unsigned long out_state;
292	const unsigned long out_mode_mask = BIT(1);
293
294	for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) {
295		index = offset / 8;
296
297		bitmask = bitmap_get_value8(bits, offset) & gpio_mask;
298
299		raw_spin_lock_irqsave(&idio24gpio->lock, flags);
300
301		/* read bits from current gpio port (port 6 is TTL GPIO) */
302		if (index < 6) {
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);
306		} else {
307			/* skip TTL GPIO if set for input */
308			raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
309			continue;
310		}
311
312		/* set requested bit states */
313		out_state &= ~gpio_mask;
314		out_state |= bitmask;
315
316		/* write bits for current gpio port (port 6 is TTL GPIO) */
317		if (index < 6)
318			iowrite8(out_state, ports[index]);
319		else
320			iowrite8(out_state, &idio24gpio->reg->ttl_out0_7);
321
322		raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
323	}
324}
325
326static void idio_24_irq_ack(struct irq_data *data)
327{
328}
329
330static void idio_24_irq_mask(struct irq_data *data)
331{
332	struct gpio_chip *const chip = irq_data_get_irq_chip_data(data);
333	struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
334	unsigned long flags;
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;
339
340	raw_spin_lock_irqsave(&idio24gpio->lock, flags);
341
342	idio24gpio->irq_mask &= BIT(bit_offset);
343	new_irq_mask = idio24gpio->irq_mask >> bank_offset;
344
345	if (!new_irq_mask) {
346		cos_enable_state = ioread8(&idio24gpio->reg->cos_enable);
347
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);
352
353		iowrite8(cos_enable_state, &idio24gpio->reg->cos_enable);
354	}
355
356	raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
357}
358
359static void idio_24_irq_unmask(struct irq_data *data)
360{
361	struct gpio_chip *const chip = irq_data_get_irq_chip_data(data);
362	struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
363	unsigned long flags;
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;
368
369	raw_spin_lock_irqsave(&idio24gpio->lock, flags);
370
371	prev_irq_mask = idio24gpio->irq_mask >> bank_offset;
372	idio24gpio->irq_mask |= BIT(bit_offset);
373
374	if (!prev_irq_mask) {
375		cos_enable_state = ioread8(&idio24gpio->reg->cos_enable);
376
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);
381
382		iowrite8(cos_enable_state, &idio24gpio->reg->cos_enable);
383	}
384
385	raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
386}
387
388static int idio_24_irq_set_type(struct irq_data *data, unsigned int flow_type)
389{
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)
393		return -EINVAL;
394
395	return 0;
396}
397
398static 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
404};
405
406static irqreturn_t idio_24_irq_handler(int irq, void *dev_id)
407{
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;
412	int gpio;
413
414	raw_spin_lock(&idio24gpio->lock);
415
416	/* Read Change-Of-State status */
417	irq_status = ioread32(&idio24gpio->reg->cos0_7);
418
419	raw_spin_unlock(&idio24gpio->lock);
420
421	/* Make sure our device generated IRQ */
422	if (!irq_status)
423		return IRQ_NONE;
424
425	/* Handle only unmasked IRQ */
426	irq_mask = idio24gpio->irq_mask & irq_status;
427
428	for_each_set_bit(gpio, &irq_mask, chip->ngpio - 24)
429		generic_handle_irq(irq_find_mapping(chip->irq.domain,
430			gpio + 24));
431
432	raw_spin_lock(&idio24gpio->lock);
433
434	/* Clear Change-Of-State status */
435	iowrite32(irq_status, &idio24gpio->reg->cos0_7);
436
437	raw_spin_unlock(&idio24gpio->lock);
438
439	return IRQ_HANDLED;
440}
441
442#define IDIO_24_NGPIO 56
443static 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"
451};
452
453static int idio_24_probe(struct pci_dev *pdev, const struct pci_device_id *id)
454{
455	struct device *const dev = &pdev->dev;
456	struct idio_24_gpio *idio24gpio;
457	int err;
458	const size_t pci_bar_index = 2;
459	const char *const name = pci_name(pdev);
460	struct gpio_irq_chip *girq;
461
462	idio24gpio = devm_kzalloc(dev, sizeof(*idio24gpio), GFP_KERNEL);
463	if (!idio24gpio)
464		return -ENOMEM;
465
466	err = pcim_enable_device(pdev);
467	if (err) {
468		dev_err(dev, "Failed to enable PCI device (%d)\n", err);
469		return err;
470	}
471
472	err = pcim_iomap_regions(pdev, BIT(pci_bar_index), name);
473	if (err) {
474		dev_err(dev, "Unable to map PCI I/O addresses (%d)\n", err);
475		return err;
476	}
477
478	idio24gpio->reg = pcim_iomap_table(pdev)[pci_bar_index];
479
480	idio24gpio->chip.label = name;
481	idio24gpio->chip.parent = dev;
482	idio24gpio->chip.owner = THIS_MODULE;
483	idio24gpio->chip.base = -1;
484	idio24gpio->chip.ngpio = IDIO_24_NGPIO;
485	idio24gpio->chip.names = idio_24_names;
486	idio24gpio->chip.get_direction = idio_24_gpio_get_direction;
487	idio24gpio->chip.direction_input = idio_24_gpio_direction_input;
488	idio24gpio->chip.direction_output = idio_24_gpio_direction_output;
489	idio24gpio->chip.get = idio_24_gpio_get;
490	idio24gpio->chip.get_multiple = idio_24_gpio_get_multiple;
491	idio24gpio->chip.set = idio_24_gpio_set;
492	idio24gpio->chip.set_multiple = idio_24_gpio_set_multiple;
493
494	girq = &idio24gpio->chip.irq;
495	girq->chip = &idio_24_irqchip;
496	/* This will let us handle the parent IRQ in the driver */
497	girq->parent_handler = NULL;
498	girq->num_parents = 0;
499	girq->parents = NULL;
500	girq->default_type = IRQ_TYPE_NONE;
501	girq->handler = handle_edge_irq;
502
503	raw_spin_lock_init(&idio24gpio->lock);
504
505	/* Software board reset */
506	iowrite8(0, &idio24gpio->reg->soft_reset);
507
508	err = devm_gpiochip_add_data(dev, &idio24gpio->chip, idio24gpio);
509	if (err) {
510		dev_err(dev, "GPIO registering failed (%d)\n", err);
511		return err;
512	}
513
514	err = devm_request_irq(dev, pdev->irq, idio_24_irq_handler, IRQF_SHARED,
515		name, idio24gpio);
516	if (err) {
517		dev_err(dev, "IRQ handler registering failed (%d)\n", err);
518		return err;
519	}
520
521	return 0;
522}
523
524static const struct pci_device_id idio_24_pci_dev_id[] = {
525	{ PCI_DEVICE(0x494F, 0x0FD0) }, { PCI_DEVICE(0x494F, 0x0BD0) },
526	{ PCI_DEVICE(0x494F, 0x07D0) }, { PCI_DEVICE(0x494F, 0x0FC0) },
527	{ 0 }
528};
529MODULE_DEVICE_TABLE(pci, idio_24_pci_dev_id);
530
531static struct pci_driver idio_24_driver = {
532	.name = "pcie-idio-24",
533	.id_table = idio_24_pci_dev_id,
534	.probe = idio_24_probe
535};
536
537module_pci_driver(idio_24_driver);
538
539MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
540MODULE_DESCRIPTION("ACCES PCIe-IDIO-24 GPIO driver");
541MODULE_LICENSE("GPL v2");