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