11ceacea2SWilliam Breathitt Gray /*
21ceacea2SWilliam Breathitt Gray  * GPIO driver for the ACCES 104-IDIO-16 family
31ceacea2SWilliam Breathitt Gray  * Copyright (C) 2015 William Breathitt Gray
41ceacea2SWilliam Breathitt Gray  *
51ceacea2SWilliam Breathitt Gray  * This program is free software; you can redistribute it and/or modify
61ceacea2SWilliam Breathitt Gray  * it under the terms of the GNU General Public License, version 2, as
71ceacea2SWilliam Breathitt Gray  * published by the Free Software Foundation.
81ceacea2SWilliam Breathitt Gray  *
91ceacea2SWilliam Breathitt Gray  * This program is distributed in the hope that it will be useful, but
101ceacea2SWilliam Breathitt Gray  * WITHOUT ANY WARRANTY; without even the implied warranty of
111ceacea2SWilliam Breathitt Gray  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
121ceacea2SWilliam Breathitt Gray  * General Public License for more details.
1386ea8a95SWilliam Breathitt Gray  *
1486ea8a95SWilliam Breathitt Gray  * This driver supports the following ACCES devices: 104-IDIO-16,
1586ea8a95SWilliam Breathitt Gray  * 104-IDIO-16E, 104-IDO-16, 104-IDIO-8, 104-IDIO-8E, and 104-IDO-8.
161ceacea2SWilliam Breathitt Gray  */
17a1184147SWilliam Breathitt Gray #include <linux/bitops.h>
181ceacea2SWilliam Breathitt Gray #include <linux/device.h>
191ceacea2SWilliam Breathitt Gray #include <linux/errno.h>
201ceacea2SWilliam Breathitt Gray #include <linux/gpio/driver.h>
211ceacea2SWilliam Breathitt Gray #include <linux/io.h>
221ceacea2SWilliam Breathitt Gray #include <linux/ioport.h>
23a1184147SWilliam Breathitt Gray #include <linux/interrupt.h>
24a1184147SWilliam Breathitt Gray #include <linux/irqdesc.h>
2586ea8a95SWilliam Breathitt Gray #include <linux/isa.h>
261ceacea2SWilliam Breathitt Gray #include <linux/kernel.h>
271ceacea2SWilliam Breathitt Gray #include <linux/module.h>
281ceacea2SWilliam Breathitt Gray #include <linux/moduleparam.h>
291ceacea2SWilliam Breathitt Gray #include <linux/spinlock.h>
301ceacea2SWilliam Breathitt Gray 
3186ea8a95SWilliam Breathitt Gray #define IDIO_16_EXTENT 8
3286ea8a95SWilliam Breathitt Gray #define MAX_NUM_IDIO_16 max_num_isa_dev(IDIO_16_EXTENT)
3386ea8a95SWilliam Breathitt Gray 
3486ea8a95SWilliam Breathitt Gray static unsigned int base[MAX_NUM_IDIO_16];
3586ea8a95SWilliam Breathitt Gray static unsigned int num_idio_16;
36d759f906SDavid Howells module_param_hw_array(base, uint, ioport, &num_idio_16, 0);
3786ea8a95SWilliam Breathitt Gray MODULE_PARM_DESC(base, "ACCES 104-IDIO-16 base addresses");
3886ea8a95SWilliam Breathitt Gray 
3986ea8a95SWilliam Breathitt Gray static unsigned int irq[MAX_NUM_IDIO_16];
40d759f906SDavid Howells module_param_hw_array(irq, uint, irq, NULL, 0);
4186ea8a95SWilliam Breathitt Gray MODULE_PARM_DESC(irq, "ACCES 104-IDIO-16 interrupt line numbers");
421ceacea2SWilliam Breathitt Gray 
431ceacea2SWilliam Breathitt Gray /**
441ceacea2SWilliam Breathitt Gray  * struct idio_16_gpio - GPIO device private data structure
451ceacea2SWilliam Breathitt Gray  * @chip:	instance of the gpio_chip
46a1184147SWilliam Breathitt Gray  * @lock:	synchronization lock to prevent I/O race conditions
47a1184147SWilliam Breathitt Gray  * @irq_mask:	I/O bits affected by interrupts
481ceacea2SWilliam Breathitt Gray  * @base:	base port address of the GPIO device
491ceacea2SWilliam Breathitt Gray  * @out_state:	output bits state
501ceacea2SWilliam Breathitt Gray  */
511ceacea2SWilliam Breathitt Gray struct idio_16_gpio {
521ceacea2SWilliam Breathitt Gray 	struct gpio_chip chip;
533906e808SJulia Cartwright 	raw_spinlock_t lock;
54a1184147SWilliam Breathitt Gray 	unsigned long irq_mask;
551ceacea2SWilliam Breathitt Gray 	unsigned base;
561ceacea2SWilliam Breathitt Gray 	unsigned out_state;
571ceacea2SWilliam Breathitt Gray };
581ceacea2SWilliam Breathitt Gray 
591ceacea2SWilliam Breathitt Gray static int idio_16_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
601ceacea2SWilliam Breathitt Gray {
611ceacea2SWilliam Breathitt Gray 	if (offset > 15)
621ceacea2SWilliam Breathitt Gray 		return 1;
631ceacea2SWilliam Breathitt Gray 
641ceacea2SWilliam Breathitt Gray 	return 0;
651ceacea2SWilliam Breathitt Gray }
661ceacea2SWilliam Breathitt Gray 
671ceacea2SWilliam Breathitt Gray static int idio_16_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
681ceacea2SWilliam Breathitt Gray {
691ceacea2SWilliam Breathitt Gray 	return 0;
701ceacea2SWilliam Breathitt Gray }
711ceacea2SWilliam Breathitt Gray 
721ceacea2SWilliam Breathitt Gray static int idio_16_gpio_direction_output(struct gpio_chip *chip,
731ceacea2SWilliam Breathitt Gray 	unsigned offset, int value)
741ceacea2SWilliam Breathitt Gray {
751ceacea2SWilliam Breathitt Gray 	chip->set(chip, offset, value);
761ceacea2SWilliam Breathitt Gray 	return 0;
771ceacea2SWilliam Breathitt Gray }
781ceacea2SWilliam Breathitt Gray 
791ceacea2SWilliam Breathitt Gray static int idio_16_gpio_get(struct gpio_chip *chip, unsigned offset)
801ceacea2SWilliam Breathitt Gray {
81d602ae90SLinus Walleij 	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
826e0171b4SWilliam Breathitt Gray 	const unsigned mask = BIT(offset-16);
831ceacea2SWilliam Breathitt Gray 
841ceacea2SWilliam Breathitt Gray 	if (offset < 16)
851ceacea2SWilliam Breathitt Gray 		return -EINVAL;
861ceacea2SWilliam Breathitt Gray 
871ceacea2SWilliam Breathitt Gray 	if (offset < 24)
886e0171b4SWilliam Breathitt Gray 		return !!(inb(idio16gpio->base + 1) & mask);
891ceacea2SWilliam Breathitt Gray 
906e0171b4SWilliam Breathitt Gray 	return !!(inb(idio16gpio->base + 5) & (mask>>8));
911ceacea2SWilliam Breathitt Gray }
921ceacea2SWilliam Breathitt Gray 
9315f59cffSWilliam Breathitt Gray static int idio_16_gpio_get_multiple(struct gpio_chip *chip,
9415f59cffSWilliam Breathitt Gray 	unsigned long *mask, unsigned long *bits)
9515f59cffSWilliam Breathitt Gray {
9615f59cffSWilliam Breathitt Gray 	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
9715f59cffSWilliam Breathitt Gray 
9815f59cffSWilliam Breathitt Gray 	*bits = 0;
9915f59cffSWilliam Breathitt Gray 	if (*mask & GENMASK(23, 16))
10015f59cffSWilliam Breathitt Gray 		*bits |= (unsigned long)inb(idio16gpio->base + 1) << 16;
10115f59cffSWilliam Breathitt Gray 	if (*mask & GENMASK(31, 24))
10215f59cffSWilliam Breathitt Gray 		*bits |= (unsigned long)inb(idio16gpio->base + 5) << 24;
10315f59cffSWilliam Breathitt Gray 
10415f59cffSWilliam Breathitt Gray 	return 0;
10515f59cffSWilliam Breathitt Gray }
10615f59cffSWilliam Breathitt Gray 
1071ceacea2SWilliam Breathitt Gray static void idio_16_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
1081ceacea2SWilliam Breathitt Gray {
109d602ae90SLinus Walleij 	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
1106e0171b4SWilliam Breathitt Gray 	const unsigned mask = BIT(offset);
1111ceacea2SWilliam Breathitt Gray 	unsigned long flags;
1121ceacea2SWilliam Breathitt Gray 
1131ceacea2SWilliam Breathitt Gray 	if (offset > 15)
1141ceacea2SWilliam Breathitt Gray 		return;
1151ceacea2SWilliam Breathitt Gray 
1163906e808SJulia Cartwright 	raw_spin_lock_irqsave(&idio16gpio->lock, flags);
1171ceacea2SWilliam Breathitt Gray 
1181ceacea2SWilliam Breathitt Gray 	if (value)
1196e0171b4SWilliam Breathitt Gray 		idio16gpio->out_state |= mask;
1201ceacea2SWilliam Breathitt Gray 	else
1216e0171b4SWilliam Breathitt Gray 		idio16gpio->out_state &= ~mask;
1221ceacea2SWilliam Breathitt Gray 
1231ceacea2SWilliam Breathitt Gray 	if (offset > 7)
1241ceacea2SWilliam Breathitt Gray 		outb(idio16gpio->out_state >> 8, idio16gpio->base + 4);
1251ceacea2SWilliam Breathitt Gray 	else
1261ceacea2SWilliam Breathitt Gray 		outb(idio16gpio->out_state, idio16gpio->base);
1271ceacea2SWilliam Breathitt Gray 
1283906e808SJulia Cartwright 	raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
1291ceacea2SWilliam Breathitt Gray }
1301ceacea2SWilliam Breathitt Gray 
1319d7ae812SWilliam Breathitt Gray static void idio_16_gpio_set_multiple(struct gpio_chip *chip,
1329d7ae812SWilliam Breathitt Gray 	unsigned long *mask, unsigned long *bits)
1339d7ae812SWilliam Breathitt Gray {
1349d7ae812SWilliam Breathitt Gray 	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
1359d7ae812SWilliam Breathitt Gray 	unsigned long flags;
1369d7ae812SWilliam Breathitt Gray 
1373906e808SJulia Cartwright 	raw_spin_lock_irqsave(&idio16gpio->lock, flags);
1389d7ae812SWilliam Breathitt Gray 
1399d7ae812SWilliam Breathitt Gray 	idio16gpio->out_state &= ~*mask;
1409d7ae812SWilliam Breathitt Gray 	idio16gpio->out_state |= *mask & *bits;
1419d7ae812SWilliam Breathitt Gray 
1429d7ae812SWilliam Breathitt Gray 	if (*mask & 0xFF)
1439d7ae812SWilliam Breathitt Gray 		outb(idio16gpio->out_state, idio16gpio->base);
1449d7ae812SWilliam Breathitt Gray 	if ((*mask >> 8) & 0xFF)
1459d7ae812SWilliam Breathitt Gray 		outb(idio16gpio->out_state >> 8, idio16gpio->base + 4);
1469d7ae812SWilliam Breathitt Gray 
1473906e808SJulia Cartwright 	raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
1489d7ae812SWilliam Breathitt Gray }
1499d7ae812SWilliam Breathitt Gray 
150a1184147SWilliam Breathitt Gray static void idio_16_irq_ack(struct irq_data *data)
151a1184147SWilliam Breathitt Gray {
152a1184147SWilliam Breathitt Gray }
153a1184147SWilliam Breathitt Gray 
154a1184147SWilliam Breathitt Gray static void idio_16_irq_mask(struct irq_data *data)
155a1184147SWilliam Breathitt Gray {
156a1184147SWilliam Breathitt Gray 	struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
157d602ae90SLinus Walleij 	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
158a1184147SWilliam Breathitt Gray 	const unsigned long mask = BIT(irqd_to_hwirq(data));
159a1184147SWilliam Breathitt Gray 	unsigned long flags;
160a1184147SWilliam Breathitt Gray 
161a1184147SWilliam Breathitt Gray 	idio16gpio->irq_mask &= ~mask;
162a1184147SWilliam Breathitt Gray 
163a1184147SWilliam Breathitt Gray 	if (!idio16gpio->irq_mask) {
1643906e808SJulia Cartwright 		raw_spin_lock_irqsave(&idio16gpio->lock, flags);
165a1184147SWilliam Breathitt Gray 
166a1184147SWilliam Breathitt Gray 		outb(0, idio16gpio->base + 2);
167a1184147SWilliam Breathitt Gray 
1683906e808SJulia Cartwright 		raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
169a1184147SWilliam Breathitt Gray 	}
170a1184147SWilliam Breathitt Gray }
171a1184147SWilliam Breathitt Gray 
172a1184147SWilliam Breathitt Gray static void idio_16_irq_unmask(struct irq_data *data)
173a1184147SWilliam Breathitt Gray {
174a1184147SWilliam Breathitt Gray 	struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
175d602ae90SLinus Walleij 	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
176a1184147SWilliam Breathitt Gray 	const unsigned long mask = BIT(irqd_to_hwirq(data));
177a1184147SWilliam Breathitt Gray 	const unsigned long prev_irq_mask = idio16gpio->irq_mask;
178a1184147SWilliam Breathitt Gray 	unsigned long flags;
179a1184147SWilliam Breathitt Gray 
180a1184147SWilliam Breathitt Gray 	idio16gpio->irq_mask |= mask;
181a1184147SWilliam Breathitt Gray 
182a1184147SWilliam Breathitt Gray 	if (!prev_irq_mask) {
1833906e808SJulia Cartwright 		raw_spin_lock_irqsave(&idio16gpio->lock, flags);
184a1184147SWilliam Breathitt Gray 
185a1184147SWilliam Breathitt Gray 		inb(idio16gpio->base + 2);
186a1184147SWilliam Breathitt Gray 
1873906e808SJulia Cartwright 		raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
188a1184147SWilliam Breathitt Gray 	}
189a1184147SWilliam Breathitt Gray }
190a1184147SWilliam Breathitt Gray 
191a1184147SWilliam Breathitt Gray static int idio_16_irq_set_type(struct irq_data *data, unsigned flow_type)
192a1184147SWilliam Breathitt Gray {
193a1184147SWilliam Breathitt Gray 	/* The only valid irq types are none and both-edges */
194a1184147SWilliam Breathitt Gray 	if (flow_type != IRQ_TYPE_NONE &&
195a1184147SWilliam Breathitt Gray 		(flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH)
196a1184147SWilliam Breathitt Gray 		return -EINVAL;
197a1184147SWilliam Breathitt Gray 
198a1184147SWilliam Breathitt Gray 	return 0;
199a1184147SWilliam Breathitt Gray }
200a1184147SWilliam Breathitt Gray 
201a1184147SWilliam Breathitt Gray static struct irq_chip idio_16_irqchip = {
202a1184147SWilliam Breathitt Gray 	.name = "104-idio-16",
203a1184147SWilliam Breathitt Gray 	.irq_ack = idio_16_irq_ack,
204a1184147SWilliam Breathitt Gray 	.irq_mask = idio_16_irq_mask,
205a1184147SWilliam Breathitt Gray 	.irq_unmask = idio_16_irq_unmask,
206a1184147SWilliam Breathitt Gray 	.irq_set_type = idio_16_irq_set_type
207a1184147SWilliam Breathitt Gray };
208a1184147SWilliam Breathitt Gray 
209a1184147SWilliam Breathitt Gray static irqreturn_t idio_16_irq_handler(int irq, void *dev_id)
210a1184147SWilliam Breathitt Gray {
211a1184147SWilliam Breathitt Gray 	struct idio_16_gpio *const idio16gpio = dev_id;
212a1184147SWilliam Breathitt Gray 	struct gpio_chip *const chip = &idio16gpio->chip;
213a1184147SWilliam Breathitt Gray 	int gpio;
214a1184147SWilliam Breathitt Gray 
215a1184147SWilliam Breathitt Gray 	for_each_set_bit(gpio, &idio16gpio->irq_mask, chip->ngpio)
216f0fbe7bcSThierry Reding 		generic_handle_irq(irq_find_mapping(chip->irq.domain, gpio));
217a1184147SWilliam Breathitt Gray 
2183906e808SJulia Cartwright 	raw_spin_lock(&idio16gpio->lock);
21912b61c9dSWilliam Breathitt Gray 
22012b61c9dSWilliam Breathitt Gray 	outb(0, idio16gpio->base + 1);
22112b61c9dSWilliam Breathitt Gray 
2223906e808SJulia Cartwright 	raw_spin_unlock(&idio16gpio->lock);
22312b61c9dSWilliam Breathitt Gray 
224a1184147SWilliam Breathitt Gray 	return IRQ_HANDLED;
225a1184147SWilliam Breathitt Gray }
226a1184147SWilliam Breathitt Gray 
227e0af4b5eSWilliam Breathitt Gray #define IDIO_16_NGPIO 32
228e0af4b5eSWilliam Breathitt Gray static const char *idio_16_names[IDIO_16_NGPIO] = {
229e0af4b5eSWilliam Breathitt Gray 	"OUT0", "OUT1", "OUT2", "OUT3", "OUT4", "OUT5", "OUT6", "OUT7",
230e0af4b5eSWilliam Breathitt Gray 	"OUT8", "OUT9", "OUT10", "OUT11", "OUT12", "OUT13", "OUT14", "OUT15",
231e0af4b5eSWilliam Breathitt Gray 	"IIN0", "IIN1", "IIN2", "IIN3", "IIN4", "IIN5", "IIN6", "IIN7",
232e0af4b5eSWilliam Breathitt Gray 	"IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15"
233e0af4b5eSWilliam Breathitt Gray };
234e0af4b5eSWilliam Breathitt Gray 
23586ea8a95SWilliam Breathitt Gray static int idio_16_probe(struct device *dev, unsigned int id)
2361ceacea2SWilliam Breathitt Gray {
2371ceacea2SWilliam Breathitt Gray 	struct idio_16_gpio *idio16gpio;
2386e0171b4SWilliam Breathitt Gray 	const char *const name = dev_name(dev);
2391ceacea2SWilliam Breathitt Gray 	int err;
2401ceacea2SWilliam Breathitt Gray 
2411ceacea2SWilliam Breathitt Gray 	idio16gpio = devm_kzalloc(dev, sizeof(*idio16gpio), GFP_KERNEL);
2421ceacea2SWilliam Breathitt Gray 	if (!idio16gpio)
2431ceacea2SWilliam Breathitt Gray 		return -ENOMEM;
2441ceacea2SWilliam Breathitt Gray 
24586ea8a95SWilliam Breathitt Gray 	if (!devm_request_region(dev, base[id], IDIO_16_EXTENT, name)) {
246cb32389cSWilliam Breathitt Gray 		dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
24786ea8a95SWilliam Breathitt Gray 			base[id], base[id] + IDIO_16_EXTENT);
248cb32389cSWilliam Breathitt Gray 		return -EBUSY;
2491ceacea2SWilliam Breathitt Gray 	}
2501ceacea2SWilliam Breathitt Gray 
2516e0171b4SWilliam Breathitt Gray 	idio16gpio->chip.label = name;
25258383c78SLinus Walleij 	idio16gpio->chip.parent = dev;
2531ceacea2SWilliam Breathitt Gray 	idio16gpio->chip.owner = THIS_MODULE;
2541ceacea2SWilliam Breathitt Gray 	idio16gpio->chip.base = -1;
255e0af4b5eSWilliam Breathitt Gray 	idio16gpio->chip.ngpio = IDIO_16_NGPIO;
256e0af4b5eSWilliam Breathitt Gray 	idio16gpio->chip.names = idio_16_names;
2571ceacea2SWilliam Breathitt Gray 	idio16gpio->chip.get_direction = idio_16_gpio_get_direction;
2581ceacea2SWilliam Breathitt Gray 	idio16gpio->chip.direction_input = idio_16_gpio_direction_input;
2591ceacea2SWilliam Breathitt Gray 	idio16gpio->chip.direction_output = idio_16_gpio_direction_output;
2601ceacea2SWilliam Breathitt Gray 	idio16gpio->chip.get = idio_16_gpio_get;
26115f59cffSWilliam Breathitt Gray 	idio16gpio->chip.get_multiple = idio_16_gpio_get_multiple;
2621ceacea2SWilliam Breathitt Gray 	idio16gpio->chip.set = idio_16_gpio_set;
2639d7ae812SWilliam Breathitt Gray 	idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple;
26486ea8a95SWilliam Breathitt Gray 	idio16gpio->base = base[id];
2651ceacea2SWilliam Breathitt Gray 	idio16gpio->out_state = 0xFFFF;
2661ceacea2SWilliam Breathitt Gray 
2673906e808SJulia Cartwright 	raw_spin_lock_init(&idio16gpio->lock);
2681ceacea2SWilliam Breathitt Gray 
269837143d3SWilliam Breathitt Gray 	err = devm_gpiochip_add_data(dev, &idio16gpio->chip, idio16gpio);
2701ceacea2SWilliam Breathitt Gray 	if (err) {
2711ceacea2SWilliam Breathitt Gray 		dev_err(dev, "GPIO registering failed (%d)\n", err);
272cb32389cSWilliam Breathitt Gray 		return err;
2731ceacea2SWilliam Breathitt Gray 	}
2741ceacea2SWilliam Breathitt Gray 
275fb50cdfeSWilliam Breathitt Gray 	/* Disable IRQ by default */
27686ea8a95SWilliam Breathitt Gray 	outb(0, base[id] + 2);
27786ea8a95SWilliam Breathitt Gray 	outb(0, base[id] + 1);
278fb50cdfeSWilliam Breathitt Gray 
279a1184147SWilliam Breathitt Gray 	err = gpiochip_irqchip_add(&idio16gpio->chip, &idio_16_irqchip, 0,
280a1184147SWilliam Breathitt Gray 		handle_edge_irq, IRQ_TYPE_NONE);
281a1184147SWilliam Breathitt Gray 	if (err) {
282a1184147SWilliam Breathitt Gray 		dev_err(dev, "Could not add irqchip (%d)\n", err);
2831ceacea2SWilliam Breathitt Gray 		return err;
2841ceacea2SWilliam Breathitt Gray 	}
2851ceacea2SWilliam Breathitt Gray 
286837143d3SWilliam Breathitt Gray 	err = devm_request_irq(dev, irq[id], idio_16_irq_handler, 0, name,
287837143d3SWilliam Breathitt Gray 		idio16gpio);
288837143d3SWilliam Breathitt Gray 	if (err) {
289837143d3SWilliam Breathitt Gray 		dev_err(dev, "IRQ handler registering failed (%d)\n", err);
290837143d3SWilliam Breathitt Gray 		return err;
291837143d3SWilliam Breathitt Gray 	}
2921ceacea2SWilliam Breathitt Gray 
2931ceacea2SWilliam Breathitt Gray 	return 0;
2941ceacea2SWilliam Breathitt Gray }
2951ceacea2SWilliam Breathitt Gray 
29686ea8a95SWilliam Breathitt Gray static struct isa_driver idio_16_driver = {
29786ea8a95SWilliam Breathitt Gray 	.probe = idio_16_probe,
2981ceacea2SWilliam Breathitt Gray 	.driver = {
2991ceacea2SWilliam Breathitt Gray 		.name = "104-idio-16"
3001ceacea2SWilliam Breathitt Gray 	},
3011ceacea2SWilliam Breathitt Gray };
3021ceacea2SWilliam Breathitt Gray 
30386ea8a95SWilliam Breathitt Gray module_isa_driver(idio_16_driver, num_idio_16);
3041ceacea2SWilliam Breathitt Gray 
3051ceacea2SWilliam Breathitt Gray MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
3061ceacea2SWilliam Breathitt Gray MODULE_DESCRIPTION("ACCES 104-IDIO-16 GPIO driver");
30722aeddb5SWilliam Breathitt Gray MODULE_LICENSE("GPL v2");
308