Merge branch 'parisc-4.9-1' of git://git.kernel.org/pub/scm/linux/kernel/git/deller...
[cascardo/linux.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_array(base, uint, &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 int gpiomm_probe(struct device *dev, unsigned int id)
196 {
197         struct gpiomm_gpio *gpiommgpio;
198         const char *const name = dev_name(dev);
199         int err;
200
201         gpiommgpio = devm_kzalloc(dev, sizeof(*gpiommgpio), GFP_KERNEL);
202         if (!gpiommgpio)
203                 return -ENOMEM;
204
205         if (!devm_request_region(dev, base[id], GPIOMM_EXTENT, name)) {
206                 dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
207                         base[id], base[id] + GPIOMM_EXTENT);
208                 return -EBUSY;
209         }
210
211         gpiommgpio->chip.label = name;
212         gpiommgpio->chip.parent = dev;
213         gpiommgpio->chip.owner = THIS_MODULE;
214         gpiommgpio->chip.base = -1;
215         gpiommgpio->chip.ngpio = 48;
216         gpiommgpio->chip.get_direction = gpiomm_gpio_get_direction;
217         gpiommgpio->chip.direction_input = gpiomm_gpio_direction_input;
218         gpiommgpio->chip.direction_output = gpiomm_gpio_direction_output;
219         gpiommgpio->chip.get = gpiomm_gpio_get;
220         gpiommgpio->chip.set = gpiomm_gpio_set;
221         gpiommgpio->base = base[id];
222
223         spin_lock_init(&gpiommgpio->lock);
224
225         dev_set_drvdata(dev, gpiommgpio);
226
227         err = gpiochip_add_data(&gpiommgpio->chip, gpiommgpio);
228         if (err) {
229                 dev_err(dev, "GPIO registering failed (%d)\n", err);
230                 return err;
231         }
232
233         /* initialize all GPIO as output */
234         outb(0x80, base[id] + 3);
235         outb(0x00, base[id]);
236         outb(0x00, base[id] + 1);
237         outb(0x00, base[id] + 2);
238         outb(0x80, base[id] + 7);
239         outb(0x00, base[id] + 4);
240         outb(0x00, base[id] + 5);
241         outb(0x00, base[id] + 6);
242
243         return 0;
244 }
245
246 static int gpiomm_remove(struct device *dev, unsigned int id)
247 {
248         struct gpiomm_gpio *const gpiommgpio = dev_get_drvdata(dev);
249
250         gpiochip_remove(&gpiommgpio->chip);
251
252         return 0;
253 }
254
255 static struct isa_driver gpiomm_driver = {
256         .probe = gpiomm_probe,
257         .driver = {
258                 .name = "gpio-mm"
259         },
260         .remove = gpiomm_remove
261 };
262
263 module_isa_driver(gpiomm_driver, num_gpiomm);
264
265 MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
266 MODULE_DESCRIPTION("Diamond Systems GPIO-MM GPIO driver");
267 MODULE_LICENSE("GPL v2");