Linux Audio

Check our new training course

Loading...
v6.13.7
  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	struct idio_16_regmap_config config = {};
 74	void __iomem *regs;
 75	struct regmap *map;
 
 
 76
 77	err = pcim_enable_device(pdev);
 78	if (err)
 79		return dev_err_probe(dev, err, "Failed to enable PCI device\n");
 
 
 
 
 
 
 
 
 
 
 
 
 
 80
 81	regs = pcim_iomap_region(pdev, pci_bar_index, pci_name(pdev));
 82	if (IS_ERR(regs))
 83		return dev_err_probe(dev, PTR_ERR(regs), "Unable to map PCI I/O addresses\n");
 84
 85	map = devm_regmap_init_mmio(dev, regs, &idio_16_regmap_config);
 86	if (IS_ERR(map))
 87		return dev_err_probe(dev, PTR_ERR(map), "Unable to initialize register map\n");
 88
 89	config.parent = dev;
 90	config.map = map;
 91	config.regmap_irqs = idio_16_regmap_irqs;
 92	config.num_regmap_irqs = ARRAY_SIZE(idio_16_regmap_irqs);
 93	config.irq = pdev->irq;
 94	config.filters = true;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 95
 96	return devm_idio_16_regmap_register(dev, &config);
 97}
 98
 99static const struct pci_device_id idio_16_pci_dev_id[] = {
100	{ PCI_DEVICE(0x494F, 0x0DC8) }, { 0 }
101};
102MODULE_DEVICE_TABLE(pci, idio_16_pci_dev_id);
103
104static struct pci_driver idio_16_driver = {
105	.name = "pci-idio-16",
106	.id_table = idio_16_pci_dev_id,
107	.probe = idio_16_probe
108};
109
110module_pci_driver(idio_16_driver);
111
112MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
113MODULE_DESCRIPTION("ACCES PCI-IDIO-16 GPIO driver");
114MODULE_LICENSE("GPL v2");
115MODULE_IMPORT_NS("GPIO_IDIO_16");
v5.4
  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/bitmap.h>
  7#include <linux/bitops.h>
  8#include <linux/device.h>
  9#include <linux/errno.h>
 10#include <linux/gpio/driver.h>
 11#include <linux/interrupt.h>
 12#include <linux/irqdesc.h>
 13#include <linux/kernel.h>
 14#include <linux/module.h>
 15#include <linux/pci.h>
 16#include <linux/spinlock.h>
 17#include <linux/types.h>
 18
 19/**
 20 * struct idio_16_gpio_reg - GPIO device registers structure
 21 * @out0_7:	Read: FET Drive Outputs 0-7
 22 *		Write: FET Drive Outputs 0-7
 23 * @in0_7:	Read: Isolated Inputs 0-7
 24 *		Write: Clear Interrupt
 25 * @irq_ctl:	Read: Enable IRQ
 26 *		Write: Disable IRQ
 27 * @filter_ctl:	Read: Activate Input Filters 0-15
 28 *		Write: Deactivate Input Filters 0-15
 29 * @out8_15:	Read: FET Drive Outputs 8-15
 30 *		Write: FET Drive Outputs 8-15
 31 * @in8_15:	Read: Isolated Inputs 8-15
 32 *		Write: Unused
 33 * @irq_status:	Read: Interrupt status
 34 *		Write: Unused
 35 */
 36struct idio_16_gpio_reg {
 37	u8 out0_7;
 38	u8 in0_7;
 39	u8 irq_ctl;
 40	u8 filter_ctl;
 41	u8 out8_15;
 42	u8 in8_15;
 43	u8 irq_status;
 44};
 45
 46/**
 47 * struct idio_16_gpio - GPIO device private data structure
 48 * @chip:	instance of the gpio_chip
 49 * @lock:	synchronization lock to prevent I/O race conditions
 50 * @reg:	I/O address offset for the GPIO device registers
 51 * @irq_mask:	I/O bits affected by interrupts
 52 */
 53struct idio_16_gpio {
 54	struct gpio_chip chip;
 55	raw_spinlock_t lock;
 56	struct idio_16_gpio_reg __iomem *reg;
 57	unsigned long irq_mask;
 58};
 59
 60static int idio_16_gpio_get_direction(struct gpio_chip *chip,
 61	unsigned int offset)
 62{
 63	if (offset > 15)
 64		return 1;
 65
 66	return 0;
 67}
 68
 69static int idio_16_gpio_direction_input(struct gpio_chip *chip,
 70	unsigned int offset)
 71{
 72	return 0;
 73}
 74
 75static int idio_16_gpio_direction_output(struct gpio_chip *chip,
 76	unsigned int offset, int value)
 77{
 78	chip->set(chip, offset, value);
 79	return 0;
 80}
 81
 82static int idio_16_gpio_get(struct gpio_chip *chip, unsigned int offset)
 83{
 84	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
 85	unsigned long mask = BIT(offset);
 86
 87	if (offset < 8)
 88		return !!(ioread8(&idio16gpio->reg->out0_7) & mask);
 89
 90	if (offset < 16)
 91		return !!(ioread8(&idio16gpio->reg->out8_15) & (mask >> 8));
 92
 93	if (offset < 24)
 94		return !!(ioread8(&idio16gpio->reg->in0_7) & (mask >> 16));
 95
 96	return !!(ioread8(&idio16gpio->reg->in8_15) & (mask >> 24));
 97}
 98
 99static int idio_16_gpio_get_multiple(struct gpio_chip *chip,
100	unsigned long *mask, unsigned long *bits)
101{
102	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
103	size_t i;
104	const unsigned int gpio_reg_size = 8;
105	unsigned int bits_offset;
106	size_t word_index;
107	unsigned int word_offset;
108	unsigned long word_mask;
109	const unsigned long port_mask = GENMASK(gpio_reg_size - 1, 0);
110	unsigned long port_state;
111	void __iomem *ports[] = {
112		&idio16gpio->reg->out0_7, &idio16gpio->reg->out8_15,
113		&idio16gpio->reg->in0_7, &idio16gpio->reg->in8_15,
114	};
115
116	/* clear bits array to a clean slate */
117	bitmap_zero(bits, chip->ngpio);
118
119	/* get bits are evaluated a gpio port register at a time */
120	for (i = 0; i < ARRAY_SIZE(ports); i++) {
121		/* gpio offset in bits array */
122		bits_offset = i * gpio_reg_size;
123
124		/* word index for bits array */
125		word_index = BIT_WORD(bits_offset);
126
127		/* gpio offset within current word of bits array */
128		word_offset = bits_offset % BITS_PER_LONG;
129
130		/* mask of get bits for current gpio within current word */
131		word_mask = mask[word_index] & (port_mask << word_offset);
132		if (!word_mask) {
133			/* no get bits in this port so skip to next one */
134			continue;
135		}
136
137		/* read bits from current gpio port */
138		port_state = ioread8(ports[i]);
139
140		/* store acquired bits at respective bits array offset */
141		bits[word_index] |= (port_state << word_offset) & word_mask;
142	}
143
144	return 0;
145}
146
147static void idio_16_gpio_set(struct gpio_chip *chip, unsigned int offset,
148	int value)
149{
150	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
151	unsigned int mask = BIT(offset);
152	void __iomem *base;
153	unsigned long flags;
154	unsigned int out_state;
155
156	if (offset > 15)
157		return;
158
159	if (offset > 7) {
160		mask >>= 8;
161		base = &idio16gpio->reg->out8_15;
162	} else
163		base = &idio16gpio->reg->out0_7;
164
165	raw_spin_lock_irqsave(&idio16gpio->lock, flags);
166
167	if (value)
168		out_state = ioread8(base) | mask;
169	else
170		out_state = ioread8(base) & ~mask;
171
172	iowrite8(out_state, base);
173
174	raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
175}
176
177static void idio_16_gpio_set_multiple(struct gpio_chip *chip,
178	unsigned long *mask, unsigned long *bits)
179{
180	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
181	unsigned long flags;
182	unsigned int out_state;
183
184	raw_spin_lock_irqsave(&idio16gpio->lock, flags);
185
186	/* process output lines 0-7 */
187	if (*mask & 0xFF) {
188		out_state = ioread8(&idio16gpio->reg->out0_7) & ~*mask;
189		out_state |= *mask & *bits;
190		iowrite8(out_state, &idio16gpio->reg->out0_7);
191	}
192
193	/* shift to next output line word */
194	*mask >>= 8;
195
196	/* process output lines 8-15 */
197	if (*mask & 0xFF) {
198		*bits >>= 8;
199		out_state = ioread8(&idio16gpio->reg->out8_15) & ~*mask;
200		out_state |= *mask & *bits;
201		iowrite8(out_state, &idio16gpio->reg->out8_15);
202	}
203
204	raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
205}
206
207static void idio_16_irq_ack(struct irq_data *data)
208{
209}
210
211static void idio_16_irq_mask(struct irq_data *data)
212{
213	struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
214	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
215	const unsigned long mask = BIT(irqd_to_hwirq(data));
216	unsigned long flags;
217
218	idio16gpio->irq_mask &= ~mask;
219
220	if (!idio16gpio->irq_mask) {
221		raw_spin_lock_irqsave(&idio16gpio->lock, flags);
222
223		iowrite8(0, &idio16gpio->reg->irq_ctl);
224
225		raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
226	}
227}
228
229static void idio_16_irq_unmask(struct irq_data *data)
230{
231	struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
232	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
233	const unsigned long mask = BIT(irqd_to_hwirq(data));
234	const unsigned long prev_irq_mask = idio16gpio->irq_mask;
235	unsigned long flags;
236
237	idio16gpio->irq_mask |= mask;
238
239	if (!prev_irq_mask) {
240		raw_spin_lock_irqsave(&idio16gpio->lock, flags);
241
242		ioread8(&idio16gpio->reg->irq_ctl);
243
244		raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
245	}
246}
247
248static int idio_16_irq_set_type(struct irq_data *data, unsigned int flow_type)
249{
250	/* The only valid irq types are none and both-edges */
251	if (flow_type != IRQ_TYPE_NONE &&
252		(flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH)
253		return -EINVAL;
254
255	return 0;
256}
257
258static struct irq_chip idio_16_irqchip = {
259	.name = "pci-idio-16",
260	.irq_ack = idio_16_irq_ack,
261	.irq_mask = idio_16_irq_mask,
262	.irq_unmask = idio_16_irq_unmask,
263	.irq_set_type = idio_16_irq_set_type
264};
265
266static irqreturn_t idio_16_irq_handler(int irq, void *dev_id)
267{
268	struct idio_16_gpio *const idio16gpio = dev_id;
269	unsigned int irq_status;
270	struct gpio_chip *const chip = &idio16gpio->chip;
271	int gpio;
272
273	raw_spin_lock(&idio16gpio->lock);
274
275	irq_status = ioread8(&idio16gpio->reg->irq_status);
276
277	raw_spin_unlock(&idio16gpio->lock);
278
279	/* Make sure our device generated IRQ */
280	if (!(irq_status & 0x3) || !(irq_status & 0x4))
281		return IRQ_NONE;
282
283	for_each_set_bit(gpio, &idio16gpio->irq_mask, chip->ngpio)
284		generic_handle_irq(irq_find_mapping(chip->irq.domain, gpio));
285
286	raw_spin_lock(&idio16gpio->lock);
287
288	/* Clear interrupt */
289	iowrite8(0, &idio16gpio->reg->in0_7);
290
291	raw_spin_unlock(&idio16gpio->lock);
292
293	return IRQ_HANDLED;
294}
295
296#define IDIO_16_NGPIO 32
297static const char *idio_16_names[IDIO_16_NGPIO] = {
298	"OUT0", "OUT1", "OUT2", "OUT3", "OUT4", "OUT5", "OUT6", "OUT7",
299	"OUT8", "OUT9", "OUT10", "OUT11", "OUT12", "OUT13", "OUT14", "OUT15",
300	"IIN0", "IIN1", "IIN2", "IIN3", "IIN4", "IIN5", "IIN6", "IIN7",
301	"IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15"
 
 
 
 
 
302};
303
304static int idio_16_probe(struct pci_dev *pdev, const struct pci_device_id *id)
305{
306	struct device *const dev = &pdev->dev;
307	struct idio_16_gpio *idio16gpio;
308	int err;
309	const size_t pci_bar_index = 2;
310	const char *const name = pci_name(pdev);
311
312	idio16gpio = devm_kzalloc(dev, sizeof(*idio16gpio), GFP_KERNEL);
313	if (!idio16gpio)
314		return -ENOMEM;
315
316	err = pcim_enable_device(pdev);
317	if (err) {
318		dev_err(dev, "Failed to enable PCI device (%d)\n", err);
319		return err;
320	}
321
322	err = pcim_iomap_regions(pdev, BIT(pci_bar_index), name);
323	if (err) {
324		dev_err(dev, "Unable to map PCI I/O addresses (%d)\n", err);
325		return err;
326	}
327
328	idio16gpio->reg = pcim_iomap_table(pdev)[pci_bar_index];
329
330	/* Deactivate input filters */
331	iowrite8(0, &idio16gpio->reg->filter_ctl);
332
333	idio16gpio->chip.label = name;
334	idio16gpio->chip.parent = dev;
335	idio16gpio->chip.owner = THIS_MODULE;
336	idio16gpio->chip.base = -1;
337	idio16gpio->chip.ngpio = IDIO_16_NGPIO;
338	idio16gpio->chip.names = idio_16_names;
339	idio16gpio->chip.get_direction = idio_16_gpio_get_direction;
340	idio16gpio->chip.direction_input = idio_16_gpio_direction_input;
341	idio16gpio->chip.direction_output = idio_16_gpio_direction_output;
342	idio16gpio->chip.get = idio_16_gpio_get;
343	idio16gpio->chip.get_multiple = idio_16_gpio_get_multiple;
344	idio16gpio->chip.set = idio_16_gpio_set;
345	idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple;
346
347	raw_spin_lock_init(&idio16gpio->lock);
348
349	err = devm_gpiochip_add_data(dev, &idio16gpio->chip, idio16gpio);
350	if (err) {
351		dev_err(dev, "GPIO registering failed (%d)\n", err);
352		return err;
353	}
354
355	/* Disable IRQ by default and clear any pending interrupt */
356	iowrite8(0, &idio16gpio->reg->irq_ctl);
357	iowrite8(0, &idio16gpio->reg->in0_7);
358
359	err = gpiochip_irqchip_add(&idio16gpio->chip, &idio_16_irqchip, 0,
360		handle_edge_irq, IRQ_TYPE_NONE);
361	if (err) {
362		dev_err(dev, "Could not add irqchip (%d)\n", err);
363		return err;
364	}
365
366	err = devm_request_irq(dev, pdev->irq, idio_16_irq_handler, IRQF_SHARED,
367		name, idio16gpio);
368	if (err) {
369		dev_err(dev, "IRQ handler registering failed (%d)\n", err);
370		return err;
371	}
372
373	return 0;
374}
375
376static const struct pci_device_id idio_16_pci_dev_id[] = {
377	{ PCI_DEVICE(0x494F, 0x0DC8) }, { 0 }
378};
379MODULE_DEVICE_TABLE(pci, idio_16_pci_dev_id);
380
381static struct pci_driver idio_16_driver = {
382	.name = "pci-idio-16",
383	.id_table = idio_16_pci_dev_id,
384	.probe = idio_16_probe
385};
386
387module_pci_driver(idio_16_driver);
388
389MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
390MODULE_DESCRIPTION("ACCES PCI-IDIO-16 GPIO driver");
391MODULE_LICENSE("GPL v2");