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