FILE
realtek-mdio.c
File preview with syntax highlighting.
linux-6.19.14/drivers/net/dsa/realtek/realtek-mdio.c
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.h> 24#include <linux/overflow.h> 25#include <linux/regmap.h> 26 27#include "realtek.h" 28#include "realtek-mdio.h" 29#include "rtl83xx.h" 30 31/* Read/write via mdiobus */ 32#define REALTEK_MDIO_CTRL0_REG 31 33#define REALTEK_MDIO_START_REG 29 34#define REALTEK_MDIO_CTRL1_REG 21 35#define REALTEK_MDIO_ADDRESS_REG 23 36#define REALTEK_MDIO_DATA_WRITE_REG 24 37#define REALTEK_MDIO_DATA_READ_REG 25 38 39#define REALTEK_MDIO_START_OP 0xFFFF 40#define REALTEK_MDIO_ADDR_OP 0x000E 41#define REALTEK_MDIO_READ_OP 0x0001 42#define REALTEK_MDIO_WRITE_OP 0x0003 43 44static int realtek_mdio_write(void *ctx, u32 reg, u32 val) 45{ 46 struct realtek_priv *priv = ctx; 47 struct mii_bus *bus = priv->bus; 48 int ret; 49 50 mutex_lock(&bus->mdio_lock); 51 52 ret = bus->write(bus, priv->mdio_addr, REALTEK_MDIO_CTRL0_REG, REALTEK_MDIO_ADDR_OP); 53 if (ret) 54 goto out_unlock; 55 56 ret = bus->write(bus, priv->mdio_addr, REALTEK_MDIO_ADDRESS_REG, reg); 57 if (ret) 58 goto out_unlock; 59 60 ret = bus->write(bus, priv->mdio_addr, REALTEK_MDIO_DATA_WRITE_REG, val); 61 if (ret) 62 goto out_unlock; 63 64 ret = bus->write(bus, priv->mdio_addr, REALTEK_MDIO_CTRL1_REG, REALTEK_MDIO_WRITE_OP); 65 66out_unlock: 67 mutex_unlock(&bus->mdio_lock); 68 69 return ret; 70} 71 72static int realtek_mdio_read(void *ctx, u32 reg, u32 *val) 73{ 74 struct realtek_priv *priv = ctx; 75 struct mii_bus *bus = priv->bus; 76 int ret; 77 78 mutex_lock(&bus->mdio_lock); 79 80 ret = bus->write(bus, priv->mdio_addr, REALTEK_MDIO_CTRL0_REG, REALTEK_MDIO_ADDR_OP); 81 if (ret) 82 goto out_unlock; 83 84 ret = bus->write(bus, priv->mdio_addr, REALTEK_MDIO_ADDRESS_REG, reg); 85 if (ret) 86 goto out_unlock; 87 88 ret = bus->write(bus, priv->mdio_addr, REALTEK_MDIO_CTRL1_REG, REALTEK_MDIO_READ_OP); 89 if (ret) 90 goto out_unlock; 91 92 ret = bus->read(bus, priv->mdio_addr, REALTEK_MDIO_DATA_READ_REG); 93 if (ret >= 0) { 94 *val = ret; 95 ret = 0; 96 } 97 98out_unlock: 99 mutex_unlock(&bus->mdio_lock); 100 101 return ret; 102} 103 104static const struct realtek_interface_info realtek_mdio_info = { 105 .reg_read = realtek_mdio_read, 106 .reg_write = realtek_mdio_write, 107}; 108 109/** 110 * realtek_mdio_probe() - Probe a platform device for an MDIO-connected switch 111 * @mdiodev: mdio_device to probe on. 112 * 113 * This function should be used as the .probe in an mdio_driver. After 114 * calling the common probe function for both interfaces, it initializes the 115 * values specific for MDIO-connected devices. Finally, it calls a common 116 * function to register the DSA switch. 117 * 118 * Context: Can sleep. Takes and releases priv->map_lock. 119 * Return: Returns 0 on success, a negative error on failure. 120 */ 121int realtek_mdio_probe(struct mdio_device *mdiodev) 122{ 123 struct device *dev = &mdiodev->dev; 124 struct realtek_priv *priv; 125 int ret; 126 127 priv = rtl83xx_probe(dev, &realtek_mdio_info); 128 if (IS_ERR(priv)) 129 return PTR_ERR(priv); 130 131 priv->bus = mdiodev->bus; 132 priv->mdio_addr = mdiodev->addr; 133 priv->write_reg_noack = realtek_mdio_write; 134 135 ret = rtl83xx_register_switch(priv); 136 if (ret) { 137 rtl83xx_remove(priv); 138 return ret; 139 } 140 141 return 0; 142} 143EXPORT_SYMBOL_NS_GPL(realtek_mdio_probe, "REALTEK_DSA"); 144 145/** 146 * realtek_mdio_remove() - Remove the driver of an MDIO-connected switch 147 * @mdiodev: mdio_device to be removed. 148 * 149 * This function should be used as the .remove in an mdio_driver. First 150 * it unregisters the DSA switch and then it calls the common remove function. 151 * 152 * Context: Can sleep. 153 * Return: Nothing. 154 */ 155void realtek_mdio_remove(struct mdio_device *mdiodev) 156{ 157 struct realtek_priv *priv = dev_get_drvdata(&mdiodev->dev); 158 159 if (!priv) 160 return; 161 162 rtl83xx_unregister_switch(priv); 163 164 rtl83xx_remove(priv); 165} 166EXPORT_SYMBOL_NS_GPL(realtek_mdio_remove, "REALTEK_DSA"); 167 168/** 169 * realtek_mdio_shutdown() - Shutdown the driver of a MDIO-connected switch 170 * @mdiodev: mdio_device shutting down. 171 * 172 * This function should be used as the .shutdown in a platform_driver. It calls 173 * the common shutdown function. 174 * 175 * Context: Can sleep. 176 * Return: Nothing. 177 */ 178void realtek_mdio_shutdown(struct mdio_device *mdiodev) 179{ 180 struct realtek_priv *priv = dev_get_drvdata(&mdiodev->dev); 181 182 if (!priv) 183 return; 184 185 rtl83xx_shutdown(priv); 186} 187EXPORT_SYMBOL_NS_GPL(realtek_mdio_shutdown, "REALTEK_DSA");
~/
Read-only file preview.