1 /*
2 * Copyright 2020-2023 NXP
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include "fsl_phyrtl8211f.h"
8
9 /*******************************************************************************
10 * Definitions
11 ******************************************************************************/
12
13 /*! @brief Defines the PHY RTL8211F vendor defined registers. */
14 #define PHY_SPECIFIC_STATUS_REG (0x1AU) /*!< The PHY specific status register. */
15 #define PHY_PAGE_SELECT_REG (0x1FU) /*!< The PHY page select register. */
16
17 /*! @brief Defines the PHY RTL8211F ID number. */
18 #define PHY_CONTROL_ID1 (0x001CU) /*!< The PHY ID1 . */
19
20 /*! @brief Defines the mask flag in interrupt enable register. */
21 #define PHY_INER_LINKSTATUS_CHANGE_MASK ((uint16_t)0x0010U) /*!< The PHY link status change interrupt mask. */
22
23 /*! @brief Defines the mask flag in specific status register. */
24 #define PHY_SSTATUS_LINKSTATUS_MASK ((uint16_t)0x0004U) /*!< The PHY link status mask. */
25 #define PHY_SSTATUS_LINKSPEED_MASK ((uint16_t)0x0030U) /*!< The PHY link speed mask. */
26 #define PHY_SSTATUS_LINKDUPLEX_MASK ((uint16_t)0x0008U) /*!< The PHY link duplex mask. */
27 #define PHY_SSTATUS_LINKSPEED_SHIFT (4U) /*!< The link speed shift */
28
29 /*! @brief Defines the PHY RTL8211F extra page and the registers in specified page. */
30 #define PHY_PAGE_RGMII_TXRX_DELAY_ADDR (0xD08U) /*!< The register page including RGMII TX/RX delay setting. */
31 #define PHY_RGMII_TX_DELAY_REG (0x11U) /*!< The RGMII TXC delay register. */
32 #define PHY_RGMII_RX_DELAY_REG (0x15U) /*!< The RGMII RXC delay register. */
33 #define PHY_RGMII_TX_DELAY_MASK ((uint16_t)0x0100U) /*!< The RGMII TXC delay mask. */
34 #define PHY_RGMII_RX_DELAY_MASK ((uint16_t)0x0008U) /*!< The RGMII RXC delay mask. */
35
36 #define PHY_PAGE_INTR_PIN_ADDR (0xD40U) /*!< The register page including PHY interrupt pin setting. */
37 #define PHY_PAGE_INTR_PIN_REG (0x16U) /*!< The PHY interrupt pin setting register. */
38 #define PHY_PAGE_INTR_PIN_MASK ((uint16_t)0x0020U) /*!< The PHY interrupt pin setting mask. */
39
40 #define PHY_PAGE_INTR_ADDR (0xA42U) /*!< The register page including interrupt control setting. */
41 #define PHY_INER_REG (0x12U) /*!< The PHY interrupt enable register. */
42 #define PHY_INSR_REG (0x1DU) /*!< The PHY interrupt status register. */
43
44 /*! @brief MDIO MMD Devices .*/
45 #define PHY_MDIO_MMD_PCS 3U
46 #define PHY_MDIO_MMD_AN 7U
47
48 /*! @brief MDIO MMD Physical Coding layer device registers .*/
49 #define PHY_MDIO_PCS_EEE_CAP 0x14U /*!< EEE capability */
50
51 /*! @brief MDIO MMD AutoNegotiation device registers .*/
52 #define PHY_MDIO_AN_EEE_ADV 0x3CU /*!< EEE advertisement */
53
54 /*! @brief MDIO MMD EEE mask flags. (common for adv and cap) */
55 #define PHY_MDIO_EEE_100TX 0x2U
56 #define PHY_MDIO_EEE_1000T 0x4U
57
58 /*! @brief Defines the timeout macro. */
59 #define PHY_READID_TIMEOUT_COUNT 1000U
60
61 /*! @brief Defines the PHY resource interface. */
62 #define PHY_RTL8211F_WRITE(handle, regAddr, data) \
63 ((phy_rtl8211f_resource_t *)(handle)->resource)->write((handle)->phyAddr, regAddr, data)
64 #define PHY_RTL8211F_READ(handle, regAddr, pData) \
65 ((phy_rtl8211f_resource_t *)(handle)->resource)->read((handle)->phyAddr, regAddr, pData)
66
67 /*******************************************************************************
68 * Prototypes
69 ******************************************************************************/
70
71 static status_t PHY_RTL8211F_MMD_SetDevice(phy_handle_t *handle,
72 uint8_t device,
73 uint16_t addr,
74 phy_mmd_access_mode_t mode);
75 static inline status_t PHY_RTL8211F_MMD_ReadData(phy_handle_t *handle, uint16_t *pData);
76 static inline status_t PHY_RTL8211F_MMD_WriteData(phy_handle_t *handle, uint16_t data);
77 static status_t PHY_RTL8211F_MMD_Read(phy_handle_t *handle, uint8_t device, uint16_t addr, uint16_t *pData);
78 static status_t PHY_RTL8211F_MMD_Write(phy_handle_t *handle, uint8_t device, uint16_t addr, uint16_t data);
79
80 /*******************************************************************************
81 * Variables
82 ******************************************************************************/
83
84 const phy_operations_t phyrtl8211f_ops = {.phyInit = PHY_RTL8211F_Init,
85 .phyWrite = PHY_RTL8211F_Write,
86 .phyRead = PHY_RTL8211F_Read,
87 .getAutoNegoStatus = PHY_RTL8211F_GetAutoNegotiationStatus,
88 .getLinkStatus = PHY_RTL8211F_GetLinkStatus,
89 .getLinkSpeedDuplex = PHY_RTL8211F_GetLinkSpeedDuplex,
90 .setLinkSpeedDuplex = PHY_RTL8211F_SetLinkSpeedDuplex,
91 .enableLoopback = PHY_RTL8211F_EnableLoopback,
92 .enableLinkInterrupt = PHY_RTL8211F_EnableLinkInterrupt,
93 .clearInterrupt = PHY_RTL8211F_ClearInterrupt};
94
95 /*******************************************************************************
96 * Code
97 ******************************************************************************/
98
PHY_RTL8211F_Init(phy_handle_t * handle,const phy_config_t * config)99 status_t PHY_RTL8211F_Init(phy_handle_t *handle, const phy_config_t *config)
100 {
101 uint32_t counter = PHY_READID_TIMEOUT_COUNT;
102 uint16_t regValue = 0U;
103 status_t result;
104
105 /* Assign PHY address and operation resource. */
106 handle->phyAddr = config->phyAddr;
107 handle->resource = config->resource;
108
109 /* Check PHY ID. */
110 do
111 {
112 result = PHY_RTL8211F_READ(handle, PHY_ID1_REG, ®Value);
113 if (result != kStatus_Success)
114 {
115 return result;
116 }
117 counter--;
118 } while ((regValue != PHY_CONTROL_ID1) && (counter != 0U));
119
120 if (counter == 0U)
121 {
122 return kStatus_Fail;
123 }
124
125 /* Reset PHY. */
126 result = PHY_RTL8211F_WRITE(handle, PHY_BASICCONTROL_REG, PHY_BCTL_RESET_MASK);
127 if (result != kStatus_Success)
128 {
129 return result;
130 }
131
132 do
133 {
134 result = PHY_RTL8211F_READ(handle, PHY_BASICCONTROL_REG, ®Value);
135 if (result != kStatus_Success)
136 {
137 return result;
138 }
139 } while ((regValue & PHY_BCTL_RESET_MASK) != 0U);
140
141 /* The RGMII specifies output TXC/RXC and TXD/RXD without any clock skew. Need to add skew on clock line
142 to make sure the other side sample right data. This can also be done in PCB traces. */
143 result = PHY_RTL8211F_WRITE(handle, PHY_PAGE_SELECT_REG, PHY_PAGE_RGMII_TXRX_DELAY_ADDR);
144 if (result != kStatus_Success)
145 {
146 return result;
147 }
148 /* Set Tx Delay. */
149 result = PHY_RTL8211F_READ(handle, PHY_RGMII_TX_DELAY_REG, ®Value);
150 if (result == kStatus_Success)
151 {
152 regValue |= PHY_RGMII_TX_DELAY_MASK;
153 result = PHY_RTL8211F_WRITE(handle, PHY_RGMII_TX_DELAY_REG, regValue);
154 if (result != kStatus_Success)
155 {
156 return result;
157 }
158 }
159 else
160 {
161 return result;
162 }
163
164 /* Set Rx Delay. */
165 result = PHY_RTL8211F_READ(handle, PHY_RGMII_RX_DELAY_REG, ®Value);
166 if (result == kStatus_Success)
167 {
168 regValue |= PHY_RGMII_RX_DELAY_MASK;
169 result = PHY_RTL8211F_WRITE(handle, PHY_RGMII_RX_DELAY_REG, regValue);
170 if (result != kStatus_Success)
171 {
172 return result;
173 }
174 }
175 else
176 {
177 return result;
178 }
179 /* Restore to default page 0 */
180 result = PHY_RTL8211F_WRITE(handle, PHY_PAGE_SELECT_REG, 0x0);
181 if (result != kStatus_Success)
182 {
183 return result;
184 }
185
186 /* Energy Efficient Ethernet configuration */
187 if (config->enableEEE)
188 {
189 /* Get capabilities */
190 result = PHY_RTL8211F_MMD_Read(handle, PHY_MDIO_MMD_PCS, PHY_MDIO_PCS_EEE_CAP, ®Value);
191 if (result == kStatus_Success)
192 {
193 /* Enable EEE for 100TX and 1000T */
194 result = PHY_RTL8211F_MMD_Write(handle, PHY_MDIO_MMD_AN, PHY_MDIO_AN_EEE_ADV,
195 regValue & (PHY_MDIO_EEE_1000T | PHY_MDIO_EEE_100TX));
196 }
197 }
198 else
199 {
200 result = PHY_RTL8211F_MMD_Write(handle, PHY_MDIO_MMD_AN, PHY_MDIO_AN_EEE_ADV, 0);
201 }
202 if (result != kStatus_Success)
203 {
204 return result;
205 }
206
207 /* Set INT pin as interrupt mode. */
208 result = PHY_RTL8211F_WRITE(handle, PHY_PAGE_SELECT_REG, PHY_PAGE_INTR_PIN_ADDR);
209 if (result != kStatus_Success)
210 {
211 return result;
212 }
213 result = PHY_RTL8211F_READ(handle, PHY_PAGE_INTR_PIN_REG, ®Value);
214 if (result == kStatus_Success)
215 {
216 regValue &= ~PHY_PAGE_INTR_PIN_MASK;
217 result = PHY_RTL8211F_WRITE(handle, PHY_PAGE_INTR_PIN_REG, regValue);
218 if (result != kStatus_Success)
219 {
220 return result;
221 }
222 }
223 else
224 {
225 return result;
226 }
227 /* Restore to default page 0 */
228 result = PHY_RTL8211F_WRITE(handle, PHY_PAGE_SELECT_REG, 0);
229 if (result != kStatus_Success)
230 {
231 return result;
232 }
233
234 result = PHY_RTL8211F_ClearInterrupt(handle);
235 if (result != kStatus_Success)
236 {
237 return result;
238 }
239
240 if (config->autoNeg)
241 {
242 /* Set the auto-negotiation. */
243 result = PHY_RTL8211F_WRITE(handle, PHY_AUTONEG_ADVERTISE_REG,
244 PHY_100BASETX_FULLDUPLEX_MASK | PHY_100BASETX_HALFDUPLEX_MASK |
245 PHY_10BASETX_FULLDUPLEX_MASK | PHY_10BASETX_HALFDUPLEX_MASK |
246 PHY_IEEE802_3_SELECTOR_MASK);
247 if (result == kStatus_Success)
248 {
249 result = PHY_RTL8211F_WRITE(handle, PHY_1000BASET_CONTROL_REG, PHY_1000BASET_FULLDUPLEX_MASK);
250 if (result == kStatus_Success)
251 {
252 result = PHY_RTL8211F_READ(handle, PHY_BASICCONTROL_REG, ®Value);
253 if (result == kStatus_Success)
254 {
255 result = PHY_RTL8211F_WRITE(handle, PHY_BASICCONTROL_REG,
256 (regValue | PHY_BCTL_AUTONEG_MASK | PHY_BCTL_RESTART_AUTONEG_MASK));
257 }
258 }
259 }
260 }
261 else
262 {
263 /* Disable isolate mode */
264 result = PHY_RTL8211F_READ(handle, PHY_BASICCONTROL_REG, ®Value);
265 if (result != kStatus_Success)
266 {
267 return result;
268 }
269 regValue &= ~PHY_BCTL_ISOLATE_MASK;
270 result = PHY_RTL8211F_WRITE(handle, PHY_BASICCONTROL_REG, regValue);
271 if (result != kStatus_Success)
272 {
273 return result;
274 }
275
276 /* Disable the auto-negotiation and set user-defined speed/duplex configuration. */
277 result = PHY_RTL8211F_SetLinkSpeedDuplex(handle, config->speed, config->duplex);
278 }
279 if (result != kStatus_Success)
280 {
281 return result;
282 }
283
284 result = PHY_RTL8211F_EnableLinkInterrupt(handle, config->intrType);
285
286 return result;
287 }
288
PHY_RTL8211F_Write(phy_handle_t * handle,uint8_t phyReg,uint16_t data)289 status_t PHY_RTL8211F_Write(phy_handle_t *handle, uint8_t phyReg, uint16_t data)
290 {
291 return PHY_RTL8211F_WRITE(handle, phyReg, data);
292 }
293
PHY_RTL8211F_Read(phy_handle_t * handle,uint8_t phyReg,uint16_t * pData)294 status_t PHY_RTL8211F_Read(phy_handle_t *handle, uint8_t phyReg, uint16_t *pData)
295 {
296 return PHY_RTL8211F_READ(handle, phyReg, pData);
297 }
298
PHY_RTL8211F_GetAutoNegotiationStatus(phy_handle_t * handle,bool * status)299 status_t PHY_RTL8211F_GetAutoNegotiationStatus(phy_handle_t *handle, bool *status)
300 {
301 assert(status);
302
303 status_t result;
304 uint16_t regValue;
305
306 *status = false;
307
308 /* Check auto negotiation complete. */
309 result = PHY_RTL8211F_READ(handle, PHY_BASICSTATUS_REG, ®Value);
310 if (result == kStatus_Success)
311 {
312 if ((regValue & PHY_BSTATUS_AUTONEGCOMP_MASK) != 0U)
313 {
314 *status = true;
315 }
316 }
317 return result;
318 }
319
PHY_RTL8211F_GetLinkStatus(phy_handle_t * handle,bool * status)320 status_t PHY_RTL8211F_GetLinkStatus(phy_handle_t *handle, bool *status)
321 {
322 assert(status);
323
324 status_t result;
325 uint16_t regValue;
326
327 /* Read the basic status register. */
328 result = PHY_RTL8211F_READ(handle, PHY_SPECIFIC_STATUS_REG, ®Value);
329 if (result == kStatus_Success)
330 {
331 if ((PHY_SSTATUS_LINKSTATUS_MASK & regValue) != 0U)
332 {
333 /* Link up. */
334 *status = true;
335 }
336 else
337 {
338 /* Link down. */
339 *status = false;
340 }
341 }
342 return result;
343 }
344
PHY_RTL8211F_GetLinkSpeedDuplex(phy_handle_t * handle,phy_speed_t * speed,phy_duplex_t * duplex)345 status_t PHY_RTL8211F_GetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t *speed, phy_duplex_t *duplex)
346 {
347 assert(!((speed == NULL) && (duplex == NULL)));
348
349 status_t result;
350 uint16_t regValue;
351
352 /* Read the status register. */
353 result = PHY_RTL8211F_READ(handle, PHY_SPECIFIC_STATUS_REG, ®Value);
354 if (result == kStatus_Success)
355 {
356 if (speed != NULL)
357 {
358 switch ((regValue & PHY_SSTATUS_LINKSPEED_MASK) >> PHY_SSTATUS_LINKSPEED_SHIFT)
359 {
360 case (uint16_t)kPHY_Speed10M:
361 *speed = kPHY_Speed10M;
362 break;
363 case (uint16_t)kPHY_Speed100M:
364 *speed = kPHY_Speed100M;
365 break;
366 case (uint16_t)kPHY_Speed1000M:
367 *speed = kPHY_Speed1000M;
368 break;
369 default:
370 *speed = kPHY_Speed10M;
371 break;
372 }
373 }
374
375 if (duplex != NULL)
376 {
377 if ((regValue & PHY_SSTATUS_LINKDUPLEX_MASK) != 0U)
378 {
379 *duplex = kPHY_FullDuplex;
380 }
381 else
382 {
383 *duplex = kPHY_HalfDuplex;
384 }
385 }
386 }
387 return result;
388 }
389
PHY_RTL8211F_SetLinkSpeedDuplex(phy_handle_t * handle,phy_speed_t speed,phy_duplex_t duplex)390 status_t PHY_RTL8211F_SetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t speed, phy_duplex_t duplex)
391 {
392 status_t result;
393 uint16_t regValue;
394
395 result = PHY_RTL8211F_READ(handle, PHY_BASICCONTROL_REG, ®Value);
396 if (result == kStatus_Success)
397 {
398 /* Disable the auto-negotiation and set according to user-defined configuration. */
399 regValue &= ~PHY_BCTL_AUTONEG_MASK;
400 if (speed == kPHY_Speed1000M)
401 {
402 regValue &= PHY_BCTL_SPEED0_MASK;
403 regValue |= PHY_BCTL_SPEED1_MASK;
404 }
405 else if (speed == kPHY_Speed100M)
406 {
407 regValue |= PHY_BCTL_SPEED0_MASK;
408 regValue &= ~PHY_BCTL_SPEED1_MASK;
409 }
410 else
411 {
412 regValue &= ~PHY_BCTL_SPEED0_MASK;
413 regValue &= ~PHY_BCTL_SPEED1_MASK;
414 }
415 if (duplex == kPHY_FullDuplex)
416 {
417 regValue |= PHY_BCTL_DUPLEX_MASK;
418 }
419 else
420 {
421 regValue &= ~PHY_BCTL_DUPLEX_MASK;
422 }
423 result = PHY_RTL8211F_WRITE(handle, PHY_BASICCONTROL_REG, regValue);
424 }
425 return result;
426 }
427
PHY_RTL8211F_EnableLoopback(phy_handle_t * handle,phy_loop_t mode,phy_speed_t speed,bool enable)428 status_t PHY_RTL8211F_EnableLoopback(phy_handle_t *handle, phy_loop_t mode, phy_speed_t speed, bool enable)
429 {
430 /* This PHY only supports local loopback. */
431 assert(mode == kPHY_LocalLoop);
432
433 status_t result;
434 uint16_t regValue;
435
436 /* Set the loop mode. */
437 if (enable)
438 {
439 if (speed == kPHY_Speed1000M)
440 {
441 regValue = PHY_BCTL_SPEED1_MASK | PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK;
442 }
443 else if (speed == kPHY_Speed100M)
444 {
445 regValue = PHY_BCTL_SPEED0_MASK | PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK;
446 }
447 else
448 {
449 regValue = PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK;
450 }
451 result = PHY_RTL8211F_WRITE(handle, PHY_BASICCONTROL_REG, regValue);
452 }
453 else
454 {
455 /* First read the current status in control register. */
456 result = PHY_RTL8211F_READ(handle, PHY_BASICCONTROL_REG, ®Value);
457 if (result == kStatus_Success)
458 {
459 regValue &= ~PHY_BCTL_LOOP_MASK;
460 result = PHY_RTL8211F_WRITE(handle, PHY_BASICCONTROL_REG, (regValue | PHY_BCTL_RESTART_AUTONEG_MASK));
461 }
462 }
463 return result;
464 }
465
PHY_RTL8211F_EnableLinkInterrupt(phy_handle_t * handle,phy_interrupt_type_t type)466 status_t PHY_RTL8211F_EnableLinkInterrupt(phy_handle_t *handle, phy_interrupt_type_t type)
467 {
468 assert(type != kPHY_IntrActiveHigh);
469
470 status_t result;
471 uint16_t regValue;
472
473 result = PHY_Write(handle, PHY_PAGE_SELECT_REG, PHY_PAGE_INTR_ADDR);
474 if (result != kStatus_Success)
475 {
476 return result;
477 }
478
479 /* Read operation will clear pending interrupt before enable interrupt. */
480 result = PHY_RTL8211F_READ(handle, PHY_INER_REG, ®Value);
481 if (result != kStatus_Success)
482 {
483 return result;
484 }
485
486 /* Enable/Disable link up+down interrupt. */
487 if (type != kPHY_IntrDisable)
488 {
489 regValue |= PHY_INER_LINKSTATUS_CHANGE_MASK;
490 }
491 else
492 {
493 regValue &= ~PHY_INER_LINKSTATUS_CHANGE_MASK;
494 }
495 result = PHY_RTL8211F_WRITE(handle, PHY_INER_REG, regValue);
496 if (result != kStatus_Success)
497 {
498 return result;
499 }
500
501 /* Restore to default page 0 */
502 result = PHY_Write(handle, PHY_PAGE_SELECT_REG, 0);
503 if (result != kStatus_Success)
504 {
505 return result;
506 }
507
508 return result;
509 }
510
PHY_RTL8211F_ClearInterrupt(phy_handle_t * handle)511 status_t PHY_RTL8211F_ClearInterrupt(phy_handle_t *handle)
512 {
513 uint16_t regValue;
514
515 /* Found both read reg 0x1D from page 0 or page 0xA42 are useful. But datasheet
516 describes it's in page 0xA42. Here use simpler implementation. */
517 return PHY_RTL8211F_READ(handle, PHY_INSR_REG, ®Value);
518 }
519
PHY_RTL8211F_MMD_SetDevice(phy_handle_t * handle,uint8_t device,uint16_t addr,phy_mmd_access_mode_t mode)520 static status_t PHY_RTL8211F_MMD_SetDevice(phy_handle_t *handle,
521 uint8_t device,
522 uint16_t addr,
523 phy_mmd_access_mode_t mode)
524 {
525 status_t result = kStatus_Success;
526
527 /* Set Function mode of address access(b00) and device address. */
528 result = PHY_RTL8211F_WRITE(handle, PHY_MMD_ACCESS_CONTROL_REG, device);
529 if (result != kStatus_Success)
530 {
531 return result;
532 }
533
534 /* Set register address. */
535 result = PHY_RTL8211F_WRITE(handle, PHY_MMD_ACCESS_DATA_REG, addr);
536 if (result != kStatus_Success)
537 {
538 return result;
539 }
540
541 /* Set Function mode of data access(b01~11) and device address. */
542 result = PHY_RTL8211F_WRITE(handle, PHY_MMD_ACCESS_CONTROL_REG, (uint16_t)mode | (uint16_t)device);
543 return result;
544 }
545
PHY_RTL8211F_MMD_ReadData(phy_handle_t * handle,uint16_t * pData)546 static inline status_t PHY_RTL8211F_MMD_ReadData(phy_handle_t *handle, uint16_t *pData)
547 {
548 return PHY_RTL8211F_READ(handle, PHY_MMD_ACCESS_DATA_REG, pData);
549 }
550
PHY_RTL8211F_MMD_WriteData(phy_handle_t * handle,uint16_t data)551 static inline status_t PHY_RTL8211F_MMD_WriteData(phy_handle_t *handle, uint16_t data)
552 {
553 return PHY_RTL8211F_WRITE(handle, PHY_MMD_ACCESS_DATA_REG, data);
554 }
555
PHY_RTL8211F_MMD_Read(phy_handle_t * handle,uint8_t device,uint16_t addr,uint16_t * pData)556 static status_t PHY_RTL8211F_MMD_Read(phy_handle_t *handle, uint8_t device, uint16_t addr, uint16_t *pData)
557 {
558 status_t result = kStatus_Success;
559 result = PHY_RTL8211F_MMD_SetDevice(handle, device, addr, kPHY_MMDAccessNoPostIncrement);
560 if (result == kStatus_Success)
561 {
562 result = PHY_RTL8211F_MMD_ReadData(handle, pData);
563 }
564 return result;
565 }
566
PHY_RTL8211F_MMD_Write(phy_handle_t * handle,uint8_t device,uint16_t addr,uint16_t data)567 static status_t PHY_RTL8211F_MMD_Write(phy_handle_t *handle, uint8_t device, uint16_t addr, uint16_t data)
568 {
569 status_t result = kStatus_Success;
570
571 result = PHY_RTL8211F_MMD_SetDevice(handle, device, addr, kPHY_MMDAccessNoPostIncrement);
572 if (result == kStatus_Success)
573 {
574 result = PHY_RTL8211F_MMD_WriteData(handle, data);
575 }
576 return result;
577 }
578