Merge branch 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6-microblaze.git] / drivers / gpio / gpio-pcie-idio-24.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * GPIO driver for the ACCES PCIe-IDIO-24 family
4  * Copyright (C) 2018 William Breathitt Gray
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License, version 2, as
8  * published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * This driver supports the following ACCES devices: PCIe-IDIO-24,
16  * PCIe-IDI-24, PCIe-IDO-24, and PCIe-IDIO-12.
17  */
18 #include <linux/bitops.h>
19 #include <linux/device.h>
20 #include <linux/errno.h>
21 #include <linux/gpio/driver.h>
22 #include <linux/interrupt.h>
23 #include <linux/irqdesc.h>
24 #include <linux/kernel.h>
25 #include <linux/module.h>
26 #include <linux/pci.h>
27 #include <linux/spinlock.h>
28 #include <linux/types.h>
29
30 /**
31  * struct idio_24_gpio_reg - GPIO device registers structure
32  * @out0_7:     Read: FET Outputs 0-7
33  *              Write: FET Outputs 0-7
34  * @out8_15:    Read: FET Outputs 8-15
35  *              Write: FET Outputs 8-15
36  * @out16_23:   Read: FET Outputs 16-23
37  *              Write: FET Outputs 16-23
38  * @ttl_out0_7: Read: TTL/CMOS Outputs 0-7
39  *              Write: TTL/CMOS Outputs 0-7
40  * @in0_7:      Read: Isolated Inputs 0-7
41  *              Write: Reserved
42  * @in8_15:     Read: Isolated Inputs 8-15
43  *              Write: Reserved
44  * @in16_23:    Read: Isolated Inputs 16-23
45  *              Write: Reserved
46  * @ttl_in0_7:  Read: TTL/CMOS Inputs 0-7
47  *              Write: Reserved
48  * @cos0_7:     Read: COS Status Inputs 0-7
49  *              Write: COS Clear Inputs 0-7
50  * @cos8_15:    Read: COS Status Inputs 8-15
51  *              Write: COS Clear Inputs 8-15
52  * @cos16_23:   Read: COS Status Inputs 16-23
53  *              Write: COS Clear Inputs 16-23
54  * @cos_ttl0_7: Read: COS Status TTL/CMOS 0-7
55  *              Write: COS Clear TTL/CMOS 0-7
56  * @ctl:        Read: Control Register
57  *              Write: Control Register
58  * @reserved:   Read: Reserved
59  *              Write: Reserved
60  * @cos_enable: Read: COS Enable
61  *              Write: COS Enable
62  * @soft_reset: Read: IRQ Output Pin Status
63  *              Write: Software Board Reset
64  */
65 struct idio_24_gpio_reg {
66         u8 out0_7;
67         u8 out8_15;
68         u8 out16_23;
69         u8 ttl_out0_7;
70         u8 in0_7;
71         u8 in8_15;
72         u8 in16_23;
73         u8 ttl_in0_7;
74         u8 cos0_7;
75         u8 cos8_15;
76         u8 cos16_23;
77         u8 cos_ttl0_7;
78         u8 ctl;
79         u8 reserved;
80         u8 cos_enable;
81         u8 soft_reset;
82 };
83
84 /**
85  * struct idio_24_gpio - GPIO device private data structure
86  * @chip:       instance of the gpio_chip
87  * @lock:       synchronization lock to prevent I/O race conditions
88  * @reg:        I/O address offset for the GPIO device registers
89  * @irq_mask:   I/O bits affected by interrupts
90  */
91 struct idio_24_gpio {
92         struct gpio_chip chip;
93         raw_spinlock_t lock;
94         struct idio_24_gpio_reg __iomem *reg;
95         unsigned long irq_mask;
96 };
97
98 static int idio_24_gpio_get_direction(struct gpio_chip *chip,
99         unsigned int offset)
100 {
101         struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
102         const unsigned long out_mode_mask = BIT(1);
103
104         /* FET Outputs */
105         if (offset < 24)
106                 return 0;
107
108         /* Isolated Inputs */
109         if (offset < 48)
110                 return 1;
111
112         /* TTL/CMOS I/O */
113         /* OUT MODE = 1 when TTL/CMOS Output Mode is set */
114         return !(ioread8(&idio24gpio->reg->ctl) & out_mode_mask);
115 }
116
117 static int idio_24_gpio_direction_input(struct gpio_chip *chip,
118         unsigned int offset)
119 {
120         struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
121         unsigned long flags;
122         unsigned int ctl_state;
123         const unsigned long out_mode_mask = BIT(1);
124
125         /* TTL/CMOS I/O */
126         if (offset > 47) {
127                 raw_spin_lock_irqsave(&idio24gpio->lock, flags);
128
129                 /* Clear TTL/CMOS Output Mode */
130                 ctl_state = ioread8(&idio24gpio->reg->ctl) & ~out_mode_mask;
131                 iowrite8(ctl_state, &idio24gpio->reg->ctl);
132
133                 raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
134         }
135
136         return 0;
137 }
138
139 static int idio_24_gpio_direction_output(struct gpio_chip *chip,
140         unsigned int offset, int value)
141 {
142         struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
143         unsigned long flags;
144         unsigned int ctl_state;
145         const unsigned long out_mode_mask = BIT(1);
146
147         /* TTL/CMOS I/O */
148         if (offset > 47) {
149                 raw_spin_lock_irqsave(&idio24gpio->lock, flags);
150
151                 /* Set TTL/CMOS Output Mode */
152                 ctl_state = ioread8(&idio24gpio->reg->ctl) | out_mode_mask;
153                 iowrite8(ctl_state, &idio24gpio->reg->ctl);
154
155                 raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
156         }
157
158         chip->set(chip, offset, value);
159         return 0;
160 }
161
162 static int idio_24_gpio_get(struct gpio_chip *chip, unsigned int offset)
163 {
164         struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
165         const unsigned long offset_mask = BIT(offset % 8);
166         const unsigned long out_mode_mask = BIT(1);
167
168         /* FET Outputs */
169         if (offset < 8)
170                 return !!(ioread8(&idio24gpio->reg->out0_7) & offset_mask);
171
172         if (offset < 16)
173                 return !!(ioread8(&idio24gpio->reg->out8_15) & offset_mask);
174
175         if (offset < 24)
176                 return !!(ioread8(&idio24gpio->reg->out16_23) & offset_mask);
177
178         /* Isolated Inputs */
179         if (offset < 32)
180                 return !!(ioread8(&idio24gpio->reg->in0_7) & offset_mask);
181
182         if (offset < 40)
183                 return !!(ioread8(&idio24gpio->reg->in8_15) & offset_mask);
184
185         if (offset < 48)
186                 return !!(ioread8(&idio24gpio->reg->in16_23) & offset_mask);
187
188         /* TTL/CMOS Outputs */
189         if (ioread8(&idio24gpio->reg->ctl) & out_mode_mask)
190                 return !!(ioread8(&idio24gpio->reg->ttl_out0_7) & offset_mask);
191
192         /* TTL/CMOS Inputs */
193         return !!(ioread8(&idio24gpio->reg->ttl_in0_7) & offset_mask);
194 }
195
196 static void idio_24_gpio_set(struct gpio_chip *chip, unsigned int offset,
197         int value)
198 {
199         struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
200         const unsigned long out_mode_mask = BIT(1);
201         void __iomem *base;
202         const unsigned int mask = BIT(offset % 8);
203         unsigned long flags;
204         unsigned int out_state;
205
206         /* Isolated Inputs */
207         if (offset > 23 && offset < 48)
208                 return;
209
210         /* TTL/CMOS Inputs */
211         if (offset > 47 && !(ioread8(&idio24gpio->reg->ctl) & out_mode_mask))
212                 return;
213
214         /* TTL/CMOS Outputs */
215         if (offset > 47)
216                 base = &idio24gpio->reg->ttl_out0_7;
217         /* FET Outputs */
218         else if (offset > 15)
219                 base = &idio24gpio->reg->out16_23;
220         else if (offset > 7)
221                 base = &idio24gpio->reg->out8_15;
222         else
223                 base = &idio24gpio->reg->out0_7;
224
225         raw_spin_lock_irqsave(&idio24gpio->lock, flags);
226
227         if (value)
228                 out_state = ioread8(base) | mask;
229         else
230                 out_state = ioread8(base) & ~mask;
231
232         iowrite8(out_state, base);
233
234         raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
235 }
236
237 static void idio_24_irq_ack(struct irq_data *data)
238 {
239 }
240
241 static void idio_24_irq_mask(struct irq_data *data)
242 {
243         struct gpio_chip *const chip = irq_data_get_irq_chip_data(data);
244         struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
245         unsigned long flags;
246         const unsigned long bit_offset = irqd_to_hwirq(data) - 24;
247         unsigned char new_irq_mask;
248         const unsigned long bank_offset = bit_offset/8 * 8;
249         unsigned char cos_enable_state;
250
251         raw_spin_lock_irqsave(&idio24gpio->lock, flags);
252
253         idio24gpio->irq_mask &= BIT(bit_offset);
254         new_irq_mask = idio24gpio->irq_mask >> bank_offset;
255
256         if (!new_irq_mask) {
257                 cos_enable_state = ioread8(&idio24gpio->reg->cos_enable);
258
259                 /* Disable Rising Edge detection */
260                 cos_enable_state &= ~BIT(bank_offset);
261                 /* Disable Falling Edge detection */
262                 cos_enable_state &= ~BIT(bank_offset + 4);
263
264                 iowrite8(cos_enable_state, &idio24gpio->reg->cos_enable);
265         }
266
267         raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
268 }
269
270 static void idio_24_irq_unmask(struct irq_data *data)
271 {
272         struct gpio_chip *const chip = irq_data_get_irq_chip_data(data);
273         struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
274         unsigned long flags;
275         unsigned char prev_irq_mask;
276         const unsigned long bit_offset = irqd_to_hwirq(data) - 24;
277         const unsigned long bank_offset = bit_offset/8 * 8;
278         unsigned char cos_enable_state;
279
280         raw_spin_lock_irqsave(&idio24gpio->lock, flags);
281
282         prev_irq_mask = idio24gpio->irq_mask >> bank_offset;
283         idio24gpio->irq_mask |= BIT(bit_offset);
284
285         if (!prev_irq_mask) {
286                 cos_enable_state = ioread8(&idio24gpio->reg->cos_enable);
287
288                 /* Enable Rising Edge detection */
289                 cos_enable_state |= BIT(bank_offset);
290                 /* Enable Falling Edge detection */
291                 cos_enable_state |= BIT(bank_offset + 4);
292
293                 iowrite8(cos_enable_state, &idio24gpio->reg->cos_enable);
294         }
295
296         raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
297 }
298
299 static int idio_24_irq_set_type(struct irq_data *data, unsigned int flow_type)
300 {
301         /* The only valid irq types are none and both-edges */
302         if (flow_type != IRQ_TYPE_NONE &&
303                 (flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH)
304                 return -EINVAL;
305
306         return 0;
307 }
308
309 static struct irq_chip idio_24_irqchip = {
310         .name = "pcie-idio-24",
311         .irq_ack = idio_24_irq_ack,
312         .irq_mask = idio_24_irq_mask,
313         .irq_unmask = idio_24_irq_unmask,
314         .irq_set_type = idio_24_irq_set_type
315 };
316
317 static irqreturn_t idio_24_irq_handler(int irq, void *dev_id)
318 {
319         struct idio_24_gpio *const idio24gpio = dev_id;
320         unsigned long irq_status;
321         struct gpio_chip *const chip = &idio24gpio->chip;
322         unsigned long irq_mask;
323         int gpio;
324
325         raw_spin_lock(&idio24gpio->lock);
326
327         /* Read Change-Of-State status */
328         irq_status = ioread32(&idio24gpio->reg->cos0_7);
329
330         raw_spin_unlock(&idio24gpio->lock);
331
332         /* Make sure our device generated IRQ */
333         if (!irq_status)
334                 return IRQ_NONE;
335
336         /* Handle only unmasked IRQ */
337         irq_mask = idio24gpio->irq_mask & irq_status;
338
339         for_each_set_bit(gpio, &irq_mask, chip->ngpio - 24)
340                 generic_handle_irq(irq_find_mapping(chip->irq.domain,
341                         gpio + 24));
342
343         raw_spin_lock(&idio24gpio->lock);
344
345         /* Clear Change-Of-State status */
346         iowrite32(irq_status, &idio24gpio->reg->cos0_7);
347
348         raw_spin_unlock(&idio24gpio->lock);
349
350         return IRQ_HANDLED;
351 }
352
353 #define IDIO_24_NGPIO 56
354 static const char *idio_24_names[IDIO_24_NGPIO] = {
355         "OUT0", "OUT1", "OUT2", "OUT3", "OUT4", "OUT5", "OUT6", "OUT7",
356         "OUT8", "OUT9", "OUT10", "OUT11", "OUT12", "OUT13", "OUT14", "OUT15",
357         "OUT16", "OUT17", "OUT18", "OUT19", "OUT20", "OUT21", "OUT22", "OUT23",
358         "IIN0", "IIN1", "IIN2", "IIN3", "IIN4", "IIN5", "IIN6", "IIN7",
359         "IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15",
360         "IIN16", "IIN17", "IIN18", "IIN19", "IIN20", "IIN21", "IIN22", "IIN23",
361         "TTL0", "TTL1", "TTL2", "TTL3", "TTL4", "TTL5", "TTL6", "TTL7"
362 };
363
364 static int idio_24_probe(struct pci_dev *pdev, const struct pci_device_id *id)
365 {
366         struct device *const dev = &pdev->dev;
367         struct idio_24_gpio *idio24gpio;
368         int err;
369         const size_t pci_bar_index = 2;
370         const char *const name = pci_name(pdev);
371
372         idio24gpio = devm_kzalloc(dev, sizeof(*idio24gpio), GFP_KERNEL);
373         if (!idio24gpio)
374                 return -ENOMEM;
375
376         err = pcim_enable_device(pdev);
377         if (err) {
378                 dev_err(dev, "Failed to enable PCI device (%d)\n", err);
379                 return err;
380         }
381
382         err = pcim_iomap_regions(pdev, BIT(pci_bar_index), name);
383         if (err) {
384                 dev_err(dev, "Unable to map PCI I/O addresses (%d)\n", err);
385                 return err;
386         }
387
388         idio24gpio->reg = pcim_iomap_table(pdev)[pci_bar_index];
389
390         idio24gpio->chip.label = name;
391         idio24gpio->chip.parent = dev;
392         idio24gpio->chip.owner = THIS_MODULE;
393         idio24gpio->chip.base = -1;
394         idio24gpio->chip.ngpio = IDIO_24_NGPIO;
395         idio24gpio->chip.names = idio_24_names;
396         idio24gpio->chip.get_direction = idio_24_gpio_get_direction;
397         idio24gpio->chip.direction_input = idio_24_gpio_direction_input;
398         idio24gpio->chip.direction_output = idio_24_gpio_direction_output;
399         idio24gpio->chip.get = idio_24_gpio_get;
400         idio24gpio->chip.set = idio_24_gpio_set;
401
402         raw_spin_lock_init(&idio24gpio->lock);
403
404         /* Software board reset */
405         iowrite8(0, &idio24gpio->reg->soft_reset);
406
407         err = devm_gpiochip_add_data(dev, &idio24gpio->chip, idio24gpio);
408         if (err) {
409                 dev_err(dev, "GPIO registering failed (%d)\n", err);
410                 return err;
411         }
412
413         err = gpiochip_irqchip_add(&idio24gpio->chip, &idio_24_irqchip, 0,
414                 handle_edge_irq, IRQ_TYPE_NONE);
415         if (err) {
416                 dev_err(dev, "Could not add irqchip (%d)\n", err);
417                 return err;
418         }
419
420         err = devm_request_irq(dev, pdev->irq, idio_24_irq_handler, IRQF_SHARED,
421                 name, idio24gpio);
422         if (err) {
423                 dev_err(dev, "IRQ handler registering failed (%d)\n", err);
424                 return err;
425         }
426
427         return 0;
428 }
429
430 static const struct pci_device_id idio_24_pci_dev_id[] = {
431         { PCI_DEVICE(0x494F, 0x0FD0) }, { PCI_DEVICE(0x494F, 0x0BD0) },
432         { PCI_DEVICE(0x494F, 0x07D0) }, { PCI_DEVICE(0x494F, 0x0FC0) },
433         { 0 }
434 };
435 MODULE_DEVICE_TABLE(pci, idio_24_pci_dev_id);
436
437 static struct pci_driver idio_24_driver = {
438         .name = "pcie-idio-24",
439         .id_table = idio_24_pci_dev_id,
440         .probe = idio_24_probe
441 };
442
443 module_pci_driver(idio_24_driver);
444
445 MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
446 MODULE_DESCRIPTION("ACCES PCIe-IDIO-24 GPIO driver");
447 MODULE_LICENSE("GPL v2");