net: dsa: realtek: support reset controller
authorLuiz Angelo Daros de Luca <luizluca@gmail.com>
Sun, 25 Feb 2024 16:29:55 +0000 (13:29 -0300)
committerDavid S. Miller <davem@davemloft.net>
Wed, 28 Feb 2024 08:21:41 +0000 (08:21 +0000)
Add support for resetting the device using a reset controller,
complementing the existing GPIO reset functionality (reset-gpios).

Although the reset is optional and the driver performs a soft reset
during setup, if the initial reset pin state was asserted, the driver
will not detect the device until the reset is deasserted.

Signed-off-by: Luiz Angelo Daros de Luca <luizluca@gmail.com>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Reviewed-by: Alvin Šipraga <alsi@bang-olufsen.dk>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/dsa/realtek/realtek.h
drivers/net/dsa/realtek/rtl83xx.c
drivers/net/dsa/realtek/rtl83xx.h

index b80bfde..e0b1aa0 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/platform_device.h>
 #include <linux/gpio/consumer.h>
 #include <net/dsa.h>
+#include <linux/reset.h>
 
 #define REALTEK_HW_STOP_DELAY          25      /* msecs */
 #define REALTEK_HW_START_DELAY         100     /* msecs */
@@ -48,6 +49,7 @@ struct rtl8366_vlan_4k {
 
 struct realtek_priv {
        struct device           *dev;
+       struct reset_control    *reset_ctl;
        struct gpio_desc        *reset;
        struct gpio_desc        *mdc;
        struct gpio_desc        *mdio;
index 8018737..d2e8768 100644 (file)
@@ -184,6 +184,13 @@ rtl83xx_probe(struct device *dev,
                                                    "realtek,disable-leds");
 
        /* TODO: if power is software controlled, set up any regulators here */
+       priv->reset_ctl = devm_reset_control_get_optional(dev, NULL);
+       if (IS_ERR(priv->reset_ctl)) {
+               ret = PTR_ERR(priv->reset_ctl);
+               dev_err_probe(dev, ret, "failed to get reset control\n");
+               return ERR_CAST(priv->reset_ctl);
+       }
+
        priv->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
        if (IS_ERR(priv->reset)) {
                dev_err(dev, "failed to get RESET GPIO\n");
@@ -192,11 +199,11 @@ rtl83xx_probe(struct device *dev,
 
        dev_set_drvdata(dev, priv);
 
-       if (priv->reset) {
-               gpiod_set_value(priv->reset, 1);
+       if (priv->reset_ctl || priv->reset) {
+               rtl83xx_reset_assert(priv);
                dev_dbg(dev, "asserted RESET\n");
                msleep(REALTEK_HW_STOP_DELAY);
-               gpiod_set_value(priv->reset, 0);
+               rtl83xx_reset_deassert(priv);
                msleep(REALTEK_HW_START_DELAY);
                dev_dbg(dev, "deasserted RESET\n");
        }
@@ -292,11 +299,36 @@ EXPORT_SYMBOL_NS_GPL(rtl83xx_shutdown, REALTEK_DSA);
 void rtl83xx_remove(struct realtek_priv *priv)
 {
        /* leave the device reset asserted */
-       if (priv->reset)
-               gpiod_set_value(priv->reset, 1);
+       rtl83xx_reset_assert(priv);
 }
 EXPORT_SYMBOL_NS_GPL(rtl83xx_remove, REALTEK_DSA);
 
+void rtl83xx_reset_assert(struct realtek_priv *priv)
+{
+       int ret;
+
+       ret = reset_control_assert(priv->reset_ctl);
+       if (ret)
+               dev_warn(priv->dev,
+                        "Failed to assert the switch reset control: %pe\n",
+                        ERR_PTR(ret));
+
+       gpiod_set_value(priv->reset, true);
+}
+
+void rtl83xx_reset_deassert(struct realtek_priv *priv)
+{
+       int ret;
+
+       ret = reset_control_deassert(priv->reset_ctl);
+       if (ret)
+               dev_warn(priv->dev,
+                        "Failed to deassert the switch reset control: %pe\n",
+                        ERR_PTR(ret));
+
+       gpiod_set_value(priv->reset, false);
+}
+
 MODULE_AUTHOR("Luiz Angelo Daros de Luca <luizluca@gmail.com>");
 MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
 MODULE_DESCRIPTION("Realtek DSA switches common module");
index 0ddff33..c8a0ff8 100644 (file)
@@ -18,5 +18,7 @@ int rtl83xx_register_switch(struct realtek_priv *priv);
 void rtl83xx_unregister_switch(struct realtek_priv *priv);
 void rtl83xx_shutdown(struct realtek_priv *priv);
 void rtl83xx_remove(struct realtek_priv *priv);
+void rtl83xx_reset_assert(struct realtek_priv *priv);
+void rtl83xx_reset_deassert(struct realtek_priv *priv);
 
 #endif /* _RTL83XX_H */