Skip to contentSkip to conversation

gpio-f7188x: Add F81886 gpio function

PATCH In review Peter Hung 3 participants 7 messages Jan 12, 2016 – Jan 13, 2016 GPIO

lore
Share & tools
lore

Peter Hung

author
#0 lore raw

cover gpio-f7188x: Add F81886 gpio function

Fintek F81886 SuperIO spec:
http://www.alldatasheet.com/datasheet-pdf/pdf/459085/FINTEK/F81866AD-I.html
The detail gpio check & configuration could be found within spec P126.

It controls gpio is the same with F7188x and has max 9 set of gpios. The gpio address is below:

	GPIO0x based: 0xf0
	GPIO1x based: 0xe0
	GPIO2x based: 0xd0
	GPIO3x based: 0xc0
	GPIO4x based: 0xb0
	GPIO5x based: 0xa0
	GPIO6x based: 0x90
	GPIO7x based: 0x80
	GPIO8x based: 0x88 <-- not 0x70.

The first patch only add basic structure for F81866 to use all unverified gpio, and second patch add filter function to make sure only enabled gpios are exported.

Peter Hung (2):
gpio-f7188x: add Fintek F81866 SuperIO support
gpio-f7188x: filter non-export gpio for F81866

 drivers/gpio/gpio-f7188x.c | 176 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 175 insertions(+), 1 deletion(-)
Signature · 1 line
1.9.1
author
#1 lore raw

PATCH 1/2 gpio-f7188x: add Fintek F81866 SuperIO support

add basic F81866 SuperIO gpio support

---
 drivers/gpio/gpio-f7188x.c | 23 ++++++++++++++++++++++-
 1 file changed, 22 insertions(+), 1 deletion(-)
drivers/gpio/gpio-f7188x.c +22 -1
index 5e3c4fa..a6a9641 100644
@@ -36,14 +36,16 @@
 #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_F81866_ID		0x1010	/* F81866 chipset ID */
 
