gpio: 104-dio-48e: Implement and utilize register structures
[linux-2.6-block.git] / drivers / gpio / gpio-104-idi-48.c
CommitLineData
1802d0be 1// SPDX-License-Identifier: GPL-2.0-only
6ddcf9b4
WBG
2/*
3 * GPIO driver for the ACCES 104-IDI-48 family
4 * Copyright (C) 2015 William Breathitt Gray
5 *
72bf7443
WBG
6 * This driver supports the following ACCES devices: 104-IDI-48A,
7 * 104-IDI-48AC, 104-IDI-48B, and 104-IDI-48BC.
6ddcf9b4 8 */
f72b1071 9#include <linux/bitmap.h>
6ddcf9b4
WBG
10#include <linux/bitops.h>
11#include <linux/device.h>
12#include <linux/errno.h>
13#include <linux/gpio/driver.h>
14#include <linux/io.h>
15#include <linux/ioport.h>
16#include <linux/interrupt.h>
17#include <linux/irqdesc.h>
72bf7443 18#include <linux/isa.h>
6ddcf9b4
WBG
19#include <linux/kernel.h>
20#include <linux/module.h>
21#include <linux/moduleparam.h>
6ddcf9b4
WBG
22#include <linux/spinlock.h>
23
72bf7443
WBG
24#define IDI_48_EXTENT 8
25#define MAX_NUM_IDI_48 max_num_isa_dev(IDI_48_EXTENT)
26
27static unsigned int base[MAX_NUM_IDI_48];
28static unsigned int num_idi_48;
d759f906 29module_param_hw_array(base, uint, ioport, &num_idi_48, 0);
72bf7443
WBG
30MODULE_PARM_DESC(base, "ACCES 104-IDI-48 base addresses");
31
32static unsigned int irq[MAX_NUM_IDI_48];
d759f906 33module_param_hw_array(irq, uint, irq, NULL, 0);
72bf7443 34MODULE_PARM_DESC(irq, "ACCES 104-IDI-48 interrupt line numbers");
6ddcf9b4
WBG
35
36/**
37 * struct idi_48_gpio - GPIO device private data structure
38 * @chip: instance of the gpio_chip
39 * @lock: synchronization lock to prevent I/O race conditions
9ae48210 40 * @ack_lock: synchronization lock to prevent IRQ handler race conditions
6ddcf9b4
WBG
41 * @irq_mask: input bits affected by interrupts
42 * @base: base port address of the GPIO device
6ddcf9b4
WBG
43 * @cos_enb: Change-Of-State IRQ enable boundaries mask
44 */
45struct idi_48_gpio {
46 struct gpio_chip chip;
e1e37d6c 47 raw_spinlock_t lock;
9ae48210 48 spinlock_t ack_lock;
6ddcf9b4 49 unsigned char irq_mask[6];
bed58069 50 void __iomem *base;
6ddcf9b4
WBG
51 unsigned char cos_enb;
52};
53
3e2d53b2 54static int idi_48_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
6ddcf9b4 55{
e42615ec 56 return GPIO_LINE_DIRECTION_IN;
6ddcf9b4
WBG
57}
58
3e2d53b2 59static int idi_48_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
6ddcf9b4
WBG
60{
61 return 0;
62}
63
3e2d53b2 64static int idi_48_gpio_get(struct gpio_chip *chip, unsigned int offset)
6ddcf9b4 65{
1f36bec5 66 struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
3e2d53b2 67 unsigned int i;
ac4062aa 68 static const unsigned int register_offset[6] = { 0, 1, 2, 4, 5, 6 };
bed58069 69 void __iomem *port_addr;
3e2d53b2 70 unsigned int mask;
6ddcf9b4
WBG
71
72 for (i = 0; i < 48; i += 8)
73 if (offset < i + 8) {
bed58069 74 port_addr = idi48gpio->base + register_offset[i / 8];
6ddcf9b4
WBG
75 mask = BIT(offset - i);
76
bed58069 77 return !!(ioread8(port_addr) & mask);
6ddcf9b4
WBG
78 }
79
80 /* The following line should never execute since offset < 48 */
81 return 0;
82}
83
f72b1071
WBG
84static int idi_48_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
85 unsigned long *bits)
86{
87 struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
9bfcce0d
WBG
88 unsigned long offset;
89 unsigned long gpio_mask;
413f9e99 90 static const size_t ports[] = { 0, 1, 2, 4, 5, 6 };
bed58069 91 void __iomem *port_addr;
f72b1071
WBG
92 unsigned long port_state;
93
94 /* clear bits array to a clean slate */
95 bitmap_zero(bits, chip->ngpio);
96
9bfcce0d
WBG
97 for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) {
98 port_addr = idi48gpio->base + ports[offset / 8];
bed58069 99 port_state = ioread8(port_addr) & gpio_mask;
f72b1071 100
9bfcce0d 101 bitmap_set_value8(bits, port_state, offset);
f72b1071
WBG
102 }
103
104 return 0;
105}
106
6ddcf9b4
WBG
107static void idi_48_irq_ack(struct irq_data *data)
108{
6ddcf9b4
WBG
109}
110
111static void idi_48_irq_mask(struct irq_data *data)
112{
113 struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
1f36bec5 114 struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
3e2d53b2
ASS
115 const unsigned int offset = irqd_to_hwirq(data);
116 unsigned int i;
117 unsigned int mask;
118 unsigned int boundary;
6ddcf9b4
WBG
119 unsigned long flags;
120
121 for (i = 0; i < 48; i += 8)
122 if (offset < i + 8) {
123 mask = BIT(offset - i);
124 boundary = i / 8;
125
126 idi48gpio->irq_mask[boundary] &= ~mask;
127
128 if (!idi48gpio->irq_mask[boundary]) {
129 idi48gpio->cos_enb &= ~BIT(boundary);
130
e1e37d6c 131 raw_spin_lock_irqsave(&idi48gpio->lock, flags);
6ddcf9b4 132
bed58069 133 iowrite8(idi48gpio->cos_enb, idi48gpio->base + 7);
6ddcf9b4 134
b9bf9710 135 raw_spin_unlock_irqrestore(&idi48gpio->lock, flags);
6ddcf9b4
WBG
136 }
137
138 return;
139 }
140}
141
142static void idi_48_irq_unmask(struct irq_data *data)
143{
144 struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
1f36bec5 145 struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
3e2d53b2
ASS
146 const unsigned int offset = irqd_to_hwirq(data);
147 unsigned int i;
148 unsigned int mask;
149 unsigned int boundary;
150 unsigned int prev_irq_mask;
6ddcf9b4
WBG
151 unsigned long flags;
152
153 for (i = 0; i < 48; i += 8)
154 if (offset < i + 8) {
155 mask = BIT(offset - i);
156 boundary = i / 8;
157 prev_irq_mask = idi48gpio->irq_mask[boundary];
158
159 idi48gpio->irq_mask[boundary] |= mask;
160
161 if (!prev_irq_mask) {
162 idi48gpio->cos_enb |= BIT(boundary);
163
e1e37d6c 164 raw_spin_lock_irqsave(&idi48gpio->lock, flags);
6ddcf9b4 165
bed58069 166 iowrite8(idi48gpio->cos_enb, idi48gpio->base + 7);
6ddcf9b4 167
b9bf9710 168 raw_spin_unlock_irqrestore(&idi48gpio->lock, flags);
6ddcf9b4
WBG
169 }
170
171 return;
172 }
173}
174
3e2d53b2 175static int idi_48_irq_set_type(struct irq_data *data, unsigned int flow_type)
6ddcf9b4
WBG
176{
177 /* The only valid irq types are none and both-edges */
178 if (flow_type != IRQ_TYPE_NONE &&
179 (flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH)
180 return -EINVAL;
181
182 return 0;
183}
184
185static struct irq_chip idi_48_irqchip = {
186 .name = "104-idi-48",
187 .irq_ack = idi_48_irq_ack,
188 .irq_mask = idi_48_irq_mask,
189 .irq_unmask = idi_48_irq_unmask,
190 .irq_set_type = idi_48_irq_set_type
191};
192
193static irqreturn_t idi_48_irq_handler(int irq, void *dev_id)
194{
195 struct idi_48_gpio *const idi48gpio = dev_id;
196 unsigned long cos_status;
197 unsigned long boundary;
198 unsigned long irq_mask;
199 unsigned long bit_num;
200 unsigned long gpio;
201 struct gpio_chip *const chip = &idi48gpio->chip;
202
9ae48210
WBG
203 spin_lock(&idi48gpio->ack_lock);
204
e1e37d6c 205 raw_spin_lock(&idi48gpio->lock);
6ddcf9b4 206
bed58069 207 cos_status = ioread8(idi48gpio->base + 7);
6ddcf9b4 208
e1e37d6c 209 raw_spin_unlock(&idi48gpio->lock);
6ddcf9b4
WBG
210
211 /* IRQ Status (bit 6) is active low (0 = IRQ generated by device) */
9ae48210
WBG
212 if (cos_status & BIT(6)) {
213 spin_unlock(&idi48gpio->ack_lock);
6ddcf9b4 214 return IRQ_NONE;
9ae48210 215 }
6ddcf9b4
WBG
216
217 /* Bit 0-5 indicate which Change-Of-State boundary triggered the IRQ */
218 cos_status &= 0x3F;
219
220 for_each_set_bit(boundary, &cos_status, 6) {
221 irq_mask = idi48gpio->irq_mask[boundary];
222
223 for_each_set_bit(bit_num, &irq_mask, 8) {
224 gpio = bit_num + boundary * 8;
225
dbd1c54f
MZ
226 generic_handle_domain_irq(chip->irq.domain,
227 gpio);
6ddcf9b4
WBG
228 }
229 }
230
9ae48210
WBG
231 spin_unlock(&idi48gpio->ack_lock);
232
6ddcf9b4
WBG
233 return IRQ_HANDLED;
234}
235
a71dc253
WBG
236#define IDI48_NGPIO 48
237static const char *idi48_names[IDI48_NGPIO] = {
238 "Bit 0 A", "Bit 1 A", "Bit 2 A", "Bit 3 A", "Bit 4 A", "Bit 5 A",
239 "Bit 6 A", "Bit 7 A", "Bit 8 A", "Bit 9 A", "Bit 10 A", "Bit 11 A",
240 "Bit 12 A", "Bit 13 A", "Bit 14 A", "Bit 15 A", "Bit 16 A", "Bit 17 A",
241 "Bit 18 A", "Bit 19 A", "Bit 20 A", "Bit 21 A", "Bit 22 A", "Bit 23 A",
242 "Bit 0 B", "Bit 1 B", "Bit 2 B", "Bit 3 B", "Bit 4 B", "Bit 5 B",
243 "Bit 6 B", "Bit 7 B", "Bit 8 B", "Bit 9 B", "Bit 10 B", "Bit 11 B",
244 "Bit 12 B", "Bit 13 B", "Bit 14 B", "Bit 15 B", "Bit 16 B", "Bit 17 B",
245 "Bit 18 B", "Bit 19 B", "Bit 20 B", "Bit 21 B", "Bit 22 B", "Bit 23 B"
246};
247
44b01cf5
LW
248static int idi_48_irq_init_hw(struct gpio_chip *gc)
249{
250 struct idi_48_gpio *const idi48gpio = gpiochip_get_data(gc);
251
252 /* Disable IRQ by default */
bed58069
WBG
253 iowrite8(0, idi48gpio->base + 7);
254 ioread8(idi48gpio->base + 7);
44b01cf5
LW
255
256 return 0;
257}
258
72bf7443 259static int idi_48_probe(struct device *dev, unsigned int id)
6ddcf9b4 260{
6ddcf9b4 261 struct idi_48_gpio *idi48gpio;
6ddcf9b4 262 const char *const name = dev_name(dev);
44b01cf5 263 struct gpio_irq_chip *girq;
6ddcf9b4 264 int err;
6ddcf9b4
WBG
265
266 idi48gpio = devm_kzalloc(dev, sizeof(*idi48gpio), GFP_KERNEL);
267 if (!idi48gpio)
268 return -ENOMEM;
269
72bf7443 270 if (!devm_request_region(dev, base[id], IDI_48_EXTENT, name)) {
5cfc0576 271 dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
72bf7443 272 base[id], base[id] + IDI_48_EXTENT);
5cfc0576 273 return -EBUSY;
6ddcf9b4
WBG
274 }
275
bed58069
WBG
276 idi48gpio->base = devm_ioport_map(dev, base[id], IDI_48_EXTENT);
277 if (!idi48gpio->base)
278 return -ENOMEM;
279
6ddcf9b4
WBG
280 idi48gpio->chip.label = name;
281 idi48gpio->chip.parent = dev;
282 idi48gpio->chip.owner = THIS_MODULE;
283 idi48gpio->chip.base = -1;
a71dc253
WBG
284 idi48gpio->chip.ngpio = IDI48_NGPIO;
285 idi48gpio->chip.names = idi48_names;
6ddcf9b4
WBG
286 idi48gpio->chip.get_direction = idi_48_gpio_get_direction;
287 idi48gpio->chip.direction_input = idi_48_gpio_direction_input;
288 idi48gpio->chip.get = idi_48_gpio_get;
f72b1071 289 idi48gpio->chip.get_multiple = idi_48_gpio_get_multiple;
6ddcf9b4 290
44b01cf5
LW
291 girq = &idi48gpio->chip.irq;
292 girq->chip = &idi_48_irqchip;
293 /* This will let us handle the parent IRQ in the driver */
294 girq->parent_handler = NULL;
295 girq->num_parents = 0;
296 girq->parents = NULL;
297 girq->default_type = IRQ_TYPE_NONE;
298 girq->handler = handle_edge_irq;
299 girq->init_hw = idi_48_irq_init_hw;
300
e1e37d6c 301 raw_spin_lock_init(&idi48gpio->lock);
053ae649 302 spin_lock_init(&idi48gpio->ack_lock);
6ddcf9b4 303
e43fee60 304 err = devm_gpiochip_add_data(dev, &idi48gpio->chip, idi48gpio);
6ddcf9b4
WBG
305 if (err) {
306 dev_err(dev, "GPIO registering failed (%d)\n", err);
5cfc0576 307 return err;
6ddcf9b4
WBG
308 }
309
e43fee60
WBG
310 err = devm_request_irq(dev, irq[id], idi_48_irq_handler, IRQF_SHARED,
311 name, idi48gpio);
6ddcf9b4
WBG
312 if (err) {
313 dev_err(dev, "IRQ handler registering failed (%d)\n", err);
e43fee60 314 return err;
6ddcf9b4
WBG
315 }
316
6ddcf9b4
WBG
317 return 0;
318}
319
72bf7443
WBG
320static struct isa_driver idi_48_driver = {
321 .probe = idi_48_probe,
6ddcf9b4
WBG
322 .driver = {
323 .name = "104-idi-48"
324 },
6ddcf9b4 325};
72bf7443 326module_isa_driver(idi_48_driver, num_idi_48);
6ddcf9b4
WBG
327
328MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
329MODULE_DESCRIPTION("ACCES 104-IDI-48 GPIO driver");
22aeddb5 330MODULE_LICENSE("GPL v2");