cw1200: drop useless LIST_HEAD
[linux-2.6-block.git] / drivers / gpio / gpio-pci-idio-16.c
CommitLineData
02e74fc0
WBG
1/*
2 * GPIO driver for the ACCES PCI-IDIO-16
3 * Copyright (C) 2017 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 */
810ebfc5 14#include <linux/bitmap.h>
02e74fc0
WBG
15#include <linux/bitops.h>
16#include <linux/device.h>
17#include <linux/errno.h>
18#include <linux/gpio/driver.h>
19#include <linux/interrupt.h>
20#include <linux/irqdesc.h>
21#include <linux/kernel.h>
22#include <linux/module.h>
23#include <linux/pci.h>
24#include <linux/spinlock.h>
25#include <linux/types.h>
26
27/**
28 * struct idio_16_gpio_reg - GPIO device registers structure
29 * @out0_7: Read: FET Drive Outputs 0-7
30 * Write: FET Drive Outputs 0-7
31 * @in0_7: Read: Isolated Inputs 0-7
32 * Write: Clear Interrupt
33 * @irq_ctl: Read: Enable IRQ
34 * Write: Disable IRQ
35 * @filter_ctl: Read: Activate Input Filters 0-15
36 * Write: Deactivate Input Filters 0-15
37 * @out8_15: Read: FET Drive Outputs 8-15
38 * Write: FET Drive Outputs 8-15
39 * @in8_15: Read: Isolated Inputs 8-15
40 * Write: Unused
41 * @irq_status: Read: Interrupt status
42 * Write: Unused
43 */
44struct idio_16_gpio_reg {
45 u8 out0_7;
46 u8 in0_7;
47 u8 irq_ctl;
48 u8 filter_ctl;
49 u8 out8_15;
50 u8 in8_15;
51 u8 irq_status;
52};
53
54/**
55 * struct idio_16_gpio - GPIO device private data structure
56 * @chip: instance of the gpio_chip
57 * @lock: synchronization lock to prevent I/O race conditions
58 * @reg: I/O address offset for the GPIO device registers
59 * @irq_mask: I/O bits affected by interrupts
60 */
61struct idio_16_gpio {
62 struct gpio_chip chip;
ea38ce08 63 raw_spinlock_t lock;
02e74fc0
WBG
64 struct idio_16_gpio_reg __iomem *reg;
65 unsigned long irq_mask;
66};
67
68static int idio_16_gpio_get_direction(struct gpio_chip *chip,
69 unsigned int offset)
70{
71 if (offset > 15)
72 return 1;
73
74 return 0;
75}
76
77static int idio_16_gpio_direction_input(struct gpio_chip *chip,
78 unsigned int offset)
79{
80 return 0;
81}
82
83static int idio_16_gpio_direction_output(struct gpio_chip *chip,
84 unsigned int offset, int value)
85{
86 chip->set(chip, offset, value);
87 return 0;
88}
89
90static int idio_16_gpio_get(struct gpio_chip *chip, unsigned int offset)
91{
92 struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
93 unsigned long mask = BIT(offset);
94
95 if (offset < 8)
96 return !!(ioread8(&idio16gpio->reg->out0_7) & mask);
97
98 if (offset < 16)
99 return !!(ioread8(&idio16gpio->reg->out8_15) & (mask >> 8));
100
101 if (offset < 24)
102 return !!(ioread8(&idio16gpio->reg->in0_7) & (mask >> 16));
103
104 return !!(ioread8(&idio16gpio->reg->in8_15) & (mask >> 24));
105}
106
810ebfc5
WBG
107static int idio_16_gpio_get_multiple(struct gpio_chip *chip,
108 unsigned long *mask, unsigned long *bits)
109{
110 struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
111 size_t i;
112 const unsigned int gpio_reg_size = 8;
113 unsigned int bits_offset;
114 size_t word_index;
115 unsigned int word_offset;
116 unsigned long word_mask;
117 const unsigned long port_mask = GENMASK(gpio_reg_size - 1, 0);
118 unsigned long port_state;
aaf96e51
WBG
119 void __iomem *ports[] = {
120 &idio16gpio->reg->out0_7, &idio16gpio->reg->out8_15,
121 &idio16gpio->reg->in0_7, &idio16gpio->reg->in8_15,
810ebfc5
WBG
122 };
123
124 /* clear bits array to a clean slate */
125 bitmap_zero(bits, chip->ngpio);
126
127 /* get bits are evaluated a gpio port register at a time */
128 for (i = 0; i < ARRAY_SIZE(ports); i++) {
129 /* gpio offset in bits array */
130 bits_offset = i * gpio_reg_size;
131
132 /* word index for bits array */
133 word_index = BIT_WORD(bits_offset);
134
135 /* gpio offset within current word of bits array */
136 word_offset = bits_offset % BITS_PER_LONG;
137
138 /* mask of get bits for current gpio within current word */
139 word_mask = mask[word_index] & (port_mask << word_offset);
140 if (!word_mask) {
141 /* no get bits in this port so skip to next one */
142 continue;
143 }
144
145 /* read bits from current gpio port */
aaf96e51 146 port_state = ioread8(ports[i]);
810ebfc5
WBG
147
148 /* store acquired bits at respective bits array offset */
f837bf6a 149 bits[word_index] |= (port_state << word_offset) & word_mask;
810ebfc5
WBG
150 }
151
152 return 0;
153}
154
02e74fc0
WBG
155static void idio_16_gpio_set(struct gpio_chip *chip, unsigned int offset,
156 int value)
157{
158 struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
159 unsigned int mask = BIT(offset);
160 void __iomem *base;
161 unsigned long flags;
162 unsigned int out_state;
163
164 if (offset > 15)
165 return;
166
167 if (offset > 7) {
168 mask >>= 8;
169 base = &idio16gpio->reg->out8_15;
170 } else
171 base = &idio16gpio->reg->out0_7;
172
ea38ce08 173 raw_spin_lock_irqsave(&idio16gpio->lock, flags);
02e74fc0
WBG
174
175 if (value)
176 out_state = ioread8(base) | mask;
177 else
178 out_state = ioread8(base) & ~mask;
179
180 iowrite8(out_state, base);
181
ea38ce08 182 raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
02e74fc0
WBG
183}
184
185static void idio_16_gpio_set_multiple(struct gpio_chip *chip,
186 unsigned long *mask, unsigned long *bits)
187{
188 struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
189 unsigned long flags;
190 unsigned int out_state;
191
ea38ce08 192 raw_spin_lock_irqsave(&idio16gpio->lock, flags);
02e74fc0
WBG
193
194 /* process output lines 0-7 */
195 if (*mask & 0xFF) {
196 out_state = ioread8(&idio16gpio->reg->out0_7) & ~*mask;
197 out_state |= *mask & *bits;
198 iowrite8(out_state, &idio16gpio->reg->out0_7);
199 }
200
201 /* shift to next output line word */
202 *mask >>= 8;
203
204 /* process output lines 8-15 */
205 if (*mask & 0xFF) {
206 *bits >>= 8;
207 out_state = ioread8(&idio16gpio->reg->out8_15) & ~*mask;
208 out_state |= *mask & *bits;
209 iowrite8(out_state, &idio16gpio->reg->out8_15);
210 }
211
ea38ce08 212 raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
02e74fc0
WBG
213}
214
215static void idio_16_irq_ack(struct irq_data *data)
216{
217}
218
219static void idio_16_irq_mask(struct irq_data *data)
220{
221 struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
222 struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
223 const unsigned long mask = BIT(irqd_to_hwirq(data));
224 unsigned long flags;
225
226 idio16gpio->irq_mask &= ~mask;
227
228 if (!idio16gpio->irq_mask) {
ea38ce08 229 raw_spin_lock_irqsave(&idio16gpio->lock, flags);
02e74fc0
WBG
230
231 iowrite8(0, &idio16gpio->reg->irq_ctl);
232
ea38ce08 233 raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
02e74fc0
WBG
234 }
235}
236
237static void idio_16_irq_unmask(struct irq_data *data)
238{
239 struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
240 struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
241 const unsigned long mask = BIT(irqd_to_hwirq(data));
242 const unsigned long prev_irq_mask = idio16gpio->irq_mask;
243 unsigned long flags;
244
245 idio16gpio->irq_mask |= mask;
246
247 if (!prev_irq_mask) {
ea38ce08 248 raw_spin_lock_irqsave(&idio16gpio->lock, flags);
02e74fc0
WBG
249
250 ioread8(&idio16gpio->reg->irq_ctl);
251
ea38ce08 252 raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
02e74fc0
WBG
253 }
254}
255
256static int idio_16_irq_set_type(struct irq_data *data, unsigned int flow_type)
257{
258 /* The only valid irq types are none and both-edges */
259 if (flow_type != IRQ_TYPE_NONE &&
260 (flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH)
261 return -EINVAL;
262
263 return 0;
264}
265
266static struct irq_chip idio_16_irqchip = {
267 .name = "pci-idio-16",
268 .irq_ack = idio_16_irq_ack,
269 .irq_mask = idio_16_irq_mask,
270 .irq_unmask = idio_16_irq_unmask,
271 .irq_set_type = idio_16_irq_set_type
272};
273
274static irqreturn_t idio_16_irq_handler(int irq, void *dev_id)
275{
276 struct idio_16_gpio *const idio16gpio = dev_id;
277 unsigned int irq_status;
278 struct gpio_chip *const chip = &idio16gpio->chip;
279 int gpio;
280
ea38ce08 281 raw_spin_lock(&idio16gpio->lock);
02e74fc0
WBG
282
283 irq_status = ioread8(&idio16gpio->reg->irq_status);
284
ea38ce08 285 raw_spin_unlock(&idio16gpio->lock);
02e74fc0
WBG
286
287 /* Make sure our device generated IRQ */
288 if (!(irq_status & 0x3) || !(irq_status & 0x4))
289 return IRQ_NONE;
290
291 for_each_set_bit(gpio, &idio16gpio->irq_mask, chip->ngpio)
f0fbe7bc 292 generic_handle_irq(irq_find_mapping(chip->irq.domain, gpio));
02e74fc0 293
ea38ce08 294 raw_spin_lock(&idio16gpio->lock);
02e74fc0
WBG
295
296 /* Clear interrupt */
297 iowrite8(0, &idio16gpio->reg->in0_7);
298
ea38ce08 299 raw_spin_unlock(&idio16gpio->lock);
02e74fc0
WBG
300
301 return IRQ_HANDLED;
302}
303
304#define IDIO_16_NGPIO 32
305static const char *idio_16_names[IDIO_16_NGPIO] = {
306 "OUT0", "OUT1", "OUT2", "OUT3", "OUT4", "OUT5", "OUT6", "OUT7",
307 "OUT8", "OUT9", "OUT10", "OUT11", "OUT12", "OUT13", "OUT14", "OUT15",
308 "IIN0", "IIN1", "IIN2", "IIN3", "IIN4", "IIN5", "IIN6", "IIN7",
309 "IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15"
310};
311
312static int idio_16_probe(struct pci_dev *pdev, const struct pci_device_id *id)
313{
314 struct device *const dev = &pdev->dev;
315 struct idio_16_gpio *idio16gpio;
316 int err;
deab2b05 317 const size_t pci_bar_index = 2;
02e74fc0
WBG
318 const char *const name = pci_name(pdev);
319
320 idio16gpio = devm_kzalloc(dev, sizeof(*idio16gpio), GFP_KERNEL);
321 if (!idio16gpio)
322 return -ENOMEM;
323
324 err = pcim_enable_device(pdev);
325 if (err) {
326 dev_err(dev, "Failed to enable PCI device (%d)\n", err);
327 return err;
328 }
329
deab2b05 330 err = pcim_iomap_regions(pdev, BIT(pci_bar_index), name);
02e74fc0
WBG
331 if (err) {
332 dev_err(dev, "Unable to map PCI I/O addresses (%d)\n", err);
333 return err;
334 }
335
deab2b05 336 idio16gpio->reg = pcim_iomap_table(pdev)[pci_bar_index];
02e74fc0
WBG
337
338 /* Deactivate input filters */
339 iowrite8(0, &idio16gpio->reg->filter_ctl);
340
341 idio16gpio->chip.label = name;
342 idio16gpio->chip.parent = dev;
343 idio16gpio->chip.owner = THIS_MODULE;
344 idio16gpio->chip.base = -1;
345 idio16gpio->chip.ngpio = IDIO_16_NGPIO;
346 idio16gpio->chip.names = idio_16_names;
347 idio16gpio->chip.get_direction = idio_16_gpio_get_direction;
348 idio16gpio->chip.direction_input = idio_16_gpio_direction_input;
349 idio16gpio->chip.direction_output = idio_16_gpio_direction_output;
350 idio16gpio->chip.get = idio_16_gpio_get;
810ebfc5 351 idio16gpio->chip.get_multiple = idio_16_gpio_get_multiple;
02e74fc0
WBG
352 idio16gpio->chip.set = idio_16_gpio_set;
353 idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple;
354
ea38ce08 355 raw_spin_lock_init(&idio16gpio->lock);
02e74fc0
WBG
356
357 err = devm_gpiochip_add_data(dev, &idio16gpio->chip, idio16gpio);
358 if (err) {
359 dev_err(dev, "GPIO registering failed (%d)\n", err);
360 return err;
361 }
362
363 /* Disable IRQ by default and clear any pending interrupt */
364 iowrite8(0, &idio16gpio->reg->irq_ctl);
365 iowrite8(0, &idio16gpio->reg->in0_7);
366
367 err = gpiochip_irqchip_add(&idio16gpio->chip, &idio_16_irqchip, 0,
368 handle_edge_irq, IRQ_TYPE_NONE);
369 if (err) {
370 dev_err(dev, "Could not add irqchip (%d)\n", err);
371 return err;
372 }
373
374 err = devm_request_irq(dev, pdev->irq, idio_16_irq_handler, IRQF_SHARED,
375 name, idio16gpio);
376 if (err) {
377 dev_err(dev, "IRQ handler registering failed (%d)\n", err);
378 return err;
379 }
380
381 return 0;
382}
383
384static const struct pci_device_id idio_16_pci_dev_id[] = {
fd254a23 385 { PCI_DEVICE(0x494F, 0x0DC8) }, { 0 }
02e74fc0
WBG
386};
387MODULE_DEVICE_TABLE(pci, idio_16_pci_dev_id);
388
389static struct pci_driver idio_16_driver = {
390 .name = "pci-idio-16",
391 .id_table = idio_16_pci_dev_id,
392 .probe = idio_16_probe
393};
394
395module_pci_driver(idio_16_driver);
396
397MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
398MODULE_DESCRIPTION("ACCES PCI-IDIO-16 GPIO driver");
399MODULE_LICENSE("GPL v2");