Linux Audio

Check our new training course

Loading...
v6.2
  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/errno.h>
  9#include <linux/gpio/driver.h>
 10#include <linux/interrupt.h>
 11#include <linux/irqdesc.h>
 12#include <linux/kernel.h>
 13#include <linux/module.h>
 14#include <linux/pci.h>
 15#include <linux/spinlock.h>
 16#include <linux/types.h>
 17
 18#include "gpio-idio-16.h"
 19
 20/**
 21 * struct idio_16_gpio - GPIO device private data structure
 22 * @chip:	instance of the gpio_chip
 23 * @lock:	synchronization lock to prevent I/O race conditions
 24 * @reg:	I/O address offset for the GPIO device registers
 25 * @state:	ACCES IDIO-16 device state
 26 * @irq_mask:	I/O bits affected by interrupts
 27 */
 28struct idio_16_gpio {
 29	struct gpio_chip chip;
 30	raw_spinlock_t lock;
 31	struct idio_16 __iomem *reg;
 32	struct idio_16_state state;
 33	unsigned long irq_mask;
 34};
 35
 36static int idio_16_gpio_get_direction(struct gpio_chip *chip,
 37	unsigned int offset)
 38{
 39	if (idio_16_get_direction(offset))
 40		return GPIO_LINE_DIRECTION_IN;
 41
 42	return GPIO_LINE_DIRECTION_OUT;
 43}
 44
 45static int idio_16_gpio_direction_input(struct gpio_chip *chip,
 46	unsigned int offset)
 47{
 48	return 0;
 49}
 50
 51static int idio_16_gpio_direction_output(struct gpio_chip *chip,
 52	unsigned int offset, int value)
 53{
 54	chip->set(chip, offset, value);
 55	return 0;
 56}
 57
 58static int idio_16_gpio_get(struct gpio_chip *chip, unsigned int offset)
 59{
 60	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
 61
 62	return idio_16_get(idio16gpio->reg, &idio16gpio->state, offset);
 63}
 64
 65static int idio_16_gpio_get_multiple(struct gpio_chip *chip,
 66	unsigned long *mask, unsigned long *bits)
 67{
 68	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
 69
 70	idio_16_get_multiple(idio16gpio->reg, &idio16gpio->state, mask, bits);
 71	return 0;
 72}
 73
 74static void idio_16_gpio_set(struct gpio_chip *chip, unsigned int offset,
 75	int value)
 76{
 77	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
 78
 79	idio_16_set(idio16gpio->reg, &idio16gpio->state, offset, value);
 80}
 81
 82static void idio_16_gpio_set_multiple(struct gpio_chip *chip,
 83	unsigned long *mask, unsigned long *bits)
 84{
 85	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
 86
 87	idio_16_set_multiple(idio16gpio->reg, &idio16gpio->state, mask, bits);
 88}
 89
 90static void idio_16_irq_ack(struct irq_data *data)
 91{
 92}
 93
 94static void idio_16_irq_mask(struct irq_data *data)
 95{
 96	struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
 97	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
 98	const unsigned long mask = BIT(irqd_to_hwirq(data));
 99	unsigned long flags;
100
101	idio16gpio->irq_mask &= ~mask;
102
103	if (!idio16gpio->irq_mask) {
104		raw_spin_lock_irqsave(&idio16gpio->lock, flags);
105
106		iowrite8(0, &idio16gpio->reg->irq_ctl);
107
108		raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
109	}
110}
111
112static void idio_16_irq_unmask(struct irq_data *data)
113{
114	struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
115	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
116	const unsigned long mask = BIT(irqd_to_hwirq(data));
117	const unsigned long prev_irq_mask = idio16gpio->irq_mask;
118	unsigned long flags;
119
120	idio16gpio->irq_mask |= mask;
121
122	if (!prev_irq_mask) {
123		raw_spin_lock_irqsave(&idio16gpio->lock, flags);
124
125		ioread8(&idio16gpio->reg->irq_ctl);
126
127		raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
128	}
129}
130
131static int idio_16_irq_set_type(struct irq_data *data, unsigned int flow_type)
132{
133	/* The only valid irq types are none and both-edges */
134	if (flow_type != IRQ_TYPE_NONE &&
135		(flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH)
136		return -EINVAL;
137
138	return 0;
139}
140
141static struct irq_chip idio_16_irqchip = {
142	.name = "pci-idio-16",
143	.irq_ack = idio_16_irq_ack,
144	.irq_mask = idio_16_irq_mask,
145	.irq_unmask = idio_16_irq_unmask,
146	.irq_set_type = idio_16_irq_set_type
147};
148
149static irqreturn_t idio_16_irq_handler(int irq, void *dev_id)
150{
151	struct idio_16_gpio *const idio16gpio = dev_id;
152	unsigned int irq_status;
153	struct gpio_chip *const chip = &idio16gpio->chip;
154	int gpio;
155
156	raw_spin_lock(&idio16gpio->lock);
157
158	irq_status = ioread8(&idio16gpio->reg->irq_status);
159
160	raw_spin_unlock(&idio16gpio->lock);
161
162	/* Make sure our device generated IRQ */
163	if (!(irq_status & 0x3) || !(irq_status & 0x4))
164		return IRQ_NONE;
165
166	for_each_set_bit(gpio, &idio16gpio->irq_mask, chip->ngpio)
167		generic_handle_domain_irq(chip->irq.domain, gpio);
168
169	raw_spin_lock(&idio16gpio->lock);
170
171	/* Clear interrupt */
172	iowrite8(0, &idio16gpio->reg->in0_7);
173
174	raw_spin_unlock(&idio16gpio->lock);
175
176	return IRQ_HANDLED;
177}
178
179#define IDIO_16_NGPIO 32
180static const char *idio_16_names[IDIO_16_NGPIO] = {
181	"OUT0", "OUT1", "OUT2", "OUT3", "OUT4", "OUT5", "OUT6", "OUT7",
182	"OUT8", "OUT9", "OUT10", "OUT11", "OUT12", "OUT13", "OUT14", "OUT15",
183	"IIN0", "IIN1", "IIN2", "IIN3", "IIN4", "IIN5", "IIN6", "IIN7",
184	"IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15"
185};
186
187static int idio_16_irq_init_hw(struct gpio_chip *gc)
188{
189	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(gc);
190
191	/* Disable IRQ by default and clear any pending interrupt */
192	iowrite8(0, &idio16gpio->reg->irq_ctl);
193	iowrite8(0, &idio16gpio->reg->in0_7);
194
195	return 0;
196}
 
 
 
 
 
 
197
198static int idio_16_probe(struct pci_dev *pdev, const struct pci_device_id *id)
199{
200	struct device *const dev = &pdev->dev;
201	struct idio_16_gpio *idio16gpio;
202	int err;
203	const size_t pci_bar_index = 2;
204	const char *const name = pci_name(pdev);
205	struct gpio_irq_chip *girq;
206
207	idio16gpio = devm_kzalloc(dev, sizeof(*idio16gpio), GFP_KERNEL);
208	if (!idio16gpio)
209		return -ENOMEM;
210
211	err = pcim_enable_device(pdev);
212	if (err) {
213		dev_err(dev, "Failed to enable PCI device (%d)\n", err);
214		return err;
215	}
216
217	err = pcim_iomap_regions(pdev, BIT(pci_bar_index), name);
218	if (err) {
219		dev_err(dev, "Unable to map PCI I/O addresses (%d)\n", err);
220		return err;
221	}
222
223	idio16gpio->reg = pcim_iomap_table(pdev)[pci_bar_index];
224
225	/* Deactivate input filters */
226	iowrite8(0, &idio16gpio->reg->filter_ctl);
227
228	idio16gpio->chip.label = name;
229	idio16gpio->chip.parent = dev;
230	idio16gpio->chip.owner = THIS_MODULE;
231	idio16gpio->chip.base = -1;
232	idio16gpio->chip.ngpio = IDIO_16_NGPIO;
233	idio16gpio->chip.names = idio_16_names;
234	idio16gpio->chip.get_direction = idio_16_gpio_get_direction;
235	idio16gpio->chip.direction_input = idio_16_gpio_direction_input;
236	idio16gpio->chip.direction_output = idio_16_gpio_direction_output;
237	idio16gpio->chip.get = idio_16_gpio_get;
238	idio16gpio->chip.get_multiple = idio_16_gpio_get_multiple;
239	idio16gpio->chip.set = idio_16_gpio_set;
240	idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple;
241
242	idio_16_state_init(&idio16gpio->state);
243
244	girq = &idio16gpio->chip.irq;
245	girq->chip = &idio_16_irqchip;
246	/* This will let us handle the parent IRQ in the driver */
247	girq->parent_handler = NULL;
248	girq->num_parents = 0;
249	girq->parents = NULL;
250	girq->default_type = IRQ_TYPE_NONE;
251	girq->handler = handle_edge_irq;
252	girq->init_hw = idio_16_irq_init_hw;
253
254	raw_spin_lock_init(&idio16gpio->lock);
255
256	err = devm_gpiochip_add_data(dev, &idio16gpio->chip, idio16gpio);
257	if (err) {
258		dev_err(dev, "GPIO registering failed (%d)\n", err);
259		return err;
260	}
261
262	err = devm_request_irq(dev, pdev->irq, idio_16_irq_handler, IRQF_SHARED,
263		name, idio16gpio);
264	if (err) {
265		dev_err(dev, "IRQ handler registering failed (%d)\n", err);
266		return err;
267	}
268
269	return 0;
270}
271
272static const struct pci_device_id idio_16_pci_dev_id[] = {
273	{ PCI_DEVICE(0x494F, 0x0DC8) }, { 0 }
274};
275MODULE_DEVICE_TABLE(pci, idio_16_pci_dev_id);
276
277static struct pci_driver idio_16_driver = {
278	.name = "pci-idio-16",
279	.id_table = idio_16_pci_dev_id,
280	.probe = idio_16_probe
281};
282
283module_pci_driver(idio_16_driver);
284
285MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
286MODULE_DESCRIPTION("ACCES PCI-IDIO-16 GPIO driver");
287MODULE_LICENSE("GPL v2");
288MODULE_IMPORT_NS(GPIO_IDIO_16);
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");