linux/drivers/net/ethernet/arc/emac_mdio.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (C) 2004-2013 Synopsys, Inc. (www.synopsys.com)
   4 *
   5 * MDIO implementation for ARC EMAC
   6 */
   7
   8#include <linux/delay.h>
   9#include <linux/of_mdio.h>
  10#include <linux/platform_device.h>
  11#include <linux/gpio/consumer.h>
  12
  13#include "emac.h"
  14
  15/* Number of seconds we wait for "MDIO complete" flag to appear */
  16#define ARC_MDIO_COMPLETE_POLL_COUNT    1
  17
  18/**
  19 * arc_mdio_complete_wait - Waits until MDIO transaction is completed.
  20 * @priv:       Pointer to ARC EMAC private data structure.
  21 *
  22 * returns:     0 on success, -ETIMEDOUT on a timeout.
  23 */
  24static int arc_mdio_complete_wait(struct arc_emac_priv *priv)
  25{
  26        unsigned int i;
  27
  28        for (i = 0; i < ARC_MDIO_COMPLETE_POLL_COUNT * 40; i++) {
  29                unsigned int status = arc_reg_get(priv, R_STATUS);
  30
  31                status &= MDIO_MASK;
  32
  33                if (status) {
  34                        /* Reset "MDIO complete" flag */
  35                        arc_reg_set(priv, R_STATUS, status);
  36                        return 0;
  37                }
  38
  39                msleep(25);
  40        }
  41
  42        return -ETIMEDOUT;
  43}
  44
  45/**
  46 * arc_mdio_read - MDIO interface read function.
  47 * @bus:        Pointer to MII bus structure.
  48 * @phy_addr:   Address of the PHY device.
  49 * @reg_num:    PHY register to read.
  50 *
  51 * returns:     The register contents on success, -ETIMEDOUT on a timeout.
  52 *
  53 * Reads the contents of the requested register from the requested PHY
  54 * address.
  55 */
  56static int arc_mdio_read(struct mii_bus *bus, int phy_addr, int reg_num)
  57{
  58        struct arc_emac_priv *priv = bus->priv;
  59        unsigned int value;
  60        int error;
  61
  62        arc_reg_set(priv, R_MDIO,
  63                    0x60020000 | (phy_addr << 23) | (reg_num << 18));
  64
  65        error = arc_mdio_complete_wait(priv);
  66        if (error < 0)
  67                return error;
  68
  69        value = arc_reg_get(priv, R_MDIO) & 0xffff;
  70
  71        dev_dbg(priv->dev, "arc_mdio_read(phy_addr=%i, reg_num=%x) = %x\n",
  72                phy_addr, reg_num, value);
  73
  74        return value;
  75}
  76
  77/**
  78 * arc_mdio_write - MDIO interface write function.
  79 * @bus:        Pointer to MII bus structure.
  80 * @phy_addr:   Address of the PHY device.
  81 * @reg_num:    PHY register to write to.
  82 * @value:      Value to be written into the register.
  83 *
  84 * returns:     0 on success, -ETIMEDOUT on a timeout.
  85 *
  86 * Writes the value to the requested register.
  87 */
  88static int arc_mdio_write(struct mii_bus *bus, int phy_addr,
  89                          int reg_num, u16 value)
  90{
  91        struct arc_emac_priv *priv = bus->priv;
  92
  93        dev_dbg(priv->dev,
  94                "arc_mdio_write(phy_addr=%i, reg_num=%x, value=%x)\n",
  95                phy_addr, reg_num, value);
  96
  97        arc_reg_set(priv, R_MDIO,
  98                    0x50020000 | (phy_addr << 23) | (reg_num << 18) | value);
  99
 100        return arc_mdio_complete_wait(priv);
 101}
 102
 103/**
 104 * arc_mdio_reset
 105 * @bus: points to the mii_bus structure
 106 * Description: reset the MII bus
 107 */
 108static int arc_mdio_reset(struct mii_bus *bus)
 109{
 110        struct arc_emac_priv *priv = bus->priv;
 111        struct arc_emac_mdio_bus_data *data = &priv->bus_data;
 112
 113        if (data->reset_gpio) {
 114                gpiod_set_value_cansleep(data->reset_gpio, 1);
 115                msleep(data->msec);
 116                gpiod_set_value_cansleep(data->reset_gpio, 0);
 117        }
 118
 119        return 0;
 120}
 121
 122/**
 123 * arc_mdio_probe - MDIO probe function.
 124 * @priv:       Pointer to ARC EMAC private data structure.
 125 *
 126 * returns:     0 on success, -ENOMEM when mdiobus_alloc
 127 * (to allocate memory for MII bus structure) fails.
 128 *
 129 * Sets up and registers the MDIO interface.
 130 */
 131int arc_mdio_probe(struct arc_emac_priv *priv)
 132{
 133        struct arc_emac_mdio_bus_data *data = &priv->bus_data;
 134        struct device_node *np = priv->dev->of_node;
 135        struct mii_bus *bus;
 136        int error;
 137
 138        bus = mdiobus_alloc();
 139        if (!bus)
 140                return -ENOMEM;
 141
 142        priv->bus = bus;
 143        bus->priv = priv;
 144        bus->parent = priv->dev;
 145        bus->name = "Synopsys MII Bus";
 146        bus->read = &arc_mdio_read;
 147        bus->write = &arc_mdio_write;
 148        bus->reset = &arc_mdio_reset;
 149
 150        /* optional reset-related properties */
 151        data->reset_gpio = devm_gpiod_get_optional(priv->dev, "phy-reset",
 152                                                   GPIOD_OUT_LOW);
 153        if (IS_ERR(data->reset_gpio)) {
 154                error = PTR_ERR(data->reset_gpio);
 155                dev_err(priv->dev, "Failed to request gpio: %d\n", error);
 156                return error;
 157        }
 158
 159        of_property_read_u32(np, "phy-reset-duration", &data->msec);
 160        /* A sane reset duration should not be longer than 1s */
 161        if (data->msec > 1000)
 162                data->msec = 1;
 163
 164        snprintf(bus->id, MII_BUS_ID_SIZE, "%s", bus->name);
 165
 166        error = of_mdiobus_register(bus, priv->dev->of_node);
 167        if (error) {
 168                dev_err(priv->dev, "cannot register MDIO bus %s\n", bus->name);
 169                mdiobus_free(bus);
 170                return error;
 171        }
 172
 173        return 0;
 174}
 175
 176/**
 177 * arc_mdio_remove - MDIO remove function.
 178 * @priv:       Pointer to ARC EMAC private data structure.
 179 *
 180 * Unregisters the MDIO and frees any associate memory for MII bus.
 181 */
 182int arc_mdio_remove(struct arc_emac_priv *priv)
 183{
 184        mdiobus_unregister(priv->bus);
 185        mdiobus_free(priv->bus);
 186        priv->bus = NULL;
 187
 188        return 0;
 189}
 190