Merge tag 'ceph-for-5.11-rc5' of git://github.com/ceph/ceph-client
[linux-2.6-block.git] / drivers / gpio / gpio-104-idio-16.c
CommitLineData
1802d0be 1// SPDX-License-Identifier: GPL-2.0-only
1ceacea2
WBG
2/*
3 * GPIO driver for the ACCES 104-IDIO-16 family
4 * Copyright (C) 2015 William Breathitt Gray
5 *
86ea8a95
WBG
6 * 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.
1ceacea2 8 */
a1184147 9#include <linux/bitops.h>
1ceacea2
WBG
10#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>
a1184147
WBG
15#include <linux/interrupt.h>
16#include <linux/irqdesc.h>
86ea8a95 17#include <linux/isa.h>
1ceacea2
WBG
18#include <linux/kernel.h>
19#include <linux/module.h>
20#include <linux/moduleparam.h>
1ceacea2
WBG
21#include <linux/spinlock.h>
22
86ea8a95
WBG
23#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;
d759f906 28module_param_hw_array(base, uint, ioport, &num_idio_16, 0);
86ea8a95
WBG
29MODULE_PARM_DESC(base, "ACCES 104-IDIO-16 base addresses");
30
31static unsigned int irq[MAX_NUM_IDIO_16];
d759f906 32module_param_hw_array(irq, uint, irq, NULL, 0);
86ea8a95 33MODULE_PARM_DESC(irq, "ACCES 104-IDIO-16 interrupt line numbers");
1ceacea2
WBG
34
35/**
36 * struct idio_16_gpio - GPIO device private data structure
37 * @chip: instance of the gpio_chip
a1184147
WBG
38 * @lock: synchronization lock to prevent I/O race conditions
39 * @irq_mask: I/O bits affected by interrupts
1ceacea2 40 * @base: base port address of the GPIO device
1ceacea2
WBG
41 * @out_state: output bits state
42 */
43struct idio_16_gpio {
44 struct gpio_chip chip;
3906e808 45 raw_spinlock_t lock;
a1184147 46 unsigned long irq_mask;
1ceacea2 47 unsigned base;
1ceacea2
WBG
48 unsigned out_state;
49};
50
51static int idio_16_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
52{
53 if (offset > 15)
e42615ec 54 return GPIO_LINE_DIRECTION_IN;
1ceacea2 55
e42615ec 56 return GPIO_LINE_DIRECTION_OUT;
1ceacea2
WBG
57}
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
1ceacea2
WBG
71static int idio_16_gpio_get(struct gpio_chip *chip, unsigned offset)
72{
d602ae90 73 struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
6e0171b4 74 const unsigned mask = BIT(offset-16);
1ceacea2
WBG
75
76 if (offset < 16)
77 return -EINVAL;
78
79 if (offset < 24)
6e0171b4 80 return !!(inb(idio16gpio->base + 1) & mask);
1ceacea2 81
6e0171b4 82 return !!(inb(idio16gpio->base + 5) & (mask>>8));
1ceacea2
WBG
83}
84
15f59cff
WBG
85static 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
1ceacea2
WBG
99static void idio_16_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
100{
d602ae90 101 struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
6e0171b4 102 const unsigned mask = BIT(offset);
1ceacea2
WBG
103 unsigned long flags;
104
105 if (offset > 15)
106 return;
107
3906e808 108 raw_spin_lock_irqsave(&idio16gpio->lock, flags);
1ceacea2
WBG
109
110 if (value)
6e0171b4 111 idio16gpio->out_state |= mask;
1ceacea2 112 else
6e0171b4 113 idio16gpio->out_state &= ~mask;
1ceacea2
WBG
114
115 if (offset > 7)
116 outb(idio16gpio->out_state >> 8, idio16gpio->base + 4);
117 else
118 outb(idio16gpio->out_state, idio16gpio->base);
119
3906e808 120 raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
1ceacea2
WBG
121}
122
9d7ae812
WBG
123static 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
3906e808 129 raw_spin_lock_irqsave(&idio16gpio->lock, flags);
9d7ae812
WBG
130
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
3906e808 139 raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
9d7ae812
WBG
140}
141
a1184147
WBG
142static void idio_16_irq_ack(struct irq_data *data)
143{
a1184147
WBG
144}
145
146static void idio_16_irq_mask(struct irq_data *data)
147{
148 struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
d602ae90 149 struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
a1184147
WBG
150 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) {
3906e808 156 raw_spin_lock_irqsave(&idio16gpio->lock, flags);
a1184147
WBG
157
158 outb(0, idio16gpio->base + 2);
159
3906e808 160 raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
a1184147
WBG
161 }
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);
d602ae90 167 struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
a1184147
WBG
168 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) {
3906e808 175 raw_spin_lock_irqsave(&idio16gpio->lock, flags);
a1184147 176
a1184147
WBG
177 inb(idio16gpio->base + 2);
178
3906e808 179 raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
a1184147
WBG
180 }
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)
f0fbe7bc 208 generic_handle_irq(irq_find_mapping(chip->irq.domain, gpio));
a1184147 209
3906e808 210 raw_spin_lock(&idio16gpio->lock);
12b61c9d
WBG
211
212 outb(0, idio16gpio->base + 1);
213
3906e808 214 raw_spin_unlock(&idio16gpio->lock);
12b61c9d 215
a1184147
WBG
216 return IRQ_HANDLED;
217}
218
e0af4b5e
WBG
219#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
82e4613d
LW
227static 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
86ea8a95 238static int idio_16_probe(struct device *dev, unsigned int id)
1ceacea2 239{
1ceacea2 240 struct idio_16_gpio *idio16gpio;
6e0171b4 241 const char *const name = dev_name(dev);
82e4613d 242 struct gpio_irq_chip *girq;
1ceacea2 243 int err;
1ceacea2
WBG
244
245 idio16gpio = devm_kzalloc(dev, sizeof(*idio16gpio), GFP_KERNEL);
246 if (!idio16gpio)
247 return -ENOMEM;
248
86ea8a95 249 if (!devm_request_region(dev, base[id], IDIO_16_EXTENT, name)) {
cb32389c 250 dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
86ea8a95 251 base[id], base[id] + IDIO_16_EXTENT);
cb32389c 252 return -EBUSY;
1ceacea2
WBG
253 }
254
6e0171b4 255 idio16gpio->chip.label = name;
58383c78 256 idio16gpio->chip.parent = dev;
1ceacea2
WBG
257 idio16gpio->chip.owner = THIS_MODULE;
258 idio16gpio->chip.base = -1;
e0af4b5e
WBG
259 idio16gpio->chip.ngpio = IDIO_16_NGPIO;
260 idio16gpio->chip.names = idio_16_names;
1ceacea2
WBG
261 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;
15f59cff 265 idio16gpio->chip.get_multiple = idio_16_gpio_get_multiple;
1ceacea2 266 idio16gpio->chip.set = idio_16_gpio_set;
9d7ae812 267 idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple;
86ea8a95 268 idio16gpio->base = base[id];
1ceacea2
WBG
269 idio16gpio->out_state = 0xFFFF;
270
82e4613d
LW
271 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
3906e808 281 raw_spin_lock_init(&idio16gpio->lock);
1ceacea2 282
837143d3 283 err = devm_gpiochip_add_data(dev, &idio16gpio->chip, idio16gpio);
1ceacea2
WBG
284 if (err) {
285 dev_err(dev, "GPIO registering failed (%d)\n", err);
cb32389c 286 return err;
1ceacea2
WBG
287 }
288
837143d3
WBG
289 err = devm_request_irq(dev, irq[id], idio_16_irq_handler, 0, name,
290 idio16gpio);
a1184147
WBG
291 if (err) {
292 dev_err(dev, "IRQ handler registering failed (%d)\n", err);
837143d3 293 return err;
a1184147
WBG
294 }
295
1ceacea2
WBG
296 return 0;
297}
298
86ea8a95
WBG
299static struct isa_driver idio_16_driver = {
300 .probe = idio_16_probe,
1ceacea2
WBG
301 .driver = {
302 .name = "104-idio-16"
303 },
1ceacea2
WBG
304};
305
86ea8a95 306module_isa_driver(idio_16_driver, num_idio_16);
1ceacea2
WBG
307
308MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
309MODULE_DESCRIPTION("ACCES 104-IDIO-16 GPIO driver");
22aeddb5 310MODULE_LICENSE("GPL v2");