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 | */ |
22 | void rtl83xx_lock(void *ctx) |
23 | { |
24 | struct realtek_priv *priv = ctx; |
25 | |
26 | mutex_lock(&priv->map_lock); |
27 | } |
28 | EXPORT_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 | */ |
39 | void rtl83xx_unlock(void *ctx) |
40 | { |
41 | struct realtek_priv *priv = ctx; |
42 | |
43 | mutex_unlock(lock: &priv->map_lock); |
44 | } |
45 | EXPORT_SYMBOL_NS_GPL(rtl83xx_unlock, REALTEK_DSA); |
46 | |
47 | static 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 | |
54 | static 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 | */ |
72 | int 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 | |
107 | err_put_node: |
108 | of_node_put(node: mdio_np); |
109 | |
110 | return ret; |
111 | } |
112 | EXPORT_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 | */ |
128 | struct realtek_priv * |
129 | rtl83xx_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 | } |
213 | EXPORT_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 | */ |
225 | int 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 | } |
249 | EXPORT_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 | */ |
260 | void rtl83xx_unregister_switch(struct realtek_priv *priv) |
261 | { |
262 | struct dsa_switch *ds = &priv->ds; |
263 | |
264 | dsa_unregister_switch(ds); |
265 | } |
266 | EXPORT_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 | */ |
279 | void 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 | } |
287 | EXPORT_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 | */ |
299 | void rtl83xx_remove(struct realtek_priv *priv) |
300 | { |
301 | /* leave the device reset asserted */ |
302 | rtl83xx_reset_assert(priv); |
303 | } |
304 | EXPORT_SYMBOL_NS_GPL(rtl83xx_remove, REALTEK_DSA); |
305 | |
306 | void 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 | |
319 | void 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 | |
332 | MODULE_AUTHOR("Luiz Angelo Daros de Luca <luizluca@gmail.com>" ); |
333 | MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>" ); |
334 | MODULE_DESCRIPTION("Realtek DSA switches common module" ); |
335 | MODULE_LICENSE("GPL" ); |
336 | |