[RFC 1/4] realtek: rtl8231 driver: dts option for GPIO state

Evan Jobling evan.jobling at mslsc.com.au
Tue Oct 22 03:21:25 PDT 2024


Default fan behaviour is broken on targets that use
GPIO's as fan output on the rtl8231 GPIO expander.
i.e. They rely on initial state of the GPIO set by
the bootloader.

This is due to the patch fixing output drivers,
due to untrusted bootloader.
i.e. This is by setting all GPIO's to input.
3810e897295cb66bc45a62bc2c0b70a01004fe3b
"realtek: ensure output drivers are enabled in RTL8231"

The specific example already merged is the HPE JG922A.
(hpe,1920-8g-poe-180w).

Add workaround by allowing for setting the GPIO state
by an array of GPIO pin, high/low state in device tree.

Additionally, send an info message that all GPIO's are
being set to input if no initial GPIO state is given.

Signed-of-by: Evan Jobling <evan.jobling at mslsc.com.au>
---
 .../files-6.6/drivers/gpio/gpio-rtl8231.c     | 53 ++++++++++++++++++-
 1 file changed, 51 insertions(+), 2 deletions(-)

diff --git a/target/linux/realtek/files-6.6/drivers/gpio/gpio-rtl8231.c b/target/linux/realtek/files-6.6/drivers/gpio/gpio-rtl8231.c
index 2821591a97..3bb5a1cb91 100644
--- a/target/linux/realtek/files-6.6/drivers/gpio/gpio-rtl8231.c
+++ b/target/linux/realtek/files-6.6/drivers/gpio/gpio-rtl8231.c
@@ -250,9 +250,14 @@ void rtl8231_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
 	rtl8231_pin_set(gpios, offset, value);
 }
 
-int rtl8231_init(struct rtl8231_gpios *gpios)
+int rtl8231_init(struct rtl8231_gpios *gpios, struct device_node *np )
 {
 	u32 ret;
+	/*return variables for GPIO init*/
+	int err;
+	int count;
+        /* local variables for gpio output init */
+        u32 gpio, data;
 
 	pr_info("%s called, MDIO bus ID: %d\n", __func__, gpios->smi_bus_id);
 
@@ -278,6 +283,50 @@ int rtl8231_init(struct rtl8231_gpios *gpios)
 	rtl8231_write(gpios, RTL8231_GPIO_DIR(16), 0xffff);
 	rtl8231_write(gpios, RTL8231_GPIO_PIN_SEL(32), 0x03ff);
 
+        /* Get/set default GPIO state from device tree as input/output driver
+        initialisation above resets GPIO configuration from bootloader.
+        Important to keep default fan behaviour in some switches.
+	Note we don't handle inverted logic GPIO's.*/
+	if ( (count = of_property_count_u32_elems(np, "gpio-output-pin-state") ) > 0 ) {
+		pr_info("%s, MDIO bus ID: %d: Set GPIO output initial state per pin\n", __func__, gpios->smi_bus_id);
+		/*we are going in pairs as we have an array which contains gpio number, gpio val.
+		The GPIO we want as output (0-36), and whether we want it to be high or low.
+		We should have less than 36 pairs of u32's and the number should be even.
+		i.e. we have a pair of u32's per gpio.*/
+		if (count > 36*2)
+			return -EINVAL;
+		if (count % 2)
+			return -EINVAL;
+
+		/*setup for array indexing*/
+		count = count / 2;
+
+		/*Loop through our array of gpio, val.
+		we should have count to be less that 36*/
+		for (u16 i = 0; i < count; i++) {
+			if ( (err = of_property_read_u32_index(np, "gpio-output-pin-state", i*2, &gpio)) )
+				return err;
+			if ( (err = of_property_read_u32_index(np, "gpio-output-pin-state", i*2+1, &data)) )
+				return err;
+
+			if (gpio > 36)
+				return -EINVAL;
+
+			if (data > 1)
+				return -EINVAL;
+
+			//set pin to output
+			if( (err = rtl8231_pin_dir(gpios, gpio, 0)) )
+				return err;
+			//set pin level
+			if( (err = rtl8231_pin_set(gpios, gpio, data)) )
+				return err;
+		}
+	}
+	else {
+		pr_info("%s, MDIO bus ID: %d: no gpio initial state, all GPIO's are forced input\n", __func__, gpios->smi_bus_id);
+	}
+
 	/* Set LED_Start to enable drivers for output mode */
 	rtl8231_write(gpios, RTL8231_LED_FUNC0, 1 << 1);
 
@@ -327,7 +376,7 @@ static int rtl8231_gpio_probe(struct platform_device *pdev)
 		return err;
 	}
 
-	err = rtl8231_init(gpios);
+	err = rtl8231_init(gpios, np);
 	if (err) {
 		dev_err(dev, "no device found at bus address %d\n", gpios->smi_bus_id);
 		return err;
-- 
2.39.5




More information about the openwrt-devel mailing list