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