xref: /linux/drivers/net/dsa/realtek/rtl83xx.c (revision 98b75c1c149c653ad11a440636213eb070325158)
1 // SPDX-License-Identifier: GPL-2.0+
2 
3 #include <linux/module.h>
4 #include <linux/regmap.h>
5 
6 #include "realtek.h"
7 #include "rtl83xx.h"
8 
9 /**
10  * rtl83xx_lock() - Locks the mutex used by regmaps
11  * @ctx: realtek_priv pointer
12  *
13  * This function is passed to regmap to be used as the lock function.
14  * It is also used externally to block regmap before executing multiple
15  * operations that must happen in sequence (which will use
16  * realtek_priv.map_nolock instead).
17  *
18  * Context: Can sleep. Holds priv->map_lock lock.
19  * Return: nothing
20  */
21 void rtl83xx_lock(void *ctx)
22 {
23 	struct realtek_priv *priv = ctx;
24 
25 	mutex_lock(&priv->map_lock);
26 }
27 EXPORT_SYMBOL_NS_GPL(rtl83xx_lock, REALTEK_DSA);
28 
29 /**
30  * rtl83xx_unlock() - Unlocks the mutex used by regmaps
31  * @ctx: realtek_priv pointer
32  *
33  * This function unlocks the lock acquired by rtl83xx_lock.
34  *
35  * Context: Releases priv->map_lock lock.
36  * Return: nothing
37  */
38 void rtl83xx_unlock(void *ctx)
39 {
40 	struct realtek_priv *priv = ctx;
41 
42 	mutex_unlock(&priv->map_lock);
43 }
44 EXPORT_SYMBOL_NS_GPL(rtl83xx_unlock, REALTEK_DSA);
45 
46 /**
47  * rtl83xx_probe() - probe a Realtek switch
48  * @dev: the device being probed
49  * @interface_info: specific management interface info.
50  *
51  * This function initializes realtek_priv and reads data from the device tree
52  * node. The switch is hard resetted if a method is provided.
53  *
54  * Context: Can sleep.
55  * Return: Pointer to the realtek_priv or ERR_PTR() in case of failure.
56  *
57  * The realtek_priv pointer does not need to be freed as it is controlled by
58  * devres.
59  */
60 struct realtek_priv *
61 rtl83xx_probe(struct device *dev,
62 	      const struct realtek_interface_info *interface_info)
63 {
64 	const struct realtek_variant *var;
65 	struct realtek_priv *priv;
66 	struct regmap_config rc = {
67 		.reg_bits = 10, /* A4..A0 R4..R0 */
68 		.val_bits = 16,
69 		.reg_stride = 1,
70 		.max_register = 0xffff,
71 		.reg_format_endian = REGMAP_ENDIAN_BIG,
72 		.reg_read = interface_info->reg_read,
73 		.reg_write = interface_info->reg_write,
74 		.cache_type = REGCACHE_NONE,
75 		.lock = rtl83xx_lock,
76 		.unlock = rtl83xx_unlock,
77 	};
78 	int ret;
79 
80 	var = of_device_get_match_data(dev);
81 	if (!var)
82 		return ERR_PTR(-EINVAL);
83 
84 	priv = devm_kzalloc(dev, size_add(sizeof(*priv), var->chip_data_sz),
85 			    GFP_KERNEL);
86 	if (!priv)
87 		return ERR_PTR(-ENOMEM);
88 
89 	mutex_init(&priv->map_lock);
90 
91 	rc.lock_arg = priv;
92 	priv->map = devm_regmap_init(dev, NULL, priv, &rc);
93 	if (IS_ERR(priv->map)) {
94 		ret = PTR_ERR(priv->map);
95 		dev_err(dev, "regmap init failed: %d\n", ret);
96 		return ERR_PTR(ret);
97 	}
98 
99 	rc.disable_locking = true;
100 	priv->map_nolock = devm_regmap_init(dev, NULL, priv, &rc);
101 	if (IS_ERR(priv->map_nolock)) {
102 		ret = PTR_ERR(priv->map_nolock);
103 		dev_err(dev, "regmap init failed: %d\n", ret);
104 		return ERR_PTR(ret);
105 	}
106 
107 	/* Link forward and backward */
108 	priv->dev = dev;
109 	priv->variant = var;
110 	priv->ops = var->ops;
111 	priv->chip_data = (void *)priv + sizeof(*priv);
112 
113 	spin_lock_init(&priv->lock);
114 
115 	priv->leds_disabled = of_property_read_bool(dev->of_node,
116 						    "realtek,disable-leds");
117 
118 	/* TODO: if power is software controlled, set up any regulators here */
119 	priv->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
120 	if (IS_ERR(priv->reset)) {
121 		dev_err(dev, "failed to get RESET GPIO\n");
122 		return ERR_CAST(priv->reset);
123 	}
124 
125 	dev_set_drvdata(dev, priv);
126 
127 	if (priv->reset) {
128 		gpiod_set_value(priv->reset, 1);
129 		dev_dbg(dev, "asserted RESET\n");
130 		msleep(REALTEK_HW_STOP_DELAY);
131 		gpiod_set_value(priv->reset, 0);
132 		msleep(REALTEK_HW_START_DELAY);
133 		dev_dbg(dev, "deasserted RESET\n");
134 	}
135 
136 	return priv;
137 }
138 EXPORT_SYMBOL_NS_GPL(rtl83xx_probe, REALTEK_DSA);
139 
140 /**
141  * rtl83xx_register_switch() - detects and register a switch
142  * @priv: realtek_priv pointer
143  *
144  * This function first checks the switch chip ID and register a DSA
145  * switch.
146  *
147  * Context: Can sleep. Takes and releases priv->map_lock.
148  * Return: 0 on success, negative value for failure.
149  */
150 int rtl83xx_register_switch(struct realtek_priv *priv)
151 {
152 	struct dsa_switch *ds;
153 	int ret;
154 
155 	ret = priv->ops->detect(priv);
156 	if (ret) {
157 		dev_err_probe(priv->dev, ret, "unable to detect switch\n");
158 		return ret;
159 	}
160 
161 	ds = devm_kzalloc(priv->dev, sizeof(*ds), GFP_KERNEL);
162 	if (!ds)
163 		return -ENOMEM;
164 
165 	ds->priv = priv;
166 	ds->dev = priv->dev;
167 	ds->ops = priv->ds_ops;
168 	ds->num_ports = priv->num_ports;
169 	priv->ds = ds;
170 
171 	ret = dsa_register_switch(ds);
172 	if (ret) {
173 		dev_err_probe(priv->dev, ret, "unable to register switch\n");
174 		return ret;
175 	}
176 
177 	return 0;
178 }
179 EXPORT_SYMBOL_NS_GPL(rtl83xx_register_switch, REALTEK_DSA);
180 
181 /**
182  * rtl83xx_unregister_switch() - unregister a switch
183  * @priv: realtek_priv pointer
184  *
185  * This function unregister a DSA switch.
186  *
187  * Context: Can sleep.
188  * Return: Nothing.
189  */
190 void rtl83xx_unregister_switch(struct realtek_priv *priv)
191 {
192 	dsa_unregister_switch(priv->ds);
193 }
194 EXPORT_SYMBOL_NS_GPL(rtl83xx_unregister_switch, REALTEK_DSA);
195 
196 /**
197  * rtl83xx_shutdown() - shutdown a switch
198  * @priv: realtek_priv pointer
199  *
200  * This function shuts down the DSA switch and cleans the platform driver data,
201  * to prevent realtek_{smi,mdio}_remove() from running afterwards, which is
202  * possible if the parent bus implements its own .shutdown() as .remove().
203  *
204  * Context: Can sleep.
205  * Return: Nothing.
206  */
207 void rtl83xx_shutdown(struct realtek_priv *priv)
208 {
209 	dsa_switch_shutdown(priv->ds);
210 
211 	dev_set_drvdata(priv->dev, NULL);
212 }
213 EXPORT_SYMBOL_NS_GPL(rtl83xx_shutdown, REALTEK_DSA);
214 
215 /**
216  * rtl83xx_remove() - Cleanup a realtek switch driver
217  * @priv: realtek_priv pointer
218  *
219  * If a method is provided, this function asserts the hard reset of the switch
220  * in order to avoid leaking traffic when the driver is gone.
221  *
222  * Context: Might sleep if priv->gdev->chip->can_sleep.
223  * Return: nothing
224  */
225 void rtl83xx_remove(struct realtek_priv *priv)
226 {
227 	/* leave the device reset asserted */
228 	if (priv->reset)
229 		gpiod_set_value(priv->reset, 1);
230 }
231 EXPORT_SYMBOL_NS_GPL(rtl83xx_remove, REALTEK_DSA);
232 
233 MODULE_AUTHOR("Luiz Angelo Daros de Luca <luizluca@gmail.com>");
234 MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
235 MODULE_DESCRIPTION("Realtek DSA switches common module");
236 MODULE_LICENSE("GPL");
237