From 1bddd96cba03da0a14b3e5144e98c9a6ff17e983 Mon Sep 17 00:00:00 2001 From: Caesar Wang Date: Mon, 14 Mar 2016 16:01:54 +0800 Subject: [PATCH] net: arc_emac: support the phy reset for emac driver This patch adds to support the emac phy reset. Different boards may require different phy reset duration. Add property phy-reset-duration for emac driver, so that the boards that need a longer reset duration can specify it in their device tree. Signed-off-by: Heiko Stuebner Signed-off-by: Caesar Wang Cc: "David S. Miller" Cc: netdev@vger.kernel.org Cc: Alexander Kochetkov Cc: Sergei Shtylyov Signed-off-by: David S. Miller --- drivers/net/ethernet/arc/emac.h | 6 +++++ drivers/net/ethernet/arc/emac_mdio.c | 37 ++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/drivers/net/ethernet/arc/emac.h b/drivers/net/ethernet/arc/emac.h index dae1ac300a49..1a4040397a4b 100644 --- a/drivers/net/ethernet/arc/emac.h +++ b/drivers/net/ethernet/arc/emac.h @@ -102,6 +102,11 @@ struct buffer_state { DEFINE_DMA_UNMAP_LEN(len); }; +struct arc_emac_mdio_bus_data { + struct gpio_desc *reset_gpio; + int msec; +}; + /** * struct arc_emac_priv - Storage of EMAC's private information. * @dev: Pointer to the current device. @@ -131,6 +136,7 @@ struct arc_emac_priv { struct device *dev; struct phy_device *phy_dev; struct mii_bus *bus; + struct arc_emac_mdio_bus_data bus_data; void __iomem *regs; struct clk *clk; diff --git a/drivers/net/ethernet/arc/emac_mdio.c b/drivers/net/ethernet/arc/emac_mdio.c index d5ee986936da..caf704264eba 100644 --- a/drivers/net/ethernet/arc/emac_mdio.c +++ b/drivers/net/ethernet/arc/emac_mdio.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "emac.h" @@ -98,6 +99,25 @@ static int arc_mdio_write(struct mii_bus *bus, int phy_addr, return arc_mdio_complete_wait(priv); } +/** + * arc_mdio_reset + * @bus: points to the mii_bus structure + * Description: reset the MII bus + */ +int arc_mdio_reset(struct mii_bus *bus) +{ + struct arc_emac_priv *priv = bus->priv; + struct arc_emac_mdio_bus_data *data = &priv->bus_data; + + if (data->reset_gpio) { + gpiod_set_value_cansleep(data->reset_gpio, 1); + msleep(data->msec); + gpiod_set_value_cansleep(data->reset_gpio, 0); + } + + return 0; +} + /** * arc_mdio_probe - MDIO probe function. * @priv: Pointer to ARC EMAC private data structure. @@ -109,6 +129,8 @@ static int arc_mdio_write(struct mii_bus *bus, int phy_addr, */ int arc_mdio_probe(struct arc_emac_priv *priv) { + struct arc_emac_mdio_bus_data *data = &priv->bus_data; + struct device_node *np = priv->dev->of_node; struct mii_bus *bus; int error; @@ -122,6 +144,21 @@ int arc_mdio_probe(struct arc_emac_priv *priv) bus->name = "Synopsys MII Bus", bus->read = &arc_mdio_read; bus->write = &arc_mdio_write; + bus->reset = &arc_mdio_reset; + + /* optional reset-related properties */ + data->reset_gpio = devm_gpiod_get_optional(priv->dev, "phy-reset", + GPIOD_OUT_LOW); + if (IS_ERR(data->reset_gpio)) { + error = PTR_ERR(data->reset_gpio); + dev_err(priv->dev, "Failed to request gpio: %d\n", error); + return error; + } + + of_property_read_u32(np, "phy-reset-duration", &data->msec); + /* A sane reset duration should not be longer than 1s */ + if (data->msec > 1000) + data->msec = 1; snprintf(bus->id, MII_BUS_ID_SIZE, "%s", bus->name);