Linux Audio

Check our new training course

Loading...
v6.8
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * GPIO driver for the ACCES PCI-IDIO-16
  4 * Copyright (C) 2017 William Breathitt Gray
 
 
 
 
 
 
 
 
 
  5 */
  6#include <linux/bits.h>
 
  7#include <linux/device.h>
  8#include <linux/err.h>
  9#include <linux/irq.h>
 
 
 10#include <linux/kernel.h>
 11#include <linux/module.h>
 12#include <linux/pci.h>
 13#include <linux/regmap.h>
 14#include <linux/types.h>
 15
 16#include "gpio-idio-16.h"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 17
 18static const struct regmap_range idio_16_wr_ranges[] = {
 19	regmap_reg_range(0x0, 0x2), regmap_reg_range(0x3, 0x4),
 
 
 
 
 
 
 
 
 
 
 20};
 21static const struct regmap_range idio_16_rd_ranges[] = {
 22	regmap_reg_range(0x1, 0x2), regmap_reg_range(0x5, 0x6),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 23};
 24static const struct regmap_range idio_16_precious_ranges[] = {
 25	regmap_reg_range(0x2, 0x2),
 26};
 27static const struct regmap_access_table idio_16_wr_table = {
 28	.yes_ranges = idio_16_wr_ranges,
 29	.n_yes_ranges = ARRAY_SIZE(idio_16_wr_ranges),
 30};
 31static const struct regmap_access_table idio_16_rd_table = {
 32	.yes_ranges = idio_16_rd_ranges,
 33	.n_yes_ranges = ARRAY_SIZE(idio_16_rd_ranges),
 34};
 35static const struct regmap_access_table idio_16_precious_table = {
 36	.yes_ranges = idio_16_precious_ranges,
 37	.n_yes_ranges = ARRAY_SIZE(idio_16_precious_ranges),
 38};
 39static const struct regmap_config idio_16_regmap_config = {
 40	.reg_bits = 8,
 41	.reg_stride = 1,
 42	.val_bits = 8,
 43	.io_port = true,
 44	.wr_table = &idio_16_wr_table,
 45	.rd_table = &idio_16_rd_table,
 46	.volatile_table = &idio_16_rd_table,
 47	.precious_table = &idio_16_precious_table,
 48	.cache_type = REGCACHE_FLAT,
 49	.use_raw_spinlock = true,
 50};
 51
 52/* Only input lines (GPIO 16-31) support interrupts */
 53#define IDIO_16_REGMAP_IRQ(_id)						\
 54	[16 + _id] = {							\
 55		.mask = BIT(2),						\
 56		.type = { .types_supported = IRQ_TYPE_EDGE_BOTH },	\
 57	}
 58
 59static const struct regmap_irq idio_16_regmap_irqs[] = {
 60	IDIO_16_REGMAP_IRQ(0), IDIO_16_REGMAP_IRQ(1), IDIO_16_REGMAP_IRQ(2), /* 0-2 */
 61	IDIO_16_REGMAP_IRQ(3), IDIO_16_REGMAP_IRQ(4), IDIO_16_REGMAP_IRQ(5), /* 3-5 */
 62	IDIO_16_REGMAP_IRQ(6), IDIO_16_REGMAP_IRQ(7), IDIO_16_REGMAP_IRQ(8), /* 6-8 */
 63	IDIO_16_REGMAP_IRQ(9), IDIO_16_REGMAP_IRQ(10), IDIO_16_REGMAP_IRQ(11), /* 9-11 */
 64	IDIO_16_REGMAP_IRQ(12), IDIO_16_REGMAP_IRQ(13), IDIO_16_REGMAP_IRQ(14), /* 12-14 */
 65	IDIO_16_REGMAP_IRQ(15), /* 15 */
 66};
 67
 68static int idio_16_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 69{
 70	struct device *const dev = &pdev->dev;
 
 71	int err;
 72	const size_t pci_bar_index = 2;
 73	const char *const name = pci_name(pdev);
 74	struct idio_16_regmap_config config = {};
 75	void __iomem *regs;
 76	struct regmap *map;
 
 77
 78	err = pcim_enable_device(pdev);
 79	if (err) {
 80		dev_err(dev, "Failed to enable PCI device (%d)\n", err);
 81		return err;
 82	}
 83
 84	err = pcim_iomap_regions(pdev, BIT(pci_bar_index), name);
 85	if (err) {
 86		dev_err(dev, "Unable to map PCI I/O addresses (%d)\n", err);
 87		return err;
 88	}
 89
 90	regs = pcim_iomap_table(pdev)[pci_bar_index];
 
 
 
 91
 92	map = devm_regmap_init_mmio(dev, regs, &idio_16_regmap_config);
 93	if (IS_ERR(map))
 94		return dev_err_probe(dev, PTR_ERR(map), "Unable to initialize register map\n");
 95
 96	config.parent = dev;
 97	config.map = map;
 98	config.regmap_irqs = idio_16_regmap_irqs;
 99	config.num_regmap_irqs = ARRAY_SIZE(idio_16_regmap_irqs);
100	config.irq = pdev->irq;
101	config.filters = true;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
103	return devm_idio_16_regmap_register(dev, &config);
104}
105
106static const struct pci_device_id idio_16_pci_dev_id[] = {
107	{ PCI_DEVICE(0x494F, 0x0DC8) }, { 0 }
108};
109MODULE_DEVICE_TABLE(pci, idio_16_pci_dev_id);
110
111static struct pci_driver idio_16_driver = {
112	.name = "pci-idio-16",
113	.id_table = idio_16_pci_dev_id,
114	.probe = idio_16_probe
115};
116
117module_pci_driver(idio_16_driver);
118
119MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
120MODULE_DESCRIPTION("ACCES PCI-IDIO-16 GPIO driver");
121MODULE_LICENSE("GPL v2");
122MODULE_IMPORT_NS(GPIO_IDIO_16);
v4.17
 
  1/*
  2 * GPIO driver for the ACCES PCI-IDIO-16
  3 * Copyright (C) 2017 William Breathitt Gray
  4 *
  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.
  8 *
  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.
 13 */
 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>
 26
 27/**
 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
 34 *		Write: Disable 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
 40 *		Write: Unused
 41 * @irq_status:	Read: Interrupt status
 42 *		Write: Unused
 43 */
 44struct idio_16_gpio_reg {
 45	u8 out0_7;
 46	u8 in0_7;
 47	u8 irq_ctl;
 48	u8 filter_ctl;
 49	u8 out8_15;
 50	u8 in8_15;
 51	u8 irq_status;
 52};
 53
 54/**
 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
 60 */
 61struct idio_16_gpio {
 62	struct gpio_chip chip;
 63	raw_spinlock_t lock;
 64	struct idio_16_gpio_reg __iomem *reg;
 65	unsigned long irq_mask;
 66};
 67
 68static int idio_16_gpio_get_direction(struct gpio_chip *chip,
 69	unsigned int offset)
 70{
 71	if (offset > 15)
 72		return 1;
 73
 74	return 0;
 75}
 76
 77static int idio_16_gpio_direction_input(struct gpio_chip *chip,
 78	unsigned int offset)
 79{
 80	return 0;
 81}
 82
 83static int idio_16_gpio_direction_output(struct gpio_chip *chip,
 84	unsigned int offset, int value)
 85{
 86	chip->set(chip, offset, value);
 87	return 0;
 88}
 89
 90static int idio_16_gpio_get(struct gpio_chip *chip, unsigned int offset)
 91{
 92	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
 93	unsigned long mask = BIT(offset);
 94
 95	if (offset < 8)
 96		return !!(ioread8(&idio16gpio->reg->out0_7) & mask);
 97
 98	if (offset < 16)
 99		return !!(ioread8(&idio16gpio->reg->out8_15) & (mask >> 8));
100
101	if (offset < 24)
102		return !!(ioread8(&idio16gpio->reg->in0_7) & (mask >> 16));
103
104	return !!(ioread8(&idio16gpio->reg->in8_15) & (mask >> 24));
105}
106
107static int idio_16_gpio_get_multiple(struct gpio_chip *chip,
108	unsigned long *mask, unsigned long *bits)
109{
110	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
111	size_t i;
112	const unsigned int gpio_reg_size = 8;
113	unsigned int bits_offset;
114	size_t word_index;
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,
122	};
123
124	/* clear bits array to a clean slate */
125	bitmap_zero(bits, chip->ngpio);
126
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;
131
132		/* word index for bits array */
133		word_index = BIT_WORD(bits_offset);
134
135		/* gpio offset within current word of bits array */
136		word_offset = bits_offset % BITS_PER_LONG;
137
138		/* mask of get bits for current gpio within current word */
139		word_mask = mask[word_index] & (port_mask << word_offset);
140		if (!word_mask) {
141			/* no get bits in this port so skip to next one */
142			continue;
143		}
144
145		/* read bits from current gpio port */
146		port_state = ioread8(ports[i]);
147
148		/* store acquired bits at respective bits array offset */
149		bits[word_index] |= port_state << word_offset;
150	}
151
152	return 0;
153}
154
155static void idio_16_gpio_set(struct gpio_chip *chip, unsigned int offset,
156	int value)
157{
158	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
159	unsigned int mask = BIT(offset);
160	void __iomem *base;
161	unsigned long flags;
162	unsigned int out_state;
163
164	if (offset > 15)
165		return;
166
167	if (offset > 7) {
168		mask >>= 8;
169		base = &idio16gpio->reg->out8_15;
170	} else
171		base = &idio16gpio->reg->out0_7;
172
173	raw_spin_lock_irqsave(&idio16gpio->lock, flags);
174
175	if (value)
176		out_state = ioread8(base) | mask;
177	else
178		out_state = ioread8(base) & ~mask;
179
180	iowrite8(out_state, base);
181
182	raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
183}
184
185static void idio_16_gpio_set_multiple(struct gpio_chip *chip,
186	unsigned long *mask, unsigned long *bits)
187{
188	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
189	unsigned long flags;
190	unsigned int out_state;
191
192	raw_spin_lock_irqsave(&idio16gpio->lock, flags);
193
194	/* process output lines 0-7 */
195	if (*mask & 0xFF) {
196		out_state = ioread8(&idio16gpio->reg->out0_7) & ~*mask;
197		out_state |= *mask & *bits;
198		iowrite8(out_state, &idio16gpio->reg->out0_7);
199	}
200
201	/* shift to next output line word */
202	*mask >>= 8;
203
204	/* process output lines 8-15 */
205	if (*mask & 0xFF) {
206		*bits >>= 8;
207		out_state = ioread8(&idio16gpio->reg->out8_15) & ~*mask;
208		out_state |= *mask & *bits;
209		iowrite8(out_state, &idio16gpio->reg->out8_15);
210	}
211
212	raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
213}
214
215static void idio_16_irq_ack(struct irq_data *data)
216{
217}
218
219static void idio_16_irq_mask(struct irq_data *data)
220{
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));
224	unsigned long flags;
225
226	idio16gpio->irq_mask &= ~mask;
227
228	if (!idio16gpio->irq_mask) {
229		raw_spin_lock_irqsave(&idio16gpio->lock, flags);
230
231		iowrite8(0, &idio16gpio->reg->irq_ctl);
232
233		raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
234	}
235}
236
237static void idio_16_irq_unmask(struct irq_data *data)
238{
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;
243	unsigned long flags;
244
245	idio16gpio->irq_mask |= mask;
246
247	if (!prev_irq_mask) {
248		raw_spin_lock_irqsave(&idio16gpio->lock, flags);
249
250		ioread8(&idio16gpio->reg->irq_ctl);
251
252		raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
253	}
254}
255
256static int idio_16_irq_set_type(struct irq_data *data, unsigned int flow_type)
257{
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)
261		return -EINVAL;
262
263	return 0;
264}
265
266static 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
272};
273
274static irqreturn_t idio_16_irq_handler(int irq, void *dev_id)
275{
276	struct idio_16_gpio *const idio16gpio = dev_id;
277	unsigned int irq_status;
278	struct gpio_chip *const chip = &idio16gpio->chip;
279	int gpio;
280
281	raw_spin_lock(&idio16gpio->lock);
282
283	irq_status = ioread8(&idio16gpio->reg->irq_status);
284
285	raw_spin_unlock(&idio16gpio->lock);
286
287	/* Make sure our device generated IRQ */
288	if (!(irq_status & 0x3) || !(irq_status & 0x4))
289		return IRQ_NONE;
290
291	for_each_set_bit(gpio, &idio16gpio->irq_mask, chip->ngpio)
292		generic_handle_irq(irq_find_mapping(chip->irq.domain, gpio));
293
294	raw_spin_lock(&idio16gpio->lock);
295
296	/* Clear interrupt */
297	iowrite8(0, &idio16gpio->reg->in0_7);
298
299	raw_spin_unlock(&idio16gpio->lock);
300
301	return IRQ_HANDLED;
302}
303
304#define IDIO_16_NGPIO 32
305static 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"
 
 
 
 
 
