xref: /openbmc/linux/drivers/gpio/gpio-gpio-mm.c (revision f7c35abe)
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 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");
308