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 #include <linux/bitops.h>
15 #include <linux/device.h>
16 #include <linux/errno.h>
17 #include <linux/gpio/driver.h>
18 #include <linux/io.h>
19 #include <linux/ioport.h>
20 #include <linux/interrupt.h>
21 #include <linux/irqdesc.h>
22 #include <linux/kernel.h>
23 #include <linux/module.h>
24 #include <linux/moduleparam.h>
25 #include <linux/platform_device.h>
26 #include <linux/spinlock.h>
27 
28 static unsigned idio_16_base;
29 module_param(idio_16_base, uint, 0);
30 MODULE_PARM_DESC(idio_16_base, "ACCES 104-IDIO-16 base address");
31 static unsigned idio_16_irq;
32 module_param(idio_16_irq, uint, 0);
33 MODULE_PARM_DESC(idio_16_irq, "ACCES 104-IDIO-16 interrupt line number");
34 
35 /**
36  * struct idio_16_gpio - GPIO device private data structure
37  * @chip:	instance of the gpio_chip
38  * @lock:	synchronization lock to prevent I/O race conditions
39  * @irq_mask:	I/O bits affected by interrupts
40  * @base:	base port address of the GPIO device
41  * @extent:	extent of port address region of the GPIO device
42  * @irq:	Interrupt line number
43  * @out_state:	output bits state
44  */
45 struct idio_16_gpio {
46 	struct gpio_chip chip;
47 	spinlock_t lock;
48 	unsigned long irq_mask;
49 	unsigned base;
50 	unsigned extent;
51 	unsigned irq;
52 	unsigned out_state;
53 };
54 
55 static int idio_16_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
56 {
57 	if (offset > 15)
58 		return 1;
59 
60 	return 0;
61 }
62 
63 static int idio_16_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
64 {
65 	return 0;
66 }
67 
68 static int idio_16_gpio_direction_output(struct gpio_chip *chip,
69 	unsigned offset, int value)
70 {
71 	chip->set(chip, offset, value);
72 	return 0;
73 }
74 
75 static int idio_16_gpio_get(struct gpio_chip *chip, unsigned offset)
76 {
77 	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
78 	const unsigned mask = BIT(offset-16);
79 
80 	if (offset < 16)
81 		return -EINVAL;
82 
83 	if (offset < 24)
84 		return !!(inb(idio16gpio->base + 1) & mask);
85 
86 	return !!(inb(idio16gpio->base + 5) & (mask>>8));
87 }
88 
89 static void idio_16_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
90 {
91 	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
92 	const unsigned mask = BIT(offset);
93 	unsigned long flags;
94 
95 	if (offset > 15)
96 		return;
97 
98 	spin_lock_irqsave(&idio16gpio->lock, flags);
99 
100 	if (value)
101 		idio16gpio->out_state |= mask;
102 	else
103 		idio16gpio->out_state &= ~mask;
104 
105 	if (offset > 7)
106 		outb(idio16gpio->out_state >> 8, idio16gpio->base + 4);
107 	else
108 		outb(idio16gpio->out_state, idio16gpio->base);
109 
110 	spin_unlock_irqrestore(&idio16gpio->lock, flags);
111 }
112 
113 static void idio_16_irq_ack(struct irq_data *data)
114 {
115 }
116 
117 static void idio_16_irq_mask(struct irq_data *data)
118 {
119 	struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
120 	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
121 	const unsigned long mask = BIT(irqd_to_hwirq(data));
122 	unsigned long flags;
123 
124 	idio16gpio->irq_mask &= ~mask;
125 
126 	if (!idio16gpio->irq_mask) {
127 		spin_lock_irqsave(&idio16gpio->lock, flags);
128 
129 		outb(0, idio16gpio->base + 2);
130 
131 		spin_unlock_irqrestore(&idio16gpio->lock, flags);
132 	}
133 }
134 
135 static void idio_16_irq_unmask(struct irq_data *data)
136 {
137 	struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
138 	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
139 	const unsigned long mask = BIT(irqd_to_hwirq(data));
140 	const unsigned long prev_irq_mask = idio16gpio->irq_mask;
141 	unsigned long flags;
142 
143 	idio16gpio->irq_mask |= mask;
144 
145 	if (!prev_irq_mask) {
146 		spin_lock_irqsave(&idio16gpio->lock, flags);
147 
148 		inb(idio16gpio->base + 2);
149 
150 		spin_unlock_irqrestore(&idio16gpio->lock, flags);
151 	}
152 }
153 
154 static int idio_16_irq_set_type(struct irq_data *data, unsigned flow_type)
155 {
156 	/* The only valid irq types are none and both-edges */
157 	if (flow_type != IRQ_TYPE_NONE &&
158 		(flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH)
159 		return -EINVAL;
160 
161 	return 0;
162 }
163 
164 static struct irq_chip idio_16_irqchip = {
165 	.name = "104-idio-16",
166 	.irq_ack = idio_16_irq_ack,
167 	.irq_mask = idio_16_irq_mask,
168 	.irq_unmask = idio_16_irq_unmask,
169 	.irq_set_type = idio_16_irq_set_type
170 };
171 
172 static irqreturn_t idio_16_irq_handler(int irq, void *dev_id)
173 {
174 	struct idio_16_gpio *const idio16gpio = dev_id;
175 	struct gpio_chip *const chip = &idio16gpio->chip;
176 	int gpio;
177 
178 	for_each_set_bit(gpio, &idio16gpio->irq_mask, chip->ngpio)
179 		generic_handle_irq(irq_find_mapping(chip->irqdomain, gpio));
180 
181 	spin_lock(&idio16gpio->lock);
182 
183 	outb(0, idio16gpio->base + 1);
184 
185 	spin_unlock(&idio16gpio->lock);
186 
187 	return IRQ_HANDLED;
188 }
189 
190 static int __init idio_16_probe(struct platform_device *pdev)
191 {
192 	struct device *dev = &pdev->dev;
193 	struct idio_16_gpio *idio16gpio;
194 	const unsigned base = idio_16_base;
195 	const unsigned extent = 8;
196 	const char *const name = dev_name(dev);
197 	int err;
198 	const unsigned irq = idio_16_irq;
199 
200 	idio16gpio = devm_kzalloc(dev, sizeof(*idio16gpio), GFP_KERNEL);
201 	if (!idio16gpio)
202 		return -ENOMEM;
203 
204 	if (!request_region(base, extent, name)) {
205 		dev_err(dev, "Unable to lock %s port addresses (0x%X-0x%X)\n",
206 			name, base, base + extent);
207 		err = -EBUSY;
208 		goto err_lock_io_port;
209 	}
210 
211 	idio16gpio->chip.label = name;
212 	idio16gpio->chip.parent = dev;
213 	idio16gpio->chip.owner = THIS_MODULE;
214 	idio16gpio->chip.base = -1;
215 	idio16gpio->chip.ngpio = 32;
216 	idio16gpio->chip.get_direction = idio_16_gpio_get_direction;
217 	idio16gpio->chip.direction_input = idio_16_gpio_direction_input;
218 	idio16gpio->chip.direction_output = idio_16_gpio_direction_output;
219 	idio16gpio->chip.get = idio_16_gpio_get;
220 	idio16gpio->chip.set = idio_16_gpio_set;
221 	idio16gpio->base = base;
222 	idio16gpio->extent = extent;
223 	idio16gpio->irq = irq;
224 	idio16gpio->out_state = 0xFFFF;
225 
226 	spin_lock_init(&idio16gpio->lock);
227 
228 	dev_set_drvdata(dev, idio16gpio);
229 
230 	err = gpiochip_add_data(&idio16gpio->chip, idio16gpio);
231 	if (err) {
232 		dev_err(dev, "GPIO registering failed (%d)\n", err);
233 		goto err_gpio_register;
234 	}
235 
236 	/* Disable IRQ by default */
237 	outb(0, base + 2);
238 	outb(0, base + 1);
239 
240 	err = gpiochip_irqchip_add(&idio16gpio->chip, &idio_16_irqchip, 0,
241 		handle_edge_irq, IRQ_TYPE_NONE);
242 	if (err) {
243 		dev_err(dev, "Could not add irqchip (%d)\n", err);
244 		goto err_gpiochip_irqchip_add;
245 	}
246 
247 	err = request_irq(irq, idio_16_irq_handler, 0, name, idio16gpio);
248 	if (err) {
249 		dev_err(dev, "IRQ handler registering failed (%d)\n", err);
250 		goto err_request_irq;
251 	}
252 
253 	return 0;
254 
255 err_request_irq:
256 err_gpiochip_irqchip_add:
257 	gpiochip_remove(&idio16gpio->chip);
258 err_gpio_register:
259 	release_region(base, extent);
260 err_lock_io_port:
261 	return err;
262 }
263 
264 static int idio_16_remove(struct platform_device *pdev)
265 {
266 	struct idio_16_gpio *const idio16gpio = platform_get_drvdata(pdev);
267 
268 	free_irq(idio16gpio->irq, idio16gpio);
269 	gpiochip_remove(&idio16gpio->chip);
270 	release_region(idio16gpio->base, idio16gpio->extent);
271 
272 	return 0;
273 }
274 
275 static struct platform_device *idio_16_device;
276 
277 static struct platform_driver idio_16_driver = {
278 	.driver = {
279 		.name = "104-idio-16"
280 	},
281 	.remove = idio_16_remove
282 };
283 
284 static void __exit idio_16_exit(void)
285 {
286 	platform_device_unregister(idio_16_device);
287 	platform_driver_unregister(&idio_16_driver);
288 }
289 
290 static int __init idio_16_init(void)
291 {
292 	int err;
293 
294 	idio_16_device = platform_device_alloc(idio_16_driver.driver.name, -1);
295 	if (!idio_16_device)
296 		return -ENOMEM;
297 
298 	err = platform_device_add(idio_16_device);
299 	if (err)
300 		goto err_platform_device;
301 
302 	err = platform_driver_probe(&idio_16_driver, idio_16_probe);
303 	if (err)
304 		goto err_platform_driver;
305 
306 	return 0;
307 
308 err_platform_driver:
309 	platform_device_del(idio_16_device);
310 err_platform_device:
311 	platform_device_put(idio_16_device);
312 	return err;
313 }
314 
315 module_init(idio_16_init);
316 module_exit(idio_16_exit);
317 
318 MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
319 MODULE_DESCRIPTION("ACCES 104-IDIO-16 GPIO driver");
320 MODULE_LICENSE("GPL");
321