310};
311
312static int idio_16_probe(struct pci_dev *pdev, const struct pci_device_id *id)
313{
314	struct device *const dev = &pdev->dev;
315	struct idio_16_gpio *idio16gpio;
316	int err;
317	const size_t pci_bar_index = 2;
318	const char *const name = pci_name(pdev);
319
320	idio16gpio = devm_kzalloc(dev, sizeof(*idio16gpio), GFP_KERNEL);
321	if (!idio16gpio)
322		return -ENOMEM;
323
324	err = pcim_enable_device(pdev);
325	if (err) {
326		dev_err(dev, "Failed to enable PCI device (%d)\n", err);
327		return err;
328	}
329
330	err = pcim_iomap_regions(pdev, BIT(pci_bar_index), name);
331	if (err) {
332		dev_err(dev, "Unable to map PCI I/O addresses (%d)\n", err);
333		return err;
334	}
335
336	idio16gpio->reg = pcim_iomap_table(pdev)[pci_bar_index];
337
338	/* Deactivate input filters */
339	iowrite8(0, &idio16gpio->reg->filter_ctl);
340
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;
354
355	raw_spin_lock_init(&idio16gpio->lock);
356
357	err = devm_gpiochip_add_data(dev, &idio16gpio->chip, idio16gpio);
358	if (err) {
359		dev_err(dev, "GPIO registering failed (%d)\n", err);
360		return err;
361	}
362
363	/* Disable IRQ by default and clear any pending interrupt */
364	iowrite8(0, &idio16gpio->reg->irq_ctl);
365	iowrite8(0, &idio16gpio->reg->in0_7);
366
367	err = gpiochip_irqchip_add(&idio16gpio->chip, &idio_16_irqchip, 0,
368		handle_edge_irq, IRQ_TYPE_NONE);
369	if (err) {
370		dev_err(dev, "Could not add irqchip (%d)\n", err);
371		return err;
372	}
373
374	err = devm_request_irq(dev, pdev->irq, idio_16_irq_handler, IRQF_SHARED,
375		name, idio16gpio);
376	if (err) {
377		dev_err(dev, "IRQ handler registering failed (%d)\n", err);
378		return err;
379	}
380
381	return 0;
382}
383
384static const struct pci_device_id idio_16_pci_dev_id[] = {
385	{ PCI_DEVICE(0x494F, 0x0DC8) }, { 0 }
386};
387MODULE_DEVICE_TABLE(pci, idio_16_pci_dev_id);
388
389static struct pci_driver idio_16_driver = {
390	.name = "pci-idio-16",
391	.id_table = idio_16_pci_dev_id,
392	.probe = idio_16_probe
393};
394
395module_pci_driver(idio_16_driver);
396
397MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
398MODULE_DESCRIPTION("ACCES PCI-IDIO-16 GPIO driver");
399MODULE_LICENSE("GPL v2");