• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * GPIO driver for the ACCES 104-IDI-48 family
4  * Copyright (C) 2015 William Breathitt Gray
5  *
6  * This driver supports the following ACCES devices: 104-IDI-48A,
7  * 104-IDI-48AC, 104-IDI-48B, and 104-IDI-48BC.
8  */
9 #include <linux/bitmap.h>
10 #include <linux/bitops.h>
11 #include <linux/device.h>
12 #include <linux/errno.h>
13 #include <linux/gpio/driver.h>
14 #include <linux/io.h>
15 #include <linux/ioport.h>
16 #include <linux/interrupt.h>
17 #include <linux/irqdesc.h>
18 #include <linux/isa.h>
19 #include <linux/kernel.h>
20 #include <linux/module.h>
21 #include <linux/moduleparam.h>
22 #include <linux/spinlock.h>
23 
24 #define IDI_48_EXTENT 8
25 #define MAX_NUM_IDI_48 max_num_isa_dev(IDI_48_EXTENT)
26 
27 static unsigned int base[MAX_NUM_IDI_48];
28 static unsigned int num_idi_48;
29 module_param_hw_array(base, uint, ioport, &num_idi_48, 0);
30 MODULE_PARM_DESC(base, "ACCES 104-IDI-48 base addresses");
31 
32 static unsigned int irq[MAX_NUM_IDI_48];
33 module_param_hw_array(irq, uint, irq, NULL, 0);
34 MODULE_PARM_DESC(irq, "ACCES 104-IDI-48 interrupt line numbers");
35 
36 /**
37  * struct idi_48_gpio - GPIO device private data structure
38  * @chip:	instance of the gpio_chip
39  * @lock:	synchronization lock to prevent I/O race conditions
40  * @ack_lock:	synchronization lock to prevent IRQ handler race conditions
41  * @irq_mask:	input bits affected by interrupts
42  * @base:	base port address of the GPIO device
43  * @cos_enb:	Change-Of-State IRQ enable boundaries mask
44  */
45 struct idi_48_gpio {
46 	struct gpio_chip chip;
47 	raw_spinlock_t lock;
48 	spinlock_t ack_lock;
49 	unsigned char irq_mask[6];
50 	unsigned base;
51 	unsigned char cos_enb;
52 };
53 
idi_48_gpio_get_direction(struct gpio_chip * chip,unsigned offset)54 static int idi_48_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
55 {
56 	return GPIO_LINE_DIRECTION_IN;
57 }
58 
idi_48_gpio_direction_input(struct gpio_chip * chip,unsigned offset)59 static int idi_48_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
60 {
61 	return 0;
62 }
63 
idi_48_gpio_get(struct gpio_chip * chip,unsigned offset)64 static int idi_48_gpio_get(struct gpio_chip *chip, unsigned offset)
65 {
66 	struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
67 	unsigned i;
68 	static const unsigned int register_offset[6] = { 0, 1, 2, 4, 5, 6 };
69 	unsigned base_offset;
70 	unsigned mask;
71 
72 	for (i = 0; i < 48; i += 8)
73 		if (offset < i + 8) {
74 			base_offset = register_offset[i / 8];
75 			mask = BIT(offset - i);
76 
77 			return !!(inb(idi48gpio->base + base_offset) & mask);
78 		}
79 
80 	/* The following line should never execute since offset < 48 */
81 	return 0;
82 }
83 
idi_48_gpio_get_multiple(struct gpio_chip * chip,unsigned long * mask,unsigned long * bits)84 static int idi_48_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
85 	unsigned long *bits)
86 {
87 	struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
88 	unsigned long offset;
89 	unsigned long gpio_mask;
90 	static const size_t ports[] = { 0, 1, 2, 4, 5, 6 };
91 	unsigned int port_addr;
92 	unsigned long port_state;
93 
94 	/* clear bits array to a clean slate */
95 	bitmap_zero(bits, chip->ngpio);
96 
97 	for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) {
98 		port_addr = idi48gpio->base + ports[offset / 8];
99 		port_state = inb(port_addr) & gpio_mask;
100 
101 		bitmap_set_value8(bits, port_state, offset);
102 	}
103 
104 	return 0;
105 }
106 
idi_48_irq_ack(struct irq_data * data)107 static void idi_48_irq_ack(struct irq_data *data)
108 {
109 }
110 
idi_48_irq_mask(struct irq_data * data)111 static void idi_48_irq_mask(struct irq_data *data)
112 {
113 	struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
114 	struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
115 	const unsigned offset = irqd_to_hwirq(data);
116 	unsigned i;
117 	unsigned mask;
118 	unsigned boundary;
119 	unsigned long flags;
120 
121 	for (i = 0; i < 48; i += 8)
122 		if (offset < i + 8) {
123 			mask = BIT(offset - i);
124 			boundary = i / 8;
125 
126 			idi48gpio->irq_mask[boundary] &= ~mask;
127 
128 			if (!idi48gpio->irq_mask[boundary]) {
129 				idi48gpio->cos_enb &= ~BIT(boundary);
130 
131 				raw_spin_lock_irqsave(&idi48gpio->lock, flags);
132 
133 				outb(idi48gpio->cos_enb, idi48gpio->base + 7);
134 
135 				raw_spin_unlock_irqrestore(&idi48gpio->lock,
136 						           flags);
137 			}
138 
139 			return;
140 		}
141 }
142 
idi_48_irq_unmask(struct irq_data * data)143 static void idi_48_irq_unmask(struct irq_data *data)
144 {
145 	struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
146 	struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
147 	const unsigned offset = irqd_to_hwirq(data);
148 	unsigned i;
149 	unsigned mask;
150 	unsigned boundary;
151 	unsigned prev_irq_mask;
152 	unsigned long flags;
153 
154 	for (i = 0; i < 48; i += 8)
155 		if (offset < i + 8) {
156 			mask = BIT(offset - i);
157 			boundary = i / 8;
158 			prev_irq_mask = idi48gpio->irq_mask[boundary];
159 
160 			idi48gpio->irq_mask[boundary] |= mask;
161 
162 			if (!prev_irq_mask) {
163 				idi48gpio->cos_enb |= BIT(boundary);
164 
165 				raw_spin_lock_irqsave(&idi48gpio->lock, flags);
166 
167 				outb(idi48gpio->cos_enb, idi48gpio->base + 7);
168 
169 				raw_spin_unlock_irqrestore(&idi48gpio->lock,
170 						           flags);
171 			}
172 
173 			return;
174 		}
175 }
176 
idi_48_irq_set_type(struct irq_data * data,unsigned flow_type)177 static int idi_48_irq_set_type(struct irq_data *data, unsigned flow_type)
178 {
179 	/* The only valid irq types are none and both-edges */
180 	if (flow_type != IRQ_TYPE_NONE &&
181 		(flow_type & IRQ_TYPE_EDGE_BOTH) != IRQ_TYPE_EDGE_BOTH)
182 		return -EINVAL;
183 
184 	return 0;
185 }
186 
187 static struct irq_chip idi_48_irqchip = {
188 	.name = "104-idi-48",
189 	.irq_ack = idi_48_irq_ack,
190 	.irq_mask = idi_48_irq_mask,
191 	.irq_unmask = idi_48_irq_unmask,
192 	.irq_set_type = idi_48_irq_set_type
193 };
194 
idi_48_irq_handler(int irq,void * dev_id)195 static irqreturn_t idi_48_irq_handler(int irq, void *dev_id)
196 {
197 	struct idi_48_gpio *const idi48gpio = dev_id;
198 	unsigned long cos_status;
199 	unsigned long boundary;
200 	unsigned long irq_mask;
201 	unsigned long bit_num;
202 	unsigned long gpio;
203 	struct gpio_chip *const chip = &idi48gpio->chip;
204 
205 	spin_lock(&idi48gpio->ack_lock);
206 
207 	raw_spin_lock(&idi48gpio->lock);
208 
209 	cos_status = inb(idi48gpio->base + 7);
210 
211 	raw_spin_unlock(&idi48gpio->lock);
212 
213 	/* IRQ Status (bit 6) is active low (0 = IRQ generated by device) */
214 	if (cos_status & BIT(6)) {
215 		spin_unlock(&idi48gpio->ack_lock);
216 		return IRQ_NONE;
217 	}
218 
219 	/* Bit 0-5 indicate which Change-Of-State boundary triggered the IRQ */
220 	cos_status &= 0x3F;
221 
222 	for_each_set_bit(boundary, &cos_status, 6) {
223 		irq_mask = idi48gpio->irq_mask[boundary];
224 
225 		for_each_set_bit(bit_num, &irq_mask, 8) {
226 			gpio = bit_num + boundary * 8;
227 
228 			generic_handle_irq(irq_find_mapping(chip->irq.domain,
229 				gpio));
230 		}
231 	}
232 
233 	spin_unlock(&idi48gpio->ack_lock);
234 
235 	return IRQ_HANDLED;
236 }
237 
238 #define IDI48_NGPIO 48
239 static const char *idi48_names[IDI48_NGPIO] = {
240 	"Bit 0 A", "Bit 1 A", "Bit 2 A", "Bit 3 A", "Bit 4 A", "Bit 5 A",
241 	"Bit 6 A", "Bit 7 A", "Bit 8 A", "Bit 9 A", "Bit 10 A", "Bit 11 A",
242 	"Bit 12 A", "Bit 13 A", "Bit 14 A", "Bit 15 A",	"Bit 16 A", "Bit 17 A",
243 	"Bit 18 A", "Bit 19 A", "Bit 20 A", "Bit 21 A", "Bit 22 A", "Bit 23 A",
244 	"Bit 0 B", "Bit 1 B", "Bit 2 B", "Bit 3 B", "Bit 4 B", "Bit 5 B",
245 	"Bit 6 B", "Bit 7 B", "Bit 8 B", "Bit 9 B", "Bit 10 B", "Bit 11 B",
246 	"Bit 12 B", "Bit 13 B", "Bit 14 B", "Bit 15 B",	"Bit 16 B", "Bit 17 B",
247 	"Bit 18 B", "Bit 19 B", "Bit 20 B", "Bit 21 B", "Bit 22 B", "Bit 23 B"
248 };
249 
idi_48_irq_init_hw(struct gpio_chip * gc)250 static int idi_48_irq_init_hw(struct gpio_chip *gc)
251 {
252 	struct idi_48_gpio *const idi48gpio = gpiochip_get_data(gc);
253 
254 	/* Disable IRQ by default */
255 	outb(0, idi48gpio->base + 7);
256 	inb(idi48gpio->base + 7);
257 
258 	return 0;
259 }
260 
idi_48_probe(struct device * dev,unsigned int id)261 static int idi_48_probe(struct device *dev, unsigned int id)
262 {
263 	struct idi_48_gpio *idi48gpio;
264 	const char *const name = dev_name(dev);
265 	struct gpio_irq_chip *girq;
266 	int err;
267 
268 	idi48gpio = devm_kzalloc(dev, sizeof(*idi48gpio), GFP_KERNEL);
269 	if (!idi48gpio)
270 		return -ENOMEM;
271 
272 	if (!devm_request_region(dev, base[id], IDI_48_EXTENT, name)) {
273 		dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
274 			base[id], base[id] + IDI_48_EXTENT);
275 		return -EBUSY;
276 	}
277 
278 	idi48gpio->chip.label = name;
279 	idi48gpio->chip.parent = dev;
280 	idi48gpio->chip.owner = THIS_MODULE;
281 	idi48gpio->chip.base = -1;
282 	idi48gpio->chip.ngpio = IDI48_NGPIO;
283 	idi48gpio->chip.names = idi48_names;
284 	idi48gpio->chip.get_direction = idi_48_gpio_get_direction;
285 	idi48gpio->chip.direction_input = idi_48_gpio_direction_input;
286 	idi48gpio->chip.get = idi_48_gpio_get;
287 	idi48gpio->chip.get_multiple = idi_48_gpio_get_multiple;
288 	idi48gpio->base = base[id];
289 
290 	girq = &idi48gpio->chip.irq;
291 	girq->chip = &idi_48_irqchip;
292 	/* This will let us handle the parent IRQ in the driver */
293 	girq->parent_handler = NULL;
294 	girq->num_parents = 0;
295 	girq->parents = NULL;
296 	girq->default_type = IRQ_TYPE_NONE;
297 	girq->handler = handle_edge_irq;
298 	girq->init_hw = idi_48_irq_init_hw;
299 
300 	raw_spin_lock_init(&idi48gpio->lock);
301 	spin_lock_init(&idi48gpio->ack_lock);
302 
303 	err = devm_gpiochip_add_data(dev, &idi48gpio->chip, idi48gpio);
304 	if (err) {
305 		dev_err(dev, "GPIO registering failed (%d)\n", err);
306 		return err;
307 	}
308 
309 	err = devm_request_irq(dev, irq[id], idi_48_irq_handler, IRQF_SHARED,
310 		name, idi48gpio);
311 	if (err) {
312 		dev_err(dev, "IRQ handler registering failed (%d)\n", err);
313 		return err;
314 	}
315 
316 	return 0;
317 }
318 
319 static struct isa_driver idi_48_driver = {
320 	.probe = idi_48_probe,
321 	.driver = {
322 		.name = "104-idi-48"
323 	},
324 };
325 module_isa_driver(idi_48_driver, num_idi_48);
326 
327 MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
328 MODULE_DESCRIPTION("ACCES 104-IDI-48 GPIO driver");
329 MODULE_LICENSE("GPL v2");
330