realtek-mdio.c (7356B)
1// SPDX-License-Identifier: GPL-2.0+ 2/* Realtek MDIO interface driver 3 * 4 * ASICs we intend to support with this driver: 5 * 6 * RTL8366 - The original version, apparently 7 * RTL8369 - Similar enough to have the same datsheet as RTL8366 8 * RTL8366RB - Probably reads out "RTL8366 revision B", has a quite 9 * different register layout from the other two 10 * RTL8366S - Is this "RTL8366 super"? 11 * RTL8367 - Has an OpenWRT driver as well 12 * RTL8368S - Seems to be an alternative name for RTL8366RB 13 * RTL8370 - Also uses SMI 14 * 15 * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org> 16 * Copyright (C) 2010 Antti Seppälä <a.seppala@gmail.com> 17 * Copyright (C) 2010 Roman Yeryomin <roman@advem.lv> 18 * Copyright (C) 2011 Colin Leitner <colin.leitner@googlemail.com> 19 * Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org> 20 */ 21 22#include <linux/module.h> 23#include <linux/of_device.h> 24#include <linux/regmap.h> 25 26#include "realtek.h" 27 28/* Read/write via mdiobus */ 29#define REALTEK_MDIO_CTRL0_REG 31 30#define REALTEK_MDIO_START_REG 29 31#define REALTEK_MDIO_CTRL1_REG 21 32#define REALTEK_MDIO_ADDRESS_REG 23 33#define REALTEK_MDIO_DATA_WRITE_REG 24 34#define REALTEK_MDIO_DATA_READ_REG 25 35 36#define REALTEK_MDIO_START_OP 0xFFFF 37#define REALTEK_MDIO_ADDR_OP 0x000E 38#define REALTEK_MDIO_READ_OP 0x0001 39#define REALTEK_MDIO_WRITE_OP 0x0003 40 41static int realtek_mdio_write(void *ctx, u32 reg, u32 val) 42{ 43 struct realtek_priv *priv = ctx; 44 struct mii_bus *bus = priv->bus; 45 int ret; 46 47 mutex_lock(&bus->mdio_lock); 48 49 ret = bus->write(bus, priv->mdio_addr, REALTEK_MDIO_CTRL0_REG, REALTEK_MDIO_ADDR_OP); 50 if (ret) 51 goto out_unlock; 52 53 ret = bus->write(bus, priv->mdio_addr, REALTEK_MDIO_ADDRESS_REG, reg); 54 if (ret) 55 goto out_unlock; 56 57 ret = bus->write(bus, priv->mdio_addr, REALTEK_MDIO_DATA_WRITE_REG, val); 58 if (ret) 59 goto out_unlock; 60 61 ret = bus->write(bus, priv->mdio_addr, REALTEK_MDIO_CTRL1_REG, REALTEK_MDIO_WRITE_OP); 62 63out_unlock: 64 mutex_unlock(&bus->mdio_lock); 65 66 return ret; 67} 68 69static int realtek_mdio_read(void *ctx, u32 reg, u32 *val) 70{ 71 struct realtek_priv *priv = ctx; 72 struct mii_bus *bus = priv->bus; 73 int ret; 74 75 mutex_lock(&bus->mdio_lock); 76 77 ret = bus->write(bus, priv->mdio_addr, REALTEK_MDIO_CTRL0_REG, REALTEK_MDIO_ADDR_OP); 78 if (ret) 79 goto out_unlock; 80 81 ret = bus->write(bus, priv->mdio_addr, REALTEK_MDIO_ADDRESS_REG, reg); 82 if (ret) 83 goto out_unlock; 84 85 ret = bus->write(bus, priv->mdio_addr, REALTEK_MDIO_CTRL1_REG, REALTEK_MDIO_READ_OP); 86 if (ret) 87 goto out_unlock; 88 89 ret = bus->read(bus, priv->mdio_addr, REALTEK_MDIO_DATA_READ_REG); 90 if (ret >= 0) { 91 *val = ret; 92 ret = 0; 93 } 94 95out_unlock: 96 mutex_unlock(&bus->mdio_lock); 97 98 return ret; 99} 100 101static void realtek_mdio_lock(void *ctx) 102{ 103 struct realtek_priv *priv = ctx; 104 105 mutex_lock(&priv->map_lock); 106} 107 108static void realtek_mdio_unlock(void *ctx) 109{ 110 struct realtek_priv *priv = ctx; 111 112 mutex_unlock(&priv->map_lock); 113} 114 115static const struct regmap_config realtek_mdio_regmap_config = { 116 .reg_bits = 10, /* A4..A0 R4..R0 */ 117 .val_bits = 16, 118 .reg_stride = 1, 119 /* PHY regs are at 0x8000 */ 120 .max_register = 0xffff, 121 .reg_format_endian = REGMAP_ENDIAN_BIG, 122 .reg_read = realtek_mdio_read, 123 .reg_write = realtek_mdio_write, 124 .cache_type = REGCACHE_NONE, 125 .lock = realtek_mdio_lock, 126 .unlock = realtek_mdio_unlock, 127}; 128 129static const struct regmap_config realtek_mdio_nolock_regmap_config = { 130 .reg_bits = 10, /* A4..A0 R4..R0 */ 131 .val_bits = 16, 132 .reg_stride = 1, 133 /* PHY regs are at 0x8000 */ 134 .max_register = 0xffff, 135 .reg_format_endian = REGMAP_ENDIAN_BIG, 136 .reg_read = realtek_mdio_read, 137 .reg_write = realtek_mdio_write, 138 .cache_type = REGCACHE_NONE, 139 .disable_locking = true, 140}; 141 142static int realtek_mdio_probe(struct mdio_device *mdiodev) 143{ 144 struct realtek_priv *priv; 145 struct device *dev = &mdiodev->dev; 146 const struct realtek_variant *var; 147 struct regmap_config rc; 148 struct device_node *np; 149 int ret; 150 151 var = of_device_get_match_data(dev); 152 if (!var) 153 return -EINVAL; 154 155 priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL); 156 if (!priv) 157 return -ENOMEM; 158 159 mutex_init(&priv->map_lock); 160 161 rc = realtek_mdio_regmap_config; 162 rc.lock_arg = priv; 163 priv->map = devm_regmap_init(dev, NULL, priv, &rc); 164 if (IS_ERR(priv->map)) { 165 ret = PTR_ERR(priv->map); 166 dev_err(dev, "regmap init failed: %d\n", ret); 167 return ret; 168 } 169 170 rc = realtek_mdio_nolock_regmap_config; 171 priv->map_nolock = devm_regmap_init(dev, NULL, priv, &rc); 172 if (IS_ERR(priv->map_nolock)) { 173 ret = PTR_ERR(priv->map_nolock); 174 dev_err(dev, "regmap init failed: %d\n", ret); 175 return ret; 176 } 177 178 priv->mdio_addr = mdiodev->addr; 179 priv->bus = mdiodev->bus; 180 priv->dev = &mdiodev->dev; 181 priv->chip_data = (void *)priv + sizeof(*priv); 182 183 priv->clk_delay = var->clk_delay; 184 priv->cmd_read = var->cmd_read; 185 priv->cmd_write = var->cmd_write; 186 priv->ops = var->ops; 187 188 priv->write_reg_noack = realtek_mdio_write; 189 190 np = dev->of_node; 191 192 dev_set_drvdata(dev, priv); 193 194 /* TODO: if power is software controlled, set up any regulators here */ 195 priv->leds_disabled = of_property_read_bool(np, "realtek,disable-leds"); 196 197 priv->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); 198 if (IS_ERR(priv->reset)) { 199 dev_err(dev, "failed to get RESET GPIO\n"); 200 return PTR_ERR(priv->reset); 201 } 202 203 if (priv->reset) { 204 gpiod_set_value(priv->reset, 1); 205 dev_dbg(dev, "asserted RESET\n"); 206 msleep(REALTEK_HW_STOP_DELAY); 207 gpiod_set_value(priv->reset, 0); 208 msleep(REALTEK_HW_START_DELAY); 209 dev_dbg(dev, "deasserted RESET\n"); 210 } 211 212 ret = priv->ops->detect(priv); 213 if (ret) { 214 dev_err(dev, "unable to detect switch\n"); 215 return ret; 216 } 217 218 priv->ds = devm_kzalloc(dev, sizeof(*priv->ds), GFP_KERNEL); 219 if (!priv->ds) 220 return -ENOMEM; 221 222 priv->ds->dev = dev; 223 priv->ds->num_ports = priv->num_ports; 224 priv->ds->priv = priv; 225 priv->ds->ops = var->ds_ops_mdio; 226 227 ret = dsa_register_switch(priv->ds); 228 if (ret) { 229 dev_err(priv->dev, "unable to register switch ret = %d\n", ret); 230 return ret; 231 } 232 233 return 0; 234} 235 236static void realtek_mdio_remove(struct mdio_device *mdiodev) 237{ 238 struct realtek_priv *priv = dev_get_drvdata(&mdiodev->dev); 239 240 if (!priv) 241 return; 242 243 dsa_unregister_switch(priv->ds); 244 245 /* leave the device reset asserted */ 246 if (priv->reset) 247 gpiod_set_value(priv->reset, 1); 248 249 dev_set_drvdata(&mdiodev->dev, NULL); 250} 251 252static void realtek_mdio_shutdown(struct mdio_device *mdiodev) 253{ 254 struct realtek_priv *priv = dev_get_drvdata(&mdiodev->dev); 255 256 if (!priv) 257 return; 258 259 dsa_switch_shutdown(priv->ds); 260 261 dev_set_drvdata(&mdiodev->dev, NULL); 262} 263 264static const struct of_device_id realtek_mdio_of_match[] = { 265#if IS_ENABLED(CONFIG_NET_DSA_REALTEK_RTL8366RB) 266 { .compatible = "realtek,rtl8366rb", .data = &rtl8366rb_variant, }, 267#endif 268#if IS_ENABLED(CONFIG_NET_DSA_REALTEK_RTL8365MB) 269 { .compatible = "realtek,rtl8365mb", .data = &rtl8365mb_variant, }, 270#endif 271 { /* sentinel */ }, 272}; 273MODULE_DEVICE_TABLE(of, realtek_mdio_of_match); 274 275static struct mdio_driver realtek_mdio_driver = { 276 .mdiodrv.driver = { 277 .name = "realtek-mdio", 278 .of_match_table = of_match_ptr(realtek_mdio_of_match), 279 }, 280 .probe = realtek_mdio_probe, 281 .remove = realtek_mdio_remove, 282 .shutdown = realtek_mdio_shutdown, 283}; 284 285mdio_module_driver(realtek_mdio_driver); 286 287MODULE_AUTHOR("Luiz Angelo Daros de Luca <luizluca@gmail.com>"); 288MODULE_DESCRIPTION("Driver for Realtek ethernet switch connected via MDIO interface"); 289MODULE_LICENSE("GPL");