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