diff mbox series

[v3,1/4] gpio-f7188x: Add GPIO support for Nuvoton NCT6116

Message ID 20220811153908.31283-2-henning.schild@siemens.com
State New
Headers show
Series add support for another simatic board | expand

Commit Message

Henning Schild Aug. 11, 2022, 3:39 p.m. UTC
Add GPIO support for Nuvoton NCT6116 chip. Nuvoton SuperIO chips are
very similar to the ones from Fintek. In other subsystems they also
share drivers and are called a family of drivers.

For the GPIO subsystem the only difference is that the direction bit is
reversed and that there is only one data bit per pin. On the SuperIO
level the logical device is another one.

Signed-off-by: Henning Schild <henning.schild@siemens.com>
---
 drivers/gpio/gpio-f7188x.c | 71 +++++++++++++++++++++++++++-----------
 1 file changed, 51 insertions(+), 20 deletions(-)

Comments

Simon Guinot Aug. 12, 2022, 8:43 a.m. UTC | #1
On Thu, Aug 11, 2022 at 05:39:05PM +0200, Henning Schild wrote:
> Add GPIO support for Nuvoton NCT6116 chip. Nuvoton SuperIO chips are
> very similar to the ones from Fintek. In other subsystems they also
> share drivers and are called a family of drivers.
> 
> For the GPIO subsystem the only difference is that the direction bit is
> reversed and that there is only one data bit per pin. On the SuperIO
> level the logical device is another one.
> 
> Signed-off-by: Henning Schild <henning.schild@siemens.com>
> ---
>  drivers/gpio/gpio-f7188x.c | 71 +++++++++++++++++++++++++++-----------
>  1 file changed, 51 insertions(+), 20 deletions(-)
> 
> diff --git a/drivers/gpio/gpio-f7188x.c b/drivers/gpio/gpio-f7188x.c
> index 18a3147f5a42..7b05ecc611e9 100644
> --- a/drivers/gpio/gpio-f7188x.c
> +++ b/drivers/gpio/gpio-f7188x.c
> @@ -1,6 +1,7 @@
>  // SPDX-License-Identifier: GPL-2.0-or-later
>  /*
>   * GPIO driver for Fintek Super-I/O F71869, F71869A, F71882, F71889 and F81866
> + * and Nuvoton Super-I/O NCT6116D
>   *
>   * Copyright (C) 2010-2013 LaCie
>   *
> @@ -22,13 +23,12 @@
>  #define SIO_LDSEL		0x07	/* Logical device select */
>  #define SIO_DEVID		0x20	/* Device ID (2 bytes) */
>  #define SIO_DEVREV		0x22	/* Device revision */
> -#define SIO_MANID		0x23	/* Fintek ID (2 bytes) */
>  
> -#define SIO_LD_GPIO		0x06	/* GPIO logical device */
>  #define SIO_UNLOCK_KEY		0x87	/* Key to enable Super-I/O */
>  #define SIO_LOCK_KEY		0xAA	/* Key to disable Super-I/O */
>  
> -#define SIO_FINTEK_ID		0x1934	/* Manufacturer ID */
> +#define SIO_LD_GPIO_FINTEK	0x06	/* GPIO logical device */
> +#define SIO_LD_GPIO_NUVOTON	0x07	/* GPIO logical device */

Please indulge me and add a new line here.

>  #define SIO_F71869_ID		0x0814	/* F71869 chipset ID */
>  #define SIO_F71869A_ID		0x1007	/* F71869A chipset ID */
>  #define SIO_F71882_ID		0x0541	/* F71882 chipset ID */
> @@ -37,7 +37,7 @@
>  #define SIO_F81866_ID		0x1010	/* F81866 chipset ID */
>  #define SIO_F81804_ID		0x1502  /* F81804 chipset ID, same for f81966 */
>  #define SIO_F81865_ID		0x0704	/* F81865 chipset ID */
> -
> +#define SIO_NCT6116D_ID		0xD283  /* NCT6116D chipset ID */
>  

... snip ...

> @@ -485,12 +516,8 @@ static int __init f7188x_find(int addr, struct f7188x_sio *sio)
>  		return err;
>  
>  	err = -ENODEV;
> -	devid = superio_inw(addr, SIO_MANID);
> -	if (devid != SIO_FINTEK_ID) {
> -		pr_debug(DRVNAME ": Not a Fintek device at 0x%08x\n", addr);
> -		goto err;
> -	}

