blob: 50ad0280fd783ea6059bbf5df3c0d1426f9f23ed [file] [log] [blame]
Thomas Gleixner1802d0b2019-05-27 08:55:21 +02001// SPDX-License-Identifier: GPL-2.0-only
William Breathitt Gray1ceacea2015-10-19 12:59:14 -04002/*
3 * GPIO driver for the ACCES 104-IDIO-16 family
4 * Copyright (C) 2015 William Breathitt Gray
5 *
William Breathitt Gray86ea8a92016-05-01 18:45:11 -04006 * This driver supports the following ACCES devices: 104-IDIO-16,
7 * 104-IDIO-16E, 104-IDO-16, 104-IDIO-8, 104-IDIO-8E, and 104-IDO-8.
William Breathitt Gray1ceacea2015-10-19 12:59:14 -04008 */
William Breathitt Graya1184142015-11-03 07:54:23 -05009#include <linux/bitops.h>
William Breathitt Gray1ceacea2015-10-19 12:59:14 -040010#include <linux/device.h>
11#include <linux/errno.h>
12#include <linux/gpio/driver.h>
13#include <linux/io.h>
14#include <linux/ioport.h>
William Breathitt Graya1184142015-11-03 07:54:23 -050015#include <linux/interrupt.h>
16#include <linux/irqdesc.h>
William Breathitt Gray86ea8a92016-05-01 18:45:11 -040017#include <linux/isa.h>
William Breathitt Gray1ceacea2015-10-19 12:59:14 -040018#include <linux/kernel.h>
19#include <linux/module.h>
20#include <linux/moduleparam.h>
William Breathitt Gray1ceacea2015-10-19 12:59:14 -040021#include <linux/spinlock.h>
22
William Breathitt Gray86ea8a92016-05-01 18:45:11 -040023#define IDIO_16_EXTENT 8
24#define MAX_NUM_IDIO_16 max_num_isa_dev(IDIO_16_EXTENT)
25
26static unsigned int base[MAX_NUM_IDIO_16];
27static unsigned int num_idio_16;
David Howellsd759f902017-04-04 16:54:22 +010028module_param_hw_array(base, uint, ioport, &num_idio_16, 0);
William Breathitt Gray86ea8a92016-05-01 18:45:11 -040029MODULE_PARM_DESC(base, "ACCES 104-IDIO-16 base addresses");
30
31static unsigned int irq[MAX_NUM_IDIO_16];
David Howellsd759f902017-04-04 16:54:22 +010032module_param_hw_array(irq, uint, irq, NULL, 0);
William Breathitt Gray86ea8a92016-05-01 18:45:11 -040033MODULE_PARM_DESC(irq, "ACCES 104-IDIO-16 interrupt line numbers");
William Breathitt Gray1ceacea2015-10-19 12:59:14 -040034
35/**
36 * struct idio_16_gpio - GPIO device private data structure
37 * @chip: instance of the gpio_chip
William Breathitt Graya1184142015-11-03 07:54:23 -050038 * @lock: synchronization lock to prevent I/O race conditions
39 * @irq_mask: I/O bits affected by interrupts
William Breathitt Gray1ceacea2015-10-19 12:59:14 -040040 * @base: base port address of the GPIO device
William Breathitt Gray1ceacea2015-10-19 12:59:14 -040041 * @out_state: output bits state
42 */
43struct idio_16_gpio {
44 struct gpio_chip chip;
Julia Cartwright3906e802017-03-21 17:43:08 -050045 raw_spinlock_t lock;
William Breathitt Graya1184142015-11-03 07:54:23 -050046 unsigned long irq_mask;
William Breathitt Gray1ceacea2015-10-19 12:59:14 -040047 unsigned base;
William Breathitt Gray1ceacea2015-10-19 12:59:14 -040048 unsigned out_state;
49};
50
51static int idio_16_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
52{
53 if (offset > 15)
Matti Vaittinene42615e2019-11-06 10:54:12 +020054 return GPIO_LINE_DIRECTION_IN;
William Breathitt Gray1ceacea2015-10-19 12:59:14 -040055
Matti Vaittinene42615e2019-11-06 10:54:12 +020056 return GPIO_LINE_DIRECTION_OUT;
William Breathitt Gray1ceacea2015-10-19 12:59:14 -040057}
58
59static int idio_16_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
60{
61 return 0;
62}
63
64static int idio_16_gpio_direction_output(struct gpio_chip *chip,
65 unsigned offset, int value)
66{
67 chip->set(chip, offset, value);
68 return 0;
69}
70
William Breathitt Gray1ceacea2015-10-19 12:59:14 -040071static int idio_16_gpio_get(struct gpio_chip *chip, unsigned offset)
72{
Linus Walleijd602ae92015-12-03 18:18:06 +010073 struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
William Breathitt Gray6e0171b2015-11-17 18:58:16 -050074 const unsigned mask = BIT(offset-16);
William Breathitt Gray1ceacea2015-10-19 12:59:14 -040075
76 if (offset < 16)
77 return -EINVAL;
78
79 if (offset < 24)
William Breathitt Gray6e0171b2015-11-17 18:58:16 -050080 return !!(inb(idio16gpio->base + 1) & mask);
William Breathitt Gray1ceacea2015-10-19 12:59:14 -040081
William Breathitt Gray6e0171b2015-11-17 18:58:16 -050082 return !!(inb(idio16gpio->base + 5) & (mask>>8));
William Breathitt Gray1ceacea2015-10-19 12:59:14 -040083}
84
William Breathitt Gray15f59cf2018-03-22 08:59:37 -040085static int idio_16_gpio_get_multiple(struct gpio_chip *chip,
86 unsigned long *mask, unsigned long *bits)
87{
88 struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
89
90 *bits = 0;
91 if (*mask & GENMASK(23, 16))
92 *bits |= (unsigned long)inb(idio16gpio->base + 1) << 16;
93 if (*mask & GENMASK(31, 24))
94 *bits |= (unsigned long)inb(idio16gpio->base + 5) << 24;
95
96 return 0;
97}
98
William Breathitt Gray1ceacea2015-10-19 12:59:14 -040099static void idio_16_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
100{
Linus Walleijd602ae92015-12-03 18:18:06 +0100101 struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
William Breathitt Gray6e0171b2015-11-17 18:58:16 -0500102 const unsigned mask = BIT(offset);
William Breathitt Gray1ceacea2015-10-19 12:59:14 -0400103 unsigned long flags;
104
105 if (offset > 15)
106 return;
107
Julia Cartwright3906e802017-03-21 17:43:08 -0500108 raw_spin_lock_irqsave(&idio16gpio->lock, flags);
William Breathitt Gray1ceacea2015-10-19 12:59:14 -0400109
110 if (value)
William Breathitt Gray6e0171b2015-11-17 18:58:16 -0500111 idio16gpio->out_state |= mask;
William Breathitt Gray1ceacea2015-10-19 12:59:14 -0400112 else
William Breathitt Gray6e0171b2015-11-17 18:58:16 -0500113 idio16gpio->out_state &= ~mask;
William Breathitt Gray1ceacea2015-10-19 12:59:14 -0400114
115 if (offset > 7)
116 outb(idio16gpio->out_state >> 8, idio16gpio->base + 4);
117 else
118 outb(idio16gpio->out_state, idio16gpio->base);
119
Julia Cartwright3906e802017-03-21 17:43:08 -0500120 raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
William Breathitt Gray1ceacea2015-10-19 12:59:14 -0400121}
122
William Breathitt Gray9d7ae812017-01-19 10:05:37 -0500123static void idio_16_gpio_set_multiple(struct gpio_chip *chip,
124 unsigned long *mask, unsigned long *bits)
125{
126 struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
127 unsigned long flags;
128
Julia Cartwright3906e802017-03-21 17:43:08 -0500129 raw_spin_lock_irqsave(&idio16gpio->lock, flags);
William Breathitt Gray9d7ae812017-01-19 10:05:37 -0500130
131 idio16gpio->out_state &= ~*mask;
132 idio16gpio->out_state |= *mask & *bits;
133
134 if (*mask & 0xFF)
135 outb(idio16gpio->out_state, idio16gpio->base);
136 if ((*mask >> 8) & 0xFF)
137 outb(idio16gpio->out_state >> 8, idio16gpio->base + 4);
138
Julia Cartwright3906e802017-03-21 17:43:08 -0500139 raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
William Breathitt Gray9d7ae812017-01-19 10:05:37 -0500140}
141
William Breathitt Graya1184142015-11-03 07:54:23 -0500142static void idio_16_irq_ack(struct irq_data *data)
143{
William Breathitt Graya1184142015-11-03 07:54:23 -0500144}
145
146static void idio_16_irq_mask(struct irq_data *data)
147{
148 struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
Linus Walleijd602ae92015-12-03 18:18:06 +0100149 struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
William Breathitt Graya1184142015-11-03 07:54:23 -0500150 const unsigned long mask = BIT(irqd_to_hwirq(data));
151 unsigned long flags;
152
153 idio16gpio->irq_mask &= ~mask;
154
155 if (!idio16gpio->irq_mask) {
Julia Cartwright3906e802017-03-21 17:43:08 -0500156 raw_spin_lock_irqsave(&idio16gpio->lock, flags);
William Breathitt Graya1184142015-11-03 07:54:23 -0500157
158 outb(0, idio16gpio->base + 2);
159
Julia Cartwright3906e802017-03-21 17:43:08 -0500160 raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
William Breathitt Graya1184142015-11-03 07:54:23 -0500161 }
162}
163
164static void idio_16_irq_unmask(struct irq_data *data)
165{
166 struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
Linus Walleijd602ae92015-12-03 18:18:06 +0100167 struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
William Breathitt Graya1184142015-11-03 07:54:23 -0500168 const unsigned long mask = BIT(irqd_to_hwirq(data));
169 const unsigned long prev_irq_mask = idio16gpio->irq_mask;
170 unsigned long flags;
171
172 idio16gpio->irq_mask |= mask;
173
174 if (!prev_irq_mask) {
Julia Cartwright3906e802017-03-21 17:43:08 -0500175 raw_spin_lock_irqsave(&idio16gpio->lock, flags);
William Breathitt Graya1184142015-11-03 07:54:23 -0500176
William Breathitt Graya1184142015-11-03 07:54:23 -0500177 inb(idio16gpio->base + 2);
178
Julia Cartwright3906e802017-03-21 17:43:08 -0500179 raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
William Breathitt Graya1184142015-11-03 07:54:23 -0500180 }
181}
182
183static int idio_16_irq_set_type(struct irq_data *data, unsigned flow_type)
184{
185 /* The only valid irq types are none and both-edges */
186 if (flow_type != IRQ_TYPE_NONE &&
187 (flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH)
188 return -EINVAL;
189
190 return 0;
191}
192
193static struct irq_chip idio_16_irqchip = {
194 .name = "104-idio-16",
195 .irq_ack = idio_16_irq_ack,
196 .irq_mask = idio_16_irq_mask,
197 .irq_unmask = idio_16_irq_unmask,
198 .irq_set_type = idio_16_irq_set_type
199};
200
201static irqreturn_t idio_16_irq_handler(int irq, void *dev_id)
202{
203 struct idio_16_gpio *const idio16gpio = dev_id;
204 struct gpio_chip *const chip = &idio16gpio->chip;
205 int gpio;
206
207 for_each_set_bit(gpio, &idio16gpio->irq_mask, chip->ngpio)
Thierry Redingf0fbe7b2017-11-07 19:15:47 +0100208 generic_handle_irq(irq_find_mapping(chip->irq.domain, gpio));
William Breathitt Graya1184142015-11-03 07:54:23 -0500209
Julia Cartwright3906e802017-03-21 17:43:08 -0500210 raw_spin_lock(&idio16gpio->lock);
William Breathitt Gray12b61c92015-12-02 20:23:04 -0500211
212 outb(0, idio16gpio->base + 1);
213
Julia Cartwright3906e802017-03-21 17:43:08 -0500214 raw_spin_unlock(&idio16gpio->lock);
William Breathitt Gray12b61c92015-12-02 20:23:04 -0500215
William Breathitt Graya1184142015-11-03 07:54:23 -0500216 return IRQ_HANDLED;
217}
218
William Breathitt Graye0af4b52017-01-30 13:33:21 -0500219#define IDIO_16_NGPIO 32
220static const char *idio_16_names[IDIO_16_NGPIO] = {
221 "OUT0", "OUT1", "OUT2", "OUT3", "OUT4", "OUT5", "OUT6", "OUT7",
222 "OUT8", "OUT9", "OUT10", "OUT11", "OUT12", "OUT13", "OUT14", "OUT15",
223 "IIN0", "IIN1", "IIN2", "IIN3", "IIN4", "IIN5", "IIN6", "IIN7",
224 "IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15"
225};
226
Linus Walleij82e46132020-07-22 12:55:17 +0200227static int idio_16_irq_init_hw(struct gpio_chip *gc)
228{
229 struct idio_16_gpio *const idio16gpio = gpiochip_get_data(gc);
230
231 /* Disable IRQ by default */
232 outb(0, idio16gpio->base + 2);
233 outb(0, idio16gpio->base + 1);
234
235 return 0;
236}
237
William Breathitt Gray86ea8a92016-05-01 18:45:11 -0400238static int idio_16_probe(struct device *dev, unsigned int id)
William Breathitt Gray1ceacea2015-10-19 12:59:14 -0400239{
William Breathitt Gray1ceacea2015-10-19 12:59:14 -0400240 struct idio_16_gpio *idio16gpio;
William Breathitt Gray6e0171b2015-11-17 18:58:16 -0500241 const char *const name = dev_name(dev);
Linus Walleij82e46132020-07-22 12:55:17 +0200242 struct gpio_irq_chip *girq;
William Breathitt Gray1ceacea2015-10-19 12:59:14 -0400243 int err;
William Breathitt Gray1ceacea2015-10-19 12:59:14 -0400244
245 idio16gpio = devm_kzalloc(dev, sizeof(*idio16gpio), GFP_KERNEL);
246 if (!idio16gpio)
247 return -ENOMEM;
248
William Breathitt Gray86ea8a92016-05-01 18:45:11 -0400249 if (!devm_request_region(dev, base[id], IDIO_16_EXTENT, name)) {
William Breathitt Graycb323892016-02-03 15:17:02 -0500250 dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
William Breathitt Gray86ea8a92016-05-01 18:45:11 -0400251 base[id], base[id] + IDIO_16_EXTENT);
William Breathitt Graycb323892016-02-03 15:17:02 -0500252 return -EBUSY;
William Breathitt Gray1ceacea2015-10-19 12:59:14 -0400253 }
254
William Breathitt Gray6e0171b2015-11-17 18:58:16 -0500255 idio16gpio->chip.label = name;
Linus Walleij58383c782015-11-04 09:56:26 +0100256 idio16gpio->chip.parent = dev;
William Breathitt Gray1ceacea2015-10-19 12:59:14 -0400257 idio16gpio->chip.owner = THIS_MODULE;
258 idio16gpio->chip.base = -1;
William Breathitt Graye0af4b52017-01-30 13:33:21 -0500259 idio16gpio->chip.ngpio = IDIO_16_NGPIO;
260 idio16gpio->chip.names = idio_16_names;
William Breathitt Gray1ceacea2015-10-19 12:59:14 -0400261 idio16gpio->chip.get_direction = idio_16_gpio_get_direction;
262 idio16gpio->chip.direction_input = idio_16_gpio_direction_input;
263 idio16gpio->chip.direction_output = idio_16_gpio_direction_output;
264 idio16gpio->chip.get = idio_16_gpio_get;
William Breathitt Gray15f59cf2018-03-22 08:59:37 -0400265 idio16gpio->chip.get_multiple = idio_16_gpio_get_multiple;
William Breathitt Gray1ceacea2015-10-19 12:59:14 -0400266 idio16gpio->chip.set = idio_16_gpio_set;
William Breathitt Gray9d7ae812017-01-19 10:05:37 -0500267 idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple;
William Breathitt Gray86ea8a92016-05-01 18:45:11 -0400268 idio16gpio->base = base[id];
William Breathitt Gray1ceacea2015-10-19 12:59:14 -0400269 idio16gpio->out_state = 0xFFFF;
270
Linus Walleij82e46132020-07-22 12:55:17 +0200271 girq = &idio16gpio->chip.irq;
272 girq->chip = &idio_16_irqchip;
273 /* This will let us handle the parent IRQ in the driver */
274 girq->parent_handler = NULL;
275 girq->num_parents = 0;
276 girq->parents = NULL;
277 girq->default_type = IRQ_TYPE_NONE;
278 girq->handler = handle_edge_irq;
279 girq->init_hw = idio_16_irq_init_hw;
280
Julia Cartwright3906e802017-03-21 17:43:08 -0500281 raw_spin_lock_init(&idio16gpio->lock);
William Breathitt Gray1ceacea2015-10-19 12:59:14 -0400282
William Breathitt Gray837143d2017-01-24 15:00:54 -0500283 err = devm_gpiochip_add_data(dev, &idio16gpio->chip, idio16gpio);
William Breathitt Gray1ceacea2015-10-19 12:59:14 -0400284 if (err) {
285 dev_err(dev, "GPIO registering failed (%d)\n", err);
William Breathitt Graycb323892016-02-03 15:17:02 -0500286 return err;
William Breathitt Gray1ceacea2015-10-19 12:59:14 -0400287 }
288
William Breathitt Gray837143d2017-01-24 15:00:54 -0500289 err = devm_request_irq(dev, irq[id], idio_16_irq_handler, 0, name,
290 idio16gpio);
William Breathitt Graya1184142015-11-03 07:54:23 -0500291 if (err) {
292 dev_err(dev, "IRQ handler registering failed (%d)\n", err);
William Breathitt Gray837143d2017-01-24 15:00:54 -0500293 return err;
William Breathitt Graya1184142015-11-03 07:54:23 -0500294 }
295
William Breathitt Gray1ceacea2015-10-19 12:59:14 -0400296 return 0;
William Breathitt Gray1ceacea2015-10-19 12:59:14 -0400297}
298
William Breathitt Gray86ea8a92016-05-01 18:45:11 -0400299static struct isa_driver idio_16_driver = {
300 .probe = idio_16_probe,
William Breathitt Gray1ceacea2015-10-19 12:59:14 -0400301 .driver = {
302 .name = "104-idio-16"
303 },
William Breathitt Gray1ceacea2015-10-19 12:59:14 -0400304};
305
William Breathitt Gray86ea8a92016-05-01 18:45:11 -0400306module_isa_driver(idio_16_driver, num_idio_16);
William Breathitt Gray1ceacea2015-10-19 12:59:14 -0400307
308MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
309MODULE_DESCRIPTION("ACCES 104-IDIO-16 GPIO driver");
William Breathitt Gray22aeddb2016-02-01 18:51:49 -0500310MODULE_LICENSE("GPL v2");