Commit 56998aa6 authored by Luiz Angelo Daros de Luca's avatar Luiz Angelo Daros de Luca Committed by David S. Miller
Browse files

net: dsa: realtek: support reset controller



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: default avatarLuiz Angelo Daros de Luca <luizluca@gmail.com>
Reviewed-by: default avatarLinus Walleij <linus.walleij@linaro.org>
Reviewed-by: default avatarAlvin Šipraga <alsi@bang-olufsen.dk>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 5fc2d68f
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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;
+37 −5
Original line number Diff line number Diff line
@@ -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");
+2 −0
Original line number Diff line number Diff line
@@ -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 */