Sorry for missing that at my first review. You can't remove this block
of code. This driver is poking around on the I2C bus, which is not
great. So we want to make sure as much as possible that we are speaking
to the right device.

Simon
Henning Schild Aug. 12, 2022, 10:23 a.m. UTC | #2
Am Fri, 12 Aug 2022 10:43:03 +0200
schrieb simon.guinot@sequanux.org:

> On Thu, Aug 11, 2022 at 05:39:05PM +0200, Henning Schild wrote:
> > Add GPIO support for Nuvoton NCT6116 chip. Nuvoton SuperIO chips are
> > very similar to the ones from Fintek. In other subsystems they also
> > share drivers and are called a family of drivers.
> > 
> > For the GPIO subsystem the only difference is that the direction
> > bit is reversed and that there is only one data bit per pin. On the
> > SuperIO level the logical device is another one.
> > 
> > Signed-off-by: Henning Schild <henning.schild@siemens.com>
> > ---
> >  drivers/gpio/gpio-f7188x.c | 71
> > +++++++++++++++++++++++++++----------- 1 file changed, 51
> > insertions(+), 20 deletions(-)
> > 
> > diff --git a/drivers/gpio/gpio-f7188x.c b/drivers/gpio/gpio-f7188x.c
> > index 18a3147f5a42..7b05ecc611e9 100644
> > --- a/drivers/gpio/gpio-f7188x.c
> > +++ b/drivers/gpio/gpio-f7188x.c
> > @@ -1,6 +1,7 @@
> >  // SPDX-License-Identifier: GPL-2.0-or-later
> >  /*
> >   * GPIO driver for Fintek Super-I/O F71869, F71869A, F71882,
> > F71889 and F81866
> > + * and Nuvoton Super-I/O NCT6116D
> >   *
> >   * Copyright (C) 2010-2013 LaCie
> >   *
> > @@ -22,13 +23,12 @@
> >  #define SIO_LDSEL		0x07	/* Logical device
> > select */ #define SIO_DEVID		0x20	/* Device ID
> > (2 bytes) */ #define SIO_DEVREV		0x22	/*
> > Device revision */ -#define SIO_MANID		0x23	/*
> > Fintek ID (2 bytes) */ 
> > -#define SIO_LD_GPIO		0x06	/* GPIO logical
> > device */ #define SIO_UNLOCK_KEY		0x87	/* Key
> > to enable Super-I/O */ #define SIO_LOCK_KEY
> > 0xAA	/* Key to disable Super-I/O */ 
> > -#define SIO_FINTEK_ID		0x1934	/* Manufacturer
> > ID */ +#define SIO_LD_GPIO_FINTEK	0x06	/* GPIO
> > logical device */ +#define SIO_LD_GPIO_NUVOTON	0x07
> > /* GPIO logical device */  
> 
> Please indulge me and add a new line here.

Mhh ... how about you write exactly how you would like to have that
define block. So we do not have taste issues in the next round.

