blob: 638d6656ce736767c15bc5fa4c97711590b0e771 [file] [log] [blame]
Thomas Gleixner1802d0b2019-05-27 08:55:21 +02001// SPDX-License-Identifier: GPL-2.0-only
William Breathitt Gray02e74fc2017-02-01 15:37:55 -05002/*
3 * GPIO driver for the ACCES PCI-IDIO-16
4 * Copyright (C) 2017 William Breathitt Gray
William Breathitt Gray02e74fc2017-02-01 15:37:55 -05005 */
William Breathitt Gray810ebfc2018-03-22 08:59:48 -04006#include <linux/bitmap.h>
William Breathitt Gray02e74fc2017-02-01 15:37:55 -05007#include <linux/bitops.h>
8#include <linux/device.h>
9#include <linux/errno.h>
10#include <linux/gpio/driver.h>
11#include <linux/interrupt.h>
12#include <linux/irqdesc.h>
13#include <linux/kernel.h>
14#include <linux/module.h>
15#include <linux/pci.h>
16#include <linux/spinlock.h>
17#include <linux/types.h>
18
19/**
20 * struct idio_16_gpio_reg - GPIO device registers structure
21 * @out0_7: Read: FET Drive Outputs 0-7
22 * Write: FET Drive Outputs 0-7
23 * @in0_7: Read: Isolated Inputs 0-7
24 * Write: Clear Interrupt
25 * @irq_ctl: Read: Enable IRQ
26 * Write: Disable IRQ
27 * @filter_ctl: Read: Activate Input Filters 0-15
28 * Write: Deactivate Input Filters 0-15
29 * @out8_15: Read: FET Drive Outputs 8-15
30 * Write: FET Drive Outputs 8-15
31 * @in8_15: Read: Isolated Inputs 8-15
32 * Write: Unused
33 * @irq_status: Read: Interrupt status
34 * Write: Unused
35 */
36struct idio_16_gpio_reg {
37 u8 out0_7;
38 u8 in0_7;
39 u8 irq_ctl;
40 u8 filter_ctl;
41 u8 out8_15;
42 u8 in8_15;
43 u8 irq_status;
44};
45
46/**
47 * struct idio_16_gpio - GPIO device private data structure
48 * @chip: instance of the gpio_chip
49 * @lock: synchronization lock to prevent I/O race conditions
50 * @reg: I/O address offset for the GPIO device registers
51 * @irq_mask: I/O bits affected by interrupts
52 */
53struct idio_16_gpio {
54 struct gpio_chip chip;
Julia Cartwrightea38ce02017-03-21 17:43:09 -050055 raw_spinlock_t lock;
William Breathitt Gray02e74fc2017-02-01 15:37:55 -050056 struct idio_16_gpio_reg __iomem *reg;
57 unsigned long irq_mask;
58};
59
60static int idio_16_gpio_get_direction(struct gpio_chip *chip,
61 unsigned int offset)
62{
63 if (offset > 15)
Matti Vaittinene42615e2019-11-06 10:54:12 +020064 return GPIO_LINE_DIRECTION_IN;
William Breathitt Gray02e74fc2017-02-01 15:37:55 -050065
Matti Vaittinene42615e2019-11-06 10:54:12 +020066 return GPIO_LINE_DIRECTION_OUT;
William Breathitt Gray02e74fc2017-02-01 15:37:55 -050067}
68
69static int idio_16_gpio_direction_input(struct gpio_chip *chip,
70 unsigned int offset)
71{
72 return 0;
73}
74
75static int idio_16_gpio_direction_output(struct gpio_chip *chip,
76 unsigned int offset, int value)
77{
78 chip->set(chip, offset, value);
79 return 0;
80}
81
82static int idio_16_gpio_get(struct gpio_chip *chip, unsigned int offset)
83{
84 struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
85 unsigned long mask = BIT(offset);
86
87 if (offset < 8)
88 return !!(ioread8(&idio16gpio->reg->out0_7) & mask);
89
90 if (offset < 16)
91 return !!(ioread8(&idio16gpio->reg->out8_15) & (mask >> 8));
92
93 if (offset < 24)
94 return !!(ioread8(&idio16gpio->reg->in0_7) & (mask >> 16));
95
96 return !!(ioread8(&idio16gpio->reg->in8_15) & (mask >> 24));
97}
98
William Breathitt Gray810ebfc2018-03-22 08:59:48 -040099static int idio_16_gpio_get_multiple(struct gpio_chip *chip,
100 unsigned long *mask, unsigned long *bits)
101{
102 struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
William Breathitt Gray2dc7c3c2019-12-04 16:51:18 -0800103 unsigned long offset;
104 unsigned long gpio_mask;
William Breathitt Grayaaf96e52018-04-18 08:53:10 -0400105 void __iomem *ports[] = {
106 &idio16gpio->reg->out0_7, &idio16gpio->reg->out8_15,
107 &idio16gpio->reg->in0_7, &idio16gpio->reg->in8_15,
William Breathitt Gray810ebfc2018-03-22 08:59:48 -0400108 };
William Breathitt Gray2dc7c3c2019-12-04 16:51:18 -0800109 void __iomem *port_addr;
110 unsigned long port_state;
William Breathitt Gray810ebfc2018-03-22 08:59:48 -0400111
112 /* clear bits array to a clean slate */
113 bitmap_zero(bits, chip->ngpio);
114
William Breathitt Gray2dc7c3c2019-12-04 16:51:18 -0800115 for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) {
116 port_addr = ports[offset / 8];
117 port_state = ioread8(port_addr) & gpio_mask;
William Breathitt Gray810ebfc2018-03-22 08:59:48 -0400118
William Breathitt Gray2dc7c3c2019-12-04 16:51:18 -0800119 bitmap_set_value8(bits, port_state, offset);
William Breathitt Gray810ebfc2018-03-22 08:59:48 -0400120 }
121
122 return 0;
123}
124
William Breathitt Gray02e74fc2017-02-01 15:37:55 -0500125static void idio_16_gpio_set(struct gpio_chip *chip, unsigned int offset,
126 int value)
127{
128 struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
129 unsigned int mask = BIT(offset);
130 void __iomem *base;
131 unsigned long flags;
132 unsigned int out_state;
133
134 if (offset > 15)
135 return;
136
137 if (offset > 7) {
138 mask >>= 8;
139 base = &idio16gpio->reg->out8_15;
140 } else
141 base = &idio16gpio->reg->out0_7;
142
Julia Cartwrightea38ce02017-03-21 17:43:09 -0500143 raw_spin_lock_irqsave(&idio16gpio->lock, flags);
William Breathitt Gray02e74fc2017-02-01 15:37:55 -0500144
145 if (value)
146 out_state = ioread8(base) | mask;
147 else
148 out_state = ioread8(base) & ~mask;
149
150 iowrite8(out_state, base);
151
Julia Cartwrightea38ce02017-03-21 17:43:09 -0500152 raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
William Breathitt Gray02e74fc2017-02-01 15:37:55 -0500153}
154
155static void idio_16_gpio_set_multiple(struct gpio_chip *chip,
156 unsigned long *mask, unsigned long *bits)
157{
158 struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
William Breathitt Gray2dc7c3c2019-12-04 16:51:18 -0800159 unsigned long offset;
160 unsigned long gpio_mask;
161 void __iomem *ports[] = {
162 &idio16gpio->reg->out0_7, &idio16gpio->reg->out8_15,
163 };
164 size_t index;
165 void __iomem *port_addr;
166 unsigned long bitmask;
William Breathitt Gray02e74fc2017-02-01 15:37:55 -0500167 unsigned long flags;
William Breathitt Gray2dc7c3c2019-12-04 16:51:18 -0800168 unsigned long out_state;
William Breathitt Gray02e74fc2017-02-01 15:37:55 -0500169
William Breathitt Gray2dc7c3c2019-12-04 16:51:18 -0800170 for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) {
171 index = offset / 8;
172 port_addr = ports[index];
William Breathitt Gray02e74fc2017-02-01 15:37:55 -0500173
William Breathitt Gray2dc7c3c2019-12-04 16:51:18 -0800174 bitmask = bitmap_get_value8(bits, offset) & gpio_mask;
175
176 raw_spin_lock_irqsave(&idio16gpio->lock, flags);
177
178 out_state = ioread8(port_addr) & ~gpio_mask;
179 out_state |= bitmask;
180 iowrite8(out_state, port_addr);
181
182 raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
William Breathitt Gray02e74fc2017-02-01 15:37:55 -0500183 }
William Breathitt Gray02e74fc2017-02-01 15:37:55 -0500184}
185
186static void idio_16_irq_ack(struct irq_data *data)
187{
188}
189
190static void idio_16_irq_mask(struct irq_data *data)
191{
192 struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
193 struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
194 const unsigned long mask = BIT(irqd_to_hwirq(data));
195 unsigned long flags;
196
197 idio16gpio->irq_mask &= ~mask;
198
199 if (!idio16gpio->irq_mask) {
Julia Cartwrightea38ce02017-03-21 17:43:09 -0500200 raw_spin_lock_irqsave(&idio16gpio->lock, flags);
William Breathitt Gray02e74fc2017-02-01 15:37:55 -0500201
202 iowrite8(0, &idio16gpio->reg->irq_ctl);
203
Julia Cartwrightea38ce02017-03-21 17:43:09 -0500204 raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
William Breathitt Gray02e74fc2017-02-01 15:37:55 -0500205 }
206}
207
208static void idio_16_irq_unmask(struct irq_data *data)
209{
210 struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
211 struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
212 const unsigned long mask = BIT(irqd_to_hwirq(data));
213 const unsigned long prev_irq_mask = idio16gpio->irq_mask;
214 unsigned long flags;
215
216 idio16gpio->irq_mask |= mask;
217
218 if (!prev_irq_mask) {
Julia Cartwrightea38ce02017-03-21 17:43:09 -0500219 raw_spin_lock_irqsave(&idio16gpio->lock, flags);
William Breathitt Gray02e74fc2017-02-01 15:37:55 -0500220
221 ioread8(&idio16gpio->reg->irq_ctl);
222
Julia Cartwrightea38ce02017-03-21 17:43:09 -0500223 raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
William Breathitt Gray02e74fc2017-02-01 15:37:55 -0500224 }
225}
226
227static int idio_16_irq_set_type(struct irq_data *data, unsigned int flow_type)
228{
229 /* The only valid irq types are none and both-edges */
230 if (flow_type != IRQ_TYPE_NONE &&
231 (flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH)
232 return -EINVAL;
233
234 return 0;
235}
236
237static struct irq_chip idio_16_irqchip = {
238 .name = "pci-idio-16",
239 .irq_ack = idio_16_irq_ack,
240 .irq_mask = idio_16_irq_mask,
241 .irq_unmask = idio_16_irq_unmask,
242 .irq_set_type = idio_16_irq_set_type
243};
244
245static irqreturn_t idio_16_irq_handler(int irq, void *dev_id)
246{
247 struct idio_16_gpio *const idio16gpio = dev_id;
248 unsigned int irq_status;
249 struct gpio_chip *const chip = &idio16gpio->chip;
250 int gpio;
251
Julia Cartwrightea38ce02017-03-21 17:43:09 -0500252 raw_spin_lock(&idio16gpio->lock);
William Breathitt Gray02e74fc2017-02-01 15:37:55 -0500253
254 irq_status = ioread8(&idio16gpio->reg->irq_status);
255
Julia Cartwrightea38ce02017-03-21 17:43:09 -0500256 raw_spin_unlock(&idio16gpio->lock);
William Breathitt Gray02e74fc2017-02-01 15:37:55 -0500257
258 /* Make sure our device generated IRQ */
259 if (!(irq_status & 0x3) || !(irq_status & 0x4))
260 return IRQ_NONE;
261
262 for_each_set_bit(gpio, &idio16gpio->irq_mask, chip->ngpio)
Thierry Redingf0fbe7b2017-11-07 19:15:47 +0100263 generic_handle_irq(irq_find_mapping(chip->irq.domain, gpio));
William Breathitt Gray02e74fc2017-02-01 15:37:55 -0500264
Julia Cartwrightea38ce02017-03-21 17:43:09 -0500265 raw_spin_lock(&idio16gpio->lock);
William Breathitt Gray02e74fc2017-02-01 15:37:55 -0500266
267 /* Clear interrupt */
268 iowrite8(0, &idio16gpio->reg->in0_7);
269
Julia Cartwrightea38ce02017-03-21 17:43:09 -0500270 raw_spin_unlock(&idio16gpio->lock);
William Breathitt Gray02e74fc2017-02-01 15:37:55 -0500271
272 return IRQ_HANDLED;
273}
274
275#define IDIO_16_NGPIO 32
276static const char *idio_16_names[IDIO_16_NGPIO] = {
277 "OUT0", "OUT1", "OUT2", "OUT3", "OUT4", "OUT5", "OUT6", "OUT7",
278 "OUT8", "OUT9", "OUT10", "OUT11", "OUT12", "OUT13", "OUT14", "OUT15",
279 "IIN0", "IIN1", "IIN2", "IIN3", "IIN4", "IIN5", "IIN6", "IIN7",
280 "IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15"
281};
282
283static int idio_16_probe(struct pci_dev *pdev, const struct pci_device_id *id)
284{
285 struct device *const dev = &pdev->dev;
286 struct idio_16_gpio *idio16gpio;
287 int err;
William Breathitt Graydeab2b02017-02-08 08:32:46 -0500288 const size_t pci_bar_index = 2;
William Breathitt Gray02e74fc2017-02-01 15:37:55 -0500289 const char *const name = pci_name(pdev);
290
291 idio16gpio = devm_kzalloc(dev, sizeof(*idio16gpio), GFP_KERNEL);
292 if (!idio16gpio)
293 return -ENOMEM;
294
295 err = pcim_enable_device(pdev);
296 if (err) {
297 dev_err(dev, "Failed to enable PCI device (%d)\n", err);
298 return err;
299 }
300
William Breathitt Graydeab2b02017-02-08 08:32:46 -0500301 err = pcim_iomap_regions(pdev, BIT(pci_bar_index), name);
William Breathitt Gray02e74fc2017-02-01 15:37:55 -0500302 if (err) {
303 dev_err(dev, "Unable to map PCI I/O addresses (%d)\n", err);
304 return err;
305 }
306
William Breathitt Graydeab2b02017-02-08 08:32:46 -0500307 idio16gpio->reg = pcim_iomap_table(pdev)[pci_bar_index];
William Breathitt Gray02e74fc2017-02-01 15:37:55 -0500308
309 /* Deactivate input filters */
310 iowrite8(0, &idio16gpio->reg->filter_ctl);
311
312 idio16gpio->chip.label = name;
313 idio16gpio->chip.parent = dev;
314 idio16gpio->chip.owner = THIS_MODULE;
315 idio16gpio->chip.base = -1;
316 idio16gpio->chip.ngpio = IDIO_16_NGPIO;
317 idio16gpio->chip.names = idio_16_names;
318 idio16gpio->chip.get_direction = idio_16_gpio_get_direction;
319 idio16gpio->chip.direction_input = idio_16_gpio_direction_input;
320 idio16gpio->chip.direction_output = idio_16_gpio_direction_output;
321 idio16gpio->chip.get = idio_16_gpio_get;
William Breathitt Gray810ebfc2018-03-22 08:59:48 -0400322 idio16gpio->chip.get_multiple = idio_16_gpio_get_multiple;
William Breathitt Gray02e74fc2017-02-01 15:37:55 -0500323 idio16gpio->chip.set = idio_16_gpio_set;
324 idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple;
325
Julia Cartwrightea38ce02017-03-21 17:43:09 -0500326 raw_spin_lock_init(&idio16gpio->lock);
William Breathitt Gray02e74fc2017-02-01 15:37:55 -0500327
328 err = devm_gpiochip_add_data(dev, &idio16gpio->chip, idio16gpio);
329 if (err) {
330 dev_err(dev, "GPIO registering failed (%d)\n", err);
331 return err;
332 }
333
334 /* Disable IRQ by default and clear any pending interrupt */
335 iowrite8(0, &idio16gpio->reg->irq_ctl);
336 iowrite8(0, &idio16gpio->reg->in0_7);
337
338 err = gpiochip_irqchip_add(&idio16gpio->chip, &idio_16_irqchip, 0,
339 handle_edge_irq, IRQ_TYPE_NONE);
340 if (err) {
341 dev_err(dev, "Could not add irqchip (%d)\n", err);
342 return err;
343 }
344
345 err = devm_request_irq(dev, pdev->irq, idio_16_irq_handler, IRQF_SHARED,
346 name, idio16gpio);
347 if (err) {
348 dev_err(dev, "IRQ handler registering failed (%d)\n", err);
349 return err;
350 }
351
352 return 0;
353}
354
355static const struct pci_device_id idio_16_pci_dev_id[] = {
William Breathitt Grayfd254a22017-02-07 11:51:19 -0500356 { PCI_DEVICE(0x494F, 0x0DC8) }, { 0 }
William Breathitt Gray02e74fc2017-02-01 15:37:55 -0500357};
358MODULE_DEVICE_TABLE(pci, idio_16_pci_dev_id);
359
360static struct pci_driver idio_16_driver = {
361 .name = "pci-idio-16",
362 .id_table = idio_16_pci_dev_id,
363 .probe = idio_16_probe
364};
365
366module_pci_driver(idio_16_driver);
367
368MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
369MODULE_DESCRIPTION("ACCES PCI-IDIO-16 GPIO driver");
370MODULE_LICENSE("GPL v2");