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