openwrt/target/linux/ar71xx/patches-4.9/902-at803x-add-reset-gpio-pdata.patch
Daniel Golle 20c64dabb6 kernel: re-add patch for AT8032 Ethernet PHY
The patch was wrongly removed by a kernel version bump to 4.9.106 in
the believe that it was merged upstream thow it wasn't. This lead to
unrecoverable link losses on devices which use those PHYs such as
many ubnt single-port CPEs.

Fixes: 6f8eb1b50f ("kernel: bump 4.9 to 4.9.106 for 18.06")
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
(cherry picked from commit a497e47762)
2018-07-31 05:39:49 +02:00

69 lines
2.1 KiB
Diff

Add support for configuring AT803x GPIO reset via platform data.
This is necessary, because ath79 is not converted to device tree yet.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/include/linux/platform_data/phy-at803x.h
+++ b/include/linux/platform_data/phy-at803x.h
@@ -6,6 +6,8 @@ struct at803x_platform_data {
int enable_rgmii_tx_delay:1;
int enable_rgmii_rx_delay:1;
int fixup_rgmii_tx_delay:1;
+ int has_reset_gpio:1;
+ int reset_gpio;
};
#endif /* _PHY_AT803X_PDATA_H */
--- a/drivers/net/phy/at803x.c
+++ b/drivers/net/phy/at803x.c
@@ -264,6 +264,7 @@ static int at803x_resume(struct phy_devi
static int at803x_probe(struct phy_device *phydev)
{
+ struct at803x_platform_data *pdata;
struct device *dev = &phydev->mdio.dev;
struct at803x_priv *priv;
struct gpio_desc *gpiod_reset;
@@ -276,6 +277,12 @@ static int at803x_probe(struct phy_devic
phydev->drv->phy_id != ATH8032_PHY_ID)
goto does_not_require_reset_workaround;
+ pdata = dev_get_platdata(dev);
+ if (pdata && pdata->has_reset_gpio) {
+ devm_gpio_request(dev, pdata->reset_gpio, "reset");
+ gpio_direction_output(pdata->reset_gpio, 1);
+ }
+
gpiod_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(gpiod_reset))
return PTR_ERR(gpiod_reset);
@@ -407,15 +414,23 @@ static void at803x_link_change_notify(st
* cannot recover from by software.
*/
if (phydev->state == PHY_NOLINK) {
- if (priv->gpiod_reset && !priv->phy_reset) {
+ if ((priv->gpiod_reset || (pdata && pdata->has_reset_gpio)) &&
+ !priv->phy_reset) {
struct at803x_context context;
at803x_context_save(phydev, &context);
- gpiod_set_value(priv->gpiod_reset, 1);
- msleep(1);
- gpiod_set_value(priv->gpiod_reset, 0);
- msleep(1);
+ if (pdata && pdata->has_reset_gpio) {
+ gpio_set_value_cansleep(pdata->reset_gpio, 0);
+ msleep(1);
+ gpio_set_value_cansleep(pdata->reset_gpio, 1);
+ msleep(1);
+ } else {
+ gpiod_set_value(priv->gpiod_reset, 1);
+ msleep(1);
+ gpiod_set_value(priv->gpiod_reset, 0);
+ msleep(1);
+ }
at803x_context_restore(phydev, &context);