11802d0beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21ceacea2SWilliam Breathitt Gray /*
31ceacea2SWilliam Breathitt Gray  * GPIO driver for the ACCES 104-IDIO-16 family
41ceacea2SWilliam Breathitt Gray  * Copyright (C) 2015 William Breathitt Gray
51ceacea2SWilliam Breathitt Gray  *
686ea8a95SWilliam Breathitt Gray  * This driver supports the following ACCES devices: 104-IDIO-16,
786ea8a95SWilliam Breathitt Gray  * 104-IDIO-16E, 104-IDO-16, 104-IDIO-8, 104-IDIO-8E, and 104-IDO-8.
81ceacea2SWilliam Breathitt Gray  */
9*c4ec384cSWilliam Breathitt Gray #include <linux/bitmap.h>
101ceacea2SWilliam Breathitt Gray #include <linux/device.h>
111ceacea2SWilliam Breathitt Gray #include <linux/errno.h>
121ceacea2SWilliam Breathitt Gray #include <linux/gpio/driver.h>
131ceacea2SWilliam Breathitt Gray #include <linux/io.h>
141ceacea2SWilliam Breathitt Gray #include <linux/ioport.h>
15a1184147SWilliam Breathitt Gray #include <linux/interrupt.h>
16a1184147SWilliam Breathitt Gray #include <linux/irqdesc.h>
1786ea8a95SWilliam Breathitt Gray #include <linux/isa.h>
181ceacea2SWilliam Breathitt Gray #include <linux/kernel.h>
191ceacea2SWilliam Breathitt Gray #include <linux/module.h>
201ceacea2SWilliam Breathitt Gray #include <linux/moduleparam.h>
211ceacea2SWilliam Breathitt Gray #include <linux/spinlock.h>
22cc442e4dSWilliam Breathitt Gray #include <linux/types.h>
231ceacea2SWilliam Breathitt Gray 
24*c4ec384cSWilliam Breathitt Gray #include "gpio-idio-16.h"
25*c4ec384cSWilliam Breathitt Gray 
2686ea8a95SWilliam Breathitt Gray #define IDIO_16_EXTENT 8
2786ea8a95SWilliam Breathitt Gray #define MAX_NUM_IDIO_16 max_num_isa_dev(IDIO_16_EXTENT)
2886ea8a95SWilliam Breathitt Gray 
2986ea8a95SWilliam Breathitt Gray static unsigned int base[MAX_NUM_IDIO_16];
3086ea8a95SWilliam Breathitt Gray static unsigned int num_idio_16;
31d759f906SDavid Howells module_param_hw_array(base, uint, ioport, &num_idio_16, 0);
3286ea8a95SWilliam Breathitt Gray MODULE_PARM_DESC(base, "ACCES 104-IDIO-16 base addresses");
3386ea8a95SWilliam Breathitt Gray 
3486ea8a95SWilliam Breathitt Gray static unsigned int irq[MAX_NUM_IDIO_16];
35c6074f3fSWilliam Breathitt Gray static unsigned int num_irq;
36c6074f3fSWilliam Breathitt Gray module_param_hw_array(irq, uint, irq, &num_irq, 0);
3786ea8a95SWilliam Breathitt Gray MODULE_PARM_DESC(irq, "ACCES 104-IDIO-16 interrupt line numbers");
381ceacea2SWilliam Breathitt Gray 
391ceacea2SWilliam Breathitt Gray /**
401ceacea2SWilliam Breathitt Gray  * struct idio_16_gpio - GPIO device private data structure
411ceacea2SWilliam Breathitt Gray  * @chip:	instance of the gpio_chip
42a1184147SWilliam Breathitt Gray  * @lock:	synchronization lock to prevent I/O race conditions
43a1184147SWilliam Breathitt Gray  * @irq_mask:	I/O bits affected by interrupts
44cc442e4dSWilliam Breathitt Gray  * @reg:	I/O address offset for the device registers
45*c4ec384cSWilliam Breathitt Gray  * @state:	ACCES IDIO-16 device state
461ceacea2SWilliam Breathitt Gray  */
471ceacea2SWilliam Breathitt Gray struct idio_16_gpio {
481ceacea2SWilliam Breathitt Gray 	struct gpio_chip chip;
493906e808SJulia Cartwright 	raw_spinlock_t lock;
50a1184147SWilliam Breathitt Gray 	unsigned long irq_mask;
51*c4ec384cSWilliam Breathitt Gray 	struct idio_16 __iomem *reg;
52*c4ec384cSWilliam Breathitt Gray 	struct idio_16_state state;
531ceacea2SWilliam Breathitt Gray };
541ceacea2SWilliam Breathitt Gray 
55cc0f53d2SNavin Sankar Velliangiri static int idio_16_gpio_get_direction(struct gpio_chip *chip,
56cc0f53d2SNavin Sankar Velliangiri 				      unsigned int offset)
571ceacea2SWilliam Breathitt Gray {
58*c4ec384cSWilliam Breathitt Gray 	if (idio_16_get_direction(offset))
59e42615ecSMatti Vaittinen 		return GPIO_LINE_DIRECTION_IN;
601ceacea2SWilliam Breathitt Gray 
61e42615ecSMatti Vaittinen 	return GPIO_LINE_DIRECTION_OUT;
621ceacea2SWilliam Breathitt Gray }
631ceacea2SWilliam Breathitt Gray 
64cc0f53d2SNavin Sankar Velliangiri static int idio_16_gpio_direction_input(struct gpio_chip *chip,
65cc0f53d2SNavin Sankar Velliangiri 					unsigned int offset)
661ceacea2SWilliam Breathitt Gray {
671ceacea2SWilliam Breathitt Gray 	return 0;
681ceacea2SWilliam Breathitt Gray }
691ceacea2SWilliam Breathitt Gray 
701ceacea2SWilliam Breathitt Gray static int idio_16_gpio_direction_output(struct gpio_chip *chip,
71cc0f53d2SNavin Sankar Velliangiri 	unsigned int offset, int value)
721ceacea2SWilliam Breathitt Gray {
731ceacea2SWilliam Breathitt Gray 	chip->set(chip, offset, value);
741ceacea2SWilliam Breathitt Gray 	return 0;
751ceacea2SWilliam Breathitt Gray }
761ceacea2SWilliam Breathitt Gray 
77cc0f53d2SNavin Sankar Velliangiri static int idio_16_gpio_get(struct gpio_chip *chip, unsigned int offset)
781ceacea2SWilliam Breathitt Gray {
79d602ae90SLinus Walleij 	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
801ceacea2SWilliam Breathitt Gray 
81*c4ec384cSWilliam Breathitt Gray 	return idio_16_get(idio16gpio->reg, &idio16gpio->state, offset);
821ceacea2SWilliam Breathitt Gray }
831ceacea2SWilliam Breathitt Gray 
8415f59cffSWilliam Breathitt Gray static int idio_16_gpio_get_multiple(struct gpio_chip *chip,
8515f59cffSWilliam Breathitt Gray 	unsigned long *mask, unsigned long *bits)
8615f59cffSWilliam Breathitt Gray {
8715f59cffSWilliam Breathitt Gray 	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
8815f59cffSWilliam Breathitt Gray 
89*c4ec384cSWilliam Breathitt Gray 	idio_16_get_multiple(idio16gpio->reg, &idio16gpio->state, mask, bits);
9015f59cffSWilliam Breathitt Gray 
9115f59cffSWilliam Breathitt Gray 	return 0;
9215f59cffSWilliam Breathitt Gray }
9315f59cffSWilliam Breathitt Gray 
94cc0f53d2SNavin Sankar Velliangiri static void idio_16_gpio_set(struct gpio_chip *chip, unsigned int offset,
95cc0f53d2SNavin Sankar Velliangiri 			     int value)
961ceacea2SWilliam Breathitt Gray {
97d602ae90SLinus Walleij 	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
981ceacea2SWilliam Breathitt Gray 
99*c4ec384cSWilliam Breathitt Gray 	idio_16_set(idio16gpio->reg, &idio16gpio->state, offset, value);
1001ceacea2SWilliam Breathitt Gray }
1011ceacea2SWilliam Breathitt Gray 
1029d7ae812SWilliam Breathitt Gray static void idio_16_gpio_set_multiple(struct gpio_chip *chip,
1039d7ae812SWilliam Breathitt Gray 	unsigned long *mask, unsigned long *bits)
1049d7ae812SWilliam Breathitt Gray {
1059d7ae812SWilliam Breathitt Gray 	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
1069d7ae812SWilliam Breathitt Gray 
107*c4ec384cSWilliam Breathitt Gray 	idio_16_set_multiple(idio16gpio->reg, &idio16gpio->state, mask, bits);
1089d7ae812SWilliam Breathitt Gray }
1099d7ae812SWilliam Breathitt Gray 
110a1184147SWilliam Breathitt Gray static void idio_16_irq_ack(struct irq_data *data)
111a1184147SWilliam Breathitt Gray {
112a1184147SWilliam Breathitt Gray }
113a1184147SWilliam Breathitt Gray 
114a1184147SWilliam Breathitt Gray static void idio_16_irq_mask(struct irq_data *data)
115a1184147SWilliam Breathitt Gray {
116a1184147SWilliam Breathitt Gray 	struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
117d602ae90SLinus Walleij 	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
118410a5041SWilliam Breathitt Gray 	const unsigned long offset = irqd_to_hwirq(data);
119a1184147SWilliam Breathitt Gray 	unsigned long flags;
120a1184147SWilliam Breathitt Gray 
121410a5041SWilliam Breathitt Gray 	idio16gpio->irq_mask &= ~BIT(offset);
122410a5041SWilliam Breathitt Gray 	gpiochip_disable_irq(chip, offset);
123a1184147SWilliam Breathitt Gray 
124a1184147SWilliam Breathitt Gray 	if (!idio16gpio->irq_mask) {
1253906e808SJulia Cartwright 		raw_spin_lock_irqsave(&idio16gpio->lock, flags);
126a1184147SWilliam Breathitt Gray 
127cc442e4dSWilliam Breathitt Gray 		iowrite8(0, &idio16gpio->reg->irq_ctl);
128a1184147SWilliam Breathitt Gray 
1293906e808SJulia Cartwright 		raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
130a1184147SWilliam Breathitt Gray 	}
131a1184147SWilliam Breathitt Gray }
132a1184147SWilliam Breathitt Gray 
133a1184147SWilliam Breathitt Gray static void idio_16_irq_unmask(struct irq_data *data)
134a1184147SWilliam Breathitt Gray {
135a1184147SWilliam Breathitt Gray 	struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
136d602ae90SLinus Walleij 	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
137410a5041SWilliam Breathitt Gray 	const unsigned long offset = irqd_to_hwirq(data);
138a1184147SWilliam Breathitt Gray 	const unsigned long prev_irq_mask = idio16gpio->irq_mask;
139a1184147SWilliam Breathitt Gray 	unsigned long flags;
140a1184147SWilliam Breathitt Gray 
141410a5041SWilliam Breathitt Gray 	gpiochip_enable_irq(chip, offset);
142410a5041SWilliam Breathitt Gray 	idio16gpio->irq_mask |= BIT(offset);
143a1184147SWilliam Breathitt Gray 
144a1184147SWilliam Breathitt Gray 	if (!prev_irq_mask) {
1453906e808SJulia Cartwright 		raw_spin_lock_irqsave(&idio16gpio->lock, flags);
146a1184147SWilliam Breathitt Gray 
147cc442e4dSWilliam Breathitt Gray 		ioread8(&idio16gpio->reg->irq_ctl);
148a1184147SWilliam Breathitt Gray 
1493906e808SJulia Cartwright 		raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
150a1184147SWilliam Breathitt Gray 	}
151a1184147SWilliam Breathitt Gray }
152a1184147SWilliam Breathitt Gray 
153cc0f53d2SNavin Sankar Velliangiri static int idio_16_irq_set_type(struct irq_data *data, unsigned int flow_type)
154a1184147SWilliam Breathitt Gray {
155a1184147SWilliam Breathitt Gray 	/* The only valid irq types are none and both-edges */
156a1184147SWilliam Breathitt Gray 	if (flow_type != IRQ_TYPE_NONE &&
157a1184147SWilliam Breathitt Gray 		(flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH)
158a1184147SWilliam Breathitt Gray 		return -EINVAL;
159a1184147SWilliam Breathitt Gray 
160a1184147SWilliam Breathitt Gray 	return 0;
161a1184147SWilliam Breathitt Gray }
162a1184147SWilliam Breathitt Gray 
163410a5041SWilliam Breathitt Gray static const struct irq_chip idio_16_irqchip = {
164a1184147SWilliam Breathitt Gray 	.name = "104-idio-16",
165a1184147SWilliam Breathitt Gray 	.irq_ack = idio_16_irq_ack,
166a1184147SWilliam Breathitt Gray 	.irq_mask = idio_16_irq_mask,
167a1184147SWilliam Breathitt Gray 	.irq_unmask = idio_16_irq_unmask,
168410a5041SWilliam Breathitt Gray 	.irq_set_type = idio_16_irq_set_type,
169410a5041SWilliam Breathitt Gray 	.flags = IRQCHIP_IMMUTABLE,
170410a5041SWilliam Breathitt Gray 	GPIOCHIP_IRQ_RESOURCE_HELPERS,
171a1184147SWilliam Breathitt Gray };
172a1184147SWilliam Breathitt Gray 
173a1184147SWilliam Breathitt Gray static irqreturn_t idio_16_irq_handler(int irq, void *dev_id)
174a1184147SWilliam Breathitt Gray {
175a1184147SWilliam Breathitt Gray 	struct idio_16_gpio *const idio16gpio = dev_id;
176a1184147SWilliam Breathitt Gray 	struct gpio_chip *const chip = &idio16gpio->chip;
177a1184147SWilliam Breathitt Gray 	int gpio;
178a1184147SWilliam Breathitt Gray 
179a1184147SWilliam Breathitt Gray 	for_each_set_bit(gpio, &idio16gpio->irq_mask, chip->ngpio)
180dbd1c54fSMarc Zyngier 		generic_handle_domain_irq(chip->irq.domain, gpio);
181a1184147SWilliam Breathitt Gray 
1823906e808SJulia Cartwright 	raw_spin_lock(&idio16gpio->lock);
18312b61c9dSWilliam Breathitt Gray 
184cc442e4dSWilliam Breathitt Gray 	iowrite8(0, &idio16gpio->reg->in0_7);
18512b61c9dSWilliam Breathitt Gray 
1863906e808SJulia Cartwright 	raw_spin_unlock(&idio16gpio->lock);
18712b61c9dSWilliam Breathitt Gray 
188a1184147SWilliam Breathitt Gray 	return IRQ_HANDLED;
189a1184147SWilliam Breathitt Gray }
190a1184147SWilliam Breathitt Gray 
191e0af4b5eSWilliam Breathitt Gray #define IDIO_16_NGPIO 32
192e0af4b5eSWilliam Breathitt Gray static const char *idio_16_names[IDIO_16_NGPIO] = {
193e0af4b5eSWilliam Breathitt Gray 	"OUT0", "OUT1", "OUT2", "OUT3", "OUT4", "OUT5", "OUT6", "OUT7",
194e0af4b5eSWilliam Breathitt Gray 	"OUT8", "OUT9", "OUT10", "OUT11", "OUT12", "OUT13", "OUT14", "OUT15",
195e0af4b5eSWilliam Breathitt Gray 	"IIN0", "IIN1", "IIN2", "IIN3", "IIN4", "IIN5", "IIN6", "IIN7",
196e0af4b5eSWilliam Breathitt Gray 	"IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15"
197e0af4b5eSWilliam Breathitt Gray };
198e0af4b5eSWilliam Breathitt Gray 
19982e4613dSLinus Walleij static int idio_16_irq_init_hw(struct gpio_chip *gc)
20082e4613dSLinus Walleij {
20182e4613dSLinus Walleij 	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(gc);
20282e4613dSLinus Walleij 
20382e4613dSLinus Walleij 	/* Disable IRQ by default */
204cc442e4dSWilliam Breathitt Gray 	iowrite8(0, &idio16gpio->reg->irq_ctl);
205cc442e4dSWilliam Breathitt Gray 	iowrite8(0, &idio16gpio->reg->in0_7);
20682e4613dSLinus Walleij 
20782e4613dSLinus Walleij 	return 0;
20882e4613dSLinus Walleij }
20982e4613dSLinus Walleij 
21086ea8a95SWilliam Breathitt Gray static int idio_16_probe(struct device *dev, unsigned int id)
2111ceacea2SWilliam Breathitt Gray {
2121ceacea2SWilliam Breathitt Gray 	struct idio_16_gpio *idio16gpio;
2136e0171b4SWilliam Breathitt Gray 	const char *const name = dev_name(dev);
21482e4613dSLinus Walleij 	struct gpio_irq_chip *girq;
2151ceacea2SWilliam Breathitt Gray 	int err;
2161ceacea2SWilliam Breathitt Gray 
2171ceacea2SWilliam Breathitt Gray 	idio16gpio = devm_kzalloc(dev, sizeof(*idio16gpio), GFP_KERNEL);
2181ceacea2SWilliam Breathitt Gray 	if (!idio16gpio)
2191ceacea2SWilliam Breathitt Gray 		return -ENOMEM;
2201ceacea2SWilliam Breathitt Gray 
22186ea8a95SWilliam Breathitt Gray 	if (!devm_request_region(dev, base[id], IDIO_16_EXTENT, name)) {
222cb32389cSWilliam Breathitt Gray 		dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
22386ea8a95SWilliam Breathitt Gray 			base[id], base[id] + IDIO_16_EXTENT);
224cb32389cSWilliam Breathitt Gray 		return -EBUSY;
2251ceacea2SWilliam Breathitt Gray 	}
2261ceacea2SWilliam Breathitt Gray 
227cc442e4dSWilliam Breathitt Gray 	idio16gpio->reg = devm_ioport_map(dev, base[id], IDIO_16_EXTENT);
228cc442e4dSWilliam Breathitt Gray 	if (!idio16gpio->reg)
229e0a574efSWilliam Breathitt Gray 		return -ENOMEM;
230e0a574efSWilliam Breathitt Gray 
2316e0171b4SWilliam Breathitt Gray 	idio16gpio->chip.label = name;
23258383c78SLinus Walleij 	idio16gpio->chip.parent = dev;
2331ceacea2SWilliam Breathitt Gray 	idio16gpio->chip.owner = THIS_MODULE;
2341ceacea2SWilliam Breathitt Gray 	idio16gpio->chip.base = -1;
235e0af4b5eSWilliam Breathitt Gray 	idio16gpio->chip.ngpio = IDIO_16_NGPIO;
236e0af4b5eSWilliam Breathitt Gray 	idio16gpio->chip.names = idio_16_names;
2371ceacea2SWilliam Breathitt Gray 	idio16gpio->chip.get_direction = idio_16_gpio_get_direction;
2381ceacea2SWilliam Breathitt Gray 	idio16gpio->chip.direction_input = idio_16_gpio_direction_input;
2391ceacea2SWilliam Breathitt Gray 	idio16gpio->chip.direction_output = idio_16_gpio_direction_output;
2401ceacea2SWilliam Breathitt Gray 	idio16gpio->chip.get = idio_16_gpio_get;
24115f59cffSWilliam Breathitt Gray 	idio16gpio->chip.get_multiple = idio_16_gpio_get_multiple;
2421ceacea2SWilliam Breathitt Gray 	idio16gpio->chip.set = idio_16_gpio_set;
2439d7ae812SWilliam Breathitt Gray 	idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple;
244*c4ec384cSWilliam Breathitt Gray 
245*c4ec384cSWilliam Breathitt Gray 	idio_16_state_init(&idio16gpio->state);
246*c4ec384cSWilliam Breathitt Gray 	/* FET off states are represented by bit values of "1" */
247*c4ec384cSWilliam Breathitt Gray 	bitmap_fill(idio16gpio->state.out_state, IDIO_16_NOUT);
2481ceacea2SWilliam Breathitt Gray 
24982e4613dSLinus Walleij 	girq = &idio16gpio->chip.irq;
250410a5041SWilliam Breathitt Gray 	gpio_irq_chip_set_chip(girq, &idio_16_irqchip);
25182e4613dSLinus Walleij 	/* This will let us handle the parent IRQ in the driver */
25282e4613dSLinus Walleij 	girq->parent_handler = NULL;
25382e4613dSLinus Walleij 	girq->num_parents = 0;
25482e4613dSLinus Walleij 	girq->parents = NULL;
25582e4613dSLinus Walleij 	girq->default_type = IRQ_TYPE_NONE;
25682e4613dSLinus Walleij 	girq->handler = handle_edge_irq;
25782e4613dSLinus Walleij 	girq->init_hw = idio_16_irq_init_hw;
25882e4613dSLinus Walleij 
2593906e808SJulia Cartwright 	raw_spin_lock_init(&idio16gpio->lock);
2601ceacea2SWilliam Breathitt Gray 
261837143d3SWilliam Breathitt Gray 	err = devm_gpiochip_add_data(dev, &idio16gpio->chip, idio16gpio);
2621ceacea2SWilliam Breathitt Gray 	if (err) {
2631ceacea2SWilliam Breathitt Gray 		dev_err(dev, "GPIO registering failed (%d)\n", err);
264cb32389cSWilliam Breathitt Gray 		return err;
2651ceacea2SWilliam Breathitt Gray 	}
2661ceacea2SWilliam Breathitt Gray 
267837143d3SWilliam Breathitt Gray 	err = devm_request_irq(dev, irq[id], idio_16_irq_handler, 0, name,
268837143d3SWilliam Breathitt Gray 		idio16gpio);
269837143d3SWilliam Breathitt Gray 	if (err) {
270837143d3SWilliam Breathitt Gray 		dev_err(dev, "IRQ handler registering failed (%d)\n", err);
271837143d3SWilliam Breathitt Gray 		return err;
272837143d3SWilliam Breathitt Gray 	}
2731ceacea2SWilliam Breathitt Gray 
2741ceacea2SWilliam Breathitt Gray 	return 0;
2751ceacea2SWilliam Breathitt Gray }
2761ceacea2SWilliam Breathitt Gray 
27786ea8a95SWilliam Breathitt Gray static struct isa_driver idio_16_driver = {
27886ea8a95SWilliam Breathitt Gray 	.probe = idio_16_probe,
2791ceacea2SWilliam Breathitt Gray 	.driver = {
2801ceacea2SWilliam Breathitt Gray 		.name = "104-idio-16"
2811ceacea2SWilliam Breathitt Gray 	},
2821ceacea2SWilliam Breathitt Gray };
2831ceacea2SWilliam Breathitt Gray 
284c6074f3fSWilliam Breathitt Gray module_isa_driver_with_irq(idio_16_driver, num_idio_16, num_irq);
2851ceacea2SWilliam Breathitt Gray 
2861ceacea2SWilliam Breathitt Gray MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
2871ceacea2SWilliam Breathitt Gray MODULE_DESCRIPTION("ACCES 104-IDIO-16 GPIO driver");
28822aeddb5SWilliam Breathitt Gray MODULE_LICENSE("GPL v2");
289*c4ec384cSWilliam Breathitt Gray MODULE_IMPORT_NS(GPIO_IDIO_16);
290