generic: ar8327: add optional gpio reset support
authorPetr Štetiar <ynezz@true.cz>
Mon, 20 May 2019 22:18:29 +0000 (00:18 +0200)
committerChristian Marangi <ansuelsmth@gmail.com>
Fri, 11 Nov 2022 18:58:57 +0000 (19:58 +0100)
Some devices like Linksys EA8500 use designated GPIO to reset the switch
and if the switch isn't reset properly before first access, it can lead
to unusable switch after soft reboot of the device:

 libphy: GPIO Bitbanged MDIO: probed
 mdio_bus gpio-0: MDIO device at address 0 is missing.
 mdio_bus gpio-0: MDIO device at address 4 is missing.

Working case:

 libphy: GPIO Bitbanged MDIO: probed
 switch0: Atheros AR8337 rev. 2 switch registered on gpio-0

So this patch introduces reset GPIO, along with duration and active
high/low properties which fixes the problem.

Ref: https://github.com/openwrt/openwrt/pull/2047
Ref: https://bugs.openwrt.org/index.php?do=details&task_id=2168
Signed-off-by: Petr Štetiar <ynezz@true.cz>
[ remove invalid tested-by and reported-by ]
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
target/linux/generic/files/drivers/net/phy/ar8327.c

index 33131495598084e122582493e977c4585dea7c1c..825a9e0be94a9495c2bda3d72cc76662d9fa3caa 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/phy.h>
 #include <linux/lockdep.h>
 #include <linux/ar8216_platform.h>
+#include <linux/gpio/consumer.h>
 #include <linux/workqueue.h>
 #include <linux/of_device.h>
 #include <linux/leds.h>
@@ -609,6 +610,29 @@ ar8327_hw_config_pdata(struct ar8xxx_priv *priv,
 }
 
 #ifdef CONFIG_OF
+static void
+ar8327_gpio_reset(struct ar8xxx_priv *priv, struct device_node *np)
+{
+       int msec;
+       int reset_init;
+       bool active_high;
+       struct gpio_desc *reset;
+
+       active_high = of_property_read_bool(np, "reset-active-high");
+       reset_init = active_high ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW;
+       reset = devm_gpiod_get_optional(priv->pdev, "reset", reset_init);
+       if (!reset)
+               return;
+
+       of_property_read_u32(np, "reset-duration", &msec);
+       if (msec > 20)
+               msleep(msec);
+       else
+               usleep_range(msec * 1000, msec * 1000 + 1000);
+
+       gpiod_set_value_cansleep(reset, !active_high);
+}
+
 static int
 ar8327_hw_config_of(struct ar8xxx_priv *priv, struct device_node *np)
 {
@@ -617,6 +641,8 @@ ar8327_hw_config_of(struct ar8xxx_priv *priv, struct device_node *np)
        int len;
        int i;
 
+       ar8327_gpio_reset(priv, np);
+
        paddr = of_get_property(np, "qca,ar8327-initvals", &len);
        if (!paddr || len < (2 * sizeof(*paddr)))
                return -EINVAL;