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, &regValue);
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, &regValue);
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, &regValue);
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, &regValue);
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, &regValue);
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, &regValue);
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, &regValue);
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, &regValue);
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, &regValue);
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, &regValue);
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, &regValue);
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, &regValue);
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, &regValue);
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, &regValue);
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, &regValue);
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