#include <linux/module.h>
#include <linux/of.h>
#include <linux/overflow.h>
#include <linux/regmap.h>
#include "realtek.h"
#include "realtek-mdio.h"
#include "rtl83xx.h"
#define REALTEK_MDIO_CTRL0_REG 31
#define REALTEK_MDIO_START_REG 29
#define REALTEK_MDIO_CTRL1_REG 21
#define REALTEK_MDIO_ADDRESS_REG 23
#define REALTEK_MDIO_DATA_WRITE_REG 24
#define REALTEK_MDIO_DATA_READ_REG 25
#define REALTEK_MDIO_START_OP 0xFFFF
#define REALTEK_MDIO_ADDR_OP 0x000E
#define REALTEK_MDIO_READ_OP 0x0001
#define REALTEK_MDIO_WRITE_OP 0x0003
static int realtek_mdio_write(void *ctx, u32 reg, u32 val)
{
struct realtek_priv *priv = ctx;
struct mii_bus *bus = priv->bus;
int ret;
mutex_lock(&bus->mdio_lock);
ret = bus->write(bus, priv->mdio_addr, REALTEK_MDIO_CTRL0_REG, REALTEK_MDIO_ADDR_OP);
if (ret)
goto out_unlock;
ret = bus->write(bus, priv->mdio_addr, REALTEK_MDIO_ADDRESS_REG, reg);
if (ret)
goto out_unlock;
ret = bus->write(bus, priv->mdio_addr, REALTEK_MDIO_DATA_WRITE_REG, val);
if (ret)
goto out_unlock;
ret = bus->write(bus, priv->mdio_addr, REALTEK_MDIO_CTRL1_REG, REALTEK_MDIO_WRITE_OP);
out_unlock:
mutex_unlock(&bus->mdio_lock);
return ret;
}
static int realtek_mdio_read(void *ctx, u32 reg, u32 *val)
{
struct realtek_priv *priv = ctx;
struct mii_bus *bus = priv->bus;
int ret;
mutex_lock(&bus->mdio_lock);
ret = bus->write(bus, priv->mdio_addr, REALTEK_MDIO_CTRL0_REG, REALTEK_MDIO_ADDR_OP);
if (ret)
goto out_unlock;
ret = bus->write(bus, priv->mdio_addr, REALTEK_MDIO_ADDRESS_REG, reg);
if (ret)
goto out_unlock;
ret = bus->write(bus, priv->mdio_addr, REALTEK_MDIO_CTRL1_REG, REALTEK_MDIO_READ_OP);
if (ret)
goto out_unlock;
ret = bus->read(bus, priv->mdio_addr, REALTEK_MDIO_DATA_READ_REG);
if (ret >= 0) {
*val = ret;
ret = 0;
}
out_unlock:
mutex_unlock(&bus->mdio_lock);
return ret;
}
static const struct realtek_interface_info realtek_mdio_info = {
.reg_read = realtek_mdio_read,
.reg_write = realtek_mdio_write,
};
int realtek_mdio_probe(struct mdio_device *mdiodev)
{
struct device *dev = &mdiodev->dev;
struct realtek_priv *priv;
int ret;
priv = rtl83xx_probe(dev, &realtek_mdio_info);
if (IS_ERR(priv))
return PTR_ERR(priv);
priv->bus = mdiodev->bus;
priv->mdio_addr = mdiodev->addr;
priv->write_reg_noack = realtek_mdio_write;
ret = rtl83xx_register_switch(priv);
if (ret) {
rtl83xx_remove(priv);
return ret;
}
return 0;
}
EXPORT_SYMBOL_NS_GPL(realtek_mdio_probe, "REALTEK_DSA");
void realtek_mdio_remove(struct mdio_device *mdiodev)
{
struct realtek_priv *priv = dev_get_drvdata(&mdiodev->dev);
if (!priv)
return;
rtl83xx_unregister_switch(priv);
rtl83xx_remove(priv);
}
EXPORT_SYMBOL_NS_GPL(realtek_mdio_remove, "REALTEK_DSA");
void realtek_mdio_shutdown(struct mdio_device *mdiodev)
{
struct realtek_priv *priv = dev_get_drvdata(&mdiodev->dev);
if (!priv)
return;
rtl83xx_shutdown(priv);
}
EXPORT_SYMBOL_NS_GPL(realtek_mdio_shutdown, "REALTEK_DSA");