Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  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		return dev_err_cast_probe(dev, priv->reset_ctl,
190					  "failed to get reset control\n");
191
192	priv->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
193	if (IS_ERR(priv->reset)) {
194		dev_err(dev, "failed to get RESET GPIO\n");
195		return ERR_CAST(priv->reset);
196	}
197
198	dev_set_drvdata(dev, priv);
199
200	if (priv->reset_ctl || priv->reset) {
201		rtl83xx_reset_assert(priv);
202		dev_dbg(dev, "asserted RESET\n");
203		msleep(REALTEK_HW_STOP_DELAY);
204		rtl83xx_reset_deassert(priv);
205		msleep(REALTEK_HW_START_DELAY);
206		dev_dbg(dev, "deasserted RESET\n");
207	}
208
209	return priv;
210}
211EXPORT_SYMBOL_NS_GPL(rtl83xx_probe, "REALTEK_DSA");
212
213/**
214 * rtl83xx_register_switch() - detects and register a switch
215 * @priv: realtek_priv pointer
216 *
217 * This function first checks the switch chip ID and register a DSA
218 * switch.
219 *
220 * Context: Can sleep. Takes and releases priv->map_lock.
221 * Return: 0 on success, negative value for failure.
222 */
223int rtl83xx_register_switch(struct realtek_priv *priv)
224{
225	struct dsa_switch *ds = &priv->ds;
226	int ret;
227
228	ret = priv->ops->detect(priv);
229	if (ret) {
230		dev_err_probe(priv->dev, ret, "unable to detect switch\n");
231		return ret;
232	}
233
234	ds->priv = priv;
235	ds->dev = priv->dev;
236	ds->ops = priv->variant->ds_ops;
237	ds->phylink_mac_ops = priv->variant->phylink_mac_ops;
238	ds->num_ports = priv->num_ports;
239
240	ret = dsa_register_switch(ds);
241	if (ret) {
242		dev_err_probe(priv->dev, ret, "unable to register switch\n");
243		return ret;
244	}
245
246	return 0;
247}
248EXPORT_SYMBOL_NS_GPL(rtl83xx_register_switch, "REALTEK_DSA");
249
250/**
251 * rtl83xx_unregister_switch() - unregister a switch
252 * @priv: realtek_priv pointer
253 *
254 * This function unregister a DSA switch.
255 *
256 * Context: Can sleep.
257 * Return: Nothing.
258 */
259void rtl83xx_unregister_switch(struct realtek_priv *priv)
260{
261	struct dsa_switch *ds = &priv->ds;
262
263	dsa_unregister_switch(ds);
264}
265EXPORT_SYMBOL_NS_GPL(rtl83xx_unregister_switch, "REALTEK_DSA");
266
267/**
268 * rtl83xx_shutdown() - shutdown a switch
269 * @priv: realtek_priv pointer
270 *
271 * This function shuts down the DSA switch and cleans the platform driver data,
272 * to prevent realtek_{smi,mdio}_remove() from running afterwards, which is
273 * possible if the parent bus implements its own .shutdown() as .remove().
274 *
275 * Context: Can sleep.
276 * Return: Nothing.
277 */
278void rtl83xx_shutdown(struct realtek_priv *priv)
279{
280	struct dsa_switch *ds = &priv->ds;
281
282	dsa_switch_shutdown(ds);
283
284	dev_set_drvdata(priv->dev, NULL);
285}
286EXPORT_SYMBOL_NS_GPL(rtl83xx_shutdown, "REALTEK_DSA");
287
288/**
289 * rtl83xx_remove() - Cleanup a realtek switch driver
290 * @priv: realtek_priv pointer
291 *
292 * Placehold for common cleanup procedures.
293 *
294 * Context: Any
295 * Return: nothing
296 */
297void rtl83xx_remove(struct realtek_priv *priv)
298{
299}
300EXPORT_SYMBOL_NS_GPL(rtl83xx_remove, "REALTEK_DSA");
301
302void rtl83xx_reset_assert(struct realtek_priv *priv)
303{
304	int ret;
305
306	ret = reset_control_assert(priv->reset_ctl);
307	if (ret)
308		dev_warn(priv->dev,
309			 "Failed to assert the switch reset control: %pe\n",
310			 ERR_PTR(ret));
311
312	gpiod_set_value(priv->reset, true);
313}
314
315void rtl83xx_reset_deassert(struct realtek_priv *priv)
316{
317	int ret;
318
319	ret = reset_control_deassert(priv->reset_ctl);
320	if (ret)
321		dev_warn(priv->dev,
322			 "Failed to deassert the switch reset control: %pe\n",
323			 ERR_PTR(ret));
324
325	gpiod_set_value(priv->reset, false);
326}
327
328MODULE_AUTHOR("Luiz Angelo Daros de Luca <luizluca@gmail.com>");
329MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
330MODULE_DESCRIPTION("Realtek DSA switches common module");
331MODULE_LICENSE("GPL");