brintos

brintos / linux-shallow public Read only

0
0
Text · 4.9 KiB · 04b758e Raw
188 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/* Realtek MDIO interface driver3 *4 * ASICs we intend to support with this driver:5 *6 * RTL8366   - The original version, apparently7 * RTL8369   - Similar enough to have the same datsheet as RTL83668 * RTL8366RB - Probably reads out "RTL8366 revision B", has a quite9 *             different register layout from the other two10 * RTL8366S  - Is this "RTL8366 super"?11 * RTL8367   - Has an OpenWRT driver as well12 * RTL8368S  - Seems to be an alternative name for RTL8366RB13 * RTL8370   - Also uses SMI14 *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		3133#define REALTEK_MDIO_START_REG		2934#define REALTEK_MDIO_CTRL1_REG		2135#define REALTEK_MDIO_ADDRESS_REG	2336#define REALTEK_MDIO_DATA_WRITE_REG	2437#define REALTEK_MDIO_DATA_READ_REG	2538 39#define REALTEK_MDIO_START_OP		0xFFFF40#define REALTEK_MDIO_ADDR_OP		0x000E41#define REALTEK_MDIO_READ_OP		0x000142#define REALTEK_MDIO_WRITE_OP		0x000343 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 switch111 * @mdiodev: mdio_device to probe on.112 *113 * This function should be used as the .probe in an mdio_driver. After114 * calling the common probe function for both interfaces, it initializes the115 * values specific for MDIO-connected devices. Finally, it calls a common116 * 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 switch147 * @mdiodev: mdio_device to be removed.148 *149 * This function should be used as the .remove_new in an mdio_driver. First150 * 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 switch170 * @mdiodev: mdio_device shutting down.171 *172 * This function should be used as the .shutdown in a platform_driver. It calls173 * 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);188