xref: /OK3568_Linux_fs/kernel/drivers/gpio/gpio-f7188x.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * GPIO driver for Fintek Super-I/O F71869, F71869A, F71882, F71889 and F81866
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2010-2013 LaCie
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Author: Simon Guinot <simon.guinot@sequanux.org>
8*4882a593Smuzhiyun  */
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include <linux/module.h>
11*4882a593Smuzhiyun #include <linux/init.h>
12*4882a593Smuzhiyun #include <linux/platform_device.h>
13*4882a593Smuzhiyun #include <linux/io.h>
14*4882a593Smuzhiyun #include <linux/gpio/driver.h>
15*4882a593Smuzhiyun #include <linux/bitops.h>
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun #define DRVNAME "gpio-f7188x"
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun /*
20*4882a593Smuzhiyun  * Super-I/O registers
21*4882a593Smuzhiyun  */
22*4882a593Smuzhiyun #define SIO_LDSEL		0x07	/* Logical device select */
23*4882a593Smuzhiyun #define SIO_DEVID		0x20	/* Device ID (2 bytes) */
24*4882a593Smuzhiyun #define SIO_DEVREV		0x22	/* Device revision */
25*4882a593Smuzhiyun #define SIO_MANID		0x23	/* Fintek ID (2 bytes) */
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun #define SIO_LD_GPIO		0x06	/* GPIO logical device */
28*4882a593Smuzhiyun #define SIO_UNLOCK_KEY		0x87	/* Key to enable Super-I/O */
29*4882a593Smuzhiyun #define SIO_LOCK_KEY		0xAA	/* Key to disable Super-I/O */
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun #define SIO_FINTEK_ID		0x1934	/* Manufacturer ID */
32*4882a593Smuzhiyun #define SIO_F71869_ID		0x0814	/* F71869 chipset ID */
33*4882a593Smuzhiyun #define SIO_F71869A_ID		0x1007	/* F71869A chipset ID */
34*4882a593Smuzhiyun #define SIO_F71882_ID		0x0541	/* F71882 chipset ID */
35*4882a593Smuzhiyun #define SIO_F71889_ID		0x0909	/* F71889 chipset ID */
36*4882a593Smuzhiyun #define SIO_F71889A_ID		0x1005	/* F71889A chipset ID */
37*4882a593Smuzhiyun #define SIO_F81866_ID		0x1010	/* F81866 chipset ID */
38*4882a593Smuzhiyun #define SIO_F81804_ID		0x1502  /* F81804 chipset ID, same for f81966 */
39*4882a593Smuzhiyun #define SIO_F81865_ID		0x0704	/* F81865 chipset ID */
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun enum chips {
43*4882a593Smuzhiyun 	f71869,
44*4882a593Smuzhiyun 	f71869a,
45*4882a593Smuzhiyun 	f71882fg,
46*4882a593Smuzhiyun 	f71889a,
47*4882a593Smuzhiyun 	f71889f,
48*4882a593Smuzhiyun 	f81866,
49*4882a593Smuzhiyun 	f81804,
50*4882a593Smuzhiyun 	f81865,
51*4882a593Smuzhiyun };
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun static const char * const f7188x_names[] = {
54*4882a593Smuzhiyun 	"f71869",
55*4882a593Smuzhiyun 	"f71869a",
56*4882a593Smuzhiyun 	"f71882fg",
57*4882a593Smuzhiyun 	"f71889a",
58*4882a593Smuzhiyun 	"f71889f",
59*4882a593Smuzhiyun 	"f81866",
60*4882a593Smuzhiyun 	"f81804",
61*4882a593Smuzhiyun 	"f81865",
62*4882a593Smuzhiyun };
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun struct f7188x_sio {
65*4882a593Smuzhiyun 	int addr;
66*4882a593Smuzhiyun 	enum chips type;
67*4882a593Smuzhiyun };
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun struct f7188x_gpio_bank {
70*4882a593Smuzhiyun 	struct gpio_chip chip;
71*4882a593Smuzhiyun 	unsigned int regbase;
72*4882a593Smuzhiyun 	struct f7188x_gpio_data *data;
73*4882a593Smuzhiyun };
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun struct f7188x_gpio_data {
76*4882a593Smuzhiyun 	struct f7188x_sio *sio;
77*4882a593Smuzhiyun 	int nr_bank;
78*4882a593Smuzhiyun 	struct f7188x_gpio_bank *bank;
79*4882a593Smuzhiyun };
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun /*
82*4882a593Smuzhiyun  * Super-I/O functions.
83*4882a593Smuzhiyun  */
84*4882a593Smuzhiyun 
superio_inb(int base,int reg)85*4882a593Smuzhiyun static inline int superio_inb(int base, int reg)
86*4882a593Smuzhiyun {
87*4882a593Smuzhiyun 	outb(reg, base);
88*4882a593Smuzhiyun 	return inb(base + 1);
89*4882a593Smuzhiyun }
90*4882a593Smuzhiyun 
superio_inw(int base,int reg)91*4882a593Smuzhiyun static int superio_inw(int base, int reg)
92*4882a593Smuzhiyun {
93*4882a593Smuzhiyun 	int val;
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun 	outb(reg++, base);
96*4882a593Smuzhiyun 	val = inb(base + 1) << 8;
97*4882a593Smuzhiyun 	outb(reg, base);
98*4882a593Smuzhiyun 	val |= inb(base + 1);
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 	return val;
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun 
superio_outb(int base,int reg,int val)103*4882a593Smuzhiyun static inline void superio_outb(int base, int reg, int val)
104*4882a593Smuzhiyun {
105*4882a593Smuzhiyun 	outb(reg, base);
106*4882a593Smuzhiyun 	outb(val, base + 1);
107*4882a593Smuzhiyun }
108*4882a593Smuzhiyun 
superio_enter(int base)109*4882a593Smuzhiyun static inline int superio_enter(int base)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun 	/* Don't step on other drivers' I/O space by accident. */
112*4882a593Smuzhiyun 	if (!request_muxed_region(base, 2, DRVNAME)) {
113*4882a593Smuzhiyun 		pr_err(DRVNAME "I/O address 0x%04x already in use\n", base);
114*4882a593Smuzhiyun 		return -EBUSY;
115*4882a593Smuzhiyun 	}
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 	/* According to the datasheet the key must be send twice. */
118*4882a593Smuzhiyun 	outb(SIO_UNLOCK_KEY, base);
119*4882a593Smuzhiyun 	outb(SIO_UNLOCK_KEY, base);
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 	return 0;
122*4882a593Smuzhiyun }
123*4882a593Smuzhiyun 
superio_select(int base,int ld)124*4882a593Smuzhiyun static inline void superio_select(int base, int ld)
125*4882a593Smuzhiyun {
126*4882a593Smuzhiyun 	outb(SIO_LDSEL, base);
127*4882a593Smuzhiyun 	outb(ld, base + 1);
128*4882a593Smuzhiyun }
129*4882a593Smuzhiyun 
superio_exit(int base)130*4882a593Smuzhiyun static inline void superio_exit(int base)
131*4882a593Smuzhiyun {
132*4882a593Smuzhiyun 	outb(SIO_LOCK_KEY, base);
133*4882a593Smuzhiyun 	release_region(base, 2);
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun /*
137*4882a593Smuzhiyun  * GPIO chip.
138*4882a593Smuzhiyun  */
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun static int f7188x_gpio_get_direction(struct gpio_chip *chip, unsigned offset);
141*4882a593Smuzhiyun static int f7188x_gpio_direction_in(struct gpio_chip *chip, unsigned offset);
142*4882a593Smuzhiyun static int f7188x_gpio_get(struct gpio_chip *chip, unsigned offset);
143*4882a593Smuzhiyun static int f7188x_gpio_direction_out(struct gpio_chip *chip,
144*4882a593Smuzhiyun 				     unsigned offset, int value);
145*4882a593Smuzhiyun static void f7188x_gpio_set(struct gpio_chip *chip, unsigned offset, int value);
146*4882a593Smuzhiyun static int f7188x_gpio_set_config(struct gpio_chip *chip, unsigned offset,
147*4882a593Smuzhiyun 				  unsigned long config);
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun #define F7188X_GPIO_BANK(_base, _ngpio, _regbase)			\
150*4882a593Smuzhiyun 	{								\
151*4882a593Smuzhiyun 		.chip = {						\
152*4882a593Smuzhiyun 			.label            = DRVNAME,			\
153*4882a593Smuzhiyun 			.owner            = THIS_MODULE,		\
154*4882a593Smuzhiyun 			.get_direction    = f7188x_gpio_get_direction,	\
155*4882a593Smuzhiyun 			.direction_input  = f7188x_gpio_direction_in,	\
156*4882a593Smuzhiyun 			.get              = f7188x_gpio_get,		\
157*4882a593Smuzhiyun 			.direction_output = f7188x_gpio_direction_out,	\
158*4882a593Smuzhiyun 			.set              = f7188x_gpio_set,		\
159*4882a593Smuzhiyun 			.set_config	  = f7188x_gpio_set_config,	\
160*4882a593Smuzhiyun 			.base             = _base,			\
161*4882a593Smuzhiyun 			.ngpio            = _ngpio,			\
162*4882a593Smuzhiyun 			.can_sleep        = true,			\
163*4882a593Smuzhiyun 		},							\
164*4882a593Smuzhiyun 		.regbase = _regbase,					\
165*4882a593Smuzhiyun 	}
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun #define gpio_dir(base) (base + 0)
168*4882a593Smuzhiyun #define gpio_data_out(base) (base + 1)
169*4882a593Smuzhiyun #define gpio_data_in(base) (base + 2)
170*4882a593Smuzhiyun /* Output mode register (0:open drain 1:push-pull). */
171*4882a593Smuzhiyun #define gpio_out_mode(base) (base + 3)
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun static struct f7188x_gpio_bank f71869_gpio_bank[] = {
174*4882a593Smuzhiyun 	F7188X_GPIO_BANK(0, 6, 0xF0),
175*4882a593Smuzhiyun 	F7188X_GPIO_BANK(10, 8, 0xE0),
176*4882a593Smuzhiyun 	F7188X_GPIO_BANK(20, 8, 0xD0),
177*4882a593Smuzhiyun 	F7188X_GPIO_BANK(30, 8, 0xC0),
178*4882a593Smuzhiyun 	F7188X_GPIO_BANK(40, 8, 0xB0),
179*4882a593Smuzhiyun 	F7188X_GPIO_BANK(50, 5, 0xA0),
180*4882a593Smuzhiyun 	F7188X_GPIO_BANK(60, 6, 0x90),
181*4882a593Smuzhiyun };
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun static struct f7188x_gpio_bank f71869a_gpio_bank[] = {
184*4882a593Smuzhiyun 	F7188X_GPIO_BANK(0, 6, 0xF0),
185*4882a593Smuzhiyun 	F7188X_GPIO_BANK(10, 8, 0xE0),
186*4882a593Smuzhiyun 	F7188X_GPIO_BANK(20, 8, 0xD0),
187*4882a593Smuzhiyun 	F7188X_GPIO_BANK(30, 8, 0xC0),
188*4882a593Smuzhiyun 	F7188X_GPIO_BANK(40, 8, 0xB0),
189*4882a593Smuzhiyun 	F7188X_GPIO_BANK(50, 5, 0xA0),
190*4882a593Smuzhiyun 	F7188X_GPIO_BANK(60, 8, 0x90),
191*4882a593Smuzhiyun 	F7188X_GPIO_BANK(70, 8, 0x80),
192*4882a593Smuzhiyun };
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun static struct f7188x_gpio_bank f71882_gpio_bank[] = {
195*4882a593Smuzhiyun 	F7188X_GPIO_BANK(0, 8, 0xF0),
196*4882a593Smuzhiyun 	F7188X_GPIO_BANK(10, 8, 0xE0),
197*4882a593Smuzhiyun 	F7188X_GPIO_BANK(20, 8, 0xD0),
198*4882a593Smuzhiyun 	F7188X_GPIO_BANK(30, 4, 0xC0),
199*4882a593Smuzhiyun 	F7188X_GPIO_BANK(40, 4, 0xB0),
200*4882a593Smuzhiyun };
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun static struct f7188x_gpio_bank f71889a_gpio_bank[] = {
203*4882a593Smuzhiyun 	F7188X_GPIO_BANK(0, 7, 0xF0),
204*4882a593Smuzhiyun 	F7188X_GPIO_BANK(10, 7, 0xE0),
205*4882a593Smuzhiyun 	F7188X_GPIO_BANK(20, 8, 0xD0),
206*4882a593Smuzhiyun 	F7188X_GPIO_BANK(30, 8, 0xC0),
207*4882a593Smuzhiyun 	F7188X_GPIO_BANK(40, 8, 0xB0),
208*4882a593Smuzhiyun 	F7188X_GPIO_BANK(50, 5, 0xA0),
209*4882a593Smuzhiyun 	F7188X_GPIO_BANK(60, 8, 0x90),
210*4882a593Smuzhiyun 	F7188X_GPIO_BANK(70, 8, 0x80),
211*4882a593Smuzhiyun };
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun static struct f7188x_gpio_bank f71889_gpio_bank[] = {
214*4882a593Smuzhiyun 	F7188X_GPIO_BANK(0, 7, 0xF0),
215*4882a593Smuzhiyun 	F7188X_GPIO_BANK(10, 7, 0xE0),
216*4882a593Smuzhiyun 	F7188X_GPIO_BANK(20, 8, 0xD0),
217*4882a593Smuzhiyun 	F7188X_GPIO_BANK(30, 8, 0xC0),
218*4882a593Smuzhiyun 	F7188X_GPIO_BANK(40, 8, 0xB0),
219*4882a593Smuzhiyun 	F7188X_GPIO_BANK(50, 5, 0xA0),
220*4882a593Smuzhiyun 	F7188X_GPIO_BANK(60, 8, 0x90),
221*4882a593Smuzhiyun 	F7188X_GPIO_BANK(70, 8, 0x80),
222*4882a593Smuzhiyun };
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun static struct f7188x_gpio_bank f81866_gpio_bank[] = {
225*4882a593Smuzhiyun 	F7188X_GPIO_BANK(0, 8, 0xF0),
226*4882a593Smuzhiyun 	F7188X_GPIO_BANK(10, 8, 0xE0),
227*4882a593Smuzhiyun 	F7188X_GPIO_BANK(20, 8, 0xD0),
228*4882a593Smuzhiyun 	F7188X_GPIO_BANK(30, 8, 0xC0),
229*4882a593Smuzhiyun 	F7188X_GPIO_BANK(40, 8, 0xB0),
230*4882a593Smuzhiyun 	F7188X_GPIO_BANK(50, 8, 0xA0),
231*4882a593Smuzhiyun 	F7188X_GPIO_BANK(60, 8, 0x90),
232*4882a593Smuzhiyun 	F7188X_GPIO_BANK(70, 8, 0x80),
233*4882a593Smuzhiyun 	F7188X_GPIO_BANK(80, 8, 0x88),
234*4882a593Smuzhiyun };
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun static struct f7188x_gpio_bank f81804_gpio_bank[] = {
238*4882a593Smuzhiyun 	F7188X_GPIO_BANK(0, 8, 0xF0),
239*4882a593Smuzhiyun 	F7188X_GPIO_BANK(10, 8, 0xE0),
240*4882a593Smuzhiyun 	F7188X_GPIO_BANK(20, 8, 0xD0),
241*4882a593Smuzhiyun 	F7188X_GPIO_BANK(50, 8, 0xA0),
242*4882a593Smuzhiyun 	F7188X_GPIO_BANK(60, 8, 0x90),
243*4882a593Smuzhiyun 	F7188X_GPIO_BANK(70, 8, 0x80),
244*4882a593Smuzhiyun 	F7188X_GPIO_BANK(90, 8, 0x98),
245*4882a593Smuzhiyun };
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun static struct f7188x_gpio_bank f81865_gpio_bank[] = {
248*4882a593Smuzhiyun 	F7188X_GPIO_BANK(0, 8, 0xF0),
249*4882a593Smuzhiyun 	F7188X_GPIO_BANK(10, 8, 0xE0),
250*4882a593Smuzhiyun 	F7188X_GPIO_BANK(20, 8, 0xD0),
251*4882a593Smuzhiyun 	F7188X_GPIO_BANK(30, 8, 0xC0),
252*4882a593Smuzhiyun 	F7188X_GPIO_BANK(40, 8, 0xB0),
253*4882a593Smuzhiyun 	F7188X_GPIO_BANK(50, 8, 0xA0),
254*4882a593Smuzhiyun 	F7188X_GPIO_BANK(60, 5, 0x90),
255*4882a593Smuzhiyun };
256*4882a593Smuzhiyun 
f7188x_gpio_get_direction(struct gpio_chip * chip,unsigned offset)257*4882a593Smuzhiyun static int f7188x_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
258*4882a593Smuzhiyun {
259*4882a593Smuzhiyun 	int err;
260*4882a593Smuzhiyun 	struct f7188x_gpio_bank *bank = gpiochip_get_data(chip);
261*4882a593Smuzhiyun 	struct f7188x_sio *sio = bank->data->sio;
262*4882a593Smuzhiyun 	u8 dir;
263*4882a593Smuzhiyun 
264*4882a593Smuzhiyun 	err = superio_enter(sio->addr);
265*4882a593Smuzhiyun 	if (err)
266*4882a593Smuzhiyun 		return err;
267*4882a593Smuzhiyun 	superio_select(sio->addr, SIO_LD_GPIO);
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun 	dir = superio_inb(sio->addr, gpio_dir(bank->regbase));
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 	superio_exit(sio->addr);
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun 	if (dir & 1 << offset)
274*4882a593Smuzhiyun 		return GPIO_LINE_DIRECTION_OUT;
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun 	return GPIO_LINE_DIRECTION_IN;
277*4882a593Smuzhiyun }
278*4882a593Smuzhiyun 
f7188x_gpio_direction_in(struct gpio_chip * chip,unsigned offset)279*4882a593Smuzhiyun static int f7188x_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
280*4882a593Smuzhiyun {
281*4882a593Smuzhiyun 	int err;
282*4882a593Smuzhiyun 	struct f7188x_gpio_bank *bank = gpiochip_get_data(chip);
283*4882a593Smuzhiyun 	struct f7188x_sio *sio = bank->data->sio;
284*4882a593Smuzhiyun 	u8 dir;
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 	err = superio_enter(sio->addr);
287*4882a593Smuzhiyun 	if (err)
288*4882a593Smuzhiyun 		return err;
289*4882a593Smuzhiyun 	superio_select(sio->addr, SIO_LD_GPIO);
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 	dir = superio_inb(sio->addr, gpio_dir(bank->regbase));
292*4882a593Smuzhiyun 	dir &= ~BIT(offset);
293*4882a593Smuzhiyun 	superio_outb(sio->addr, gpio_dir(bank->regbase), dir);
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun 	superio_exit(sio->addr);
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun 	return 0;
298*4882a593Smuzhiyun }
299*4882a593Smuzhiyun 
f7188x_gpio_get(struct gpio_chip * chip,unsigned offset)300*4882a593Smuzhiyun static int f7188x_gpio_get(struct gpio_chip *chip, unsigned offset)
301*4882a593Smuzhiyun {
302*4882a593Smuzhiyun 	int err;
303*4882a593Smuzhiyun 	struct f7188x_gpio_bank *bank = gpiochip_get_data(chip);
304*4882a593Smuzhiyun 	struct f7188x_sio *sio = bank->data->sio;
305*4882a593Smuzhiyun 	u8 dir, data;
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun 	err = superio_enter(sio->addr);
308*4882a593Smuzhiyun 	if (err)
309*4882a593Smuzhiyun 		return err;
310*4882a593Smuzhiyun 	superio_select(sio->addr, SIO_LD_GPIO);
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun 	dir = superio_inb(sio->addr, gpio_dir(bank->regbase));
313*4882a593Smuzhiyun 	dir = !!(dir & BIT(offset));
314*4882a593Smuzhiyun 	if (dir)
315*4882a593Smuzhiyun 		data = superio_inb(sio->addr, gpio_data_out(bank->regbase));
316*4882a593Smuzhiyun 	else
317*4882a593Smuzhiyun 		data = superio_inb(sio->addr, gpio_data_in(bank->regbase));
318*4882a593Smuzhiyun 
319*4882a593Smuzhiyun 	superio_exit(sio->addr);
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun 	return !!(data & BIT(offset));
322*4882a593Smuzhiyun }
323*4882a593Smuzhiyun 
f7188x_gpio_direction_out(struct gpio_chip * chip,unsigned offset,int value)324*4882a593Smuzhiyun static int f7188x_gpio_direction_out(struct gpio_chip *chip,
325*4882a593Smuzhiyun 				     unsigned offset, int value)
326*4882a593Smuzhiyun {
327*4882a593Smuzhiyun 	int err;
328*4882a593Smuzhiyun 	struct f7188x_gpio_bank *bank = gpiochip_get_data(chip);
329*4882a593Smuzhiyun 	struct f7188x_sio *sio = bank->data->sio;
330*4882a593Smuzhiyun 	u8 dir, data_out;
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun 	err = superio_enter(sio->addr);
333*4882a593Smuzhiyun 	if (err)
334*4882a593Smuzhiyun 		return err;
335*4882a593Smuzhiyun 	superio_select(sio->addr, SIO_LD_GPIO);
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun 	data_out = superio_inb(sio->addr, gpio_data_out(bank->regbase));
338*4882a593Smuzhiyun 	if (value)
339*4882a593Smuzhiyun 		data_out |= BIT(offset);
340*4882a593Smuzhiyun 	else
341*4882a593Smuzhiyun 		data_out &= ~BIT(offset);
342*4882a593Smuzhiyun 	superio_outb(sio->addr, gpio_data_out(bank->regbase), data_out);
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun 	dir = superio_inb(sio->addr, gpio_dir(bank->regbase));
345*4882a593Smuzhiyun 	dir |= BIT(offset);
346*4882a593Smuzhiyun 	superio_outb(sio->addr, gpio_dir(bank->regbase), dir);
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun 	superio_exit(sio->addr);
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun 	return 0;
351*4882a593Smuzhiyun }
352*4882a593Smuzhiyun 
f7188x_gpio_set(struct gpio_chip * chip,unsigned offset,int value)353*4882a593Smuzhiyun static void f7188x_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
354*4882a593Smuzhiyun {
355*4882a593Smuzhiyun 	int err;
356*4882a593Smuzhiyun 	struct f7188x_gpio_bank *bank = gpiochip_get_data(chip);
357*4882a593Smuzhiyun 	struct f7188x_sio *sio = bank->data->sio;
358*4882a593Smuzhiyun 	u8 data_out;
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun 	err = superio_enter(sio->addr);
361*4882a593Smuzhiyun 	if (err)
362*4882a593Smuzhiyun 		return;
363*4882a593Smuzhiyun 	superio_select(sio->addr, SIO_LD_GPIO);
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun 	data_out = superio_inb(sio->addr, gpio_data_out(bank->regbase));
366*4882a593Smuzhiyun 	if (value)
367*4882a593Smuzhiyun 		data_out |= BIT(offset);
368*4882a593Smuzhiyun 	else
369*4882a593Smuzhiyun 		data_out &= ~BIT(offset);
370*4882a593Smuzhiyun 	superio_outb(sio->addr, gpio_data_out(bank->regbase), data_out);
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun 	superio_exit(sio->addr);
373*4882a593Smuzhiyun }
374*4882a593Smuzhiyun 
f7188x_gpio_set_config(struct gpio_chip * chip,unsigned offset,unsigned long config)375*4882a593Smuzhiyun static int f7188x_gpio_set_config(struct gpio_chip *chip, unsigned offset,
376*4882a593Smuzhiyun 				  unsigned long config)
377*4882a593Smuzhiyun {
378*4882a593Smuzhiyun 	int err;
379*4882a593Smuzhiyun 	enum pin_config_param param = pinconf_to_config_param(config);
380*4882a593Smuzhiyun 	struct f7188x_gpio_bank *bank = gpiochip_get_data(chip);
381*4882a593Smuzhiyun 	struct f7188x_sio *sio = bank->data->sio;
382*4882a593Smuzhiyun 	u8 data;
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun 	if (param != PIN_CONFIG_DRIVE_OPEN_DRAIN &&
385*4882a593Smuzhiyun 	    param != PIN_CONFIG_DRIVE_PUSH_PULL)
386*4882a593Smuzhiyun 		return -ENOTSUPP;
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun 	err = superio_enter(sio->addr);
389*4882a593Smuzhiyun 	if (err)
390*4882a593Smuzhiyun 		return err;
391*4882a593Smuzhiyun 	superio_select(sio->addr, SIO_LD_GPIO);
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun 	data = superio_inb(sio->addr, gpio_out_mode(bank->regbase));
394*4882a593Smuzhiyun 	if (param == PIN_CONFIG_DRIVE_OPEN_DRAIN)
395*4882a593Smuzhiyun 		data &= ~BIT(offset);
396*4882a593Smuzhiyun 	else
397*4882a593Smuzhiyun 		data |= BIT(offset);
398*4882a593Smuzhiyun 	superio_outb(sio->addr, gpio_out_mode(bank->regbase), data);
399*4882a593Smuzhiyun 
400*4882a593Smuzhiyun 	superio_exit(sio->addr);
401*4882a593Smuzhiyun 	return 0;
402*4882a593Smuzhiyun }
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun /*
405*4882a593Smuzhiyun  * Platform device and driver.
406*4882a593Smuzhiyun  */
407*4882a593Smuzhiyun 
f7188x_gpio_probe(struct platform_device * pdev)408*4882a593Smuzhiyun static int f7188x_gpio_probe(struct platform_device *pdev)
409*4882a593Smuzhiyun {
410*4882a593Smuzhiyun 	int err;
411*4882a593Smuzhiyun 	int i;
412*4882a593Smuzhiyun 	struct f7188x_sio *sio = dev_get_platdata(&pdev->dev);
413*4882a593Smuzhiyun 	struct f7188x_gpio_data *data;
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun 	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
416*4882a593Smuzhiyun 	if (!data)
417*4882a593Smuzhiyun 		return -ENOMEM;
418*4882a593Smuzhiyun 
419*4882a593Smuzhiyun 	switch (sio->type) {
420*4882a593Smuzhiyun 	case f71869:
421*4882a593Smuzhiyun 		data->nr_bank = ARRAY_SIZE(f71869_gpio_bank);
422*4882a593Smuzhiyun 		data->bank = f71869_gpio_bank;
423*4882a593Smuzhiyun 		break;
424*4882a593Smuzhiyun 	case f71869a:
425*4882a593Smuzhiyun 		data->nr_bank = ARRAY_SIZE(f71869a_gpio_bank);
426*4882a593Smuzhiyun 		data->bank = f71869a_gpio_bank;
427*4882a593Smuzhiyun 		break;
428*4882a593Smuzhiyun 	case f71882fg:
429*4882a593Smuzhiyun 		data->nr_bank = ARRAY_SIZE(f71882_gpio_bank);
430*4882a593Smuzhiyun 		data->bank = f71882_gpio_bank;
431*4882a593Smuzhiyun 		break;
432*4882a593Smuzhiyun 	case f71889a:
433*4882a593Smuzhiyun 		data->nr_bank = ARRAY_SIZE(f71889a_gpio_bank);
434*4882a593Smuzhiyun 		data->bank = f71889a_gpio_bank;
435*4882a593Smuzhiyun 		break;
436*4882a593Smuzhiyun 	case f71889f:
437*4882a593Smuzhiyun 		data->nr_bank = ARRAY_SIZE(f71889_gpio_bank);
438*4882a593Smuzhiyun 		data->bank = f71889_gpio_bank;
439*4882a593Smuzhiyun 		break;
440*4882a593Smuzhiyun 	case f81866:
441*4882a593Smuzhiyun 		data->nr_bank = ARRAY_SIZE(f81866_gpio_bank);
442*4882a593Smuzhiyun 		data->bank = f81866_gpio_bank;
443*4882a593Smuzhiyun 		break;
444*4882a593Smuzhiyun 	case  f81804:
445*4882a593Smuzhiyun 		data->nr_bank = ARRAY_SIZE(f81804_gpio_bank);
446*4882a593Smuzhiyun 		data->bank = f81804_gpio_bank;
447*4882a593Smuzhiyun 		break;
448*4882a593Smuzhiyun 	case f81865:
449*4882a593Smuzhiyun 		data->nr_bank = ARRAY_SIZE(f81865_gpio_bank);
450*4882a593Smuzhiyun 		data->bank = f81865_gpio_bank;
451*4882a593Smuzhiyun 		break;
452*4882a593Smuzhiyun 	default:
453*4882a593Smuzhiyun 		return -ENODEV;
454*4882a593Smuzhiyun 	}
455*4882a593Smuzhiyun 	data->sio = sio;
456*4882a593Smuzhiyun 
457*4882a593Smuzhiyun 	platform_set_drvdata(pdev, data);
458*4882a593Smuzhiyun 
459*4882a593Smuzhiyun 	/* For each GPIO bank, register a GPIO chip. */
460*4882a593Smuzhiyun 	for (i = 0; i < data->nr_bank; i++) {
461*4882a593Smuzhiyun 		struct f7188x_gpio_bank *bank = &data->bank[i];
462*4882a593Smuzhiyun 
463*4882a593Smuzhiyun 		bank->chip.parent = &pdev->dev;
464*4882a593Smuzhiyun 		bank->data = data;
465*4882a593Smuzhiyun 
466*4882a593Smuzhiyun 		err = devm_gpiochip_add_data(&pdev->dev, &bank->chip, bank);
467*4882a593Smuzhiyun 		if (err) {
468*4882a593Smuzhiyun 			dev_err(&pdev->dev,
469*4882a593Smuzhiyun 				"Failed to register gpiochip %d: %d\n",
470*4882a593Smuzhiyun 				i, err);
471*4882a593Smuzhiyun 			return err;
472*4882a593Smuzhiyun 		}
473*4882a593Smuzhiyun 	}
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun 	return 0;
476*4882a593Smuzhiyun }
477*4882a593Smuzhiyun 
f7188x_find(int addr,struct f7188x_sio * sio)478*4882a593Smuzhiyun static int __init f7188x_find(int addr, struct f7188x_sio *sio)
479*4882a593Smuzhiyun {
480*4882a593Smuzhiyun 	int err;
481*4882a593Smuzhiyun 	u16 devid;
482*4882a593Smuzhiyun 
483*4882a593Smuzhiyun 	err = superio_enter(addr);
484*4882a593Smuzhiyun 	if (err)
485*4882a593Smuzhiyun 		return err;
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun 	err = -ENODEV;
488*4882a593Smuzhiyun 	devid = superio_inw(addr, SIO_MANID);
489*4882a593Smuzhiyun 	if (devid != SIO_FINTEK_ID) {
490*4882a593Smuzhiyun 		pr_debug(DRVNAME ": Not a Fintek device at 0x%08x\n", addr);
491*4882a593Smuzhiyun 		goto err;
492*4882a593Smuzhiyun 	}
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun 	devid = superio_inw(addr, SIO_DEVID);
495*4882a593Smuzhiyun 	switch (devid) {
496*4882a593Smuzhiyun 	case SIO_F71869_ID:
497*4882a593Smuzhiyun 		sio->type = f71869;
498*4882a593Smuzhiyun 		break;
499*4882a593Smuzhiyun 	case SIO_F71869A_ID:
500*4882a593Smuzhiyun 		sio->type = f71869a;
501*4882a593Smuzhiyun 		break;
502*4882a593Smuzhiyun 	case SIO_F71882_ID:
503*4882a593Smuzhiyun 		sio->type = f71882fg;
504*4882a593Smuzhiyun 		break;
505*4882a593Smuzhiyun 	case SIO_F71889A_ID:
506*4882a593Smuzhiyun 		sio->type = f71889a;
507*4882a593Smuzhiyun 		break;
508*4882a593Smuzhiyun 	case SIO_F71889_ID:
509*4882a593Smuzhiyun 		sio->type = f71889f;
510*4882a593Smuzhiyun 		break;
511*4882a593Smuzhiyun 	case SIO_F81866_ID:
512*4882a593Smuzhiyun 		sio->type = f81866;
513*4882a593Smuzhiyun 		break;
514*4882a593Smuzhiyun 	case SIO_F81804_ID:
515*4882a593Smuzhiyun 		sio->type = f81804;
516*4882a593Smuzhiyun 		break;
517*4882a593Smuzhiyun 	case SIO_F81865_ID:
518*4882a593Smuzhiyun 		sio->type = f81865;
519*4882a593Smuzhiyun 		break;
520*4882a593Smuzhiyun 	default:
521*4882a593Smuzhiyun 		pr_info(DRVNAME ": Unsupported Fintek device 0x%04x\n", devid);
522*4882a593Smuzhiyun 		goto err;
523*4882a593Smuzhiyun 	}
524*4882a593Smuzhiyun 	sio->addr = addr;
525*4882a593Smuzhiyun 	err = 0;
526*4882a593Smuzhiyun 
527*4882a593Smuzhiyun 	pr_info(DRVNAME ": Found %s at %#x, revision %d\n",
528*4882a593Smuzhiyun 		f7188x_names[sio->type],
529*4882a593Smuzhiyun 		(unsigned int) addr,
530*4882a593Smuzhiyun 		(int) superio_inb(addr, SIO_DEVREV));
531*4882a593Smuzhiyun 
532*4882a593Smuzhiyun err:
533*4882a593Smuzhiyun 	superio_exit(addr);
534*4882a593Smuzhiyun 	return err;
535*4882a593Smuzhiyun }
536*4882a593Smuzhiyun 
537*4882a593Smuzhiyun static struct platform_device *f7188x_gpio_pdev;
538*4882a593Smuzhiyun 
539*4882a593Smuzhiyun static int __init
f7188x_gpio_device_add(const struct f7188x_sio * sio)540*4882a593Smuzhiyun f7188x_gpio_device_add(const struct f7188x_sio *sio)
541*4882a593Smuzhiyun {
542*4882a593Smuzhiyun 	int err;
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun 	f7188x_gpio_pdev = platform_device_alloc(DRVNAME, -1);
545*4882a593Smuzhiyun 	if (!f7188x_gpio_pdev)
546*4882a593Smuzhiyun 		return -ENOMEM;
547*4882a593Smuzhiyun 
548*4882a593Smuzhiyun 	err = platform_device_add_data(f7188x_gpio_pdev,
549*4882a593Smuzhiyun 				       sio, sizeof(*sio));
550*4882a593Smuzhiyun 	if (err) {
551*4882a593Smuzhiyun 		pr_err(DRVNAME "Platform data allocation failed\n");
552*4882a593Smuzhiyun 		goto err;
553*4882a593Smuzhiyun 	}
554*4882a593Smuzhiyun 
555*4882a593Smuzhiyun 	err = platform_device_add(f7188x_gpio_pdev);
556*4882a593Smuzhiyun 	if (err) {
557*4882a593Smuzhiyun 		pr_err(DRVNAME "Device addition failed\n");
558*4882a593Smuzhiyun 		goto err;
559*4882a593Smuzhiyun 	}
560*4882a593Smuzhiyun 
561*4882a593Smuzhiyun 	return 0;
562*4882a593Smuzhiyun 
563*4882a593Smuzhiyun err:
564*4882a593Smuzhiyun 	platform_device_put(f7188x_gpio_pdev);
565*4882a593Smuzhiyun 
566*4882a593Smuzhiyun 	return err;
567*4882a593Smuzhiyun }
568*4882a593Smuzhiyun 
569*4882a593Smuzhiyun /*
570*4882a593Smuzhiyun  * Try to match a supported Fintek device by reading the (hard-wired)
571*4882a593Smuzhiyun  * configuration I/O ports. If available, then register both the platform
572*4882a593Smuzhiyun  * device and driver to support the GPIOs.
573*4882a593Smuzhiyun  */
574*4882a593Smuzhiyun 
575*4882a593Smuzhiyun static struct platform_driver f7188x_gpio_driver = {
576*4882a593Smuzhiyun 	.driver = {
577*4882a593Smuzhiyun 		.name	= DRVNAME,
578*4882a593Smuzhiyun 	},
579*4882a593Smuzhiyun 	.probe		= f7188x_gpio_probe,
580*4882a593Smuzhiyun };
581*4882a593Smuzhiyun 
f7188x_gpio_init(void)582*4882a593Smuzhiyun static int __init f7188x_gpio_init(void)
583*4882a593Smuzhiyun {
584*4882a593Smuzhiyun 	int err;
585*4882a593Smuzhiyun 	struct f7188x_sio sio;
586*4882a593Smuzhiyun 
587*4882a593Smuzhiyun 	if (f7188x_find(0x2e, &sio) &&
588*4882a593Smuzhiyun 	    f7188x_find(0x4e, &sio))
589*4882a593Smuzhiyun 		return -ENODEV;
590*4882a593Smuzhiyun 
591*4882a593Smuzhiyun 	err = platform_driver_register(&f7188x_gpio_driver);
592*4882a593Smuzhiyun 	if (!err) {
593*4882a593Smuzhiyun 		err = f7188x_gpio_device_add(&sio);
594*4882a593Smuzhiyun 		if (err)
595*4882a593Smuzhiyun 			platform_driver_unregister(&f7188x_gpio_driver);
596*4882a593Smuzhiyun 	}
597*4882a593Smuzhiyun 
598*4882a593Smuzhiyun 	return err;
599*4882a593Smuzhiyun }
600*4882a593Smuzhiyun subsys_initcall(f7188x_gpio_init);
601*4882a593Smuzhiyun 
f7188x_gpio_exit(void)602*4882a593Smuzhiyun static void __exit f7188x_gpio_exit(void)
603*4882a593Smuzhiyun {
604*4882a593Smuzhiyun 	platform_device_unregister(f7188x_gpio_pdev);
605*4882a593Smuzhiyun 	platform_driver_unregister(&f7188x_gpio_driver);
606*4882a593Smuzhiyun }
607*4882a593Smuzhiyun module_exit(f7188x_gpio_exit);
608*4882a593Smuzhiyun 
609*4882a593Smuzhiyun MODULE_DESCRIPTION("GPIO driver for Super-I/O chips F71869, F71869A, F71882FG, F71889A, F71889F and F81866");
610*4882a593Smuzhiyun MODULE_AUTHOR("Simon Guinot <simon.guinot@sequanux.org>");
611*4882a593Smuzhiyun MODULE_LICENSE("GPL");
612