1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Copyright (c) 2014-2015 Hisilicon Limited. |
4 | */ |
5 | |
6 | #include <linux/acpi.h> |
7 | #include <linux/errno.h> |
8 | #include <linux/etherdevice.h> |
9 | #include <linux/init.h> |
10 | #include <linux/kernel.h> |
11 | #include <linux/mfd/syscon.h> |
12 | #include <linux/module.h> |
13 | #include <linux/mutex.h> |
14 | #include <linux/netdevice.h> |
15 | #include <linux/of_address.h> |
16 | #include <linux/of.h> |
17 | #include <linux/of_mdio.h> |
18 | #include <linux/of_platform.h> |
19 | #include <linux/phy.h> |
20 | #include <linux/platform_device.h> |
21 | #include <linux/regmap.h> |
22 | |
23 | #define MDIO_DRV_NAME "Hi-HNS_MDIO" |
24 | #define MDIO_BUS_NAME "Hisilicon MII Bus" |
25 | |
26 | #define MDIO_TIMEOUT 1000000 |
27 | |
28 | struct hns_mdio_sc_reg { |
29 | u16 mdio_clk_en; |
30 | u16 mdio_clk_dis; |
31 | u16 mdio_reset_req; |
32 | u16 mdio_reset_dreq; |
33 | u16 mdio_clk_st; |
34 | u16 mdio_reset_st; |
35 | }; |
36 | |
37 | struct hns_mdio_device { |
38 | u8 __iomem *vbase; /* mdio reg base address */ |
39 | struct regmap *subctrl_vbase; |
40 | struct hns_mdio_sc_reg sc_reg; |
41 | }; |
42 | |
43 | /* mdio reg */ |
44 | #define MDIO_COMMAND_REG 0x0 |
45 | #define MDIO_ADDR_REG 0x4 |
46 | #define MDIO_WDATA_REG 0x8 |
47 | #define MDIO_RDATA_REG 0xc |
48 | #define MDIO_STA_REG 0x10 |
49 | |
50 | /* cfg phy bit map */ |
51 | #define MDIO_CMD_DEVAD_M 0x1f |
52 | #define MDIO_CMD_DEVAD_S 0 |
53 | #define MDIO_CMD_PRTAD_M 0x1f |
54 | #define MDIO_CMD_PRTAD_S 5 |
55 | #define MDIO_CMD_OP_S 10 |
56 | #define MDIO_CMD_ST_S 12 |
57 | #define MDIO_CMD_START_B 14 |
58 | |
59 | #define MDIO_ADDR_DATA_M 0xffff |
60 | #define MDIO_ADDR_DATA_S 0 |
61 | |
62 | #define MDIO_WDATA_DATA_M 0xffff |
63 | #define MDIO_WDATA_DATA_S 0 |
64 | |
65 | #define MDIO_RDATA_DATA_M 0xffff |
66 | #define MDIO_RDATA_DATA_S 0 |
67 | |
68 | #define MDIO_STATE_STA_B 0 |
69 | |
70 | enum mdio_st_clause { |
71 | MDIO_ST_CLAUSE_45 = 0, |
72 | MDIO_ST_CLAUSE_22 |
73 | }; |
74 | |
75 | enum mdio_c22_op_seq { |
76 | MDIO_C22_WRITE = 1, |
77 | MDIO_C22_READ = 2 |
78 | }; |
79 | |
80 | enum mdio_c45_op_seq { |
81 | MDIO_C45_WRITE_ADDR = 0, |
82 | MDIO_C45_WRITE_DATA, |
83 | MDIO_C45_READ_INCREMENT, |
84 | MDIO_C45_READ |
85 | }; |
86 | |
87 | /* peri subctrl reg */ |
88 | #define MDIO_SC_CLK_EN 0x338 |
89 | #define MDIO_SC_CLK_DIS 0x33C |
90 | #define MDIO_SC_RESET_REQ 0xA38 |
91 | #define MDIO_SC_RESET_DREQ 0xA3C |
92 | #define MDIO_SC_CLK_ST 0x531C |
93 | #define MDIO_SC_RESET_ST 0x5A1C |
94 | |
95 | static void mdio_write_reg(u8 __iomem *base, u32 reg, u32 value) |
96 | { |
97 | writel_relaxed(value, base + reg); |
98 | } |
99 | |
100 | #define MDIO_WRITE_REG(a, reg, value) \ |
101 | mdio_write_reg((a)->vbase, (reg), (value)) |
102 | |
103 | static u32 mdio_read_reg(u8 __iomem *base, u32 reg) |
104 | { |
105 | return readl_relaxed(base + reg); |
106 | } |
107 | |
108 | #define mdio_set_field(origin, mask, shift, val) \ |
109 | do { \ |
110 | (origin) &= (~((mask) << (shift))); \ |
111 | (origin) |= (((val) & (mask)) << (shift)); \ |
112 | } while (0) |
113 | |
114 | #define mdio_get_field(origin, mask, shift) (((origin) >> (shift)) & (mask)) |
115 | |
116 | static void mdio_set_reg_field(u8 __iomem *base, u32 reg, u32 mask, u32 shift, |
117 | u32 val) |
118 | { |
119 | u32 origin = mdio_read_reg(base, reg); |
120 | |
121 | mdio_set_field(origin, mask, shift, val); |
122 | mdio_write_reg(base, reg, value: origin); |
123 | } |
124 | |
125 | #define MDIO_SET_REG_FIELD(dev, reg, mask, shift, val) \ |
126 | mdio_set_reg_field((dev)->vbase, (reg), (mask), (shift), (val)) |
127 | |
128 | static u32 mdio_get_reg_field(u8 __iomem *base, u32 reg, u32 mask, u32 shift) |
129 | { |
130 | u32 origin; |
131 | |
132 | origin = mdio_read_reg(base, reg); |
133 | return mdio_get_field(origin, mask, shift); |
134 | } |
135 | |
136 | #define MDIO_GET_REG_FIELD(dev, reg, mask, shift) \ |
137 | mdio_get_reg_field((dev)->vbase, (reg), (mask), (shift)) |
138 | |
139 | #define MDIO_GET_REG_BIT(dev, reg, bit) \ |
140 | mdio_get_reg_field((dev)->vbase, (reg), 0x1ull, (bit)) |
141 | |
142 | #define MDIO_CHECK_SET_ST 1 |
143 | #define MDIO_CHECK_CLR_ST 0 |
144 | |
145 | static int mdio_sc_cfg_reg_write(struct hns_mdio_device *mdio_dev, |
146 | u32 cfg_reg, u32 set_val, |
147 | u32 st_reg, u32 st_msk, u8 check_st) |
148 | { |
149 | u32 time_cnt; |
150 | u32 reg_value; |
151 | int ret; |
152 | |
153 | regmap_write(map: mdio_dev->subctrl_vbase, reg: cfg_reg, val: set_val); |
154 | |
155 | for (time_cnt = MDIO_TIMEOUT; time_cnt; time_cnt--) { |
156 | ret = regmap_read(map: mdio_dev->subctrl_vbase, reg: st_reg, val: ®_value); |
157 | if (ret) |
158 | return ret; |
159 | |
160 | reg_value &= st_msk; |
161 | if ((!!check_st) == (!!reg_value)) |
162 | break; |
163 | } |
164 | |
165 | if ((!!check_st) != (!!reg_value)) |
166 | return -EBUSY; |
167 | |
168 | return 0; |
169 | } |
170 | |
171 | static int hns_mdio_wait_ready(struct mii_bus *bus) |
172 | { |
173 | struct hns_mdio_device *mdio_dev = bus->priv; |
174 | u32 cmd_reg_value; |
175 | int i; |
176 | |
177 | /* waiting for MDIO_COMMAND_REG's mdio_start==0 */ |
178 | /* after that can do read or write*/ |
179 | for (i = 0; i < MDIO_TIMEOUT; i++) { |
180 | cmd_reg_value = MDIO_GET_REG_BIT(mdio_dev, |
181 | MDIO_COMMAND_REG, |
182 | MDIO_CMD_START_B); |
183 | if (!cmd_reg_value) |
184 | break; |
185 | } |
186 | if ((i == MDIO_TIMEOUT) && cmd_reg_value) |
187 | return -ETIMEDOUT; |
188 | |
189 | return 0; |
190 | } |
191 | |
192 | static void hns_mdio_cmd_write(struct hns_mdio_device *mdio_dev, |
193 | u8 is_c45, u8 op, u8 phy_id, u16 cmd) |
194 | { |
195 | u32 cmd_reg_value; |
196 | u8 st = is_c45 ? MDIO_ST_CLAUSE_45 : MDIO_ST_CLAUSE_22; |
197 | |
198 | cmd_reg_value = st << MDIO_CMD_ST_S; |
199 | cmd_reg_value |= op << MDIO_CMD_OP_S; |
200 | cmd_reg_value |= |
201 | (phy_id & MDIO_CMD_PRTAD_M) << MDIO_CMD_PRTAD_S; |
202 | cmd_reg_value |= (cmd & MDIO_CMD_DEVAD_M) << MDIO_CMD_DEVAD_S; |
203 | cmd_reg_value |= 1 << MDIO_CMD_START_B; |
204 | |
205 | MDIO_WRITE_REG(mdio_dev, MDIO_COMMAND_REG, cmd_reg_value); |
206 | } |
207 | |
208 | /** |
209 | * hns_mdio_write_c22 - access phy register |
210 | * @bus: mdio bus |
211 | * @phy_id: phy id |
212 | * @regnum: register num |
213 | * @data: register value |
214 | * |
215 | * Return 0 on success, negative on failure |
216 | */ |
217 | static int hns_mdio_write_c22(struct mii_bus *bus, |
218 | int phy_id, int regnum, u16 data) |
219 | { |
220 | struct hns_mdio_device *mdio_dev = bus->priv; |
221 | u16 reg = (u16)(regnum & 0xffff); |
222 | u16 cmd_reg_cfg; |
223 | int ret; |
224 | u8 op; |
225 | |
226 | dev_dbg(&bus->dev, "mdio write %s,base is %p\n" , |
227 | bus->id, mdio_dev->vbase); |
228 | dev_dbg(&bus->dev, "phy id=%d, reg=%#x, write data=%d\n" , |
229 | phy_id, reg, data); |
230 | |
231 | /* wait for ready */ |
232 | ret = hns_mdio_wait_ready(bus); |
233 | if (ret) { |
234 | dev_err(&bus->dev, "MDIO bus is busy\n" ); |
235 | return ret; |
236 | } |
237 | |
238 | cmd_reg_cfg = reg; |
239 | op = MDIO_C22_WRITE; |
240 | |
241 | MDIO_SET_REG_FIELD(mdio_dev, MDIO_WDATA_REG, MDIO_WDATA_DATA_M, |
242 | MDIO_WDATA_DATA_S, data); |
243 | |
244 | hns_mdio_cmd_write(mdio_dev, is_c45: false, op, phy_id, cmd: cmd_reg_cfg); |
245 | |
246 | return 0; |
247 | } |
248 | |
249 | /** |
250 | * hns_mdio_write_c45 - access phy register |
251 | * @bus: mdio bus |
252 | * @phy_id: phy id |
253 | * @devad: device address to read |
254 | * @regnum: register num |
255 | * @data: register value |
256 | * |
257 | * Return 0 on success, negative on failure |
258 | */ |
259 | static int hns_mdio_write_c45(struct mii_bus *bus, int phy_id, int devad, |
260 | int regnum, u16 data) |
261 | { |
262 | struct hns_mdio_device *mdio_dev = bus->priv; |
263 | u16 reg = (u16)(regnum & 0xffff); |
264 | u16 cmd_reg_cfg; |
265 | int ret; |
266 | u8 op; |
267 | |
268 | dev_dbg(&bus->dev, "mdio write %s,base is %p\n" , |
269 | bus->id, mdio_dev->vbase); |
270 | dev_dbg(&bus->dev, "phy id=%d, devad=%d, reg=%#x, write data=%d\n" , |
271 | phy_id, devad, reg, data); |
272 | |
273 | /* wait for ready */ |
274 | ret = hns_mdio_wait_ready(bus); |
275 | if (ret) { |
276 | dev_err(&bus->dev, "MDIO bus is busy\n" ); |
277 | return ret; |
278 | } |
279 | |
280 | /* config the cmd-reg to write addr*/ |
281 | MDIO_SET_REG_FIELD(mdio_dev, MDIO_ADDR_REG, MDIO_ADDR_DATA_M, |
282 | MDIO_ADDR_DATA_S, reg); |
283 | |
284 | hns_mdio_cmd_write(mdio_dev, is_c45: true, op: MDIO_C45_WRITE_ADDR, phy_id, cmd: devad); |
285 | |
286 | /* check for read or write opt is finished */ |
287 | ret = hns_mdio_wait_ready(bus); |
288 | if (ret) { |
289 | dev_err(&bus->dev, "MDIO bus is busy\n" ); |
290 | return ret; |
291 | } |
292 | |
293 | /* config the data needed writing */ |
294 | cmd_reg_cfg = devad; |
295 | op = MDIO_C45_WRITE_DATA; |
296 | |
297 | MDIO_SET_REG_FIELD(mdio_dev, MDIO_WDATA_REG, MDIO_WDATA_DATA_M, |
298 | MDIO_WDATA_DATA_S, data); |
299 | |
300 | hns_mdio_cmd_write(mdio_dev, is_c45: true, op, phy_id, cmd: cmd_reg_cfg); |
301 | |
302 | return 0; |
303 | } |
304 | |
305 | /** |
306 | * hns_mdio_read_c22 - access phy register |
307 | * @bus: mdio bus |
308 | * @phy_id: phy id |
309 | * @regnum: register num |
310 | * |
311 | * Return phy register value |
312 | */ |
313 | static int hns_mdio_read_c22(struct mii_bus *bus, int phy_id, int regnum) |
314 | { |
315 | struct hns_mdio_device *mdio_dev = bus->priv; |
316 | u16 reg = (u16)(regnum & 0xffff); |
317 | u16 reg_val; |
318 | int ret; |
319 | |
320 | dev_dbg(&bus->dev, "mdio read %s,base is %p\n" , |
321 | bus->id, mdio_dev->vbase); |
322 | dev_dbg(&bus->dev, "phy id=%d, reg=%#x!\n" , phy_id, reg); |
323 | |
324 | /* Step 1: wait for ready */ |
325 | ret = hns_mdio_wait_ready(bus); |
326 | if (ret) { |
327 | dev_err(&bus->dev, "MDIO bus is busy\n" ); |
328 | return ret; |
329 | } |
330 | |
331 | hns_mdio_cmd_write(mdio_dev, is_c45: false, op: MDIO_C22_READ, phy_id, cmd: reg); |
332 | |
333 | /* Step 2: waiting for MDIO_COMMAND_REG 's mdio_start==0,*/ |
334 | /* check for read or write opt is finished */ |
335 | ret = hns_mdio_wait_ready(bus); |
336 | if (ret) { |
337 | dev_err(&bus->dev, "MDIO bus is busy\n" ); |
338 | return ret; |
339 | } |
340 | |
341 | reg_val = MDIO_GET_REG_BIT(mdio_dev, MDIO_STA_REG, MDIO_STATE_STA_B); |
342 | if (reg_val) { |
343 | dev_err(&bus->dev, " ERROR! MDIO Read failed!\n" ); |
344 | return -EBUSY; |
345 | } |
346 | |
347 | /* Step 3; get out data*/ |
348 | reg_val = (u16)MDIO_GET_REG_FIELD(mdio_dev, MDIO_RDATA_REG, |
349 | MDIO_RDATA_DATA_M, MDIO_RDATA_DATA_S); |
350 | |
351 | return reg_val; |
352 | } |
353 | |
354 | /** |
355 | * hns_mdio_read_c45 - access phy register |
356 | * @bus: mdio bus |
357 | * @phy_id: phy id |
358 | * @devad: device address to read |
359 | * @regnum: register num |
360 | * |
361 | * Return phy register value |
362 | */ |
363 | static int hns_mdio_read_c45(struct mii_bus *bus, int phy_id, int devad, |
364 | int regnum) |
365 | { |
366 | struct hns_mdio_device *mdio_dev = bus->priv; |
367 | u16 reg = (u16)(regnum & 0xffff); |
368 | u16 reg_val; |
369 | int ret; |
370 | |
371 | dev_dbg(&bus->dev, "mdio read %s,base is %p\n" , |
372 | bus->id, mdio_dev->vbase); |
373 | dev_dbg(&bus->dev, "phy id=%d, devad=%d, reg=%#x!\n" , |
374 | phy_id, devad, reg); |
375 | |
376 | /* Step 1: wait for ready */ |
377 | ret = hns_mdio_wait_ready(bus); |
378 | if (ret) { |
379 | dev_err(&bus->dev, "MDIO bus is busy\n" ); |
380 | return ret; |
381 | } |
382 | |
383 | MDIO_SET_REG_FIELD(mdio_dev, MDIO_ADDR_REG, MDIO_ADDR_DATA_M, |
384 | MDIO_ADDR_DATA_S, reg); |
385 | |
386 | /* Step 2; config the cmd-reg to write addr*/ |
387 | hns_mdio_cmd_write(mdio_dev, is_c45: true, op: MDIO_C45_WRITE_ADDR, phy_id, cmd: devad); |
388 | |
389 | /* Step 3: check for read or write opt is finished */ |
390 | ret = hns_mdio_wait_ready(bus); |
391 | if (ret) { |
392 | dev_err(&bus->dev, "MDIO bus is busy\n" ); |
393 | return ret; |
394 | } |
395 | |
396 | hns_mdio_cmd_write(mdio_dev, is_c45: true, op: MDIO_C45_READ, phy_id, cmd: devad); |
397 | |
398 | /* Step 5: waiting for MDIO_COMMAND_REG 's mdio_start==0,*/ |
399 | /* check for read or write opt is finished */ |
400 | ret = hns_mdio_wait_ready(bus); |
401 | if (ret) { |
402 | dev_err(&bus->dev, "MDIO bus is busy\n" ); |
403 | return ret; |
404 | } |
405 | |
406 | reg_val = MDIO_GET_REG_BIT(mdio_dev, MDIO_STA_REG, MDIO_STATE_STA_B); |
407 | if (reg_val) { |
408 | dev_err(&bus->dev, " ERROR! MDIO Read failed!\n" ); |
409 | return -EBUSY; |
410 | } |
411 | |
412 | /* Step 6; get out data*/ |
413 | reg_val = (u16)MDIO_GET_REG_FIELD(mdio_dev, MDIO_RDATA_REG, |
414 | MDIO_RDATA_DATA_M, MDIO_RDATA_DATA_S); |
415 | |
416 | return reg_val; |
417 | } |
418 | |
419 | /** |
420 | * hns_mdio_reset - reset mdio bus |
421 | * @bus: mdio bus |
422 | * |
423 | * Return 0 on success, negative on failure |
424 | */ |
425 | static int hns_mdio_reset(struct mii_bus *bus) |
426 | { |
427 | struct hns_mdio_device *mdio_dev = bus->priv; |
428 | const struct hns_mdio_sc_reg *sc_reg; |
429 | int ret; |
430 | |
431 | if (dev_of_node(dev: bus->parent)) { |
432 | if (!mdio_dev->subctrl_vbase) { |
433 | dev_err(&bus->dev, "mdio sys ctl reg has not mapped\n" ); |
434 | return -ENODEV; |
435 | } |
436 | |
437 | sc_reg = &mdio_dev->sc_reg; |
438 | /* 1. reset req, and read reset st check */ |
439 | ret = mdio_sc_cfg_reg_write(mdio_dev, cfg_reg: sc_reg->mdio_reset_req, |
440 | set_val: 0x1, st_reg: sc_reg->mdio_reset_st, st_msk: 0x1, |
441 | MDIO_CHECK_SET_ST); |
442 | if (ret) { |
443 | dev_err(&bus->dev, "MDIO reset fail\n" ); |
444 | return ret; |
445 | } |
446 | |
447 | /* 2. dis clk, and read clk st check */ |
448 | ret = mdio_sc_cfg_reg_write(mdio_dev, cfg_reg: sc_reg->mdio_clk_dis, |
449 | set_val: 0x1, st_reg: sc_reg->mdio_clk_st, st_msk: 0x1, |
450 | MDIO_CHECK_CLR_ST); |
451 | if (ret) { |
452 | dev_err(&bus->dev, "MDIO dis clk fail\n" ); |
453 | return ret; |
454 | } |
455 | |
456 | /* 3. reset dreq, and read reset st check */ |
457 | ret = mdio_sc_cfg_reg_write(mdio_dev, cfg_reg: sc_reg->mdio_reset_dreq, |
458 | set_val: 0x1, st_reg: sc_reg->mdio_reset_st, st_msk: 0x1, |
459 | MDIO_CHECK_CLR_ST); |
460 | if (ret) { |
461 | dev_err(&bus->dev, "MDIO dis clk fail\n" ); |
462 | return ret; |
463 | } |
464 | |
465 | /* 4. en clk, and read clk st check */ |
466 | ret = mdio_sc_cfg_reg_write(mdio_dev, cfg_reg: sc_reg->mdio_clk_en, |
467 | set_val: 0x1, st_reg: sc_reg->mdio_clk_st, st_msk: 0x1, |
468 | MDIO_CHECK_SET_ST); |
469 | if (ret) |
470 | dev_err(&bus->dev, "MDIO en clk fail\n" ); |
471 | } else if (is_acpi_node(fwnode: bus->parent->fwnode)) { |
472 | acpi_status s; |
473 | |
474 | s = acpi_evaluate_object(ACPI_HANDLE(bus->parent), |
475 | pathname: "_RST" , NULL, NULL); |
476 | if (ACPI_FAILURE(s)) { |
477 | dev_err(&bus->dev, "Reset failed, return:%#x\n" , s); |
478 | ret = -EBUSY; |
479 | } else { |
480 | ret = 0; |
481 | } |
482 | } else { |
483 | dev_err(&bus->dev, "Can not get cfg data from DT or ACPI\n" ); |
484 | ret = -ENXIO; |
485 | } |
486 | return ret; |
487 | } |
488 | |
489 | /** |
490 | * hns_mdio_probe - probe mdio device |
491 | * @pdev: mdio platform device |
492 | * |
493 | * Return 0 on success, negative on failure |
494 | */ |
495 | static int hns_mdio_probe(struct platform_device *pdev) |
496 | { |
497 | struct hns_mdio_device *mdio_dev; |
498 | struct mii_bus *new_bus; |
499 | int ret; |
500 | |
501 | if (!pdev) { |
502 | dev_err(NULL, "pdev is NULL!\r\n" ); |
503 | return -ENODEV; |
504 | } |
505 | |
506 | mdio_dev = devm_kzalloc(dev: &pdev->dev, size: sizeof(*mdio_dev), GFP_KERNEL); |
507 | if (!mdio_dev) |
508 | return -ENOMEM; |
509 | |
510 | new_bus = devm_mdiobus_alloc(dev: &pdev->dev); |
511 | if (!new_bus) { |
512 | dev_err(&pdev->dev, "mdiobus_alloc fail!\n" ); |
513 | return -ENOMEM; |
514 | } |
515 | |
516 | new_bus->name = MDIO_BUS_NAME; |
517 | new_bus->read = hns_mdio_read_c22; |
518 | new_bus->write = hns_mdio_write_c22; |
519 | new_bus->read_c45 = hns_mdio_read_c45; |
520 | new_bus->write_c45 = hns_mdio_write_c45; |
521 | new_bus->reset = hns_mdio_reset; |
522 | new_bus->priv = mdio_dev; |
523 | new_bus->parent = &pdev->dev; |
524 | |
525 | mdio_dev->vbase = devm_platform_ioremap_resource(pdev, index: 0); |
526 | if (IS_ERR(ptr: mdio_dev->vbase)) { |
527 | ret = PTR_ERR(ptr: mdio_dev->vbase); |
528 | return ret; |
529 | } |
530 | |
531 | platform_set_drvdata(pdev, data: new_bus); |
532 | snprintf(buf: new_bus->id, MII_BUS_ID_SIZE, fmt: "%s-%s" , "Mii" , |
533 | dev_name(dev: &pdev->dev)); |
534 | if (dev_of_node(dev: &pdev->dev)) { |
535 | struct of_phandle_args reg_args; |
536 | |
537 | ret = of_parse_phandle_with_fixed_args(np: pdev->dev.of_node, |
538 | list_name: "subctrl-vbase" , |
539 | cell_count: 4, |
540 | index: 0, |
541 | out_args: ®_args); |
542 | if (!ret) { |
543 | mdio_dev->subctrl_vbase = |
544 | syscon_node_to_regmap(np: reg_args.np); |
545 | if (IS_ERR(ptr: mdio_dev->subctrl_vbase)) { |
546 | dev_warn(&pdev->dev, "syscon_node_to_regmap error\n" ); |
547 | mdio_dev->subctrl_vbase = NULL; |
548 | } else { |
549 | if (reg_args.args_count == 4) { |
550 | mdio_dev->sc_reg.mdio_clk_en = |
551 | (u16)reg_args.args[0]; |
552 | mdio_dev->sc_reg.mdio_clk_dis = |
553 | (u16)reg_args.args[0] + 4; |
554 | mdio_dev->sc_reg.mdio_reset_req = |
555 | (u16)reg_args.args[1]; |
556 | mdio_dev->sc_reg.mdio_reset_dreq = |
557 | (u16)reg_args.args[1] + 4; |
558 | mdio_dev->sc_reg.mdio_clk_st = |
559 | (u16)reg_args.args[2]; |
560 | mdio_dev->sc_reg.mdio_reset_st = |
561 | (u16)reg_args.args[3]; |
562 | } else { |
563 | /* for compatible */ |
564 | mdio_dev->sc_reg.mdio_clk_en = |
565 | MDIO_SC_CLK_EN; |
566 | mdio_dev->sc_reg.mdio_clk_dis = |
567 | MDIO_SC_CLK_DIS; |
568 | mdio_dev->sc_reg.mdio_reset_req = |
569 | MDIO_SC_RESET_REQ; |
570 | mdio_dev->sc_reg.mdio_reset_dreq = |
571 | MDIO_SC_RESET_DREQ; |
572 | mdio_dev->sc_reg.mdio_clk_st = |
573 | MDIO_SC_CLK_ST; |
574 | mdio_dev->sc_reg.mdio_reset_st = |
575 | MDIO_SC_RESET_ST; |
576 | } |
577 | } |
578 | } else { |
579 | dev_warn(&pdev->dev, "find syscon ret = %#x\n" , ret); |
580 | mdio_dev->subctrl_vbase = NULL; |
581 | } |
582 | |
583 | ret = of_mdiobus_register(mdio: new_bus, np: pdev->dev.of_node); |
584 | } else if (is_acpi_node(fwnode: pdev->dev.fwnode)) { |
585 | /* Clear all the IRQ properties */ |
586 | memset(new_bus->irq, PHY_POLL, 4 * PHY_MAX_ADDR); |
587 | |
588 | /* Mask out all PHYs from auto probing. */ |
589 | new_bus->phy_mask = ~0; |
590 | |
591 | /* Register the MDIO bus */ |
592 | ret = mdiobus_register(new_bus); |
593 | } else { |
594 | dev_err(&pdev->dev, "Can not get cfg data from DT or ACPI\n" ); |
595 | ret = -ENXIO; |
596 | } |
597 | |
598 | if (ret) { |
599 | dev_err(&pdev->dev, "Cannot register as MDIO bus!\n" ); |
600 | platform_set_drvdata(pdev, NULL); |
601 | return ret; |
602 | } |
603 | |
604 | return 0; |
605 | } |
606 | |
607 | /** |
608 | * hns_mdio_remove - remove mdio device |
609 | * @pdev: mdio platform device |
610 | * |
611 | * Return 0 on success, negative on failure |
612 | */ |
613 | static void hns_mdio_remove(struct platform_device *pdev) |
614 | { |
615 | struct mii_bus *bus; |
616 | |
617 | bus = platform_get_drvdata(pdev); |
618 | |
619 | mdiobus_unregister(bus); |
620 | platform_set_drvdata(pdev, NULL); |
621 | } |
622 | |
623 | static const struct of_device_id hns_mdio_match[] = { |
624 | {.compatible = "hisilicon,mdio" }, |
625 | {.compatible = "hisilicon,hns-mdio" }, |
626 | {} |
627 | }; |
628 | MODULE_DEVICE_TABLE(of, hns_mdio_match); |
629 | |
630 | static const struct acpi_device_id hns_mdio_acpi_match[] = { |
631 | { "HISI0141" , 0 }, |
632 | { }, |
633 | }; |
634 | MODULE_DEVICE_TABLE(acpi, hns_mdio_acpi_match); |
635 | |
636 | static struct platform_driver hns_mdio_driver = { |
637 | .probe = hns_mdio_probe, |
638 | .remove_new = hns_mdio_remove, |
639 | .driver = { |
640 | .name = MDIO_DRV_NAME, |
641 | .of_match_table = hns_mdio_match, |
642 | .acpi_match_table = ACPI_PTR(hns_mdio_acpi_match), |
643 | }, |
644 | }; |
645 | |
646 | module_platform_driver(hns_mdio_driver); |
647 | |
648 | MODULE_LICENSE("GPL" ); |
649 | MODULE_AUTHOR("Huawei Tech. Co., Ltd." ); |
650 | MODULE_DESCRIPTION("Hisilicon HNS MDIO driver" ); |
651 | MODULE_ALIAS("platform:" MDIO_DRV_NAME); |
652 | |