xref: /linux/drivers/net/dsa/realtek/realtek-mdio.c (revision 1f8d99de1d1b4b3764203ae02db57041475dab84)
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 
41 static 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 
63 out_unlock:
64 	mutex_unlock(&bus->mdio_lock);
65 
66 	return ret;
67 }
68 
69 static 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 
95 out_unlock:
96 	mutex_unlock(&bus->mdio_lock);
97 
98 	return ret;
99 }
100 
101 static const struct regmap_config realtek_mdio_regmap_config = {
102 	.reg_bits = 10, /* A4..A0 R4..R0 */
103 	.val_bits = 16,
104 	.reg_stride = 1,
105 	/* PHY regs are at 0x8000 */
106 	.max_register = 0xffff,
107 	.reg_format_endian = REGMAP_ENDIAN_BIG,
108 	.reg_read = realtek_mdio_read,
109 	.reg_write = realtek_mdio_write,
110 	.cache_type = REGCACHE_NONE,
111 };
112 
113 static int realtek_mdio_probe(struct mdio_device *mdiodev)
114 {
115 	struct realtek_priv *priv;
116 	struct device *dev = &mdiodev->dev;
117 	const struct realtek_variant *var;
118 	int ret;
119 	struct device_node *np;
120 
121 	var = of_device_get_match_data(dev);
122 	if (!var)
123 		return -EINVAL;
124 
125 	priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL);
126 	if (!priv)
127 		return -ENOMEM;
128 
129 	priv->map = devm_regmap_init(dev, NULL, priv, &realtek_mdio_regmap_config);
130 	if (IS_ERR(priv->map)) {
131 		ret = PTR_ERR(priv->map);
132 		dev_err(dev, "regmap init failed: %d\n", ret);
133 		return ret;
134 	}
135 
136 	priv->mdio_addr = mdiodev->addr;
137 	priv->bus = mdiodev->bus;
138 	priv->dev = &mdiodev->dev;
139 	priv->chip_data = (void *)priv + sizeof(*priv);
140 
141 	priv->clk_delay = var->clk_delay;
142 	priv->cmd_read = var->cmd_read;
143 	priv->cmd_write = var->cmd_write;
144 	priv->ops = var->ops;
145 
146 	priv->write_reg_noack = realtek_mdio_write;
147 
148 	np = dev->of_node;
149 
150 	dev_set_drvdata(dev, priv);
151 
152 	/* TODO: if power is software controlled, set up any regulators here */
153 	priv->leds_disabled = of_property_read_bool(np, "realtek,disable-leds");
154 
155 	ret = priv->ops->detect(priv);
156 	if (ret) {
157 		dev_err(dev, "unable to detect switch\n");
158 		return ret;
159 	}
160 
161 	priv->ds = devm_kzalloc(dev, sizeof(*priv->ds), GFP_KERNEL);
162 	if (!priv->ds)
163 		return -ENOMEM;
164 
165 	priv->ds->dev = dev;
166 	priv->ds->num_ports = priv->num_ports;
167 	priv->ds->priv = priv;
168 	priv->ds->ops = var->ds_ops_mdio;
169 
170 	ret = dsa_register_switch(priv->ds);
171 	if (ret) {
172 		dev_err(priv->dev, "unable to register switch ret = %d\n", ret);
173 		return ret;
174 	}
175 
176 	return 0;
177 }
178 
179 static void realtek_mdio_remove(struct mdio_device *mdiodev)
180 {
181 	struct realtek_priv *priv = dev_get_drvdata(&mdiodev->dev);
182 
183 	if (!priv)
184 		return;
185 
186 	dsa_unregister_switch(priv->ds);
187 
188 	dev_set_drvdata(&mdiodev->dev, NULL);
189 }
190 
191 static void realtek_mdio_shutdown(struct mdio_device *mdiodev)
192 {
193 	struct realtek_priv *priv = dev_get_drvdata(&mdiodev->dev);
194 
195 	if (!priv)
196 		return;
197 
198 	dsa_switch_shutdown(priv->ds);
199 
200 	dev_set_drvdata(&mdiodev->dev, NULL);
201 }
202 
203 static const struct of_device_id realtek_mdio_of_match[] = {
204 #if IS_ENABLED(CONFIG_NET_DSA_REALTEK_RTL8366RB)
205 	{ .compatible = "realtek,rtl8366rb", .data = &rtl8366rb_variant, },
206 #endif
207 #if IS_ENABLED(CONFIG_NET_DSA_REALTEK_RTL8365MB)
208 	{ .compatible = "realtek,rtl8365mb", .data = &rtl8365mb_variant, },
209 	{ .compatible = "realtek,rtl8367s", .data = &rtl8365mb_variant, },
210 #endif
211 	{ /* sentinel */ },
212 };
213 MODULE_DEVICE_TABLE(of, realtek_mdio_of_match);
214 
215 static struct mdio_driver realtek_mdio_driver = {
216 	.mdiodrv.driver = {
217 		.name = "realtek-mdio",
218 		.of_match_table = of_match_ptr(realtek_mdio_of_match),
219 	},
220 	.probe  = realtek_mdio_probe,
221 	.remove = realtek_mdio_remove,
222 	.shutdown = realtek_mdio_shutdown,
223 };
224 
225 mdio_module_driver(realtek_mdio_driver);
226 
227 MODULE_AUTHOR("Luiz Angelo Daros de Luca <luizluca@gmail.com>");
228 MODULE_DESCRIPTION("Driver for Realtek ethernet switch connected via MDIO interface");
229 MODULE_LICENSE("GPL");
230