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