net: dsa: sja1105: register the MDIO buses for 100base-T1 and 100base-TX
[linux-2.6-microblaze.git] / drivers / net / dsa / sja1105 / sja1105_mdio.c
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright 2021, NXP Semiconductors
3  */
4 #include <linux/of_mdio.h>
5 #include "sja1105.h"
6
7 enum sja1105_mdio_opcode {
8         SJA1105_C45_ADDR = 0,
9         SJA1105_C22 = 1,
10         SJA1105_C45_DATA = 2,
11         SJA1105_C45_DATA_AUTOINC = 3,
12 };
13
14 static u64 sja1105_base_t1_encode_addr(struct sja1105_private *priv,
15                                        int phy, enum sja1105_mdio_opcode op,
16                                        int xad)
17 {
18         const struct sja1105_regs *regs = priv->info->regs;
19
20         return regs->mdio_100base_t1 | (phy << 7) | (op << 5) | (xad << 0);
21 }
22
23 static int sja1105_base_t1_mdio_read(struct mii_bus *bus, int phy, int reg)
24 {
25         struct sja1105_mdio_private *mdio_priv = bus->priv;
26         struct sja1105_private *priv = mdio_priv->priv;
27         u64 addr;
28         u32 tmp;
29         int rc;
30
31         if (reg & MII_ADDR_C45) {
32                 u16 mmd = (reg >> MII_DEVADDR_C45_SHIFT) & 0x1f;
33
34                 addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C45_ADDR,
35                                                    mmd);
36
37                 tmp = reg & MII_REGADDR_C45_MASK;
38
39                 rc = sja1105_xfer_u32(priv, SPI_WRITE, addr, &tmp, NULL);
40                 if (rc < 0)
41                         return rc;
42
43                 addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C45_DATA,
44                                                    mmd);
45
46                 rc = sja1105_xfer_u32(priv, SPI_READ, addr, &tmp, NULL);
47                 if (rc < 0)
48                         return rc;
49
50                 return tmp & 0xffff;
51         }
52
53         /* Clause 22 read */
54         addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C22, reg & 0x1f);
55
56         rc = sja1105_xfer_u32(priv, SPI_READ, addr, &tmp, NULL);
57         if (rc < 0)
58                 return rc;
59
60         return tmp & 0xffff;
61 }
62
63 static int sja1105_base_t1_mdio_write(struct mii_bus *bus, int phy, int reg,
64                                       u16 val)
65 {
66         struct sja1105_mdio_private *mdio_priv = bus->priv;
67         struct sja1105_private *priv = mdio_priv->priv;
68         u64 addr;
69         u32 tmp;
70         int rc;
71
72         if (reg & MII_ADDR_C45) {
73                 u16 mmd = (reg >> MII_DEVADDR_C45_SHIFT) & 0x1f;
74
75                 addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C45_ADDR,
76                                                    mmd);
77
78                 tmp = reg & MII_REGADDR_C45_MASK;
79
80                 rc = sja1105_xfer_u32(priv, SPI_WRITE, addr, &tmp, NULL);
81                 if (rc < 0)
82                         return rc;
83
84                 addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C45_DATA,
85                                                    mmd);
86
87                 tmp = val & 0xffff;
88
89                 rc = sja1105_xfer_u32(priv, SPI_WRITE, addr, &tmp, NULL);
90                 if (rc < 0)
91                         return rc;
92
93                 return 0;
94         }
95
96         /* Clause 22 write */
97         addr = sja1105_base_t1_encode_addr(priv, phy, SJA1105_C22, reg & 0x1f);
98
99         tmp = val & 0xffff;
100
101         return sja1105_xfer_u32(priv, SPI_WRITE, addr, &tmp, NULL);
102 }
103
104 static int sja1105_base_tx_mdio_read(struct mii_bus *bus, int phy, int reg)
105 {
106         struct sja1105_mdio_private *mdio_priv = bus->priv;
107         struct sja1105_private *priv = mdio_priv->priv;
108         const struct sja1105_regs *regs = priv->info->regs;
109         u32 tmp;
110         int rc;
111
112         rc = sja1105_xfer_u32(priv, SPI_READ, regs->mdio_100base_tx + reg,
113                               &tmp, NULL);
114         if (rc < 0)
115                 return rc;
116
117         return tmp & 0xffff;
118 }
119
120 static int sja1105_base_tx_mdio_write(struct mii_bus *bus, int phy, int reg,
121                                       u16 val)
122 {
123         struct sja1105_mdio_private *mdio_priv = bus->priv;
124         struct sja1105_private *priv = mdio_priv->priv;
125         const struct sja1105_regs *regs = priv->info->regs;
126         u32 tmp = val;
127
128         return sja1105_xfer_u32(priv, SPI_WRITE, regs->mdio_100base_tx + reg,
129                                 &tmp, NULL);
130 }
131
132 static int sja1105_mdiobus_base_tx_register(struct sja1105_private *priv,
133                                             struct device_node *mdio_node)
134 {
135         struct sja1105_mdio_private *mdio_priv;
136         struct device_node *np;
137         struct mii_bus *bus;
138         int rc = 0;
139
140         np = of_find_compatible_node(mdio_node, NULL,
141                                      "nxp,sja1110-base-tx-mdio");
142         if (!np)
143                 return 0;
144
145         if (!of_device_is_available(np))
146                 goto out_put_np;
147
148         bus = mdiobus_alloc_size(sizeof(*mdio_priv));
149         if (!bus) {
150                 rc = -ENOMEM;
151                 goto out_put_np;
152         }
153
154         bus->name = "SJA1110 100base-TX MDIO bus";
155         snprintf(bus->id, MII_BUS_ID_SIZE, "%s-base-tx",
156                  dev_name(priv->ds->dev));
157         bus->read = sja1105_base_tx_mdio_read;
158         bus->write = sja1105_base_tx_mdio_write;
159         bus->parent = priv->ds->dev;
160         mdio_priv = bus->priv;
161         mdio_priv->priv = priv;
162
163         rc = of_mdiobus_register(bus, np);
164         if (rc) {
165                 mdiobus_free(bus);
166                 goto out_put_np;
167         }
168
169         priv->mdio_base_tx = bus;
170
171 out_put_np:
172         of_node_put(np);
173
174         return 0;
175 }
176
177 static void sja1105_mdiobus_base_tx_unregister(struct sja1105_private *priv)
178 {
179         if (!priv->mdio_base_tx)
180                 return;
181
182         mdiobus_unregister(priv->mdio_base_tx);
183         mdiobus_free(priv->mdio_base_tx);
184         priv->mdio_base_tx = NULL;
185 }
186
187 static int sja1105_mdiobus_base_t1_register(struct sja1105_private *priv,
188                                             struct device_node *mdio_node)
189 {
190         struct sja1105_mdio_private *mdio_priv;
191         struct device_node *np;
192         struct mii_bus *bus;
193         int rc = 0;
194
195         np = of_find_compatible_node(mdio_node, NULL,
196                                      "nxp,sja1110-base-t1-mdio");
197         if (!np)
198                 return 0;
199
200         if (!of_device_is_available(np))
201                 goto out_put_np;
202
203         bus = mdiobus_alloc_size(sizeof(*mdio_priv));
204         if (!bus) {
205                 rc = -ENOMEM;
206                 goto out_put_np;
207         }
208
209         bus->name = "SJA1110 100base-T1 MDIO bus";
210         snprintf(bus->id, MII_BUS_ID_SIZE, "%s-base-t1",
211                  dev_name(priv->ds->dev));
212         bus->read = sja1105_base_t1_mdio_read;
213         bus->write = sja1105_base_t1_mdio_write;
214         bus->parent = priv->ds->dev;
215         mdio_priv = bus->priv;
216         mdio_priv->priv = priv;
217
218         rc = of_mdiobus_register(bus, np);
219         if (rc) {
220                 mdiobus_free(bus);
221                 goto out_put_np;
222         }
223
224         priv->mdio_base_t1 = bus;
225
226 out_put_np:
227         of_node_put(np);
228
229         return rc;
230 }
231
232 static void sja1105_mdiobus_base_t1_unregister(struct sja1105_private *priv)
233 {
234         if (!priv->mdio_base_t1)
235                 return;
236
237         mdiobus_unregister(priv->mdio_base_t1);
238         mdiobus_free(priv->mdio_base_t1);
239         priv->mdio_base_t1 = NULL;
240 }
241
242 int sja1105_mdiobus_register(struct dsa_switch *ds)
243 {
244         struct sja1105_private *priv = ds->priv;
245         const struct sja1105_regs *regs = priv->info->regs;
246         struct device_node *switch_node = ds->dev->of_node;
247         struct device_node *mdio_node;
248         int rc;
249
250         mdio_node = of_get_child_by_name(switch_node, "mdios");
251         if (!mdio_node)
252                 return 0;
253
254         if (!of_device_is_available(mdio_node))
255                 goto out_put_mdio_node;
256
257         if (regs->mdio_100base_tx != SJA1105_RSV_ADDR) {
258                 rc = sja1105_mdiobus_base_tx_register(priv, mdio_node);
259                 if (rc)
260                         goto err_put_mdio_node;
261         }
262
263         if (regs->mdio_100base_t1 != SJA1105_RSV_ADDR) {
264                 rc = sja1105_mdiobus_base_t1_register(priv, mdio_node);
265                 if (rc)
266                         goto err_free_base_tx_mdiobus;
267         }
268
269 out_put_mdio_node:
270         of_node_put(mdio_node);
271
272         return 0;
273
274 err_free_base_tx_mdiobus:
275         sja1105_mdiobus_base_tx_unregister(priv);
276 err_put_mdio_node:
277         of_node_put(mdio_node);
278
279         return rc;
280 }
281
282 void sja1105_mdiobus_unregister(struct dsa_switch *ds)
283 {
284         struct sja1105_private *priv = ds->priv;
285
286         sja1105_mdiobus_base_t1_unregister(priv);
287         sja1105_mdiobus_base_tx_unregister(priv);
288 }