1// SPDX-License-Identifier: GPL-2.0+
2
3#include <linux/module.h>
4#include <linux/regmap.h>
5#include <linux/of_mdio.h>
6
7#include "realtek.h"
8#include "rtl83xx.h"
9
10/**
11 * rtl83xx_lock() - Locks the mutex used by regmaps
12 * @ctx: realtek_priv pointer
13 *
14 * This function is passed to regmap to be used as the lock function.
15 * It is also used externally to block regmap before executing multiple
16 * operations that must happen in sequence (which will use
17 * realtek_priv.map_nolock instead).
18 *
19 * Context: Can sleep. Holds priv->map_lock lock.
20 * Return: nothing
21 */
22void rtl83xx_lock(void *ctx)
23{
24 struct realtek_priv *priv = ctx;
25
26 mutex_lock(&priv->map_lock);
27}
28EXPORT_SYMBOL_NS_GPL(rtl83xx_lock, REALTEK_DSA);
29
30/**
31 * rtl83xx_unlock() - Unlocks the mutex used by regmaps
32 * @ctx: realtek_priv pointer
33 *
34 * This function unlocks the lock acquired by rtl83xx_lock.
35 *
36 * Context: Releases priv->map_lock lock.
37 * Return: nothing
38 */
39void rtl83xx_unlock(void *ctx)
40{
41 struct realtek_priv *priv = ctx;
42
43 mutex_unlock(lock: &priv->map_lock);
44}
45EXPORT_SYMBOL_NS_GPL(rtl83xx_unlock, REALTEK_DSA);
46
47static int rtl83xx_user_mdio_read(struct mii_bus *bus, int addr, int regnum)
48{
49 struct realtek_priv *priv = bus->priv;
50
51 return priv->ops->phy_read(priv, addr, regnum);
52}
53
54static int rtl83xx_user_mdio_write(struct mii_bus *bus, int addr, int regnum,
55 u16 val)
56{
57 struct realtek_priv *priv = bus->priv;
58
59 return priv->ops->phy_write(priv, addr, regnum, val);
60}
61
62/**
63 * rtl83xx_setup_user_mdio() - register the user mii bus driver
64 * @ds: DSA switch associated with this user_mii_bus
65 *
66 * Registers the MDIO bus for built-in Ethernet PHYs, and associates it with
67 * the mandatory 'mdio' child OF node of the switch.
68 *
69 * Context: Can sleep.
70 * Return: 0 on success, negative value for failure.
71 */
72int rtl83xx_setup_user_mdio(struct dsa_switch *ds)
73{
74 struct realtek_priv *priv = ds->priv;
75 struct device_node *mdio_np;
76 struct mii_bus *bus;
77 int ret = 0;
78
79 mdio_np = of_get_child_by_name(node: priv->dev->of_node, name: "mdio");
80 if (!mdio_np) {
81 dev_err(priv->dev, "no MDIO bus node\n");
82 return -ENODEV;
83 }
84
85 bus = devm_mdiobus_alloc(dev: priv->dev);
86 if (!bus) {
87 ret = -ENOMEM;
88 goto err_put_node;
89 }
90
91 bus->priv = priv;
92 bus->name = "Realtek user MII";
93 bus->read = rtl83xx_user_mdio_read;
94 bus->write = rtl83xx_user_mdio_write;
95 snprintf(buf: bus->id, MII_BUS_ID_SIZE, fmt: "%s:user_mii", dev_name(dev: priv->dev));
96 bus->parent = priv->dev;
97
98 ret = devm_of_mdiobus_register(dev: priv->dev, mdio: bus, np: mdio_np);
99 if (ret) {
100 dev_err(priv->dev, "unable to register MDIO bus %s\n",
101 bus->id);
102 goto err_put_node;
103 }
104
105 priv->user_mii_bus = bus;
106
107err_put_node:
108 of_node_put(node: mdio_np);
109
110 return ret;
111}
112EXPORT_SYMBOL_NS_GPL(rtl83xx_setup_user_mdio, REALTEK_DSA);
113
114/**
115 * rtl83xx_probe() - probe a Realtek switch
116 * @dev: the device being probed
117 * @interface_info: specific management interface info.
118 *
119 * This function initializes realtek_priv and reads data from the device tree
120 * node. The switch is hard resetted if a method is provided.
121 *
122 * Context: Can sleep.
123 * Return: Pointer to the realtek_priv or ERR_PTR() in case of failure.
124 *
125 * The realtek_priv pointer does not need to be freed as it is controlled by
126 * devres.
127 */
128struct realtek_priv *
129rtl83xx_probe(struct device *dev,
130 const struct realtek_interface_info *interface_info)
131{
132 const struct realtek_variant *var;
133 struct realtek_priv *priv;
134 struct regmap_config rc = {
135 .reg_bits = 10, /* A4..A0 R4..R0 */
136 .val_bits = 16,
137 .reg_stride = 1,
138 .max_register = 0xffff,
139 .reg_format_endian = REGMAP_ENDIAN_BIG,
140 .reg_read = interface_info->reg_read,
141 .reg_write = interface_info->reg_write,
142 .cache_type = REGCACHE_NONE,
143 .lock = rtl83xx_lock,
144 .unlock = rtl83xx_unlock,
145 };
146 int ret;
147
148 var = of_device_get_match_data(dev);
149 if (!var)
150 return ERR_PTR(error: -EINVAL);
151
152 priv = devm_kzalloc(dev, size: size_add(addend1: sizeof(*priv), addend2: var->chip_data_sz),
153 GFP_KERNEL);
154 if (!priv)
155 return ERR_PTR(error: -ENOMEM);
156
157 mutex_init(&priv->map_lock);
158
159 rc.lock_arg = priv;
160 priv->map = devm_regmap_init(dev, NULL, priv, &rc);
161 if (IS_ERR(ptr: priv->map)) {
162 ret = PTR_ERR(ptr: priv->map);
163 dev_err(dev, "regmap init failed: %d\n", ret);
164 return ERR_PTR(error: ret);
165 }
166
167 rc.disable_locking = true;
168 priv->map_nolock = devm_regmap_init(dev, NULL, priv, &rc);
169 if (IS_ERR(ptr: priv->map_nolock)) {
170 ret = PTR_ERR(ptr: priv->map_nolock);
171 dev_err(dev, "regmap init failed: %d\n", ret);
172 return ERR_PTR(error: ret);
173 }
174
175 /* Link forward and backward */
176 priv->dev = dev;
177 priv->variant = var;
178 priv->ops = var->ops;
179 priv->chip_data = (void *)priv + sizeof(*priv);
180
181 spin_lock_init(&priv->lock);
182
183 priv->leds_disabled = of_property_read_bool(np: dev->of_node,
184 propname: "realtek,disable-leds");
185
186 /* TODO: if power is software controlled, set up any regulators here */
187 priv->reset_ctl = devm_reset_control_get_optional(dev, NULL);
188 if (IS_ERR(ptr: priv->reset_ctl)) {
189 ret = PTR_ERR(ptr: priv->reset_ctl);
190 dev_err_probe(dev, err: ret, fmt: "failed to get reset control\n");
191 return ERR_CAST(ptr: priv->reset_ctl);
192 }
193
194 priv->reset = devm_gpiod_get_optional(dev, con_id: "reset", flags: GPIOD_OUT_LOW);
195 if (IS_ERR(ptr: priv->reset)) {
196 dev_err(dev, "failed to get RESET GPIO\n");
197 return ERR_CAST(ptr: priv->reset);
198 }
199
200 dev_set_drvdata(dev, data: priv);
201
202 if (priv->reset_ctl || priv->reset) {
203 rtl83xx_reset_assert(priv);
204 dev_dbg(dev, "asserted RESET\n");
205 msleep(REALTEK_HW_STOP_DELAY);
206 rtl83xx_reset_deassert(priv);
207 msleep(REALTEK_HW_START_DELAY);
208 dev_dbg(dev, "deasserted RESET\n");
209 }
210
211 return priv;
212}
213EXPORT_SYMBOL_NS_GPL(rtl83xx_probe, REALTEK_DSA);
214
215/**
216 * rtl83xx_register_switch() - detects and register a switch
217 * @priv: realtek_priv pointer
218 *
219 * This function first checks the switch chip ID and register a DSA
220 * switch.
221 *
222 * Context: Can sleep. Takes and releases priv->map_lock.
223 * Return: 0 on success, negative value for failure.
224 */
225int rtl83xx_register_switch(struct realtek_priv *priv)
226{
227 struct dsa_switch *ds = &priv->ds;
228 int ret;
229
230 ret = priv->ops->detect(priv);
231 if (ret) {
232 dev_err_probe(dev: priv->dev, err: ret, fmt: "unable to detect switch\n");
233 return ret;
234 }
235
236 ds->priv = priv;
237 ds->dev = priv->dev;
238 ds->ops = priv->variant->ds_ops;
239 ds->num_ports = priv->num_ports;
240
241 ret = dsa_register_switch(ds);
242 if (ret) {
243 dev_err_probe(dev: priv->dev, err: ret, fmt: "unable to register switch\n");
244 return ret;
245 }
246
247 return 0;
248}
249EXPORT_SYMBOL_NS_GPL(rtl83xx_register_switch, REALTEK_DSA);
250
251/**
252 * rtl83xx_unregister_switch() - unregister a switch
253 * @priv: realtek_priv pointer
254 *
255 * This function unregister a DSA switch.
256 *
257 * Context: Can sleep.
258 * Return: Nothing.
259 */
260void rtl83xx_unregister_switch(struct realtek_priv *priv)
261{
262 struct dsa_switch *ds = &priv->ds;
263
264 dsa_unregister_switch(ds);
265}
266EXPORT_SYMBOL_NS_GPL(rtl83xx_unregister_switch, REALTEK_DSA);
267
268/**
269 * rtl83xx_shutdown() - shutdown a switch
270 * @priv: realtek_priv pointer
271 *
272 * This function shuts down the DSA switch and cleans the platform driver data,
273 * to prevent realtek_{smi,mdio}_remove() from running afterwards, which is
274 * possible if the parent bus implements its own .shutdown() as .remove().
275 *
276 * Context: Can sleep.
277 * Return: Nothing.
278 */
279void rtl83xx_shutdown(struct realtek_priv *priv)
280{
281 struct dsa_switch *ds = &priv->ds;
282
283 dsa_switch_shutdown(ds);
284
285 dev_set_drvdata(dev: priv->dev, NULL);
286}
287EXPORT_SYMBOL_NS_GPL(rtl83xx_shutdown, REALTEK_DSA);
288
289/**
290 * rtl83xx_remove() - Cleanup a realtek switch driver
291 * @priv: realtek_priv pointer
292 *
293 * If a method is provided, this function asserts the hard reset of the switch
294 * in order to avoid leaking traffic when the driver is gone.
295 *
296 * Context: Might sleep if priv->gdev->chip->can_sleep.
297 * Return: nothing
298 */
299void rtl83xx_remove(struct realtek_priv *priv)
300{
301 /* leave the device reset asserted */
302 rtl83xx_reset_assert(priv);
303}
304EXPORT_SYMBOL_NS_GPL(rtl83xx_remove, REALTEK_DSA);
305
306void rtl83xx_reset_assert(struct realtek_priv *priv)
307{
308 int ret;
309
310 ret = reset_control_assert(rstc: priv->reset_ctl);
311 if (ret)
312 dev_warn(priv->dev,
313 "Failed to assert the switch reset control: %pe\n",
314 ERR_PTR(ret));
315
316 gpiod_set_value(desc: priv->reset, value: true);
317}
318
319void rtl83xx_reset_deassert(struct realtek_priv *priv)
320{
321 int ret;
322
323 ret = reset_control_deassert(rstc: priv->reset_ctl);
324 if (ret)
325 dev_warn(priv->dev,
326 "Failed to deassert the switch reset control: %pe\n",
327 ERR_PTR(ret));
328
329 gpiod_set_value(desc: priv->reset, value: false);
330}
331
332MODULE_AUTHOR("Luiz Angelo Daros de Luca <luizluca@gmail.com>");
333MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
334MODULE_DESCRIPTION("Realtek DSA switches common module");
335MODULE_LICENSE("GPL");
336

source code of linux/drivers/net/dsa/realtek/rtl83xx.c