1 /*
2  * GPIO driver for the ACCES 104-IDIO-16 family
3  * Copyright (C) 2015 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  * This driver supports the following ACCES devices: 104-IDIO-16,
15  * 104-IDIO-16E, 104-IDO-16, 104-IDIO-8, 104-IDIO-8E, and 104-IDO-8.
16  */
17 #include <linux/bitops.h>
18 #include <linux/device.h>
19 #include <linux/errno.h>
20 #include <linux/gpio/driver.h>
21 #include <linux/io.h>
22 #include <linux/ioport.h>
23 #include <linux/interrupt.h>
24 #include <linux/irqdesc.h>
25 #include <linux/isa.h>
26 #include <linux/kernel.h>
27 #include <linux/module.h>
28 #include <linux/moduleparam.h>
29 #include <linux/spinlock.h>
30 
31 #define IDIO_16_EXTENT 8
32 #define MAX_NUM_IDIO_16 max_num_isa_dev(IDIO_16_EXTENT)
33 
34 static unsigned int base[MAX_NUM_IDIO_16];
35 static unsigned int num_idio_16;
36 module_param_hw_array(base, uint, ioport, &num_idio_16, 0);
37 MODULE_PARM_DESC(base, "ACCES 104-IDIO-16 base addresses");
38 
39 static unsigned int irq[MAX_NUM_IDIO_16];
40 module_param_hw_array(irq, uint, irq, NULL, 0);
41 MODULE_PARM_DESC(irq, "ACCES 104-IDIO-16 interrupt line numbers");
42 
43 /**
44  * struct idio_16_gpio - GPIO device private data structure
45  * @chip:	instance of the gpio_chip
46  * @lock:	synchronization lock to prevent I/O race conditions
47  * @irq_mask:	I/O bits affected by interrupts
48  * @base:	base port address of the GPIO device
49  * @out_state:	output bits state
50  */
51 struct idio_16_gpio {
52 	struct gpio_chip chip;
53 	raw_spinlock_t lock;
54 	unsigned long irq_mask;
55 	unsigned base;
56 	unsigned out_state;
57 };
58 
idio_16_gpio_get_direction(struct gpio_chip * chip,unsigned offset)59 static int idio_16_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
60 {
61 	if (offset > 15)
62 		return 1;
63 
64 	return 0;
65 }
66 
idio_16_gpio_direction_input(struct gpio_chip * chip,unsigned offset)67 static int idio_16_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
68 {
69 	return 0;
70 }
71 
idio_16_gpio_direction_output(struct gpio_chip * chip,unsigned offset,int value)72 static int idio_16_gpio_direction_output(struct gpio_chip *chip,
73 	unsigned offset, int value)
74 {
75 	chip->set(chip, offset, value);
76 	return 0;
77 }
78 
idio_16_gpio_get(struct gpio_chip * chip,unsigned offset)79 static int idio_16_gpio_get(struct gpio_chip *chip, unsigned offset)
80 {
81 	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
82 	const unsigned mask = BIT(offset-16);
83 
84 	if (offset < 16)
85 		return -EINVAL;
86 
87 	if (offset < 24)
88 		return !!(inb(idio16gpio->base + 1) & mask);
89 
90 	return !!(inb(idio16gpio->base + 5) & (mask>>8));
91 }
92 
idio_16_gpio_get_multiple(struct gpio_chip * chip,unsigned long * mask,unsigned long * bits)93 static int idio_16_gpio_get_multiple(struct gpio_chip *chip,
94 	unsigned long *mask, unsigned long *bits)
95 {
96 	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
97 
98 	*bits = 0;
99 	if (*mask & GENMASK(23, 16))
100 		*bits |= (unsigned long)inb(idio16gpio->base + 1) << 16;
101 	if (*mask & GENMASK(31, 24))
102 		*bits |= (unsigned long)inb(idio16gpio->base + 5) << 24;
103 
104 	return 0;
105 }
106 
idio_16_gpio_set(struct gpio_chip * chip,unsigned offset,int value)107 static void idio_16_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
108 {
109 	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
110 	const unsigned mask = BIT(offset);
111 	unsigned long flags;
112 
113 	if (offset > 15)
114 		return;
115 
116 	raw_spin_lock_irqsave(&idio16gpio->lock, flags);
117 
118 	if (value)
119 		idio16gpio->out_state |= mask;
120 	else
121 		idio16gpio->out_state &= ~mask;
122 
123 	if (offset > 7)
124 		outb(idio16gpio->out_state >> 8, idio16gpio->base + 4);
125 	else
126 		outb(idio16gpio->out_state, idio16gpio->base);
127 
128 	raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
129 }
130 
idio_16_gpio_set_multiple(struct gpio_chip * chip,unsigned long * mask,unsigned long * bits)131 static void idio_16_gpio_set_multiple(struct gpio_chip *chip,
132 	unsigned long *mask, unsigned long *bits)
133 {
134 	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
135 	unsigned long flags;
136 
137 	raw_spin_lock_irqsave(&idio16gpio->lock, flags);
138 
139 	idio16gpio->out_state &= ~*mask;
140 	idio16gpio->out_state |= *mask & *bits;
141 
142 	if (*mask & 0xFF)
143 		outb(idio16gpio->out_state, idio16gpio->base);
144 	if ((*mask >> 8) & 0xFF)
145 		outb(idio16gpio->out_state >> 8, idio16gpio->base + 4);
146 
147 	raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
148 }
149 
idio_16_irq_ack(struct irq_data * data)150 static void idio_16_irq_ack(struct irq_data *data)
151 {
152 }
153 
idio_16_irq_mask(struct irq_data * data)154 static void idio_16_irq_mask(struct irq_data *data)
155 {
156 	struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
157 	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
158 	const unsigned long mask = BIT(irqd_to_hwirq(data));
159 	unsigned long flags;
160 
161 	idio16gpio->irq_mask &= ~mask;
162 
163 	if (!idio16gpio->irq_mask) {
164 		raw_spin_lock_irqsave(&idio16gpio->lock, flags);
165 
166 		outb(0, idio16gpio->base + 2);
167 
168 		raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
169 	}
170 }
171 
idio_16_irq_unmask(struct irq_data * data)172 static void idio_16_irq_unmask(struct irq_data *data)
173 {
174 	struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
175 	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
176 	const unsigned long mask = BIT(irqd_to_hwirq(data));
177 	const unsigned long prev_irq_mask = idio16gpio->irq_mask;
178 	unsigned long flags;
179 
180 	idio16gpio->irq_mask |= mask;
181 
182 	if (!prev_irq_mask) {
183 		raw_spin_lock_irqsave(&idio16gpio->lock, flags);
184 
185 		inb(idio16gpio->base + 2);
186 
187 		raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
188 	}
189 }
190 
idio_16_irq_set_type(struct irq_data * data,unsigned flow_type)191 static int idio_16_irq_set_type(struct irq_data *data, unsigned flow_type)
192 {
193 	/* The only valid irq types are none and both-edges */
194 	if (flow_type != IRQ_TYPE_NONE &&
195 		(flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH)
196 		return -EINVAL;
197 
198 	return 0;
199 }
200 
201 static struct irq_chip idio_16_irqchip = {
202 	.name = "104-idio-16",
203 	.irq_ack = idio_16_irq_ack,
204 	.irq_mask = idio_16_irq_mask,
205 	.irq_unmask = idio_16_irq_unmask,
206 	.irq_set_type = idio_16_irq_set_type
207 };
208 
idio_16_irq_handler(int irq,void * dev_id)209 static irqreturn_t idio_16_irq_handler(int irq, void *dev_id)
210 {
211 	struct idio_16_gpio *const idio16gpio = dev_id;
212 	struct gpio_chip *const chip = &idio16gpio->chip;
213 	int gpio;
214 
215 	for_each_set_bit(gpio, &idio16gpio->irq_mask, chip->ngpio)
216 		generic_handle_irq(irq_find_mapping(chip->irq.domain, gpio));
217 
218 	raw_spin_lock(&idio16gpio->lock);
219 
220 	outb(0, idio16gpio->base + 1);
221 
222 	raw_spin_unlock(&idio16gpio->lock);
223 
224 	return IRQ_HANDLED;
225 }
226 
227 #define IDIO_16_NGPIO 32
228 static const char *idio_16_names[IDIO_16_NGPIO] = {
229 	"OUT0", "OUT1", "OUT2", "OUT3", "OUT4", "OUT5", "OUT6", "OUT7",
230 	"OUT8", "OUT9", "OUT10", "OUT11", "OUT12", "OUT13", "OUT14", "OUT15",
231 	"IIN0", "IIN1", "IIN2", "IIN3", "IIN4", "IIN5", "IIN6", "IIN7",
232 	"IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15"
233 };
234 
idio_16_probe(struct device * dev,unsigned int id)235 static int idio_16_probe(struct device *dev, unsigned int id)
236 {
237 	struct idio_16_gpio *idio16gpio;
238 	const char *const name = dev_name(dev);
239 	int err;
240 
241 	idio16gpio = devm_kzalloc(dev, sizeof(*idio16gpio), GFP_KERNEL);
242 	if (!idio16gpio)
243 		return -ENOMEM;
244 
245 	if (!devm_request_region(dev, base[id], IDIO_16_EXTENT, name)) {
246 		dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
247 			base[id], base[id] + IDIO_16_EXTENT);
248 		return -EBUSY;
249 	}
250 
251 	idio16gpio->chip.label = name;
252 	idio16gpio->chip.parent = dev;
253 	idio16gpio->chip.owner = THIS_MODULE;
254 	idio16gpio->chip.base = -1;
255 	idio16gpio->chip.ngpio = IDIO_16_NGPIO;
256 	idio16gpio->chip.names = idio_16_names;
257 	idio16gpio->chip.get_direction = idio_16_gpio_get_direction;
258 	idio16gpio->chip.direction_input = idio_16_gpio_direction_input;
259 	idio16gpio->chip.direction_output = idio_16_gpio_direction_output;
260 	idio16gpio->chip.get = idio_16_gpio_get;
261 	idio16gpio->chip.get_multiple = idio_16_gpio_get_multiple;
262 	idio16gpio->chip.set = idio_16_gpio_set;
263 	idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple;
264 	idio16gpio->base = base[id];
265 	idio16gpio->out_state = 0xFFFF;
266 
267 	raw_spin_lock_init(&idio16gpio->lock);
268 
269 	err = devm_gpiochip_add_data(dev, &idio16gpio->chip, idio16gpio);
270 	if (err) {
271 		dev_err(dev, "GPIO registering failed (%d)\n", err);
272 		return err;
273 	}
274 
275 	/* Disable IRQ by default */
276 	outb(0, base[id] + 2);
277 	outb(0, base[id] + 1);
278 
279 	err = gpiochip_irqchip_add(&idio16gpio->chip, &idio_16_irqchip, 0,
280 		handle_edge_irq, IRQ_TYPE_NONE);
281 	if (err) {
282 		dev_err(dev, "Could not add irqchip (%d)\n", err);
283 		return err;
284 	}
285 
286 	err = devm_request_irq(dev, irq[id], idio_16_irq_handler, 0, name,
287 		idio16gpio);
288 	if (err) {
289 		dev_err(dev, "IRQ handler registering failed (%d)\n", err);
290 		return err;
291 	}
292 
293 	return 0;
294 }
295 
296 static struct isa_driver idio_16_driver = {
297 	.probe = idio_16_probe,
298 	.driver = {
299 		.name = "104-idio-16"
300 	},
301 };
302 
303 module_isa_driver(idio_16_driver, num_idio_16);
304 
305 MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
306 MODULE_DESCRIPTION("ACCES 104-IDIO-16 GPIO driver");
307 MODULE_LICENSE("GPL v2");
308