]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - drivers/gpio/gpio-104-idio-16.c
Annotate hardware config module parameters in drivers/gpio/
[mirror_ubuntu-artful-kernel.git] / drivers / gpio / gpio-104-idio-16.c
CommitLineData
1ceacea2
WBG
1/*
2 * GPIO driver for the ACCES 104-IDIO-16 family
3 * Copyright (C) 2015 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.
86ea8a95
WBG
13 *
14 * This driver supports the following ACCES devices: 104-IDIO-16,
15 * 104-IDIO-16E, 104-IDO-16, 104-IDIO-8, 104-IDIO-8E, and 104-IDO-8.
1ceacea2 16 */
a1184147 17#include <linux/bitops.h>
1ceacea2
WBG
18#include <linux/device.h>
19#include <linux/errno.h>
20#include <linux/gpio/driver.h>
21#include <linux/io.h>
22#include <linux/ioport.h>
a1184147
WBG
23#include <linux/interrupt.h>
24#include <linux/irqdesc.h>
86ea8a95 25#include <linux/isa.h>
1ceacea2
WBG
26#include <linux/kernel.h>
27#include <linux/module.h>
28#include <linux/moduleparam.h>
1ceacea2
WBG
29#include <linux/spinlock.h>
30
86ea8a95
WBG
31#define IDIO_16_EXTENT 8
32#define MAX_NUM_IDIO_16 max_num_isa_dev(IDIO_16_EXTENT)
33
34static unsigned int base[MAX_NUM_IDIO_16];
35static unsigned int num_idio_16;
d759f906 36module_param_hw_array(base, uint, ioport, &num_idio_16, 0);
86ea8a95
WBG
37MODULE_PARM_DESC(base, "ACCES 104-IDIO-16 base addresses");
38
39static unsigned int irq[MAX_NUM_IDIO_16];
d759f906 40module_param_hw_array(irq, uint, irq, NULL, 0);
86ea8a95 41MODULE_PARM_DESC(irq, "ACCES 104-IDIO-16 interrupt line numbers");
1ceacea2
WBG
42
43/**
44 * struct idio_16_gpio - GPIO device private data structure
45 * @chip: instance of the gpio_chip
a1184147
WBG
46 * @lock: synchronization lock to prevent I/O race conditions
47 * @irq_mask: I/O bits affected by interrupts
1ceacea2 48 * @base: base port address of the GPIO device
1ceacea2
WBG
49 * @out_state: output bits state
50 */
51struct idio_16_gpio {
52 struct gpio_chip chip;
53 spinlock_t lock;
a1184147 54 unsigned long irq_mask;
1ceacea2 55 unsigned base;
1ceacea2
WBG
56 unsigned out_state;
57};
58
59static int idio_16_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
60{
61 if (offset > 15)
62 return 1;
63
64 return 0;
65}
66
67static int idio_16_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
68{
69 return 0;
70}
71
72static int idio_16_gpio_direction_output(struct gpio_chip *chip,
73 unsigned offset, int value)
74{
75 chip->set(chip, offset, value);
76 return 0;
77}
78
1ceacea2
WBG
79static int idio_16_gpio_get(struct gpio_chip *chip, unsigned offset)
80{
d602ae90 81 struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
6e0171b4 82 const unsigned mask = BIT(offset-16);
1ceacea2
WBG
83
84 if (offset < 16)
85 return -EINVAL;
86
87 if (offset < 24)
6e0171b4 88 return !!(inb(idio16gpio->base + 1) & mask);
1ceacea2 89
6e0171b4 90 return !!(inb(idio16gpio->base + 5) & (mask>>8));
1ceacea2
WBG
91}
92
93static void idio_16_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
94{
d602ae90 95 struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
6e0171b4 96 const unsigned mask = BIT(offset);
1ceacea2
WBG
97 unsigned long flags;
98
99 if (offset > 15)
100 return;
101
102 spin_lock_irqsave(&idio16gpio->lock, flags);
103
104 if (value)
6e0171b4 105 idio16gpio->out_state |= mask;
1ceacea2 106 else
6e0171b4 107 idio16gpio->out_state &= ~mask;
1ceacea2
WBG
108
109 if (offset > 7)
110 outb(idio16gpio->out_state >> 8, idio16gpio->base + 4);
111 else
112 outb(idio16gpio->out_state, idio16gpio->base);
113
114 spin_unlock_irqrestore(&idio16gpio->lock, flags);
115}
116
9d7ae812
WBG
117static void idio_16_gpio_set_multiple(struct gpio_chip *chip,
118 unsigned long *mask, unsigned long *bits)
119{
120 struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
121 unsigned long flags;
122
123 spin_lock_irqsave(&idio16gpio->lock, flags);
124
125 idio16gpio->out_state &= ~*mask;
126 idio16gpio->out_state |= *mask & *bits;
127
128 if (*mask & 0xFF)
129 outb(idio16gpio->out_state, idio16gpio->base);
130 if ((*mask >> 8) & 0xFF)
131 outb(idio16gpio->out_state >> 8, idio16gpio->base + 4);
132
133 spin_unlock_irqrestore(&idio16gpio->lock, flags);
134}
135
a1184147
WBG
136static void idio_16_irq_ack(struct irq_data *data)
137{
a1184147
WBG
138}
139
140static void idio_16_irq_mask(struct irq_data *data)
141{
142 struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
d602ae90 143 struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
a1184147
WBG
144 const unsigned long mask = BIT(irqd_to_hwirq(data));
145 unsigned long flags;
146
147 idio16gpio->irq_mask &= ~mask;
148
149 if (!idio16gpio->irq_mask) {
150 spin_lock_irqsave(&idio16gpio->lock, flags);
151
152 outb(0, idio16gpio->base + 2);
153
154 spin_unlock_irqrestore(&idio16gpio->lock, flags);
155 }
156}
157
158static void idio_16_irq_unmask(struct irq_data *data)
159{
160 struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
d602ae90 161 struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
a1184147
WBG
162 const unsigned long mask = BIT(irqd_to_hwirq(data));
163 const unsigned long prev_irq_mask = idio16gpio->irq_mask;
164 unsigned long flags;
165
166 idio16gpio->irq_mask |= mask;
167
168 if (!prev_irq_mask) {
169 spin_lock_irqsave(&idio16gpio->lock, flags);
170
a1184147
WBG
171 inb(idio16gpio->base + 2);
172
173 spin_unlock_irqrestore(&idio16gpio->lock, flags);
174 }
175}
176
177static int idio_16_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
187static struct irq_chip idio_16_irqchip = {
188 .name = "104-idio-16",
189 .irq_ack = idio_16_irq_ack,
190 .irq_mask = idio_16_irq_mask,
191 .irq_unmask = idio_16_irq_unmask,
192 .irq_set_type = idio_16_irq_set_type
193};
194
195static irqreturn_t idio_16_irq_handler(int irq, void *dev_id)
196{
197 struct idio_16_gpio *const idio16gpio = dev_id;
198 struct gpio_chip *const chip = &idio16gpio->chip;
199 int gpio;
200
201 for_each_set_bit(gpio, &idio16gpio->irq_mask, chip->ngpio)
202 generic_handle_irq(irq_find_mapping(chip->irqdomain, gpio));
203
12b61c9d
WBG
204 spin_lock(&idio16gpio->lock);
205
206 outb(0, idio16gpio->base + 1);
207
208 spin_unlock(&idio16gpio->lock);
209
a1184147
WBG
210 return IRQ_HANDLED;
211}
212
e0af4b5e
WBG
213#define IDIO_16_NGPIO 32
214static const char *idio_16_names[IDIO_16_NGPIO] = {
215 "OUT0", "OUT1", "OUT2", "OUT3", "OUT4", "OUT5", "OUT6", "OUT7",
216 "OUT8", "OUT9", "OUT10", "OUT11", "OUT12", "OUT13", "OUT14", "OUT15",
217 "IIN0", "IIN1", "IIN2", "IIN3", "IIN4", "IIN5", "IIN6", "IIN7",
218 "IIN8", "IIN9", "IIN10", "IIN11", "IIN12", "IIN13", "IIN14", "IIN15"
219};
220
86ea8a95 221static int idio_16_probe(struct device *dev, unsigned int id)
1ceacea2 222{
1ceacea2 223 struct idio_16_gpio *idio16gpio;
6e0171b4 224 const char *const name = dev_name(dev);
1ceacea2 225 int err;
1ceacea2
WBG
226
227 idio16gpio = devm_kzalloc(dev, sizeof(*idio16gpio), GFP_KERNEL);
228 if (!idio16gpio)
229 return -ENOMEM;
230
86ea8a95 231 if (!devm_request_region(dev, base[id], IDIO_16_EXTENT, name)) {
cb32389c 232 dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
86ea8a95 233 base[id], base[id] + IDIO_16_EXTENT);
cb32389c 234 return -EBUSY;
1ceacea2
WBG
235 }
236
6e0171b4 237 idio16gpio->chip.label = name;
58383c78 238 idio16gpio->chip.parent = dev;
1ceacea2
WBG
239 idio16gpio->chip.owner = THIS_MODULE;
240 idio16gpio->chip.base = -1;
e0af4b5e
WBG
241 idio16gpio->chip.ngpio = IDIO_16_NGPIO;
242 idio16gpio->chip.names = idio_16_names;
1ceacea2
WBG
243 idio16gpio->chip.get_direction = idio_16_gpio_get_direction;
244 idio16gpio->chip.direction_input = idio_16_gpio_direction_input;
245 idio16gpio->chip.direction_output = idio_16_gpio_direction_output;
246 idio16gpio->chip.get = idio_16_gpio_get;
247 idio16gpio->chip.set = idio_16_gpio_set;
9d7ae812 248 idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple;
86ea8a95 249 idio16gpio->base = base[id];
1ceacea2
WBG
250 idio16gpio->out_state = 0xFFFF;
251
252 spin_lock_init(&idio16gpio->lock);
253
837143d3 254 err = devm_gpiochip_add_data(dev, &idio16gpio->chip, idio16gpio);
1ceacea2
WBG
255 if (err) {
256 dev_err(dev, "GPIO registering failed (%d)\n", err);
cb32389c 257 return err;
1ceacea2
WBG
258 }
259
fb50cdfe 260 /* Disable IRQ by default */
86ea8a95
WBG
261 outb(0, base[id] + 2);
262 outb(0, base[id] + 1);
fb50cdfe 263
a1184147
WBG
264 err = gpiochip_irqchip_add(&idio16gpio->chip, &idio_16_irqchip, 0,
265 handle_edge_irq, IRQ_TYPE_NONE);
266 if (err) {
267 dev_err(dev, "Could not add irqchip (%d)\n", err);
837143d3 268 return err;
a1184147
WBG
269 }
270
837143d3
WBG
271 err = devm_request_irq(dev, irq[id], idio_16_irq_handler, 0, name,
272 idio16gpio);
a1184147
WBG
273 if (err) {
274 dev_err(dev, "IRQ handler registering failed (%d)\n", err);
837143d3 275 return err;
a1184147
WBG
276 }
277
1ceacea2
WBG
278 return 0;
279}
280
86ea8a95
WBG
281static struct isa_driver idio_16_driver = {
282 .probe = idio_16_probe,
1ceacea2
WBG
283 .driver = {
284 .name = "104-idio-16"
285 },
1ceacea2
WBG
286};
287
86ea8a95 288module_isa_driver(idio_16_driver, num_idio_16);
1ceacea2
WBG
289
290MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
291MODULE_DESCRIPTION("ACCES 104-IDIO-16 GPIO driver");
22aeddb5 292MODULE_LICENSE("GPL v2");