xref: /openbmc/linux/drivers/gpio/gpio-it87.c (revision 01062ad3)
1b8664924SDiego Elio Pettenò /*
2b8664924SDiego Elio Pettenò  *  GPIO interface for IT87xx Super I/O chips
3b8664924SDiego Elio Pettenò  *
4b8664924SDiego Elio Pettenò  *  Author: Diego Elio Pettenò <flameeyes@flameeyes.eu>
501062ad3SDiego Elio Pettenò  *  Copyright (c) 2017 Google, Inc.
6b8664924SDiego Elio Pettenò  *
7b8664924SDiego Elio Pettenò  *  Based on it87_wdt.c     by Oliver Schuster
8b8664924SDiego Elio Pettenò  *           gpio-it8761e.c by Denis Turischev
9b8664924SDiego Elio Pettenò  *           gpio-stmpe.c   by Rabin Vincent
10b8664924SDiego Elio Pettenò  *
11b8664924SDiego Elio Pettenò  *  This program is free software; you can redistribute it and/or modify
12b8664924SDiego Elio Pettenò  *  it under the terms of the GNU General Public License 2 as published
13b8664924SDiego Elio Pettenò  *  by the Free Software Foundation.
14b8664924SDiego Elio Pettenò  *
15b8664924SDiego Elio Pettenò  *  This program is distributed in the hope that it will be useful,
16b8664924SDiego Elio Pettenò  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17b8664924SDiego Elio Pettenò  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18b8664924SDiego Elio Pettenò  *  GNU General Public License for more details.
19b8664924SDiego Elio Pettenò  *
20b8664924SDiego Elio Pettenò  *  You should have received a copy of the GNU General Public License
21b8664924SDiego Elio Pettenò  *  along with this program; see the file COPYING.  If not, write to
22b8664924SDiego Elio Pettenò  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23b8664924SDiego Elio Pettenò  */
24b8664924SDiego Elio Pettenò 
25b8664924SDiego Elio Pettenò #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
26b8664924SDiego Elio Pettenò 
27b8664924SDiego Elio Pettenò #include <linux/init.h>
28b8664924SDiego Elio Pettenò #include <linux/kernel.h>
29b8664924SDiego Elio Pettenò #include <linux/module.h>
30b8664924SDiego Elio Pettenò #include <linux/io.h>
31b8664924SDiego Elio Pettenò #include <linux/errno.h>
32b8664924SDiego Elio Pettenò #include <linux/ioport.h>
33b8664924SDiego Elio Pettenò #include <linux/slab.h>
34b8664924SDiego Elio Pettenò #include <linux/gpio.h>
35b8664924SDiego Elio Pettenò 
36b8664924SDiego Elio Pettenò /* Chip Id numbers */
37b8664924SDiego Elio Pettenò #define NO_DEV_ID	0xffff
388fccdb58SMartin Blumenstingl #define IT8620_ID	0x8620
398fccdb58SMartin Blumenstingl #define IT8628_ID	0x8628
40b8664924SDiego Elio Pettenò #define IT8728_ID	0x8728
41b8664924SDiego Elio Pettenò #define IT8732_ID	0x8732
42b8664924SDiego Elio Pettenò #define IT8761_ID	0x8761
4301062ad3SDiego Elio Pettenò #define IT8772_ID	0x8772
44b8664924SDiego Elio Pettenò 
45b8664924SDiego Elio Pettenò /* IO Ports */
46b8664924SDiego Elio Pettenò #define REG		0x2e
47b8664924SDiego Elio Pettenò #define VAL		0x2f
48b8664924SDiego Elio Pettenò 
49b8664924SDiego Elio Pettenò /* Logical device Numbers LDN */
50b8664924SDiego Elio Pettenò #define GPIO		0x07
51b8664924SDiego Elio Pettenò 
52b8664924SDiego Elio Pettenò /* Configuration Registers and Functions */
53b8664924SDiego Elio Pettenò #define LDNREG		0x07
54b8664924SDiego Elio Pettenò #define CHIPID		0x20
55b8664924SDiego Elio Pettenò #define CHIPREV		0x22
56b8664924SDiego Elio Pettenò 
57b8664924SDiego Elio Pettenò /**
58b8664924SDiego Elio Pettenò  * struct it87_gpio - it87-specific GPIO chip
59b8664924SDiego Elio Pettenò  * @chip the underlying gpio_chip structure
60b8664924SDiego Elio Pettenò  * @lock a lock to avoid races between operations
61b8664924SDiego Elio Pettenò  * @io_base base address for gpio ports
62b8664924SDiego Elio Pettenò  * @io_size size of the port rage starting from io_base.
63b8664924SDiego Elio Pettenò  * @output_base Super I/O register address for Output Enable register
64b8664924SDiego Elio Pettenò  * @simple_base Super I/O 'Simple I/O' Enable register
65b8664924SDiego Elio Pettenò  * @simple_size Super IO 'Simple I/O' Enable register size; this is
66b8664924SDiego Elio Pettenò  *	required because IT87xx chips might only provide Simple I/O
67b8664924SDiego Elio Pettenò  *	switches on a subset of lines, whereas the others keep the
68b8664924SDiego Elio Pettenò  *	same status all time.
69b8664924SDiego Elio Pettenò  */
70b8664924SDiego Elio Pettenò struct it87_gpio {
71b8664924SDiego Elio Pettenò 	struct gpio_chip chip;
72b8664924SDiego Elio Pettenò 	spinlock_t lock;
73b8664924SDiego Elio Pettenò 	u16 io_base;
74b8664924SDiego Elio Pettenò 	u16 io_size;
75b8664924SDiego Elio Pettenò 	u8 output_base;
76b8664924SDiego Elio Pettenò 	u8 simple_base;
77b8664924SDiego Elio Pettenò 	u8 simple_size;
78b8664924SDiego Elio Pettenò };
79b8664924SDiego Elio Pettenò 
80b8664924SDiego Elio Pettenò static struct it87_gpio it87_gpio_chip = {
81b8664924SDiego Elio Pettenò 	.lock = __SPIN_LOCK_UNLOCKED(it87_gpio_chip.lock),
82b8664924SDiego Elio Pettenò };
83b8664924SDiego Elio Pettenò 
84b8664924SDiego Elio Pettenò /* Superio chip access functions; copied from wdt_it87 */
85b8664924SDiego Elio Pettenò 
86b8664924SDiego Elio Pettenò static inline int superio_enter(void)
87b8664924SDiego Elio Pettenò {
88b8664924SDiego Elio Pettenò 	/*
89b8664924SDiego Elio Pettenò 	 * Try to reserve REG and REG + 1 for exclusive access.
90b8664924SDiego Elio Pettenò 	 */
91b8664924SDiego Elio Pettenò 	if (!request_muxed_region(REG, 2, KBUILD_MODNAME))
92b8664924SDiego Elio Pettenò 		return -EBUSY;
93b8664924SDiego Elio Pettenò 
94b8664924SDiego Elio Pettenò 	outb(0x87, REG);
95b8664924SDiego Elio Pettenò 	outb(0x01, REG);
96b8664924SDiego Elio Pettenò 	outb(0x55, REG);
97b8664924SDiego Elio Pettenò 	outb(0x55, REG);
98b8664924SDiego Elio Pettenò 	return 0;
99b8664924SDiego Elio Pettenò }
100b8664924SDiego Elio Pettenò 
101b8664924SDiego Elio Pettenò static inline void superio_exit(void)
102b8664924SDiego Elio Pettenò {
103b8664924SDiego Elio Pettenò 	outb(0x02, REG);
104b8664924SDiego Elio Pettenò 	outb(0x02, VAL);
105b8664924SDiego Elio Pettenò 	release_region(REG, 2);
106b8664924SDiego Elio Pettenò }
107b8664924SDiego Elio Pettenò 
108b8664924SDiego Elio Pettenò static inline void superio_select(int ldn)
109b8664924SDiego Elio Pettenò {
110b8664924SDiego Elio Pettenò 	outb(LDNREG, REG);
111b8664924SDiego Elio Pettenò 	outb(ldn, VAL);
112b8664924SDiego Elio Pettenò }
113b8664924SDiego Elio Pettenò 
114b8664924SDiego Elio Pettenò static inline int superio_inb(int reg)
115b8664924SDiego Elio Pettenò {
116b8664924SDiego Elio Pettenò 	outb(reg, REG);
117b8664924SDiego Elio Pettenò 	return inb(VAL);
118b8664924SDiego Elio Pettenò }
119b8664924SDiego Elio Pettenò 
120b8664924SDiego Elio Pettenò static inline void superio_outb(int val, int reg)
121b8664924SDiego Elio Pettenò {
122b8664924SDiego Elio Pettenò 	outb(reg, REG);
123b8664924SDiego Elio Pettenò 	outb(val, VAL);
124b8664924SDiego Elio Pettenò }
125b8664924SDiego Elio Pettenò 
126b8664924SDiego Elio Pettenò static inline int superio_inw(int reg)
127b8664924SDiego Elio Pettenò {
128b8664924SDiego Elio Pettenò 	int val;
129b8664924SDiego Elio Pettenò 
130b8664924SDiego Elio Pettenò 	outb(reg++, REG);
131b8664924SDiego Elio Pettenò 	val = inb(VAL) << 8;
132b8664924SDiego Elio Pettenò 	outb(reg, REG);
133b8664924SDiego Elio Pettenò 	val |= inb(VAL);
134b8664924SDiego Elio Pettenò 	return val;
135b8664924SDiego Elio Pettenò }
136b8664924SDiego Elio Pettenò 
137b8664924SDiego Elio Pettenò static inline void superio_outw(int val, int reg)
138b8664924SDiego Elio Pettenò {
139b8664924SDiego Elio Pettenò 	outb(reg++, REG);
140b8664924SDiego Elio Pettenò 	outb(val >> 8, VAL);
141b8664924SDiego Elio Pettenò 	outb(reg, REG);
142b8664924SDiego Elio Pettenò 	outb(val, VAL);
143b8664924SDiego Elio Pettenò }
144b8664924SDiego Elio Pettenò 
145b8664924SDiego Elio Pettenò static inline void superio_set_mask(int mask, int reg)
146b8664924SDiego Elio Pettenò {
147b8664924SDiego Elio Pettenò 	u8 curr_val = superio_inb(reg);
148b8664924SDiego Elio Pettenò 	u8 new_val = curr_val | mask;
149b8664924SDiego Elio Pettenò 
150b8664924SDiego Elio Pettenò 	if (curr_val != new_val)
151b8664924SDiego Elio Pettenò 		superio_outb(new_val, reg);
152b8664924SDiego Elio Pettenò }
153b8664924SDiego Elio Pettenò 
154b8664924SDiego Elio Pettenò static inline void superio_clear_mask(int mask, int reg)
155b8664924SDiego Elio Pettenò {
156b8664924SDiego Elio Pettenò 	u8 curr_val = superio_inb(reg);
157b8664924SDiego Elio Pettenò 	u8 new_val = curr_val & ~mask;
158b8664924SDiego Elio Pettenò 
159b8664924SDiego Elio Pettenò 	if (curr_val != new_val)
160b8664924SDiego Elio Pettenò 		superio_outb(new_val, reg);
161b8664924SDiego Elio Pettenò }
162b8664924SDiego Elio Pettenò 
163b8664924SDiego Elio Pettenò static int it87_gpio_request(struct gpio_chip *chip, unsigned gpio_num)
164b8664924SDiego Elio Pettenò {
165b8664924SDiego Elio Pettenò 	u8 mask, group;
166b8664924SDiego Elio Pettenò 	int rc = 0;
1670a38fd94SLinus Walleij 	struct it87_gpio *it87_gpio = gpiochip_get_data(chip);
168b8664924SDiego Elio Pettenò 
169b8664924SDiego Elio Pettenò 	mask = 1 << (gpio_num % 8);
170b8664924SDiego Elio Pettenò 	group = (gpio_num / 8);
171b8664924SDiego Elio Pettenò 
172b8664924SDiego Elio Pettenò 	spin_lock(&it87_gpio->lock);
173b8664924SDiego Elio Pettenò 
174b8664924SDiego Elio Pettenò 	rc = superio_enter();
175b8664924SDiego Elio Pettenò 	if (rc)
176b8664924SDiego Elio Pettenò 		goto exit;
177b8664924SDiego Elio Pettenò 
178b8664924SDiego Elio Pettenò 	/* not all the IT87xx chips support Simple I/O and not all of
179b8664924SDiego Elio Pettenò 	 * them allow all the lines to be set/unset to Simple I/O.
180b8664924SDiego Elio Pettenò 	 */
181b8664924SDiego Elio Pettenò 	if (group < it87_gpio->simple_size)
182b8664924SDiego Elio Pettenò 		superio_set_mask(mask, group + it87_gpio->simple_base);
183b8664924SDiego Elio Pettenò 
184b8664924SDiego Elio Pettenò 	/* clear output enable, setting the pin to input, as all the
185b8664924SDiego Elio Pettenò 	 * newly-exported GPIO interfaces are set to input.
186b8664924SDiego Elio Pettenò 	 */
187b8664924SDiego Elio Pettenò 	superio_clear_mask(mask, group + it87_gpio->output_base);
188b8664924SDiego Elio Pettenò 
189b8664924SDiego Elio Pettenò 	superio_exit();
190b8664924SDiego Elio Pettenò 
191b8664924SDiego Elio Pettenò exit:
192b8664924SDiego Elio Pettenò 	spin_unlock(&it87_gpio->lock);
193b8664924SDiego Elio Pettenò 	return rc;
194b8664924SDiego Elio Pettenò }
195b8664924SDiego Elio Pettenò 
196b8664924SDiego Elio Pettenò static int it87_gpio_get(struct gpio_chip *chip, unsigned gpio_num)
197b8664924SDiego Elio Pettenò {
198b8664924SDiego Elio Pettenò 	u16 reg;
199b8664924SDiego Elio Pettenò 	u8 mask;
2000a38fd94SLinus Walleij 	struct it87_gpio *it87_gpio = gpiochip_get_data(chip);
201b8664924SDiego Elio Pettenò 
202b8664924SDiego Elio Pettenò 	mask = 1 << (gpio_num % 8);
203b8664924SDiego Elio Pettenò 	reg = (gpio_num / 8) + it87_gpio->io_base;
204b8664924SDiego Elio Pettenò 
205b8664924SDiego Elio Pettenò 	return !!(inb(reg) & mask);
206b8664924SDiego Elio Pettenò }
207b8664924SDiego Elio Pettenò 
208b8664924SDiego Elio Pettenò static int it87_gpio_direction_in(struct gpio_chip *chip, unsigned gpio_num)
209b8664924SDiego Elio Pettenò {
210b8664924SDiego Elio Pettenò 	u8 mask, group;
211b8664924SDiego Elio Pettenò 	int rc = 0;
2120a38fd94SLinus Walleij 	struct it87_gpio *it87_gpio = gpiochip_get_data(chip);
213b8664924SDiego Elio Pettenò 
214b8664924SDiego Elio Pettenò 	mask = 1 << (gpio_num % 8);
215b8664924SDiego Elio Pettenò 	group = (gpio_num / 8);
216b8664924SDiego Elio Pettenò 
217b8664924SDiego Elio Pettenò 	spin_lock(&it87_gpio->lock);
218b8664924SDiego Elio Pettenò 
219b8664924SDiego Elio Pettenò 	rc = superio_enter();
220b8664924SDiego Elio Pettenò 	if (rc)
221b8664924SDiego Elio Pettenò 		goto exit;
222b8664924SDiego Elio Pettenò 
223b8664924SDiego Elio Pettenò 	/* clear the output enable bit */
224b8664924SDiego Elio Pettenò 	superio_clear_mask(mask, group + it87_gpio->output_base);
225b8664924SDiego Elio Pettenò 
226b8664924SDiego Elio Pettenò 	superio_exit();
227b8664924SDiego Elio Pettenò 
228b8664924SDiego Elio Pettenò exit:
229b8664924SDiego Elio Pettenò 	spin_unlock(&it87_gpio->lock);
230b8664924SDiego Elio Pettenò 	return rc;
231b8664924SDiego Elio Pettenò }
232b8664924SDiego Elio Pettenò 
233b8664924SDiego Elio Pettenò static void it87_gpio_set(struct gpio_chip *chip,
234b8664924SDiego Elio Pettenò 			  unsigned gpio_num, int val)
235b8664924SDiego Elio Pettenò {
236b8664924SDiego Elio Pettenò 	u8 mask, curr_vals;
237b8664924SDiego Elio Pettenò 	u16 reg;
2380a38fd94SLinus Walleij 	struct it87_gpio *it87_gpio = gpiochip_get_data(chip);
239b8664924SDiego Elio Pettenò 
240b8664924SDiego Elio Pettenò 	mask = 1 << (gpio_num % 8);
241b8664924SDiego Elio Pettenò 	reg = (gpio_num / 8) + it87_gpio->io_base;
242b8664924SDiego Elio Pettenò 
243b8664924SDiego Elio Pettenò 	curr_vals = inb(reg);
244b8664924SDiego Elio Pettenò 	if (val)
245b8664924SDiego Elio Pettenò 		outb(curr_vals | mask, reg);
246b8664924SDiego Elio Pettenò 	else
247b8664924SDiego Elio Pettenò 		outb(curr_vals & ~mask, reg);
248b8664924SDiego Elio Pettenò }
249b8664924SDiego Elio Pettenò 
250b8664924SDiego Elio Pettenò static int it87_gpio_direction_out(struct gpio_chip *chip,
251b8664924SDiego Elio Pettenò 				   unsigned gpio_num, int val)
252b8664924SDiego Elio Pettenò {
253b8664924SDiego Elio Pettenò 	u8 mask, group;
254b8664924SDiego Elio Pettenò 	int rc = 0;
2550a38fd94SLinus Walleij 	struct it87_gpio *it87_gpio = gpiochip_get_data(chip);
256b8664924SDiego Elio Pettenò 
257b8664924SDiego Elio Pettenò 	mask = 1 << (gpio_num % 8);
258b8664924SDiego Elio Pettenò 	group = (gpio_num / 8);
259b8664924SDiego Elio Pettenò 
260b8664924SDiego Elio Pettenò 	spin_lock(&it87_gpio->lock);
261b8664924SDiego Elio Pettenò 
262b8664924SDiego Elio Pettenò 	rc = superio_enter();
263b8664924SDiego Elio Pettenò 	if (rc)
264b8664924SDiego Elio Pettenò 		goto exit;
265b8664924SDiego Elio Pettenò 
266b8664924SDiego Elio Pettenò 	/* set the output enable bit */
267b8664924SDiego Elio Pettenò 	superio_set_mask(mask, group + it87_gpio->output_base);
268b8664924SDiego Elio Pettenò 
269b8664924SDiego Elio Pettenò 	it87_gpio_set(chip, gpio_num, val);
270b8664924SDiego Elio Pettenò 
271b8664924SDiego Elio Pettenò 	superio_exit();
272b8664924SDiego Elio Pettenò 
273b8664924SDiego Elio Pettenò exit:
274b8664924SDiego Elio Pettenò 	spin_unlock(&it87_gpio->lock);
275b8664924SDiego Elio Pettenò 	return rc;
276b8664924SDiego Elio Pettenò }
277b8664924SDiego Elio Pettenò 
278e35b5ab0SJulia Lawall static const struct gpio_chip it87_template_chip = {
279b8664924SDiego Elio Pettenò 	.label			= KBUILD_MODNAME,
280b8664924SDiego Elio Pettenò 	.owner			= THIS_MODULE,
281b8664924SDiego Elio Pettenò 	.request		= it87_gpio_request,
282b8664924SDiego Elio Pettenò 	.get			= it87_gpio_get,
283b8664924SDiego Elio Pettenò 	.direction_input	= it87_gpio_direction_in,
284b8664924SDiego Elio Pettenò 	.set			= it87_gpio_set,
285b8664924SDiego Elio Pettenò 	.direction_output	= it87_gpio_direction_out,
286b8664924SDiego Elio Pettenò 	.base			= -1
287b8664924SDiego Elio Pettenò };
288b8664924SDiego Elio Pettenò 
289b8664924SDiego Elio Pettenò static int __init it87_gpio_init(void)
290b8664924SDiego Elio Pettenò {
291b8664924SDiego Elio Pettenò 	int rc = 0, i;
292b8664924SDiego Elio Pettenò 	u16 chip_type;
293b8664924SDiego Elio Pettenò 	u8 chip_rev, gpio_ba_reg;
294b8664924SDiego Elio Pettenò 	char *labels, **labels_table;
295b8664924SDiego Elio Pettenò 
296b8664924SDiego Elio Pettenò 	struct it87_gpio *it87_gpio = &it87_gpio_chip;
297b8664924SDiego Elio Pettenò 
298b8664924SDiego Elio Pettenò 	rc = superio_enter();
299b8664924SDiego Elio Pettenò 	if (rc)
300b8664924SDiego Elio Pettenò 		return rc;
301b8664924SDiego Elio Pettenò 
302b8664924SDiego Elio Pettenò 	chip_type = superio_inw(CHIPID);
303b8664924SDiego Elio Pettenò 	chip_rev  = superio_inb(CHIPREV) & 0x0f;
304b8664924SDiego Elio Pettenò 	superio_exit();
305b8664924SDiego Elio Pettenò 
306b8664924SDiego Elio Pettenò 	it87_gpio->chip = it87_template_chip;
307b8664924SDiego Elio Pettenò 
308b8664924SDiego Elio Pettenò 	switch (chip_type) {
3098fccdb58SMartin Blumenstingl 	case IT8620_ID:
3108fccdb58SMartin Blumenstingl 	case IT8628_ID:
3118fccdb58SMartin Blumenstingl 		gpio_ba_reg = 0x62;
3128fccdb58SMartin Blumenstingl 		it87_gpio->io_size = 11;
3138fccdb58SMartin Blumenstingl 		it87_gpio->output_base = 0xc8;
3148fccdb58SMartin Blumenstingl 		it87_gpio->simple_size = 0;
3158fccdb58SMartin Blumenstingl 		it87_gpio->chip.ngpio = 64;
3168fccdb58SMartin Blumenstingl 		break;
317b8664924SDiego Elio Pettenò 	case IT8728_ID:
318b8664924SDiego Elio Pettenò 	case IT8732_ID:
31901062ad3SDiego Elio Pettenò 	case IT8772_ID:
320b8664924SDiego Elio Pettenò 		gpio_ba_reg = 0x62;
321b8664924SDiego Elio Pettenò 		it87_gpio->io_size = 8;
322b8664924SDiego Elio Pettenò 		it87_gpio->output_base = 0xc8;
323b8664924SDiego Elio Pettenò 		it87_gpio->simple_base = 0xc0;
324b8664924SDiego Elio Pettenò 		it87_gpio->simple_size = 5;
325b8664924SDiego Elio Pettenò 		it87_gpio->chip.ngpio = 64;
326b8664924SDiego Elio Pettenò 		break;
327b8664924SDiego Elio Pettenò 	case IT8761_ID:
328b8664924SDiego Elio Pettenò 		gpio_ba_reg = 0x60;
329b8664924SDiego Elio Pettenò 		it87_gpio->io_size = 4;
330b8664924SDiego Elio Pettenò 		it87_gpio->output_base = 0xf0;
331b8664924SDiego Elio Pettenò 		it87_gpio->simple_size = 0;
332b8664924SDiego Elio Pettenò 		it87_gpio->chip.ngpio = 16;
333b8664924SDiego Elio Pettenò 		break;
334b8664924SDiego Elio Pettenò 	case NO_DEV_ID:
335b8664924SDiego Elio Pettenò 		pr_err("no device\n");
336b8664924SDiego Elio Pettenò 		return -ENODEV;
337b8664924SDiego Elio Pettenò 	default:
338b8664924SDiego Elio Pettenò 		pr_err("Unknown Chip found, Chip %04x Revision %x\n",
339b8664924SDiego Elio Pettenò 		       chip_type, chip_rev);
340b8664924SDiego Elio Pettenò 		return -ENODEV;
341b8664924SDiego Elio Pettenò 	}
342b8664924SDiego Elio Pettenò 
343b8664924SDiego Elio Pettenò 	rc = superio_enter();
344b8664924SDiego Elio Pettenò 	if (rc)
345b8664924SDiego Elio Pettenò 		return rc;
346b8664924SDiego Elio Pettenò 
347b8664924SDiego Elio Pettenò 	superio_select(GPIO);
348b8664924SDiego Elio Pettenò 
349b8664924SDiego Elio Pettenò 	/* fetch GPIO base address */
350b8664924SDiego Elio Pettenò 	it87_gpio->io_base = superio_inw(gpio_ba_reg);
351b8664924SDiego Elio Pettenò 
352b8664924SDiego Elio Pettenò 	superio_exit();
353b8664924SDiego Elio Pettenò 
354b8664924SDiego Elio Pettenò 	pr_info("Found Chip IT%04x rev %x. %u GPIO lines starting at %04xh\n",
355b8664924SDiego Elio Pettenò 		chip_type, chip_rev, it87_gpio->chip.ngpio,
356b8664924SDiego Elio Pettenò 		it87_gpio->io_base);
357b8664924SDiego Elio Pettenò 
358b8664924SDiego Elio Pettenò 	if (!request_region(it87_gpio->io_base, it87_gpio->io_size,
359b8664924SDiego Elio Pettenò 							KBUILD_MODNAME))
360b8664924SDiego Elio Pettenò 		return -EBUSY;
361b8664924SDiego Elio Pettenò 
362b8664924SDiego Elio Pettenò 	/* Set up aliases for the GPIO connection.
363b8664924SDiego Elio Pettenò 	 *
364b8664924SDiego Elio Pettenò 	 * ITE documentation for recent chips such as the IT8728F
365b8664924SDiego Elio Pettenò 	 * refers to the GPIO lines as GPxy, with a coordinates system
366b8664924SDiego Elio Pettenò 	 * where x is the GPIO group (starting from 1) and y is the
367b8664924SDiego Elio Pettenò 	 * bit within the group.
368b8664924SDiego Elio Pettenò 	 *
369b8664924SDiego Elio Pettenò 	 * By creating these aliases, we make it easier to understand
370b8664924SDiego Elio Pettenò 	 * to which GPIO pin we're referring to.
371b8664924SDiego Elio Pettenò 	 */
372b8664924SDiego Elio Pettenò 	labels = kcalloc(it87_gpio->chip.ngpio, sizeof("it87_gpXY"),
373b8664924SDiego Elio Pettenò 								GFP_KERNEL);
374b8664924SDiego Elio Pettenò 	labels_table = kcalloc(it87_gpio->chip.ngpio, sizeof(const char *),
375b8664924SDiego Elio Pettenò 								GFP_KERNEL);
376b8664924SDiego Elio Pettenò 
377b8664924SDiego Elio Pettenò 	if (!labels || !labels_table) {
378b8664924SDiego Elio Pettenò 		rc = -ENOMEM;
379b8664924SDiego Elio Pettenò 		goto labels_free;
380b8664924SDiego Elio Pettenò 	}
381b8664924SDiego Elio Pettenò 
382b8664924SDiego Elio Pettenò 	for (i = 0; i < it87_gpio->chip.ngpio; i++) {
383b8664924SDiego Elio Pettenò 		char *label = &labels[i * sizeof("it87_gpXY")];
384b8664924SDiego Elio Pettenò 
385b8664924SDiego Elio Pettenò 		sprintf(label, "it87_gp%u%u", 1+(i/8), i%8);
386b8664924SDiego Elio Pettenò 		labels_table[i] = label;
387b8664924SDiego Elio Pettenò 	}
388b8664924SDiego Elio Pettenò 
389b8664924SDiego Elio Pettenò 	it87_gpio->chip.names = (const char *const*)labels_table;
390b8664924SDiego Elio Pettenò 
3910a38fd94SLinus Walleij 	rc = gpiochip_add_data(&it87_gpio->chip, it87_gpio);
392b8664924SDiego Elio Pettenò 	if (rc)
393b8664924SDiego Elio Pettenò 		goto labels_free;
394b8664924SDiego Elio Pettenò 
395b8664924SDiego Elio Pettenò 	return 0;
396b8664924SDiego Elio Pettenò 
397b8664924SDiego Elio Pettenò labels_free:
398b8664924SDiego Elio Pettenò 	kfree(labels_table);
399b8664924SDiego Elio Pettenò 	kfree(labels);
400b8664924SDiego Elio Pettenò 	release_region(it87_gpio->io_base, it87_gpio->io_size);
401b8664924SDiego Elio Pettenò 	return rc;
402b8664924SDiego Elio Pettenò }
403b8664924SDiego Elio Pettenò 
404b8664924SDiego Elio Pettenò static void __exit it87_gpio_exit(void)
405b8664924SDiego Elio Pettenò {
406b8664924SDiego Elio Pettenò 	struct it87_gpio *it87_gpio = &it87_gpio_chip;
407b8664924SDiego Elio Pettenò 
408b8664924SDiego Elio Pettenò 	gpiochip_remove(&it87_gpio->chip);
409b8664924SDiego Elio Pettenò 	release_region(it87_gpio->io_base, it87_gpio->io_size);
410b8664924SDiego Elio Pettenò 	kfree(it87_gpio->chip.names[0]);
411b8664924SDiego Elio Pettenò 	kfree(it87_gpio->chip.names);
412b8664924SDiego Elio Pettenò }
413b8664924SDiego Elio Pettenò 
414b8664924SDiego Elio Pettenò module_init(it87_gpio_init);
415b8664924SDiego Elio Pettenò module_exit(it87_gpio_exit);
416b8664924SDiego Elio Pettenò 
417b8664924SDiego Elio Pettenò MODULE_AUTHOR("Diego Elio Pettenò <flameeyes@flameeyes.eu>");
418b8664924SDiego Elio Pettenò MODULE_DESCRIPTION("GPIO interface for IT87xx Super I/O chips");
419b8664924SDiego Elio Pettenò MODULE_LICENSE("GPL");
420