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