> >  #define SIO_F71869_ID		0x0814	/* F71869
> > chipset ID */ #define SIO_F71869A_ID		0x1007
> > /* F71869A chipset ID */ #define SIO_F71882_ID
> > 0x0541	/* F71882 chipset ID */ @@ -37,7 +37,7 @@
> >  #define SIO_F81866_ID		0x1010	/* F81866
> > chipset ID */ #define SIO_F81804_ID		0x1502  /*
> > F81804 chipset ID, same for f81966 */ #define SIO_F81865_ID
> > 	0x0704	/* F81865 chipset ID */ -
> > +#define SIO_NCT6116D_ID		0xD283  /* NCT6116D chipset
> > ID */ 
> 
> ... snip ...
> 
> > @@ -485,12 +516,8 @@ static int __init f7188x_find(int addr, struct
> > f7188x_sio *sio) return err;
> >  
> >  	err = -ENODEV;
> > -	devid = superio_inw(addr, SIO_MANID);
> > -	if (devid != SIO_FINTEK_ID) {
> > -		pr_debug(DRVNAME ": Not a Fintek device at
> > 0x%08x\n", addr);
> > -		goto err;
> > -	}  
> 
> Sorry for missing that at my first review. You can't remove this block
> of code. This driver is poking around on the I2C bus, which is not
> great. So we want to make sure as much as possible that we are
> speaking to the right device.

Ok fair enough, we can make that more conservative and match the two
manufacturers and also make sure that not one can bring a chip id that
the other one uses for another chip.
A v4 is coming earliest in 1.5 weeks.

Henning

> Simon
Simon Guinot Aug. 12, 2022, 11:22 a.m. UTC | #3
On Fri, Aug 12, 2022 at 12:23:12PM +0200, Henning Schild wrote:
> Am Fri, 12 Aug 2022 10:43:03 +0200
> schrieb simon.guinot@sequanux.org:
> 
> > On Thu, Aug 11, 2022 at 05:39:05PM +0200, Henning Schild wrote:
> > > Add GPIO support for Nuvoton NCT6116 chip. Nuvoton SuperIO chips are
> > > very similar to the ones from Fintek. In other subsystems they also
> > > share drivers and are called a family of drivers.
> > > 
> > > For the GPIO subsystem the only difference is that the direction
> > > bit is reversed and that there is only one data bit per pin. On the
> > > SuperIO level the logical device is another one.
> > > 
> > > Signed-off-by: Henning Schild <henning.schild@siemens.com>
> > > ---
> > >  drivers/gpio/gpio-f7188x.c | 71
> > > +++++++++++++++++++++++++++----------- 1 file changed, 51
> > > insertions(+), 20 deletions(-)
> > > 
> > > diff --git a/drivers/gpio/gpio-f7188x.c b/drivers/gpio/gpio-f7188x.c
> > > index 18a3147f5a42..7b05ecc611e9 100644
> > > --- a/drivers/gpio/gpio-f7188x.c
> > > +++ b/drivers/gpio/gpio-f7188x.c
> > > @@ -1,6 +1,7 @@
> > >  // SPDX-License-Identifier: GPL-2.0-or-later
> > >  /*
> > >   * GPIO driver for Fintek Super-I/O F71869, F71869A, F71882,
> > > F71889 and F81866
> > > + * and Nuvoton Super-I/O NCT6116D
> > >   *
> > >   * Copyright (C) 2010-2013 LaCie
> > >   *
> > > @@ -22,13 +23,12 @@
> > >  #define SIO_LDSEL		0x07	/* Logical device
> > > select */ #define SIO_DEVID		0x20	/* Device ID
> > > (2 bytes) */ #define SIO_DEVREV		0x22	/*
> > > Device revision */ -#define SIO_MANID		0x23	/*
> > > Fintek ID (2 bytes) */ 
> > > -#define SIO_LD_GPIO		0x06	/* GPIO logical
> > > device */ #define SIO_UNLOCK_KEY		0x87	/* Key
> > > to enable Super-I/O */ #define SIO_LOCK_KEY
> > > 0xAA	/* Key to disable Super-I/O */ 
> > > -#define SIO_FINTEK_ID		0x1934	/* Manufacturer
> > > ID */ +#define SIO_LD_GPIO_FINTEK	0x06	/* GPIO
> > > logical device */ +#define SIO_LD_GPIO_NUVOTON	0x07
> > > /* GPIO logical device */  
> > 
> > Please indulge me and add a new line here.
> 
> Mhh ... how about you write exactly how you would like to have that
> define block. So we do not have taste issues in the next round.

Sure. Considering the manufacturer IDs you have to keep and add, I would
go with your original approach (i.e. a section per manufacturer). But
I would add extra new lines and comments and use a sligthly different
namming for the LD_GPIO definitions.

/*
 * Super-I/O registers
 */
#define SIO_LDSEL               0x07    /* Logical device select */
#define SIO_DEVID               0x20    /* Device ID (2 bytes) */
#define SIO_DEVREV              0x22    /* Device revision */
#define SIO_MANID               0x23    /* Fintek ID (2 bytes) */

#define SIO_UNLOCK_KEY          0x87    /* Key to enable Super-I/O */
#define SIO_LOCK_KEY            0xAA    /* Key to disable Super-I/O */

/*
 * Fintek devices.
 */
#define SIO_FINTEK_ID           0x1934  /* Manufacturer ID */

#define SIO_F71869_ID           0x0814  /* F71869 chipset ID */
#define SIO_F71869A_ID          0x1007  /* F71869A chipset ID */
#define SIO_F71882_ID           0x0541  /* F71882 chipset ID */
#define SIO_F71889_ID           0x0909  /* F71889 chipset ID */
#define SIO_F71889A_ID          0x1005  /* F71889A chipset ID */
#define SIO_F81866_ID           0x1010  /* F81866 chipset ID */
#define SIO_F81804_ID           0x1502  /* F81804 chipset ID, same for
					   f81966 */ 
#define SIO_F81865_ID           0x0704  /* F81865 chipset ID */

#define SIO_FINTEK_LD_GPIO      0x06    /* GPIO logical device */

/*
 * Nuvoton devices.
 */
#define SIO_NUVOTON_ID          0xXXXX  /* Manufacturer ID */

#define SIO_NCT6116D_ID         0xD283  /* NCT6116D chipset ID */

#define SIO_NUVOTON_LD_GPIO     0x07    /* GPIO logical device */

Please, note it is not only a matter of taste. New lines and comments
are really helping the reader. Also, note that I am not asking for this
change, only suggesting it.

> 
> > >  #define SIO_F71869_ID		0x0814	/* F71869
> > > chipset ID */ #define SIO_F71869A_ID		0x1007
> > > /* F71869A chipset ID */ #define SIO_F71882_ID
> > > 0x0541	/* F71882 chipset ID */ @@ -37,7 +37,7 @@
> > >  #define SIO_F81866_ID		0x1010	/* F81866
> > > chipset ID */ #define SIO_F81804_ID		0x1502  /*
> > > F81804 chipset ID, same for f81966 */ #define SIO_F81865_ID
> > > 	0x0704	/* F81865 chipset ID */ -
> > > +#define SIO_NCT6116D_ID		0xD283  /* NCT6116D chipset
> > > ID */ 
> > 
> > ... snip ...
> > 
> > > @@ -485,12 +516,8 @@ static int __init f7188x_find(int addr, struct
> > > f7188x_sio *sio) return err;
> > >  
> > >  	err = -ENODEV;
> > > -	devid = superio_inw(addr, SIO_MANID);
> > > -	if (devid != SIO_FINTEK_ID) {
> > > -		pr_debug(DRVNAME ": Not a Fintek device at
> > > 0x%08x\n", addr);
> > > -		goto err;
> > > -	}  
> > 
> > Sorry for missing that at my first review. You can't remove this block
> > of code. This driver is poking around on the I2C bus, which is not
> > great. So we want to make sure as much as possible that we are
> > speaking to the right device.
> 
> Ok fair enough, we can make that more conservative and match the two
> manufacturers and also make sure that not one can bring a chip id that
> the other one uses for another chip.
> A v4 is coming earliest in 1.5 weeks.

Great. Thanks for your patience.

Simon
Henning Schild Aug. 22, 2022, 4:01 p.m. UTC | #4
Am Fri, 12 Aug 2022 10:43:03 +0200
schrieb simon.guinot@sequanux.org:

> On Thu, Aug 11, 2022 at 05:39:05PM +0200, Henning Schild wrote:
> > Add GPIO support for Nuvoton NCT6116 chip. Nuvoton SuperIO chips are
> > very similar to the ones from Fintek. In other subsystems they also
> > share drivers and are called a family of drivers.
> > 
> > For the GPIO subsystem the only difference is that the direction
> > bit is reversed and that there is only one data bit per pin. On the
> > SuperIO level the logical device is another one.
> > 
> > Signed-off-by: Henning Schild <henning.schild@siemens.com>
> > ---
> >  drivers/gpio/gpio-f7188x.c | 71
> > +++++++++++++++++++++++++++----------- 1 file changed, 51
> > insertions(+), 20 deletions(-)
> > 
> > diff --git a/drivers/gpio/gpio-f7188x.c b/drivers/gpio/gpio-f7188x.c
> > index 18a3147f5a42..7b05ecc611e9 100644
> > --- a/drivers/gpio/gpio-f7188x.c
> > +++ b/drivers/gpio/gpio-f7188x.c
> > @@ -1,6 +1,7 @@
> >  // SPDX-License-Identifier: GPL-2.0-or-later
> >  /*
> >   * GPIO driver for Fintek Super-I/O F71869, F71869A, F71882,
> > F71889 and F81866
> > + * and Nuvoton Super-I/O NCT6116D
> >   *
> >   * Copyright (C) 2010-2013 LaCie
> >   *
> > @@ -22,13 +23,12 @@
> >  #define SIO_LDSEL		0x07	/* Logical device
> > select */ #define SIO_DEVID		0x20	/* Device ID
> > (2 bytes) */ #define SIO_DEVREV		0x22	/*
> > Device revision */ -#define SIO_MANID		0x23	/*
> > Fintek ID (2 bytes) */ 
> > -#define SIO_LD_GPIO		0x06	/* GPIO logical
> > device */ #define SIO_UNLOCK_KEY		0x87	/* Key
> > to enable Super-I/O */ #define SIO_LOCK_KEY
> > 0xAA	/* Key to disable Super-I/O */ 
> > -#define SIO_FINTEK_ID		0x1934	/* Manufacturer
> > ID */ +#define SIO_LD_GPIO_FINTEK	0x06	/* GPIO
> > logical device */ +#define SIO_LD_GPIO_NUVOTON	0x07
> > /* GPIO logical device */  
> 
> Please indulge me and add a new line here.
> 
> >  #define SIO_F71869_ID		0x0814	/* F71869
> > chipset ID */ #define SIO_F71869A_ID		0x1007
> > /* F71869A chipset ID */ #define SIO_F71882_ID
> > 0x0541	/* F71882 chipset ID */ @@ -37,7 +37,7 @@
> >  #define SIO_F81866_ID		0x1010	/* F81866
> > chipset ID */ #define SIO_F81804_ID		0x1502  /*
> > F81804 chipset ID, same for f81966 */ #define SIO_F81865_ID
> > 	0x0704	/* F81865 chipset ID */ -
> > +#define SIO_NCT6116D_ID		0xD283  /* NCT6116D chipset
> > ID */ 
> 
> ... snip ...
> 
> > @@ -485,12 +516,8 @@ static int __init f7188x_find(int addr, struct
> > f7188x_sio *sio) return err;
> >  
> >  	err = -ENODEV;
> > -	devid = superio_inw(addr, SIO_MANID);
> > -	if (devid != SIO_FINTEK_ID) {
> > -		pr_debug(DRVNAME ": Not a Fintek device at
> > 0x%08x\n", addr);
> > -		goto err;
> > -	}  
> 
> Sorry for missing that at my first review. You can't remove this block
> of code. This driver is poking around on the I2C bus, which is not
> great. So we want to make sure as much as possible that we are
> speaking to the right device.

Unfortunately the Nuvoton Super IOs do not have a global manufacturer
ID, just that chip ID in their global control registers.

So i think we should really just drop the checking of the manufacturer
ID all together, like proposed here. Or we could check manid+chipid for
fintek and only chipid for nuvoton (like i.e. all the wdt and hwmon
drivers for nuvoton do already).

In fact i will implement the best checking we can do, so match
manufacturer and chip where possible and drop to chip only where not.

Henning

> Simon
diff mbox series

Patch

diff --git a/drivers/gpio/gpio-f7188x.c b/drivers/gpio/gpio-f7188x.c
index 18a3147f5a42..7b05ecc611e9 100644
--- a/drivers/gpio/gpio-f7188x.c
+++ b/drivers/gpio/gpio-f7188x.c
@@ -1,6 +1,7 @@ 
 // SPDX-License-Identifier: GPL-2.0-or-later
 /*
  * GPIO driver for Fintek Super-I/O F71869, F71869A, F71882, F71889 and F81866
+ * and Nuvoton Super-I/O NCT6116D
  *
  * Copyright (C) 2010-2013 LaCie
  *
@@ -22,13 +23,12 @@ 
 #define SIO_LDSEL		0x07	/* Logical device select */
 #define SIO_DEVID		0x20	/* Device ID (2 bytes) */
 #define SIO_DEVREV		0x22	/* Device revision */
-#define SIO_MANID		0x23	/* Fintek ID (2 bytes) */
 
-#define SIO_LD_GPIO		0x06	/* GPIO logical device */
 #define SIO_UNLOCK_KEY		0x87	/* Key to enable Super-I/O */
 #define SIO_LOCK_KEY		0xAA	/* Key to disable Super-I/O */
 
-#define SIO_FINTEK_ID		0x1934	/* Manufacturer ID */
+#define SIO_LD_GPIO_FINTEK	0x06	/* GPIO logical device */
+#define SIO_LD_GPIO_NUVOTON	0x07	/* GPIO logical device */
 #define SIO_F71869_ID		0x0814	/* F71869 chipset ID */
 #define SIO_F71869A_ID		0x1007	/* F71869A chipset ID */
 #define SIO_F71882_ID		0x0541	/* F71882 chipset ID */
@@ -37,7 +37,7 @@ 
 #define SIO_F81866_ID		0x1010	/* F81866 chipset ID */
 #define SIO_F81804_ID		0x1502  /* F81804 chipset ID, same for f81966 */
 #define SIO_F81865_ID		0x0704	/* F81865 chipset ID */
-
+#define SIO_NCT6116D_ID		0xD283  /* NCT6116D chipset ID */
 
 enum chips {
 	f71869,
@@ -48,6 +48,7 @@  enum chips {
 	f81866,
 	f81804,
 	f81865,
+	nct6116d,
 };
 
 static const char * const f7188x_names[] = {
@@ -59,10 +60,12 @@  static const char * const f7188x_names[] = {
 	"f81866",
 	"f81804",
 	"f81865",
+	"nct6116d",
 };
 
 struct f7188x_sio {
 	int addr;
+	int device;
 	enum chips type;
 };
 
@@ -170,6 +173,9 @@  static int f7188x_gpio_set_config(struct gpio_chip *chip, unsigned offset,
 /* Output mode register (0:open drain 1:push-pull). */
 #define gpio_out_mode(base) (base + 3)
 
+#define gpio_dir_invert(type)	((type) == nct6116d)
+#define gpio_data_single(type)	((type) == nct6116d)
+
 static struct f7188x_gpio_bank f71869_gpio_bank[] = {
 	F7188X_GPIO_BANK(0, 6, 0xF0),
 	F7188X_GPIO_BANK(10, 8, 0xE0),
@@ -254,6 +260,17 @@  static struct f7188x_gpio_bank f81865_gpio_bank[] = {
 	F7188X_GPIO_BANK(60, 5, 0x90),
 };
 
+static struct f7188x_gpio_bank nct6116d_gpio_bank[] = {
+	F7188X_GPIO_BANK(0, 8, 0xE0),
+	F7188X_GPIO_BANK(10, 8, 0xE4),
+	F7188X_GPIO_BANK(20, 8, 0xE8),
+	F7188X_GPIO_BANK(30, 8, 0xEC),
+	F7188X_GPIO_BANK(40, 8, 0xF0),
+	F7188X_GPIO_BANK(50, 8, 0xF4),
+	F7188X_GPIO_BANK(60, 8, 0xF8),
+	F7188X_GPIO_BANK(70, 1, 0xFC),
+};
+
 static int f7188x_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
 {
 	int err;
@@ -264,13 +281,16 @@  static int f7188x_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
 	err = superio_enter(sio->addr);
 	if (err)
 		return err;
-	superio_select(sio->addr, SIO_LD_GPIO);
+	superio_select(sio->addr, sio->device);
 
 	dir = superio_inb(sio->addr, gpio_dir(bank->regbase));
 
 	superio_exit(sio->addr);
 
-	if (dir & 1 << offset)
+	if (gpio_dir_invert(sio->type))
+		dir = ~dir;
+
+	if (dir & BIT(offset))
 		return GPIO_LINE_DIRECTION_OUT;
 
 	return GPIO_LINE_DIRECTION_IN;
@@ -286,10 +306,14 @@  static int f7188x_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
 	err = superio_enter(sio->addr);
 	if (err)
 		return err;
-	superio_select(sio->addr, SIO_LD_GPIO);
+	superio_select(sio->addr, sio->device);
 
 	dir = superio_inb(sio->addr, gpio_dir(bank->regbase));
-	dir &= ~BIT(offset);
+
+	if (gpio_dir_invert(sio->type))
+		dir |= BIT(offset);
+	else
+		dir &= ~BIT(offset);
 	superio_outb(sio->addr, gpio_dir(bank->regbase), dir);
 
 	superio_exit(sio->addr);
@@ -307,11 +331,11 @@  static int f7188x_gpio_get(struct gpio_chip *chip, unsigned offset)
 	err = superio_enter(sio->addr);
 	if (err)
 		return err;
-	superio_select(sio->addr, SIO_LD_GPIO);
+	superio_select(sio->addr, sio->device);
 
 	dir = superio_inb(sio->addr, gpio_dir(bank->regbase));
 	dir = !!(dir & BIT(offset));
-	if (dir)
+	if (gpio_data_single(sio->type) || dir)
 		data = superio_inb(sio->addr, gpio_data_out(bank->regbase));
 	else
 		data = superio_inb(sio->addr, gpio_data_in(bank->regbase));
@@ -332,7 +356,7 @@  static int f7188x_gpio_direction_out(struct gpio_chip *chip,
 	err = superio_enter(sio->addr);
 	if (err)
 		return err;
-	superio_select(sio->addr, SIO_LD_GPIO);
+	superio_select(sio->addr, sio->device);
 
 	data_out = superio_inb(sio->addr, gpio_data_out(bank->regbase));
 	if (value)
@@ -342,7 +366,10 @@  static int f7188x_gpio_direction_out(struct gpio_chip *chip,
 	superio_outb(sio->addr, gpio_data_out(bank->regbase), data_out);
 
 	dir = superio_inb(sio->addr, gpio_dir(bank->regbase));
-	dir |= BIT(offset);
+	if (gpio_dir_invert(sio->type))
+		dir &= ~BIT(offset);
+	else
+		dir |= BIT(offset);
 	superio_outb(sio->addr, gpio_dir(bank->regbase), dir);
 
 	superio_exit(sio->addr);
@@ -360,7 +387,7 @@  static void f7188x_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 	err = superio_enter(sio->addr);
 	if (err)
 		return;
-	superio_select(sio->addr, SIO_LD_GPIO);
+	superio_select(sio->addr, sio->device);
 
 	data_out = superio_inb(sio->addr, gpio_data_out(bank->regbase));
 	if (value)
@@ -388,7 +415,7 @@  static int f7188x_gpio_set_config(struct gpio_chip *chip, unsigned offset,
 	err = superio_enter(sio->addr);
 	if (err)
 		return err;
-	superio_select(sio->addr, SIO_LD_GPIO);
+	superio_select(sio->addr, sio->device);
 
 	data = superio_inb(sio->addr, gpio_out_mode(bank->regbase));
 	if (param == PIN_CONFIG_DRIVE_OPEN_DRAIN)
@@ -449,6 +476,10 @@  static int f7188x_gpio_probe(struct platform_device *pdev)
 		data->nr_bank = ARRAY_SIZE(f81865_gpio_bank);
 		data->bank = f81865_gpio_bank;
 		break;
+	case nct6116d:
+		data->nr_bank = ARRAY_SIZE(nct6116d_gpio_bank);
+		data->bank = nct6116d_gpio_bank;
+		break;
 	default:
 		return -ENODEV;
 	}
@@ -485,12 +516,8 @@  static int __init f7188x_find(int addr, struct f7188x_sio *sio)
 		return err;
 
 	err = -ENODEV;
-	devid = superio_inw(addr, SIO_MANID);
-	if (devid != SIO_FINTEK_ID) {
-		pr_debug(DRVNAME ": Not a Fintek device at 0x%08x\n", addr);
-		goto err;
-	}
 
+	sio->device = SIO_LD_GPIO_FINTEK;
 	devid = superio_inw(addr, SIO_DEVID);
 	switch (devid) {
 	case SIO_F71869_ID:
@@ -517,8 +544,12 @@  static int __init f7188x_find(int addr, struct f7188x_sio *sio)
 	case SIO_F81865_ID:
 		sio->type = f81865;
 		break;
+	case SIO_NCT6116D_ID:
+		sio->device = SIO_LD_GPIO_NUVOTON;
+		sio->type = nct6116d;
+		break;
 	default:
-		pr_info(DRVNAME ": Unsupported Fintek device 0x%04x\n", devid);
+		pr_info(DRVNAME ": Unsupported device 0x%04x\n", devid);
 		goto err;
 	}
 	sio->addr = addr;