xref: /linux/drivers/net/dsa/mt7530-mdio.c (revision 2d7eaeb05ae265bd64270376e6a2c0d80244771f)
1 // SPDX-License-Identifier: GPL-2.0-only
2 
3 #include <linux/gpio/consumer.h>
4 #include <linux/mdio.h>
5 #include <linux/module.h>
6 #include <linux/pcs/pcs-mtk-lynxi.h>
7 #include <linux/of_irq.h>
8 #include <linux/of_mdio.h>
9 #include <linux/of_net.h>
10 #include <linux/of_platform.h>
11 #include <linux/regmap.h>
12 #include <linux/reset.h>
13 #include <linux/regulator/consumer.h>
14 #include <net/dsa.h>
15 
16 #include "mt7530.h"
17 
18 static int
19 mt7530_regmap_write(void *context, unsigned int reg, unsigned int val)
20 {
21 	struct mt7530_priv *priv = context;
22 	struct mii_bus *bus = priv->bus;
23 	u16 page, r, lo, hi;
24 	int ret;
25 
26 	page = (reg >> 6) & 0x3ff;
27 	r  = (reg >> 2) & 0xf;
28 	lo = val & 0xffff;
29 	hi = val >> 16;
30 
31 	ret = bus->write(bus, priv->mdiodev->addr, 0x1f, page);
32 	if (ret < 0)
33 		return ret;
34 
35 	ret = bus->write(bus, priv->mdiodev->addr, r, lo);
36 	if (ret < 0)
37 		return ret;
38 
39 	ret = bus->write(bus, priv->mdiodev->addr, 0x10, hi);
40 	return ret;
41 }
42 
43 static int
44 mt7530_regmap_read(void *context, unsigned int reg, unsigned int *val)
45 {
46 	struct mt7530_priv *priv = context;
47 	struct mii_bus *bus = priv->bus;
48 	u16 page, r, lo, hi;
49 	int ret;
50 
51 	/* Callers do not check for errors, keep the value deterministic */
52 	*val = 0;
53 
54 	page = (reg >> 6) & 0x3ff;
55 	r = (reg >> 2) & 0xf;
56 
57 	ret = bus->write(bus, priv->mdiodev->addr, 0x1f, page);
58 	if (ret < 0)
59 		return ret;
60 
61 	ret = bus->read(bus, priv->mdiodev->addr, r);
62 	if (ret < 0)
63 		return ret;
64 	lo = ret;
65 
66 	ret = bus->read(bus, priv->mdiodev->addr, 0x10);
67 	if (ret < 0)
68 		return ret;
69 	hi = ret;
70 
71 	*val = (hi << 16) | (lo & 0xffff);
72 
73 	return 0;
74 }
75 
76 static void
77 mt7530_mdio_regmap_lock(void *mdio_lock)
78 {
79 	mutex_lock_nested(mdio_lock, MDIO_MUTEX_NESTED);
80 }
81 
82 static void
83 mt7530_mdio_regmap_unlock(void *mdio_lock)
84 {
85 	mutex_unlock(mdio_lock);
86 }
87 
88 static const struct regmap_bus mt7530_regmap_bus = {
89 	.reg_write = mt7530_regmap_write,
90 	.reg_read = mt7530_regmap_read,
91 };
92 
93 static int
94 mt7531_create_sgmii(struct mt7530_priv *priv)
95 {
96 	struct regmap_config *mt7531_pcs_config[2] = {};
97 	struct phylink_pcs *pcs;
98 	struct regmap *regmap;
99 	int i, ret = 0;
100 
101 	for (i = priv->p5_sgmii ? 0 : 1; i < 2; i++) {
102 		mt7531_pcs_config[i] = devm_kzalloc(priv->dev,
103 						    sizeof(struct regmap_config),
104 						    GFP_KERNEL);
105 		if (!mt7531_pcs_config[i]) {
106 			ret = -ENOMEM;
107 			break;
108 		}
109 
110 		mt7531_pcs_config[i]->name = i ? "port6" : "port5";
111 		mt7531_pcs_config[i]->reg_bits = 16;
112 		mt7531_pcs_config[i]->val_bits = 32;
113 		mt7531_pcs_config[i]->reg_stride = 4;
114 		mt7531_pcs_config[i]->reg_base = MT7531_SGMII_REG_BASE(5 + i);
115 		mt7531_pcs_config[i]->max_register = 0x17c;
116 		mt7531_pcs_config[i]->lock = mt7530_mdio_regmap_lock;
117 		mt7531_pcs_config[i]->unlock = mt7530_mdio_regmap_unlock;
118 		mt7531_pcs_config[i]->lock_arg = &priv->bus->mdio_lock;
119 
120 		regmap = devm_regmap_init(priv->dev, &mt7530_regmap_bus, priv,
121 					  mt7531_pcs_config[i]);
122 		if (IS_ERR(regmap)) {
123 			ret = PTR_ERR(regmap);
124 			break;
125 		}
126 		pcs = mtk_pcs_lynxi_create(priv->dev, NULL, regmap,
127 					   MT7531_PHYA_CTRL_SIGNAL3);
128 		if (!pcs) {
129 			ret = -ENXIO;
130 			break;
131 		}
132 		priv->ports[5 + i].sgmii_pcs = pcs;
133 	}
134 
135 	if (ret && i)
136 		mtk_pcs_lynxi_destroy(priv->ports[5].sgmii_pcs);
137 
138 	return ret;
139 }
140 
141 static const struct of_device_id mt7530_of_match[] = {
142 	{ .compatible = "mediatek,mt7621", .data = &mt753x_table[ID_MT7621], },
143 	{ .compatible = "mediatek,mt7530", .data = &mt753x_table[ID_MT7530], },
144 	{ .compatible = "mediatek,mt7531", .data = &mt753x_table[ID_MT7531], },
145 	{ /* sentinel */ }
146 };
147 MODULE_DEVICE_TABLE(of, mt7530_of_match);
148 
149 static const struct regmap_config regmap_config = {
150 	.reg_bits = 16,
151 	.val_bits = 32,
152 	.reg_stride = 4,
153 	.max_register = MT7530_CREV,
154 	.lock = mt7530_mdio_regmap_lock,
155 	.unlock = mt7530_mdio_regmap_unlock,
156 };
157 
158 static int
159 mt7530_probe(struct mdio_device *mdiodev)
160 {
161 	struct regmap_config rc = regmap_config;
162 	struct mt7530_priv *priv;
163 	struct device_node *dn;
164 	int ret;
165 
166 	dn = mdiodev->dev.of_node;
167 
168 	priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL);
169 	if (!priv)
170 		return -ENOMEM;
171 
172 	priv->bus = mdiodev->bus;
173 	priv->dev = &mdiodev->dev;
174 	priv->mdiodev = mdiodev;
175 
176 	ret = mt7530_probe_common(priv);
177 	if (ret)
178 		return ret;
179 
180 	/* Use medatek,mcm property to distinguish hardware type that would
181 	 * cause a little bit differences on power-on sequence.
182 	 * Not MCM that indicates switch works as the remote standalone
183 	 * integrated circuit so the GPIO pin would be used to complete
184 	 * the reset, otherwise memory-mapped register accessing used
185 	 * through syscon provides in the case of MCM.
186 	 */
187 	priv->mcm = of_property_read_bool(dn, "mediatek,mcm");
188 	if (priv->mcm) {
189 		dev_info(&mdiodev->dev, "MT7530 adapts as multi-chip module\n");
190 
191 		priv->rstc = devm_reset_control_get(&mdiodev->dev, "mcm");
192 		if (IS_ERR(priv->rstc)) {
193 			dev_err(&mdiodev->dev, "Couldn't get our reset line\n");
194 			return PTR_ERR(priv->rstc);
195 		}
196 	} else {
197 		priv->reset = devm_gpiod_get_optional(&mdiodev->dev, "reset",
198 						      GPIOD_OUT_LOW);
199 		if (IS_ERR(priv->reset)) {
200 			dev_err(&mdiodev->dev, "Couldn't get our reset line\n");
201 			return PTR_ERR(priv->reset);
202 		}
203 	}
204 
205 	if (priv->id == ID_MT7530) {
206 		priv->core_pwr = devm_regulator_get(&mdiodev->dev, "core");
207 		if (IS_ERR(priv->core_pwr))
208 			return PTR_ERR(priv->core_pwr);
209 
210 		priv->io_pwr = devm_regulator_get(&mdiodev->dev, "io");
211 		if (IS_ERR(priv->io_pwr))
212 			return PTR_ERR(priv->io_pwr);
213 	}
214 
215 	rc.lock_arg = &priv->bus->mdio_lock;
216 	priv->regmap = devm_regmap_init(priv->dev, &mt7530_regmap_bus,
217 					priv, &rc);
218 	if (IS_ERR(priv->regmap))
219 		return PTR_ERR(priv->regmap);
220 
221 	if (priv->id == ID_MT7531)
222 		priv->create_sgmii = mt7531_create_sgmii;
223 
224 	return dsa_register_switch(priv->ds);
225 }
226 
227 static void
228 mt7530_remove(struct mdio_device *mdiodev)
229 {
230 	struct mt7530_priv *priv = dev_get_drvdata(&mdiodev->dev);
231 	int ret = 0, i;
232 
233 	if (!priv)
234 		return;
235 
236 	if (priv->id == ID_MT7530) {
237 		ret = regulator_disable(priv->core_pwr);
238 		if (ret < 0)
239 			dev_err(priv->dev,
240 				"Failed to disable core power: %d\n", ret);
241 
242 		ret = regulator_disable(priv->io_pwr);
243 		if (ret < 0)
244 			dev_err(priv->dev, "Failed to disable io pwr: %d\n",
245 				ret);
246 	}
247 
248 	mt7530_remove_common(priv);
249 
250 	for (i = 0; i < 2; ++i)
251 		mtk_pcs_lynxi_destroy(priv->ports[5 + i].sgmii_pcs);
252 }
253 
254 static void mt7530_shutdown(struct mdio_device *mdiodev)
255 {
256 	struct mt7530_priv *priv = dev_get_drvdata(&mdiodev->dev);
257 
258 	if (!priv)
259 		return;
260 
261 	dsa_switch_shutdown(priv->ds);
262 
263 	dev_set_drvdata(&mdiodev->dev, NULL);
264 }
265 
266 static struct mdio_driver mt7530_mdio_driver = {
267 	.probe  = mt7530_probe,
268 	.remove = mt7530_remove,
269 	.shutdown = mt7530_shutdown,
270 	.mdiodrv.driver = {
271 		.name = "mt7530-mdio",
272 		.of_match_table = mt7530_of_match,
273 	},
274 };
275 
276 mdio_module_driver(mt7530_mdio_driver);
277 
278 MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
279 MODULE_DESCRIPTION("Driver for Mediatek MT7530 Switch (MDIO)");
280 MODULE_LICENSE("GPL");
281