1
2
3
4
5
6
7
8
9#include <linux/export.h>
10#include <linux/phy.h>
11
12static void mmd_phy_indirect(struct mii_bus *bus, int phy_addr, int devad,
13 u16 regnum)
14{
15
16 __mdiobus_write(bus, phy_addr, MII_MMD_CTRL, devad);
17
18
19 __mdiobus_write(bus, phy_addr, MII_MMD_DATA, regnum);
20
21
22 __mdiobus_write(bus, phy_addr, MII_MMD_CTRL,
23 devad | MII_MMD_CTRL_NOINCR);
24}
25
26
27
28
29
30
31
32
33
34
35int __phy_read_mmd(struct phy_device *phydev, int devad, u32 regnum)
36{
37 int val;
38
39 if (regnum > (u16)~0 || devad > 32)
40 return -EINVAL;
41
42 if (phydev->drv->read_mmd) {
43 val = phydev->drv->read_mmd(phydev, devad, regnum);
44 } else if (phydev->is_c45) {
45 u32 addr = MII_ADDR_C45 | (devad << 16) | (regnum & 0xffff);
46
47 val = __mdiobus_read(phydev->mdio_bus, phydev->mdio_addr, addr);
48 } else {
49 struct mii_bus *bus = phydev->mdio_bus;
50 int phy_addr = phydev->mdio_addr;
51
52 mmd_phy_indirect(bus, phy_addr, devad, regnum);
53
54
55 val = __mdiobus_read(bus, phy_addr, MII_MMD_DATA);
56 }
57 return val;
58}
59EXPORT_SYMBOL(__phy_read_mmd);
60
61
62
63
64
65
66
67
68
69
70int phy_read_mmd(struct phy_device *phydev, int devad, u32 regnum)
71{
72 int ret;
73
74 mutex_lock(&phydev->mdio_bus->mdio_lock);
75 ret = __phy_read_mmd(phydev, devad, regnum);
76 mutex_unlock(&phydev->mdio_bus->mdio_lock);
77
78 return ret;
79}
80EXPORT_SYMBOL(phy_read_mmd);
81
82
83
84
85
86
87
88
89
90
91
92int __phy_write_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val)
93{
94 int ret;
95
96 if (regnum > (u16)~0 || devad > 32)
97 return -EINVAL;
98
99 if (phydev->drv->write_mmd) {
100 ret = phydev->drv->write_mmd(phydev, devad, regnum, val);
101 } else if (phydev->is_c45) {
102 u32 addr = MII_ADDR_C45 | (devad << 16) | (regnum & 0xffff);
103
104 ret = __mdiobus_write(phydev->mdio_bus, phydev->mdio_addr,
105 addr, val);
106 } else {
107 struct mii_bus *bus = phydev->mdio_bus;
108 int phy_addr = phydev->mdio_addr;
109
110 mmd_phy_indirect(bus, phy_addr, devad, regnum);
111
112
113 __mdiobus_write(bus, phy_addr, MII_MMD_DATA, val);
114
115 ret = 0;
116 }
117 return ret;
118}
119EXPORT_SYMBOL(__phy_write_mmd);
120
121
122
123
124
125
126
127
128
129
130
131int phy_write_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val)
132{
133 int ret;
134
135 mutex_lock(&phydev->mdio_bus->mdio_lock);
136 ret = __phy_write_mmd(phydev, devad, regnum, val);
137 mutex_unlock(&phydev->mdio_bus->mdio_lock);
138
139 return ret;
140}
141EXPORT_SYMBOL(phy_write_mmd);
142
143
144
145
146
147
148
149
150
151
152
153
154
155int __phy_modify_changed(struct phy_device *phydev, u32 regnum, u16 mask,
156 u16 set)
157{
158 int new, ret;
159
160 ret = __phy_read(phydev, regnum);
161 if (ret < 0)
162 return ret;
163
164 new = (ret & ~mask) | set;
165 if (new == ret)
166 return 0;
167
168 ret = __phy_write(phydev, regnum, new);
169
170 return ret < 0 ? ret : 1;
171}
172EXPORT_SYMBOL_GPL(__phy_modify_changed);
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187int phy_modify_changed(struct phy_device *phydev, u32 regnum, u16 mask, u16 set)
188{
189 int ret;
190
191 mutex_lock(&phydev->mdio_bus->mdio_lock);
192 ret = __phy_modify_changed(phydev, regnum, mask, set);
193 mutex_unlock(&phydev->mdio_bus->mdio_lock);
194
195 return ret;
196}
197EXPORT_SYMBOL_GPL(phy_modify_changed);
198
199
200
201
202
203
204
205
206
207
208
209
210int __phy_modify(struct phy_device *phydev, u32 regnum, u16 mask, u16 set)
211{
212 int ret;
213
214 ret = __phy_modify_changed(phydev, regnum, mask, set);
215
216 return ret < 0 ? ret : 0;
217}
218EXPORT_SYMBOL_GPL(__phy_modify);
219
220
221
222
223
224
225
226
227
228
229
230
231int phy_modify(struct phy_device *phydev, u32 regnum, u16 mask, u16 set)
232{
233 int ret;
234
235 mutex_lock(&phydev->mdio_bus->mdio_lock);
236 ret = __phy_modify(phydev, regnum, mask, set);
237 mutex_unlock(&phydev->mdio_bus->mdio_lock);
238
239 return ret;
240}
241EXPORT_SYMBOL_GPL(phy_modify);
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256int __phy_modify_mmd_changed(struct phy_device *phydev, int devad, u32 regnum,
257 u16 mask, u16 set)
258{
259 int new, ret;
260
261 ret = __phy_read_mmd(phydev, devad, regnum);
262 if (ret < 0)
263 return ret;
264
265 new = (ret & ~mask) | set;
266 if (new == ret)
267 return 0;
268
269 ret = __phy_write_mmd(phydev, devad, regnum, new);
270
271 return ret < 0 ? ret : 1;
272}
273EXPORT_SYMBOL_GPL(__phy_modify_mmd_changed);
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289int phy_modify_mmd_changed(struct phy_device *phydev, int devad, u32 regnum,
290 u16 mask, u16 set)
291{
292 int ret;
293
294 mutex_lock(&phydev->mdio_bus->mdio_lock);
295 ret = __phy_modify_mmd_changed(phydev, devad, regnum, mask, set);
296 mutex_unlock(&phydev->mdio_bus->mdio_lock);
297
298 return ret;
299}
300EXPORT_SYMBOL_GPL(phy_modify_mmd_changed);
301
302
303
304
305
306
307
308
309
310
311
312
313
314int __phy_modify_mmd(struct phy_device *phydev, int devad, u32 regnum,
315 u16 mask, u16 set)
316{
317 int ret;
318
319 ret = __phy_modify_mmd_changed(phydev, devad, regnum, mask, set);
320
321 return ret < 0 ? ret : 0;
322}
323EXPORT_SYMBOL_GPL(__phy_modify_mmd);
324
325
326
327
328
329
330
331
332
333
334
335
336
337int phy_modify_mmd(struct phy_device *phydev, int devad, u32 regnum,
338 u16 mask, u16 set)
339{
340 int ret;
341
342 mutex_lock(&phydev->mdio_bus->mdio_lock);
343 ret = __phy_modify_mmd(phydev, devad, regnum, mask, set);
344 mutex_unlock(&phydev->mdio_bus->mdio_lock);
345
346 return ret;
347}
348EXPORT_SYMBOL_GPL(phy_modify_mmd);
349
350static int __phy_read_page(struct phy_device *phydev)
351{
352 return phydev->drv->read_page(phydev);
353}
354
355static int __phy_write_page(struct phy_device *phydev, int page)
356{
357 return phydev->drv->write_page(phydev, page);
358}
359
360
361
362
363
364
365
366
367
368int phy_save_page(struct phy_device *phydev)
369{
370 mutex_lock(&phydev->mdio_bus->mdio_lock);
371 return __phy_read_page(phydev);
372}
373EXPORT_SYMBOL_GPL(phy_save_page);
374
375
376
377
378
379
380
381
382
383
384
385
386int phy_select_page(struct phy_device *phydev, int page)
387{
388 int ret, oldpage;
389
390 oldpage = ret = phy_save_page(phydev);
391 if (ret < 0)
392 return ret;
393
394 if (oldpage != page) {
395 ret = __phy_write_page(phydev, page);
396 if (ret < 0)
397 return ret;
398 }
399
400 return oldpage;
401}
402EXPORT_SYMBOL_GPL(phy_select_page);
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420int phy_restore_page(struct phy_device *phydev, int oldpage, int ret)
421{
422 int r;
423
424 if (oldpage >= 0) {
425 r = __phy_write_page(phydev, oldpage);
426
427
428
429
430 if (ret >= 0 && r < 0)
431 ret = r;
432 } else {
433
434 ret = oldpage;
435 }
436
437 mutex_unlock(&phydev->mdio_bus->mdio_lock);
438
439 return ret;
440}
441EXPORT_SYMBOL_GPL(phy_restore_page);
442
443
444
445
446
447
448
449
450
451int phy_read_paged(struct phy_device *phydev, int page, u32 regnum)
452{
453 int ret = 0, oldpage;
454
455 oldpage = phy_select_page(phydev, page);
456 if (oldpage >= 0)
457 ret = __phy_read(phydev, regnum);
458
459 return phy_restore_page(phydev, oldpage, ret);
460}
461EXPORT_SYMBOL(phy_read_paged);
462
463
464
465
466
467
468
469
470
471
472int phy_write_paged(struct phy_device *phydev, int page, u32 regnum, u16 val)
473{
474 int ret = 0, oldpage;
475
476 oldpage = phy_select_page(phydev, page);
477 if (oldpage >= 0)
478 ret = __phy_write(phydev, regnum, val);
479
480 return phy_restore_page(phydev, oldpage, ret);
481}
482EXPORT_SYMBOL(phy_write_paged);
483
484
485
486
487
488
489
490
491
492
493
494int phy_modify_paged(struct phy_device *phydev, int page, u32 regnum,
495 u16 mask, u16 set)
496{
497 int ret = 0, oldpage;
498
499 oldpage = phy_select_page(phydev, page);
500 if (oldpage >= 0)
501 ret = __phy_modify(phydev, regnum, mask, set);
502
503 return phy_restore_page(phydev, oldpage, ret);
504}
505EXPORT_SYMBOL(phy_modify_paged);
506