-enum chips { f71869, f71869a, f71882fg, f71889f };
+enum chips { f71869, f71869a, f71882fg, f71889f, f81866 };
 
 static const char * const f7188x_names[] = {
 	"f71869",
 	"f71869a",
 	"f71882fg",
 	"f71889f",
+	"f81866",
 };
 
 struct f7188x_sio {
@@ -190,6 +192,18 @@ static struct f7188x_gpio_bank f71889_gpio_bank[] = {
 	F7188X_GPIO_BANK(70, 8, 0x80),
 };
 
+static struct f7188x_gpio_bank f81866_gpio_bank[] = {
+	F7188X_GPIO_BANK(0, 8, 0xF0),
+	F7188X_GPIO_BANK(10, 8, 0xE0),
+	F7188X_GPIO_BANK(20, 8, 0xD0),
+	F7188X_GPIO_BANK(30, 8, 0xC0),
+	F7188X_GPIO_BANK(40, 8, 0xB0),
+	F7188X_GPIO_BANK(50, 8, 0xA0),
+	F7188X_GPIO_BANK(60, 8, 0x90),
+	F7188X_GPIO_BANK(70, 8, 0x80),
+	F7188X_GPIO_BANK(80, 8, 0x88),
+};
+
 static int f7188x_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
 {
 	int err;
@@ -322,6 +336,10 @@ static int f7188x_gpio_probe(struct platform_device *pdev)
 		data->nr_bank = ARRAY_SIZE(f71889_gpio_bank);
 		data->bank = f71889_gpio_bank;
 		break;
+	case f81866:
+		data->nr_bank = ARRAY_SIZE(f81866_gpio_bank);
+		data->bank = f81866_gpio_bank;
+		break;
 	default:
 		return -ENODEV;
 	}
@@ -399,6 +417,9 @@ static int __init f7188x_find(int addr, struct f7188x_sio *sio)
 	case SIO_F71889_ID:
 		sio->type = f71889f;
 		break;
+	case SIO_F81866_ID:
+		sio->type = f81866;
+		break;
 	default:
 		pr_info(DRVNAME ": Unsupported Fintek device 0x%04x\n", devid);
 		goto err;
Signature · 1 line
1.9.1
author
#2 lore raw

PATCH 2/2 gpio-f7188x: filter non-export gpio for F81866

In reply to Peter Hung

Dont export gpios which not enabled by motherboard manufacturer.

---
 drivers/gpio/gpio-f7188x.c | 153 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 153 insertions(+)
drivers/gpio/gpio-f7188x.c +153 -0
index a6a9641..f7fe7aa 100644
@@ -38,6 +38,12 @@
 #define SIO_F71889_ID		0x0909	/* F71889 chipset ID */
 #define SIO_F81866_ID		0x1010	/* F81866 chipset ID */
 
+#define F81866_PORT_SEL_REG	0x27
+#define F81866_MULTI_FUN1_REG	0x28
+#define F81866_MULTI_FUN3_REG	0x29
+#define F81866_MULTI_FUN4_REG	0x2B
+#define F81866_GPIO_EN_REG	0x2C
+
 enum chips { f71869, f71869a, f71882fg, f71889f, f81866 };
 
 static const char * const f7188x_names[] = {
@@ -93,6 +99,15 @@ static inline void superio_outb(int base, int reg, int val)
 	outb(val, base + 1);
 }
 
+static inline void superio_mask_outb(int base, int reg, int mask, int val)
+{
+	u8 tmp;
+
+	tmp = superio_inb(base, reg);
+	tmp = (tmp & ~mask) | (val & mask);
+	superio_outb(base, reg, tmp);
+}
+
 static inline int superio_enter(int base)
 {
 	/* Don't step on other drivers' I/O space by accident. */
@@ -304,6 +319,125 @@ static void f7188x_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 	superio_exit(sio->addr);
 }
 
+static int f81866_verify_gpioset(int base, int set)
+{
+	int err;
+	u8 tmp;
+
+	err = superio_enter(base);
+	if (err)
+		return err;
+
+	err = -ENODEV;
+
+	switch (set) {
+	case 0:
+		superio_mask_outb(base, F81866_PORT_SEL_REG, BIT(3) | BIT(2) |
+				BIT(0), 0);
+		tmp = superio_inb(base, F81866_GPIO_EN_REG);
+		if ((tmp & 0x1f) != 0x1f)
+			break; /* one in GPIO00~GPIO04 is not enable */
+
+		tmp = superio_inb(base, F81866_MULTI_FUN1_REG);
+		if ((tmp & 0xc) != 0x0)
+			break;
+
+		err = 0; /* GPIO0x set is all enabled */
+		break;
+	case 1:
+		superio_mask_outb(base, F81866_PORT_SEL_REG, BIT(3) | BIT(2) |
+				BIT(0), BIT(2));
+		tmp = superio_inb(base, F81866_GPIO_EN_REG);
+		if ((tmp & 0xef) != 0xef)
+			break; /* one in GPIO10~GPIO17 is not enable */
+
+		tmp = superio_inb(base, F81866_MULTI_FUN3_REG);
+		if ((tmp & 0x03) != 0x00)
+			break; /* one in GPIO12~GPIO13 is not enable */
+
+		err = 0; /* GPIO1x set is all enabled */
+		break;
+	case 2:
+		superio_mask_outb(base, F81866_PORT_SEL_REG, BIT(3) | BIT(2) |
+				BIT(0), BIT(3));
+		tmp = superio_inb(base, F81866_GPIO_EN_REG);
+		if ((tmp & 0xff) != 0xff)
+			break; /* one in GPIO20~GPIO27 is not enable */
+
+		tmp = superio_inb(base, F81866_MULTI_FUN3_REG);
+		if ((tmp & 0x08) != 0x00)
+			break; /* GPIO20 is not enable */
+
+		err = 0; /* GPIO2x set is all enabled */
+		break;
+	case 3:
+		superio_mask_outb(base, F81866_PORT_SEL_REG, BIT(0), 0);
+		tmp = superio_inb(base, F81866_MULTI_FUN3_REG);
+		if ((tmp & 0x30) != 0x00)
+			break; /* GPIO3x is not enable */
+
+		err = 0; /* GPIO3x set is all enabled */
+		break;
+	case 4:
+		superio_mask_outb(base, F81866_PORT_SEL_REG, BIT(0), 0);
+		tmp = superio_inb(base, F81866_MULTI_FUN3_REG);
+		if ((tmp & 0xc0) != 0x00)
+			break; /* GPIO4x is not enable */
+
+		err = 0; /* GPIO4x set is all enabled */
+		break;
+	case 5:
+		superio_mask_outb(base, F81866_PORT_SEL_REG, BIT(3) | BIT(2),
+				0);
+		tmp = superio_inb(base, F81866_MULTI_FUN1_REG);
+		if ((tmp & 0x43) != 0x40)
+			break; /* GPIO5x is not enable */
+
+		err = 0; /* GPIO5x set is all enabled */
+		break;
+	case 6:
+		superio_mask_outb(base, F81866_PORT_SEL_REG, BIT(3) | BIT(2) |
+				BIT(0), 0);
+		tmp = superio_inb(base, F81866_MULTI_FUN1_REG);
+		if ((tmp & 0x4c) != 0x40)
+			break; /* GPIO60~64 is not enable */
+
+		tmp = superio_inb(base, F81866_MULTI_FUN4_REG);
+		if ((tmp & 0xe0) != 0xe0)
+			break; /* GPIO65~67 is not enable */
+
+		err = 0; /* GPIO6x set is all enabled */
+		break;
+	case 7:
+		superio_mask_outb(base, F81866_PORT_SEL_REG, BIT(3) | BIT(2) |
+				BIT(0), 0);
+		tmp = superio_inb(base, F81866_MULTI_FUN1_REG);
+		if ((tmp & 0x20) != 0x20)
+			break; /* GPIO7x is not enable */
+
+		tmp = superio_inb(base, F81866_MULTI_FUN4_REG);
+		if ((tmp & 0x01) != 0x00)
+			break; /* GPIO70 is not enable */
+
+		err = 0; /* GPIO7x set is all enabled */
+		break;
+	case 8:
+		superio_mask_outb(base, F81866_PORT_SEL_REG, BIT(3) | BIT(2),
+				0);
+		tmp = superio_inb(base, F81866_MULTI_FUN1_REG);
+		if ((tmp & 0x20) != 0x20)
+			break; /* GPIO8x is not enable */
+
+		err = 0; /* GPIO8x set is all enabled */
+		break;
+	default:
+		break;
+	}
+
+	superio_exit(base);
+	return err;
+}
+
 /*
  * Platform device and driver.
  */
@@ -351,6 +485,15 @@ static int f7188x_gpio_probe(struct platform_device *pdev)
 	for (i = 0; i < data->nr_bank; i++) {
 		struct f7188x_gpio_bank *bank = &data->bank[i];
 
+		/*
+		 * Dont export GPIO sysfs if pin set is not enable by MB
+		 * manufacturer.
+		 */
+		if (sio->type == f81866 && f81866_verify_gpioset(sio->addr, i))
+			continue;
+
+		dev_dbg(&pdev->dev, "%s: register GPIO%xx set\n", __func__,
+				bank->chip.base >> 4);
 		bank->chip.dev = &pdev->dev;
 		bank->data = data;
 
@@ -368,6 +511,11 @@ static int f7188x_gpio_probe(struct platform_device *pdev)
 err_gpiochip:
 	for (i = i - 1; i >= 0; i--) {
 		struct f7188x_gpio_bank *bank = &data->bank[i];
+
+		/* Some GPIO is not export, not need to remove */
+		if (!bank->data || !bank->chip.dev)
+			continue;
+
 		gpiochip_remove(&bank->chip);
 	}
 
@@ -381,6 +529,11 @@ static int f7188x_gpio_remove(struct platform_device *pdev)
 
 	for (i = 0; i < data->nr_bank; i++) {
 		struct f7188x_gpio_bank *bank = &data->bank[i];
+
+		/* Some GPIO is not export, not need to remove */
+		if (!bank->data || !bank->chip.dev)
+			continue;
+
 		gpiochip_remove(&bank->chip);
 	}
 
Signature · 1 line
1.9.1
#3 lore raw

Re: [PATCH 2/2] gpio-f7188x: filter non-export gpio for F81866

Quoted 1 line · Peter Hung

Dont export gpios which not enabled by motherboard manufacturer.

'Do not' or 'Don't'.

Perhaps 'GPIOs'.

'which are not enabled'

drivers/gpio/gpio-f7188x.c line 46

Quoted 6 lines
drivers/gpio/gpio-f7188x.c +6 -0
+#define F81866_PORT_SEL_REG    0x27
+#define F81866_MULTI_FUN1_REG  0x28
+#define F81866_MULTI_FUN3_REG  0x29
+#define F81866_MULTI_FUN4_REG  0x2B
+#define F81866_GPIO_EN_REG     0x2C
+

Move this before IDs block.

Use same prefix SIO_ and drop _REG, e.g.
SIO_F81866_PORT_SEL

FUN -> FN or FUNC (Personally I prefer shorter)

drivers/gpio/gpio-f7188x.c static inline void superio_outb(int base, int reg, int val) · line 102

Quoted 8 lines

enum chips { f71869, f71869a, f71882fg, f71889f, f81866 };

static const char * const f7188x_names[] = {

drivers/gpio/gpio-f7188x.c +1 -0
@@ -93,6 +99,15 @@ static inline void superio_outb(int base, int reg, int val)
        outb(val, base + 1);
 }
 
+static inline void superio_mask_outb(int base, int reg, int mask, int val)

Usually we named such as _update or _update_bits.
superio_update()

Quoted 12 lines
drivers/gpio/gpio-f7188x.c +8 -0
+{
+       u8 tmp;
+
+       tmp = superio_inb(base, reg);
+       tmp = (tmp & ~mask) | (val & mask);
+       superio_outb(base, reg, tmp);
+}
+
 static inline int superio_enter(int base)
 {
        /* Don't step on other drivers' I/O space by accident. */

drivers/gpio/gpio-f7188x.c static void f7188x_gpio_set(struct gpio_chip *chip, unsigned offset, int value) · line 322

Quoted 4 lines
drivers/gpio/gpio-f7188x.c +1 -0
@@ -304,6 +319,125 @@ static void f7188x_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
        superio_exit(sio->addr);
 }
 
+static int f81866_verify_gpioset(int base, int set)

…_gpio_verify() looks more suitable to the existing scheme.

Quoted 6 lines
drivers/gpio/gpio-f7188x.c +6 -0
+{
+       int err;
+       u8 tmp;
+
+       err = superio_enter(base);
+       if (err)

drivers/gpio/gpio-f7188x.c static void f7188x_gpio_set(struct gpio_chip *chip, unsigned offset, int value) · line 338

Quoted 10 lines
drivers/gpio/gpio-f7188x.c +10 -0
+               return err;
+
+       err = -ENODEV;
+
+       switch (set) {
+       case 0:
+               superio_mask_outb(base, F81866_PORT_SEL_REG, BIT(3) | BIT(2) |
+                               BIT(0), 0);
+               tmp = superio_inb(base, F81866_GPIO_EN_REG);
+               if ((tmp & 0x1f) != 0x1f)

Magic number.

drivers/gpio/gpio-f7188x.c static void f7188x_gpio_set(struct gpio_chip *chip, unsigned offset, int value) · line 342

Quoted 4 lines
drivers/gpio/gpio-f7188x.c +4 -0
+                       break; /* one in GPIO00~GPIO04 is not enable */
+
+               tmp = superio_inb(base, F81866_MULTI_FUN1_REG);
+               if ((tmp & 0xc) != 0x0)

Magic and no need to compare to != 0 explicitly.

drivers/gpio/gpio-f7188x.c static void f7188x_gpio_set(struct gpio_chip *chip, unsigned offset, int value) · line 345

Quoted 3 lines
drivers/gpio/gpio-f7188x.c +3 -0
+                       break;
+
+               err = 0; /* GPIO0x set is all enabled */

Maybe you can refactor this in better way.
Assign set of values in switch-case and do check after, only once.

Same comments are applicable to other cases below.

Quoted 99 lines
drivers/gpio/gpio-f7188x.c +95 -0
+               break;
+       case 1:
+               superio_mask_outb(base, F81866_PORT_SEL_REG, BIT(3) | BIT(2) |
+                               BIT(0), BIT(2));
+               tmp = superio_inb(base, F81866_GPIO_EN_REG);
+               if ((tmp & 0xef) != 0xef)
+                       break; /* one in GPIO10~GPIO17 is not enable */
+
+               tmp = superio_inb(base, F81866_MULTI_FUN3_REG);
+               if ((tmp & 0x03) != 0x00)
+                       break; /* one in GPIO12~GPIO13 is not enable */
+
+               err = 0; /* GPIO1x set is all enabled */
+               break;
+       case 2:
+               superio_mask_outb(base, F81866_PORT_SEL_REG, BIT(3) | BIT(2) |
+                               BIT(0), BIT(3));
+               tmp = superio_inb(base, F81866_GPIO_EN_REG);
+               if ((tmp & 0xff) != 0xff)
+                       break; /* one in GPIO20~GPIO27 is not enable */
+
+               tmp = superio_inb(base, F81866_MULTI_FUN3_REG);
+               if ((tmp & 0x08) != 0x00)
+                       break; /* GPIO20 is not enable */
+
+               err = 0; /* GPIO2x set is all enabled */
+               break;
+       case 3:
+               superio_mask_outb(base, F81866_PORT_SEL_REG, BIT(0), 0);
+               tmp = superio_inb(base, F81866_MULTI_FUN3_REG);
+               if ((tmp & 0x30) != 0x00)
+                       break; /* GPIO3x is not enable */
+
+               err = 0; /* GPIO3x set is all enabled */
+               break;
+       case 4:
+               superio_mask_outb(base, F81866_PORT_SEL_REG, BIT(0), 0);
+               tmp = superio_inb(base, F81866_MULTI_FUN3_REG);
+               if ((tmp & 0xc0) != 0x00)
+                       break; /* GPIO4x is not enable */
+
+               err = 0; /* GPIO4x set is all enabled */
+               break;
+       case 5:
+               superio_mask_outb(base, F81866_PORT_SEL_REG, BIT(3) | BIT(2),
+                               0);
+               tmp = superio_inb(base, F81866_MULTI_FUN1_REG);
+               if ((tmp & 0x43) != 0x40)
+                       break; /* GPIO5x is not enable */
+
+               err = 0; /* GPIO5x set is all enabled */
+               break;
+       case 6:
+               superio_mask_outb(base, F81866_PORT_SEL_REG, BIT(3) | BIT(2) |
+                               BIT(0), 0);
+               tmp = superio_inb(base, F81866_MULTI_FUN1_REG);
+               if ((tmp & 0x4c) != 0x40)
+                       break; /* GPIO60~64 is not enable */
+
+               tmp = superio_inb(base, F81866_MULTI_FUN4_REG);
+               if ((tmp & 0xe0) != 0xe0)
+                       break; /* GPIO65~67 is not enable */
+
+               err = 0; /* GPIO6x set is all enabled */
+               break;
+       case 7:
+               superio_mask_outb(base, F81866_PORT_SEL_REG, BIT(3) | BIT(2) |
+                               BIT(0), 0);
+               tmp = superio_inb(base, F81866_MULTI_FUN1_REG);
+               if ((tmp & 0x20) != 0x20)
+                       break; /* GPIO7x is not enable */
+
+               tmp = superio_inb(base, F81866_MULTI_FUN4_REG);
+               if ((tmp & 0x01) != 0x00)
+                       break; /* GPIO70 is not enable */
+
+               err = 0; /* GPIO7x set is all enabled */
+               break;
+       case 8:
+               superio_mask_outb(base, F81866_PORT_SEL_REG, BIT(3) | BIT(2),
+                               0);
+               tmp = superio_inb(base, F81866_MULTI_FUN1_REG);
+               if ((tmp & 0x20) != 0x20)
+                       break; /* GPIO8x is not enable */
+
+               err = 0; /* GPIO8x set is all enabled */
+               break;
+       default:
+               break;
+       }
+
+       superio_exit(base);
+       return err;
+}
+
 /*
  * Platform device and driver.
  */

drivers/gpio/gpio-f7188x.c static int f7188x_gpio_probe(struct platform_device *pdev) · line 489

Quoted 5 lines
drivers/gpio/gpio-f7188x.c +2 -0
@@ -351,6 +485,15 @@ static int f7188x_gpio_probe(struct platform_device *pdev)
        for (i = 0; i < data->nr_bank; i++) {
                struct f7188x_gpio_bank *bank = &data->bank[i];
 
+               /*
+                * Dont export GPIO sysfs if pin set is not enable by MB

Don't

drivers/gpio/gpio-f7188x.c static int f7188x_gpio_probe(struct platform_device *pdev) · line 495

Quoted 6 lines
drivers/gpio/gpio-f7188x.c +6 -0
+                * manufacturer.
+                */
+               if (sio->type == f81866 && f81866_verify_gpioset(sio->addr, i))
+                       continue;
+
+               dev_dbg(&pdev->dev, "%s: register GPIO%xx set\n", __func__,

%x ?

Quoted 26 lines
drivers/gpio/gpio-f7188x.c +11 -0
+                               bank->chip.base >> 4);
                bank->chip.dev = &pdev->dev;
                bank->data = data;
 
@@ -368,6 +511,11 @@ static int f7188x_gpio_probe(struct platform_device *pdev)
 err_gpiochip:
        for (i = i - 1; i >= 0; i--) {
                struct f7188x_gpio_bank *bank = &data->bank[i];
+
+               /* Some GPIO is not export, not need to remove */
+               if (!bank->data || !bank->chip.dev)
+                       continue;
+
                gpiochip_remove(&bank->chip);
        }
 
@@ -381,6 +529,11 @@ static int f7188x_gpio_remove(struct platform_device *pdev)
 
        for (i = 0; i < data->nr_bank; i++) {
                struct f7188x_gpio_bank *bank = &data->bank[i];
+
+               /* Some GPIO is not export, not need to remove */
+               if (!bank->data || !bank->chip.dev)
+                       continue;
+
                gpiochip_remove(&bank->chip);
Signature · 2 lines
With Best Regards,
Andy Shevchenko
author
#4 lore raw

Re: [PATCH 2/2] gpio-f7188x: filter non-export gpio for F81866

Hi Andy,

Andy Shevchenko 於 2016/1/12 下午 05:33 寫道:

Quoted 8 lines · Peter Hung
Quoted 1 line

Dont export gpios which not enabled by motherboard manufacturer.

'Do not' or 'Don't'.

Perhaps 'GPIOs'.

'which are not enabled'

OK.

Quoted 8 lines

drivers/gpio/gpio-f7188x.c line 46

Quoted 6 lines
drivers/gpio/gpio-f7188x.c +6 -0
+#define F81866_PORT_SEL_REG    0x27
+#define F81866_MULTI_FUN1_REG  0x28
+#define F81866_MULTI_FUN3_REG  0x29
+#define F81866_MULTI_FUN4_REG  0x2B
+#define F81866_GPIO_EN_REG     0x2C
+

Move this before IDs block.

OK.

Quoted 4 lines
Quoted 1 line

+static inline void superio_mask_outb(int base, int reg, int mask, int val)

Usually we named such as _update or _update_bits.
superio_update()

OK

Quoted 3 lines
Quoted 1 line

+static int f81866_verify_gpioset(int base, int set)

…_gpio_verify() looks more suitable to the existing scheme.

OK

Quoted 8 lines

drivers/gpio/gpio-f7188x.c static int f7188x_gpio_probe(struct platform_device *pdev) · line 495

Quoted 6 lines
drivers/gpio/gpio-f7188x.c +6 -0
+                * manufacturer.
+                */
+               if (sio->type == f81866 && f81866_verify_gpioset(sio->addr, i))
+                       continue;
+
+               dev_dbg(&pdev->dev, "%s: register GPIO%xx set\n", __func__,

%x ?

Sorry for misunderstand. This section will print debug message as GPIO3x set if GPIO3 set enabled, so I used %xx.

We are discussing about the patch with maintainer. It maybe drop if don't need filter.

Thanks for your advices.

Signature · 6 lines
With Best Regards,
Peter Hung
--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#5 lore raw

Re: [PATCH 2/2] gpio-f7188x: filter non-export gpio for F81866

In reply to Peter Hung
Quoted 3 lines · Peter Hung

Dont export gpios which not enabled by motherboard manufacturer.

Hi Peter,

Quoted 164 lines
---
 drivers/gpio/gpio-f7188x.c | 153 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 153 insertions(+)
drivers/gpio/gpio-f7188x.c +134 -0
index a6a9641..f7fe7aa 100644
@@ -38,6 +38,12 @@
 #define SIO_F71889_ID		0x0909	/* F71889 chipset ID */
 #define SIO_F81866_ID		0x1010	/* F81866 chipset ID */
 
+#define F81866_PORT_SEL_REG	0x27
+#define F81866_MULTI_FUN1_REG	0x28
+#define F81866_MULTI_FUN3_REG	0x29
+#define F81866_MULTI_FUN4_REG	0x2B
+#define F81866_GPIO_EN_REG	0x2C
+
 enum chips { f71869, f71869a, f71882fg, f71889f, f81866 };
 
 static const char * const f7188x_names[] = {
@@ -93,6 +99,15 @@ static inline void superio_outb(int base, int reg, int val)
 	outb(val, base + 1);
 }
 
+static inline void superio_mask_outb(int base, int reg, int mask, int val)
+{
+	u8 tmp;
+
+	tmp = superio_inb(base, reg);
+	tmp = (tmp & ~mask) | (val & mask);
+	superio_outb(base, reg, tmp);
+}
+
 static inline int superio_enter(int base)
 {
 	/* Don't step on other drivers' I/O space by accident. */
@@ -304,6 +319,125 @@ static void f7188x_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 	superio_exit(sio->addr);
 }
 
+static int f81866_verify_gpioset(int base, int set)
+{
+	int err;
+	u8 tmp;
+
+	err = superio_enter(base);
+	if (err)
+		return err;
+
+	err = -ENODEV;
+
+	switch (set) {
+	case 0:
+		superio_mask_outb(base, F81866_PORT_SEL_REG, BIT(3) | BIT(2) |
+				BIT(0), 0);
+		tmp = superio_inb(base, F81866_GPIO_EN_REG);
+		if ((tmp & 0x1f) != 0x1f)
+			break; /* one in GPIO00~GPIO04 is not enable */
+
+		tmp = superio_inb(base, F81866_MULTI_FUN1_REG);
+		if ((tmp & 0xc) != 0x0)
+			break;
+
+		err = 0; /* GPIO0x set is all enabled */
+		break;
+	case 1:
+		superio_mask_outb(base, F81866_PORT_SEL_REG, BIT(3) | BIT(2) |
+				BIT(0), BIT(2));
+		tmp = superio_inb(base, F81866_GPIO_EN_REG);
+		if ((tmp & 0xef) != 0xef)
+			break; /* one in GPIO10~GPIO17 is not enable */
+
+		tmp = superio_inb(base, F81866_MULTI_FUN3_REG);
+		if ((tmp & 0x03) != 0x00)
+			break; /* one in GPIO12~GPIO13 is not enable */
+
+		err = 0; /* GPIO1x set is all enabled */
+		break;
+	case 2:
+		superio_mask_outb(base, F81866_PORT_SEL_REG, BIT(3) | BIT(2) |
+				BIT(0), BIT(3));
+		tmp = superio_inb(base, F81866_GPIO_EN_REG);
+		if ((tmp & 0xff) != 0xff)
+			break; /* one in GPIO20~GPIO27 is not enable */
+
+		tmp = superio_inb(base, F81866_MULTI_FUN3_REG);
+		if ((tmp & 0x08) != 0x00)
+			break; /* GPIO20 is not enable */
+
+		err = 0; /* GPIO2x set is all enabled */
+		break;
+	case 3:
+		superio_mask_outb(base, F81866_PORT_SEL_REG, BIT(0), 0);
+		tmp = superio_inb(base, F81866_MULTI_FUN3_REG);
+		if ((tmp & 0x30) != 0x00)
+			break; /* GPIO3x is not enable */
+
+		err = 0; /* GPIO3x set is all enabled */
+		break;
+	case 4:
+		superio_mask_outb(base, F81866_PORT_SEL_REG, BIT(0), 0);
+		tmp = superio_inb(base, F81866_MULTI_FUN3_REG);
+		if ((tmp & 0xc0) != 0x00)
+			break; /* GPIO4x is not enable */
+
+		err = 0; /* GPIO4x set is all enabled */
+		break;
+	case 5:
+		superio_mask_outb(base, F81866_PORT_SEL_REG, BIT(3) | BIT(2),
+				0);
+		tmp = superio_inb(base, F81866_MULTI_FUN1_REG);
+		if ((tmp & 0x43) != 0x40)
+			break; /* GPIO5x is not enable */
+
+		err = 0; /* GPIO5x set is all enabled */
+		break;
+	case 6:
+		superio_mask_outb(base, F81866_PORT_SEL_REG, BIT(3) | BIT(2) |
+				BIT(0), 0);
+		tmp = superio_inb(base, F81866_MULTI_FUN1_REG);
+		if ((tmp & 0x4c) != 0x40)
+			break; /* GPIO60~64 is not enable */
+
+		tmp = superio_inb(base, F81866_MULTI_FUN4_REG);
+		if ((tmp & 0xe0) != 0xe0)
+			break; /* GPIO65~67 is not enable */
+
+		err = 0; /* GPIO6x set is all enabled */
+		break;
+	case 7:
+		superio_mask_outb(base, F81866_PORT_SEL_REG, BIT(3) | BIT(2) |
+				BIT(0), 0);
+		tmp = superio_inb(base, F81866_MULTI_FUN1_REG);
+		if ((tmp & 0x20) != 0x20)
+			break; /* GPIO7x is not enable */
+
+		tmp = superio_inb(base, F81866_MULTI_FUN4_REG);
+		if ((tmp & 0x01) != 0x00)
+			break; /* GPIO70 is not enable */
+
+		err = 0; /* GPIO7x set is all enabled */
+		break;
+	case 8:
+		superio_mask_outb(base, F81866_PORT_SEL_REG, BIT(3) | BIT(2),
+				0);
+		tmp = superio_inb(base, F81866_MULTI_FUN1_REG);
+		if ((tmp & 0x20) != 0x20)
+			break; /* GPIO8x is not enable */
+
+		err = 0; /* GPIO8x set is all enabled */
+		break;
+	default:
+		break;
+	}
+
+	superio_exit(base);
+	return err;
+}
+
 /*
  * Platform device and driver.
  */

drivers/gpio/gpio-f7188x.c static int f7188x_gpio_probe(struct platform_device *pdev) · line 490

Quoted 6 lines
drivers/gpio/gpio-f7188x.c +3 -0
@@ -351,6 +485,15 @@ static int f7188x_gpio_probe(struct platform_device *pdev)
 	for (i = 0; i < data->nr_bank; i++) {
 		struct f7188x_gpio_bank *bank = &data->bank[i];
 
+		/*
+		 * Dont export GPIO sysfs if pin set is not enable by MB
+		 * manufacturer.

What does MB stands for ?

drivers/gpio/gpio-f7188x.c static int f7188x_gpio_probe(struct platform_device *pdev) · line 493

Quoted 3 lines
drivers/gpio/gpio-f7188x.c +3 -0
+		 */
+		if (sio->type == f81866 && f81866_verify_gpioset(sio->addr, i))
+			continue;

This whole filtering mechanism relies on the fact that the multiplexing configuration has been correctly applied by the BIOS (if applied at all). But I wonder if it is often the case. For example, I have several boards for which it is not true. And to make the GPIOs available, I need first to fix the multiplexing pin configuration of the Super I/O.

Maybe it would be more correct to rely on the hardware description of a board (Device Tree or ACPI) to decide which GPIO bank can be enabled or not.

Simon

author
#6 lore raw

Re: [PATCH 2/2] gpio-f7188x: filter non-export gpio for F81866

Hi Simon,

Quoted 9 lines

drivers/gpio/gpio-f7188x.c static int f7188x_gpio_probe(struct platform_device *pdev) · line 490

Quoted 7 lines
drivers/gpio/gpio-f7188x.c +3 -0
@@ -351,6 +485,15 @@ static int f7188x_gpio_probe(struct platform_device *pdev)
  	for (i = 0; i < data->nr_bank; i++) {
  		struct f7188x_gpio_bank *bank = &data->bank[i];
 
+		/*
+		 * Dont export GPIO sysfs if pin set is not enable by MB
+		 * manufacturer.

What does MB stands for ?

The MB is stands for "Motherboard", Due to the limit of 80 words length, I use the abbreviation.

Quoted 10 lines

drivers/gpio/gpio-f7188x.c static int f7188x_gpio_probe(struct platform_device *pdev) · line 493

Quoted 3 lines
drivers/gpio/gpio-f7188x.c +3 -0
+		 */
+		if (sio->type == f81866 && f81866_verify_gpioset(sio->addr, i))
+			continue;

This whole filtering mechanism relies on the fact that the multiplexing configuration has been correctly applied by the BIOS (if applied at all). But I wonder if it is often the case. For example, I have several boards for which it is not true. And to make the GPIOs available, I need first to fix the multiplexing pin configuration of the Super I/O.

Quoted 3 lines

Maybe it would be more correct to rely on the hardware description of a board (Device Tree or ACPI) to decide which GPIO bank can be enabled or not.

That's good for control by Device Tree or ACPI.

IMO, we shouldn't export GPIOs not enabled if the BIOS had written wrong configuration to SuperIO, but it's only my opinion. Should I do filter for this?

Thanks for your advices.

Signature · 2 lines
With Best Regards,
Peter Hung