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 	raw_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 	raw_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 	raw_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 	raw_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 	raw_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 		raw_spin_lock_irqsave(&idio16gpio->lock, flags);
181 
182 		iowrite8(0, &idio16gpio->reg->irq_ctl);
183 
184 		raw_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 		raw_spin_lock_irqsave(&idio16gpio->lock, flags);
200 
201 		ioread8(&idio16gpio->reg->irq_ctl);
202 
203 		raw_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 	raw_spin_lock(&idio16gpio->lock);
233 
234 	irq_status = ioread8(&idio16gpio->reg->irq_status);
235 
236 	raw_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 	raw_spin_lock(&idio16gpio->lock);
246 
247 	/* Clear interrupt */
248 	iowrite8(0, &idio16gpio->reg->in0_7);
249 
250 	raw_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 	raw_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");
350