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