blob: 96700308c1e380f76b694a55f198c9267afb7781 [file] [log] [blame]
William Breathitt Gray1ceacea2015-10-19 12:59:14 -04001/*
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.
William Breathitt Gray86ea8a92016-05-01 18:45:11 -040013 *
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.
William Breathitt Gray1ceacea2015-10-19 12:59:14 -040016 */
William Breathitt Graya1184142015-11-03 07:54:23 -050017#include <linux/bitops.h>
William Breathitt Gray1ceacea2015-10-19 12:59:14 -040018#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>
William Breathitt Graya1184142015-11-03 07:54:23 -050023#include <linux/interrupt.h>
24#include <linux/irqdesc.h>
William Breathitt Gray86ea8a92016-05-01 18:45:11 -040025#include <linux/isa.h>
William Breathitt Gray1ceacea2015-10-19 12:59:14 -040026#include <linux/kernel.h>
27#include <linux/module.h>
28#include <linux/moduleparam.h>
William Breathitt Gray1ceacea2015-10-19 12:59:14 -040029#include <linux/spinlock.h>
30
William Breathitt Gray86ea8a92016-05-01 18:45:11 -040031#define IDIO_16_EXTENT 8
32#define MAX_NUM_IDIO_16 max_num_isa_dev(IDIO_16_EXTENT)
33
34static unsigned int base[MAX_NUM_IDIO_16];
35static unsigned int num_idio_16;
David Howellsd759f902017-04-04 16:54:22 +010036module_param_hw_array(base, uint, ioport, &num_idio_16, 0);
William Breathitt Gray86ea8a92016-05-01 18:45:11 -040037MODULE_PARM_DESC(base, "ACCES 104-IDIO-16 base addresses");
38
39static unsigned int irq[MAX_NUM_IDIO_16];
David Howellsd759f902017-04-04 16:54:22 +010040module_param_hw_array(irq, uint, irq, NULL, 0);
William Breathitt Gray86ea8a92016-05-01 18:45:11 -040041MODULE_PARM_DESC(irq, "ACCES 104-IDIO-16 interrupt line numbers");
William Breathitt Gray1ceacea2015-10-19 12:59:14 -040042
43/**
44 * struct idio_16_gpio - GPIO device private data structure
45 * @chip: instance of the gpio_chip
William Breathitt Graya1184142015-11-03 07:54:23 -050046 * @lock: synchronization lock to prevent I/O race conditions
47 * @irq_mask: I/O bits affected by interrupts
William Breathitt Gray1ceacea2015-10-19 12:59:14 -040048 * @base: base port address of the GPIO device
William Breathitt Gray1ceacea2015-10-19 12:59:14 -040049 * @out_state: output bits state
50 */
51struct idio_16_gpio {
52 struct gpio_chip chip;
Julia Cartwright3906e802017-03-21 17:43:08 -050053 raw_spinlock_t lock;
William Breathitt Graya1184142015-11-03 07:54:23 -050054 unsigned long irq_mask;
William Breathitt Gray1ceacea2015-10-19 12:59:14 -040055 unsigned base;
William Breathitt Gray1ceacea2015-10-19 12:59:14 -040056 unsigned out_state;
57};
58
59static 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
67static int idio_16_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
68{
69 return 0;
70}
71
72static 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
William Breathitt Gray1ceacea2015-10-19 12:59:14 -040079static int idio_16_gpio_get(struct gpio_chip *chip, unsigned offset)
80{
Linus Walleijd602ae92015-12-03 18:18:06 +010081 struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
William Breathitt Gray6e0171b2015-11-17 18:58:16 -050082 const unsigned mask = BIT(offset-16);
William Breathitt Gray1ceacea2015-10-19 12:59:14 -040083
84 if (offset < 16)
85 return -EINVAL;
86
87 if (offset < 24)
William Breathitt Gray6e0171b2015-11-17 18:58:16 -050088 return !!(inb(idio16gpio->base + 1) & mask);
William Breathitt Gray1ceacea2015-10-19 12:59:14 -040089
William Breathitt Gray6e0171b2015-11-17 18:58:16 -050090 return !!(inb(idio16gpio->base + 5) & (mask>>8));
William Breathitt Gray1ceacea2015-10-19 12:59:14 -040091}
92
William Breathitt Gray15f59cf2018-03-22 08:59:37 -040093static 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
William Breathitt Gray1ceacea2015-10-19 12:59:14 -0400107static void idio_16_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
108{
Linus Walleijd602ae92015-12-03 18:18:06 +0100109 struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
William Breathitt Gray6e0171b2015-11-17 18:58:16 -0500110 const unsigned mask = BIT(offset);
William Breathitt Gray1ceacea2015-10-19 12:59:14 -0400111 unsigned long flags;
112
113 if (offset > 15)
114 return;
115
Julia Cartwright3906e802017-03-21 17:43:08 -0500116 raw_spin_lock_irqsave(&idio16gpio->lock, flags);
William Breathitt Gray1ceacea2015-10-19 12:59:14 -0400117
118 if (value)
William Breathitt Gray6e0171b2015-11-17 18:58:16 -0500119 idio16gpio->out_state |= mask;
William Breathitt Gray1ceacea2015-10-19 12:59:14 -0400120 else
William Breathitt Gray6e0171b2015-11-17 18:58:16 -0500121 idio16gpio->out_state &= ~mask;
William Breathitt Gray1ceacea2015-10-19 12:59:14 -0400122
123 if (offset > 7)
124 outb(idio16gpio->out_state >> 8, idio16gpio->base + 4);
125 else
126 outb(idio16gpio->out_state, idio16gpio->base);
127
Julia Cartwright3906e802017-03-21 17:43:08 -0500128 raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
William Breathitt Gray1ceacea2015-10-19 12:59:14 -0400129}
130
William Breathitt Gray9d7ae812017-01-19 10:05:37 -0500131static 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
Julia Cartwright3906e802017-03-21 17:43:08 -0500137 raw_spin_lock_irqsave(&idio16gpio->lock, flags);
William Breathitt Gray9d7ae812017-01-19 10:05:37 -0500138
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
Julia Cartwright3906e802017-03-21 17:43:08 -0500147 raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
William Breathitt Gray9d7ae812017-01-19 10:05:37 -0500148}
149
William Breathitt Graya1184142015-11-03 07:54:23 -0500150static void idio_16_irq_ack(struct irq_data *data)
151{
William Breathitt Graya1184142015-11-03 07:54:23 -0500152}
153
154static void idio_16_irq_mask(struct irq_data *data)
155{
156 struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
Linus Walleijd602ae92015-12-03 18:18:06 +0100157 struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
William Breathitt Graya1184142015-11-03 07:54:23 -0500158 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) {
Julia Cartwright3906e802017-03-21 17:43:08 -0500164 raw_spin_lock_irqsave(&idio16gpio->lock, flags);
William Breathitt Graya1184142015-11-03 07:54:23 -0500165
166 outb(0, idio16gpio->base + 2);
167
Julia Cartwright3906e802017-03-21 17:43:08 -0500168 raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
William Breathitt Graya1184142015-11-03 07:54:23 -0500169 }
170}
171
172static void idio_16_irq_unmask(struct irq_data *data)
173{
174 struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
Linus Walleijd602ae92015-12-03 18:18:06 +0100175 struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
William Breathitt Graya1184142015-11-03 07:54:23 -0500176 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) {
Julia Cartwright3906e802017-03-21 17:43:08 -0500183 raw_spin_lock_irqsave(&idio16gpio->lock, flags);
William Breathitt Graya1184142015-11-03 07:54:23 -0500184
William Breathitt Graya1184142015-11-03 07:54:23 -0500185 inb(idio16gpio->base + 2);
186
Julia Cartwright3906e802017-03-21 17:43:08 -0500187 raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
William Breathitt Graya1184142015-11-03 07:54:23 -0500188 }
189}
190
191static 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
201static 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
209static 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)
Thierry Redingf0fbe7b2017-11-07 19:15:47 +0100216 generic_handle_irq(irq_find_mapping(chip->irq.domain, gpio));
William Breathitt Graya1184142015-11-03 07:54:23 -0500217
Julia Cartwright3906e802017-03-21 17:43:08 -0500218 raw_spin_lock(&idio16gpio->lock);
William Breathitt Gray12b61c92015-12-02 20:23:04 -0500219
220 outb(0, idio16gpio->base + 1);
221
Julia Cartwright3906e802017-03-21 17:43:08 -0500222 raw_spin_unlock(&idio16gpio->lock);
William Breathitt Gray12b61c92015-12-02 20:23:04 -0500223
William Breathitt Graya1184142015-11-03 07:54:23 -0500224 return IRQ_HANDLED;
225}
226
William Breathitt Graye0af4b52017-01-30 13:33:21 -0500227#define IDIO_16_NGPIO 32
228static 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
William Breathitt Gray86ea8a92016-05-01 18:45:11 -0400235static int idio_16_probe(struct device *dev, unsigned int id)
William Breathitt Gray1ceacea2015-10-19 12:59:14 -0400236{
William Breathitt Gray1ceacea2015-10-19 12:59:14 -0400237 struct idio_16_gpio *idio16gpio;
William Breathitt Gray6e0171b2015-11-17 18:58:16 -0500238 const char *const name = dev_name(dev);
William Breathitt Gray1ceacea2015-10-19 12:59:14 -0400239 int err;
William Breathitt Gray1ceacea2015-10-19 12:59:14 -0400240
241 idio16gpio = devm_kzalloc(dev, sizeof(*idio16gpio), GFP_KERNEL);
242 if (!idio16gpio)
243 return -ENOMEM;
244
William Breathitt Gray86ea8a92016-05-01 18:45:11 -0400245 if (!devm_request_region(dev, base[id], IDIO_16_EXTENT, name)) {
William Breathitt Graycb323892016-02-03 15:17:02 -0500246 dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
William Breathitt Gray86ea8a92016-05-01 18:45:11 -0400247 base[id], base[id] + IDIO_16_EXTENT);
William Breathitt Graycb323892016-02-03 15:17:02 -0500248 return -EBUSY;
William Breathitt Gray1ceacea2015-10-19 12:59:14 -0400249 }
250
William Breathitt Gray6e0171b2015-11-17 18:58:16 -0500251 idio16gpio->chip.label = name;
Linus Walleij58383c782015-11-04 09:56:26 +0100252 idio16gpio->chip.parent = dev;
William Breathitt Gray1ceacea2015-10-19 12:59:14 -0400253 idio16gpio->chip.owner = THIS_MODULE;
254 idio16gpio->chip.base = -1;
William Breathitt Graye0af4b52017-01-30 13:33:21 -0500255 idio16gpio->chip.ngpio = IDIO_16_NGPIO;
256 idio16gpio->chip.names = idio_16_names;
William Breathitt Gray1ceacea2015-10-19 12:59:14 -0400257 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;
William Breathitt Gray15f59cf2018-03-22 08:59:37 -0400261 idio16gpio->chip.get_multiple = idio_16_gpio_get_multiple;
William Breathitt Gray1ceacea2015-10-19 12:59:14 -0400262 idio16gpio->chip.set = idio_16_gpio_set;
William Breathitt Gray9d7ae812017-01-19 10:05:37 -0500263 idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple;
William Breathitt Gray86ea8a92016-05-01 18:45:11 -0400264 idio16gpio->base = base[id];
William Breathitt Gray1ceacea2015-10-19 12:59:14 -0400265 idio16gpio->out_state = 0xFFFF;
266
Julia Cartwright3906e802017-03-21 17:43:08 -0500267 raw_spin_lock_init(&idio16gpio->lock);
William Breathitt Gray1ceacea2015-10-19 12:59:14 -0400268
William Breathitt Gray837143d2017-01-24 15:00:54 -0500269 err = devm_gpiochip_add_data(dev, &idio16gpio->chip, idio16gpio);
William Breathitt Gray1ceacea2015-10-19 12:59:14 -0400270 if (err) {
271 dev_err(dev, "GPIO registering failed (%d)\n", err);
William Breathitt Graycb323892016-02-03 15:17:02 -0500272 return err;
William Breathitt Gray1ceacea2015-10-19 12:59:14 -0400273 }
274
William Breathitt Grayfb50cdf2015-11-22 11:38:55 -0500275 /* Disable IRQ by default */
William Breathitt Gray86ea8a92016-05-01 18:45:11 -0400276 outb(0, base[id] + 2);
277 outb(0, base[id] + 1);
William Breathitt Grayfb50cdf2015-11-22 11:38:55 -0500278
William Breathitt Graya1184142015-11-03 07:54:23 -0500279 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);
William Breathitt Gray837143d2017-01-24 15:00:54 -0500283 return err;
William Breathitt Graya1184142015-11-03 07:54:23 -0500284 }
285
William Breathitt Gray837143d2017-01-24 15:00:54 -0500286 err = devm_request_irq(dev, irq[id], idio_16_irq_handler, 0, name,
287 idio16gpio);
William Breathitt Graya1184142015-11-03 07:54:23 -0500288 if (err) {
289 dev_err(dev, "IRQ handler registering failed (%d)\n", err);
William Breathitt Gray837143d2017-01-24 15:00:54 -0500290 return err;
William Breathitt Graya1184142015-11-03 07:54:23 -0500291 }
292
William Breathitt Gray1ceacea2015-10-19 12:59:14 -0400293 return 0;
William Breathitt Gray1ceacea2015-10-19 12:59:14 -0400294}
295
William Breathitt Gray86ea8a92016-05-01 18:45:11 -0400296static struct isa_driver idio_16_driver = {
297 .probe = idio_16_probe,
William Breathitt Gray1ceacea2015-10-19 12:59:14 -0400298 .driver = {
299 .name = "104-idio-16"
300 },
William Breathitt Gray1ceacea2015-10-19 12:59:14 -0400301};
302
William Breathitt Gray86ea8a92016-05-01 18:45:11 -0400303module_isa_driver(idio_16_driver, num_idio_16);
William Breathitt Gray1ceacea2015-10-19 12:59:14 -0400304
305MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
306MODULE_DESCRIPTION("ACCES 104-IDIO-16 GPIO driver");
William Breathitt Gray22aeddb2016-02-01 18:51:49 -0500307MODULE_LICENSE("GPL v2");