Merge branch 'misc.poll' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
[sfrench/cifs-2.6.git] / drivers / gpio / gpio-gpio-mm.c
1 /*
2  * GPIO driver for the Diamond Systems GPIO-MM
3  * Copyright (C) 2016 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  * This driver supports the following Diamond Systems devices: GPIO-MM and
15  * GPIO-MM-12.
16  */
17 #include <linux/bitops.h>
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>
23 #include <linux/isa.h>
24 #include <linux/kernel.h>
25 #include <linux/module.h>
26 #include <linux/moduleparam.h>
27 #include <linux/spinlock.h>
28
29 #define GPIOMM_EXTENT 8
30 #define MAX_NUM_GPIOMM max_num_isa_dev(GPIOMM_EXTENT)
31
32 static unsigned int base[MAX_NUM_GPIOMM];
33 static unsigned int num_gpiomm;
34 module_param_hw_array(base, uint, ioport, &num_gpiomm, 0);
35 MODULE_PARM_DESC(base, "Diamond Systems GPIO-MM base addresses");
36
37 /**
38  * struct gpiomm_gpio - GPIO device private data structure
39  * @chip:       instance of the gpio_chip
40  * @io_state:   bit I/O state (whether bit is set to input or output)
41  * @out_state:  output bits state
42  * @control:    Control registers state
43  * @lock:       synchronization lock to prevent I/O race conditions
44  * @base:       base port address of the GPIO device
45  */
46 struct gpiomm_gpio {
47         struct gpio_chip chip;
48         unsigned char io_state[6];
49         unsigned char out_state[6];
50         unsigned char control[2];
51         spinlock_t lock;
52         unsigned int base;
53 };
54
55 static int gpiomm_gpio_get_direction(struct gpio_chip *chip,
56         unsigned int offset)
57 {
58         struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
59         const unsigned int port = offset / 8;
60         const unsigned int mask = BIT(offset % 8);
61
62         return !!(gpiommgpio->io_state[port] & mask);
63 }
64
65 static int gpiomm_gpio_direction_input(struct gpio_chip *chip,
66         unsigned int offset)
67 {
68         struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
69         const unsigned int io_port = offset / 8;
70         const unsigned int control_port = io_port / 3;
71         const unsigned int control_addr = gpiommgpio->base + 3 + control_port*4;
72         unsigned long flags;
73         unsigned int control;
74
75         spin_lock_irqsave(&gpiommgpio->lock, flags);
76
77         /* Check if configuring Port C */
78         if (io_port == 2 || io_port == 5) {
79                 /* Port C can be configured by nibble */
80                 if (offset % 8 > 3) {
81                         gpiommgpio->io_state[io_port] |= 0xF0;
82                         gpiommgpio->control[control_port] |= BIT(3);
83                 } else {
84                         gpiommgpio->io_state[io_port] |= 0x0F;
85                         gpiommgpio->control[control_port] |= BIT(0);
86                 }
87         } else {
88                 gpiommgpio->io_state[io_port] |= 0xFF;
89                 if (io_port == 0 || io_port == 3)
90                         gpiommgpio->control[control_port] |= BIT(4);
91                 else
92                         gpiommgpio->control[control_port] |= BIT(1);
93         }
94
95         control = BIT(7) | gpiommgpio->control[control_port];
96         outb(control, control_addr);
97
98         spin_unlock_irqrestore(&gpiommgpio->lock, flags);
99
100         return 0;
101 }
102
103 static int gpiomm_gpio_direction_output(struct gpio_chip *chip,
104         unsigned int offset, int value)
105 {
106         struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
107         const unsigned int io_port = offset / 8;
108         const unsigned int control_port = io_port / 3;
109         const unsigned int mask = BIT(offset % 8);
110         const unsigned int control_addr = gpiommgpio->base + 3 + control_port*4;
111         const unsigned int out_port = (io_port > 2) ? io_port + 1 : io_port;
112         unsigned long flags;
113         unsigned int control;
114
115         spin_lock_irqsave(&gpiommgpio->lock, flags);
116
117         /* Check if configuring Port C */
118         if (io_port == 2 || io_port == 5) {
119                 /* Port C can be configured by nibble */
120                 if (offset % 8 > 3) {
121                         gpiommgpio->io_state[io_port] &= 0x0F;
122                         gpiommgpio->control[control_port] &= ~BIT(3);
123                 } else {
124                         gpiommgpio->io_state[io_port] &= 0xF0;
125                         gpiommgpio->control[control_port] &= ~BIT(0);
126                 }
127         } else {
128                 gpiommgpio->io_state[io_port] &= 0x00;
129                 if (io_port == 0 || io_port == 3)
130                         gpiommgpio->control[control_port] &= ~BIT(4);
131                 else
132                         gpiommgpio->control[control_port] &= ~BIT(1);
133         }
134
135         if (value)
136                 gpiommgpio->out_state[io_port] |= mask;
137         else
138                 gpiommgpio->out_state[io_port] &= ~mask;
139
140         control = BIT(7) | gpiommgpio->control[control_port];
141         outb(control, control_addr);
142
143         outb(gpiommgpio->out_state[io_port], gpiommgpio->base + out_port);
144
145         spin_unlock_irqrestore(&gpiommgpio->lock, flags);
146
147         return 0;
148 }
149
150 static int gpiomm_gpio_get(struct gpio_chip *chip, unsigned int offset)
151 {
152         struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
153         const unsigned int port = offset / 8;
154         const unsigned int mask = BIT(offset % 8);
155         const unsigned int in_port = (port > 2) ? port + 1 : port;
156         unsigned long flags;
157         unsigned int port_state;
158
159         spin_lock_irqsave(&gpiommgpio->lock, flags);
160
161         /* ensure that GPIO is set for input */
162         if (!(gpiommgpio->io_state[port] & mask)) {
163                 spin_unlock_irqrestore(&gpiommgpio->lock, flags);
164                 return -EINVAL;
165         }
166
167         port_state = inb(gpiommgpio->base + in_port);
168
169         spin_unlock_irqrestore(&gpiommgpio->lock, flags);
170
171         return !!(port_state & mask);
172 }
173
174 static void gpiomm_gpio_set(struct gpio_chip *chip, unsigned int offset,
175         int value)
176 {
177         struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
178         const unsigned int port = offset / 8;
179         const unsigned int mask = BIT(offset % 8);
180         const unsigned int out_port = (port > 2) ? port + 1 : port;
181         unsigned long flags;
182
183         spin_lock_irqsave(&gpiommgpio->lock, flags);
184
185         if (value)
186                 gpiommgpio->out_state[port] |= mask;
187         else
188                 gpiommgpio->out_state[port] &= ~mask;
189
190         outb(gpiommgpio->out_state[port], gpiommgpio->base + out_port);
191
192         spin_unlock_irqrestore(&gpiommgpio->lock, flags);
193 }
194
195 static void gpiomm_gpio_set_multiple(struct gpio_chip *chip,
196         unsigned long *mask, unsigned long *bits)
197 {
198         struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
199         unsigned int i;
200         const unsigned int gpio_reg_size = 8;
201         unsigned int port;
202         unsigned int out_port;
203         unsigned int bitmask;
204         unsigned long flags;
205
206         /* set bits are evaluated a gpio register size at a time */
207         for (i = 0; i < chip->ngpio; i += gpio_reg_size) {
208                 /* no more set bits in this mask word; skip to the next word */
209                 if (!mask[BIT_WORD(i)]) {
210                         i = (BIT_WORD(i) + 1) * BITS_PER_LONG - gpio_reg_size;
211                         continue;
212                 }
213
214                 port = i / gpio_reg_size;
215                 out_port = (port > 2) ? port + 1 : port;
216                 bitmask = mask[BIT_WORD(i)] & bits[BIT_WORD(i)];
217
218                 spin_lock_irqsave(&gpiommgpio->lock, flags);
219
220                 /* update output state data and set device gpio register */
221                 gpiommgpio->out_state[port] &= ~mask[BIT_WORD(i)];
222                 gpiommgpio->out_state[port] |= bitmask;
223                 outb(gpiommgpio->out_state[port], gpiommgpio->base + out_port);
224
225                 spin_unlock_irqrestore(&gpiommgpio->lock, flags);
226
227                 /* prepare for next gpio register set */
228                 mask[BIT_WORD(i)] >>= gpio_reg_size;
229                 bits[BIT_WORD(i)] >>= gpio_reg_size;
230         }
231 }
232
233 #define GPIOMM_NGPIO 48
234 static const char *gpiomm_names[GPIOMM_NGPIO] = {
235         "Port 1A0", "Port 1A1", "Port 1A2", "Port 1A3", "Port 1A4", "Port 1A5",
236         "Port 1A6", "Port 1A7", "Port 1B0", "Port 1B1", "Port 1B2", "Port 1B3",
237         "Port 1B4", "Port 1B5", "Port 1B6", "Port 1B7", "Port 1C0", "Port 1C1",
238         "Port 1C2", "Port 1C3", "Port 1C4", "Port 1C5", "Port 1C6", "Port 1C7",
239         "Port 2A0", "Port 2A1", "Port 2A2", "Port 2A3", "Port 2A4", "Port 2A5",
240         "Port 2A6", "Port 2A7", "Port 2B0", "Port 2B1", "Port 2B2", "Port 2B3",
241         "Port 2B4", "Port 2B5", "Port 2B6", "Port 2B7", "Port 2C0", "Port 2C1",
242         "Port 2C2", "Port 2C3", "Port 2C4", "Port 2C5", "Port 2C6", "Port 2C7",
243 };
244
245 static int gpiomm_probe(struct device *dev, unsigned int id)
246 {
247         struct gpiomm_gpio *gpiommgpio;
248         const char *const name = dev_name(dev);
249         int err;
250
251         gpiommgpio = devm_kzalloc(dev, sizeof(*gpiommgpio), GFP_KERNEL);
252         if (!gpiommgpio)
253                 return -ENOMEM;
254
255         if (!devm_request_region(dev, base[id], GPIOMM_EXTENT, name)) {
256                 dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
257                         base[id], base[id] + GPIOMM_EXTENT);
258                 return -EBUSY;
259         }
260
261         gpiommgpio->chip.label = name;
262         gpiommgpio->chip.parent = dev;
263         gpiommgpio->chip.owner = THIS_MODULE;
264         gpiommgpio->chip.base = -1;
265         gpiommgpio->chip.ngpio = GPIOMM_NGPIO;
266         gpiommgpio->chip.names = gpiomm_names;
267         gpiommgpio->chip.get_direction = gpiomm_gpio_get_direction;
268         gpiommgpio->chip.direction_input = gpiomm_gpio_direction_input;
269         gpiommgpio->chip.direction_output = gpiomm_gpio_direction_output;
270         gpiommgpio->chip.get = gpiomm_gpio_get;
271         gpiommgpio->chip.set = gpiomm_gpio_set;
272         gpiommgpio->chip.set_multiple = gpiomm_gpio_set_multiple;
273         gpiommgpio->base = base[id];
274
275         spin_lock_init(&gpiommgpio->lock);
276
277         err = devm_gpiochip_add_data(dev, &gpiommgpio->chip, gpiommgpio);
278         if (err) {
279                 dev_err(dev, "GPIO registering failed (%d)\n", err);
280                 return err;
281         }
282
283         /* initialize all GPIO as output */
284         outb(0x80, base[id] + 3);
285         outb(0x00, base[id]);
286         outb(0x00, base[id] + 1);
287         outb(0x00, base[id] + 2);
288         outb(0x80, base[id] + 7);
289         outb(0x00, base[id] + 4);
290         outb(0x00, base[id] + 5);
291         outb(0x00, base[id] + 6);
292
293         return 0;
294 }
295
296 static struct isa_driver gpiomm_driver = {
297         .probe = gpiomm_probe,
298         .driver = {
299                 .name = "gpio-mm"
300         },
301 };
302
303 module_isa_driver(gpiomm_driver, num_gpiomm);
304
305 MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
306 MODULE_DESCRIPTION("Diamond Systems GPIO-MM GPIO driver");
307 MODULE_LICENSE("GPL v2");