File Index
Files and directories
Sign in
FILE

gpio-f7188x.c

File preview with syntax highlighting.

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