Linux Audio

Check our new training course

Linux debugging, profiling, tracing and performance analysis training

Apr 14-17, 2025
Register
Loading...
Note: File does not exist in v4.17.
  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(&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(priv->dev->of_node, "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(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(bus->id, MII_BUS_ID_SIZE, "%s:user_mii", dev_name(priv->dev));
 96	bus->parent = priv->dev;
 97
 98	ret = devm_of_mdiobus_register(priv->dev, bus, 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(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(-EINVAL);
151
152	priv = devm_kzalloc(dev, size_add(sizeof(*priv), var->chip_data_sz),
153			    GFP_KERNEL);
154	if (!priv)
155		return ERR_PTR(-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(priv->map)) {
162		ret = PTR_ERR(priv->map);
163		dev_err(dev, "regmap init failed: %d\n", ret);
164		return ERR_PTR(ret);
165	}
166
167	rc.disable_locking = true;
168	priv->map_nolock = devm_regmap_init(dev, NULL, priv, &rc);
169	if (IS_ERR(priv->map_nolock)) {
170		ret = PTR_ERR(priv->map_nolock);
171		dev_err(dev, "regmap init failed: %d\n", ret);
172		return ERR_PTR(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(dev->of_node,
184						    "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(priv->reset_ctl)) {
189		ret = PTR_ERR(priv->reset_ctl);
190		dev_err_probe(dev, ret, "failed to get reset control\n");
191		return ERR_CAST(priv->reset_ctl);
192	}
193
194	priv->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
195	if (IS_ERR(priv->reset)) {
196		dev_err(dev, "failed to get RESET GPIO\n");
197		return ERR_CAST(priv->reset);
198	}
199
200	dev_set_drvdata(dev, 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(priv->dev, ret, "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(priv->dev, ret, "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(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(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(priv->reset, true);
317}
318
319void rtl83xx_reset_deassert(struct realtek_priv *priv)
320{
321	int ret;
322
323	ret = reset_control_deassert(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(priv->reset, 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");