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