aboutsummaryrefslogtreecommitdiff
path: root/lib/chibios-contrib/ext/mcux-sdk/components/phy/device/phylan8720a/fsl_phylan8720a.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/chibios-contrib/ext/mcux-sdk/components/phy/device/phylan8720a/fsl_phylan8720a.c')
-rw-r--r--lib/chibios-contrib/ext/mcux-sdk/components/phy/device/phylan8720a/fsl_phylan8720a.c330
1 files changed, 330 insertions, 0 deletions
diff --git a/lib/chibios-contrib/ext/mcux-sdk/components/phy/device/phylan8720a/fsl_phylan8720a.c b/lib/chibios-contrib/ext/mcux-sdk/components/phy/device/phylan8720a/fsl_phylan8720a.c
new file mode 100644
index 000000000..67353b4fa
--- /dev/null
+++ b/lib/chibios-contrib/ext/mcux-sdk/components/phy/device/phylan8720a/fsl_phylan8720a.c
@@ -0,0 +1,330 @@
1/*
2 * Copyright 2020 NXP
3 * All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8#include "fsl_phylan8720a.h"
9
10/*******************************************************************************
11 * Definitions
12 ******************************************************************************/
13
14/*! @brief Defines the PHY LAN8720A vendor defined registers. */
15#define PHY_CONTROL_REG 0x11U /*!< The PHY control/status register. */
16#define PHY_SEPCIAL_CONTROL_REG 0x1FU /*!< The PHY special control/status register. */
17
18/*! @brief Defines the PHY LAN8720A ID number. */
19#define PHY_CONTROL_ID1 0x07U /*!< The PHY ID1*/
20
21/*!@brief Defines the mask flag of operation mode in control register*/
22#define PHY_CTL_FARLOOPBACK_MASK 0x200U
23
24/*!@brief Defines the mask flag of operation mode in special control register*/
25#define PHY_SPECIALCTL_AUTONEGDONE_MASK 0x1000U /*!< The PHY auto-negotiation complete mask. */
26#define PHY_SPECIALCTL_DUPLEX_MASK 0x0010U /*!< The PHY duplex mask. */
27#define PHY_SPECIALCTL_100SPEED_MASK 0x0008U /*!< The PHY speed mask. */
28#define PHY_SPECIALCTL_10SPEED_MASK 0x0004U /*!< The PHY speed mask. */
29#define PHY_SPECIALCTL_SPEEDUPLX_MASK 0x001CU /*!< The PHY speed and duplex mask. */
30
31/*! @brief Defines the mask flag in PHY auto-negotiation advertise register. */
32#define PHY_ALL_CAPABLE_MASK 0x1E0U
33
34/*! @brief Defines the timeout macro. */
35#define PHY_TIMEOUT_COUNT 500000U
36
37/*******************************************************************************
38 * Prototypes
39 ******************************************************************************/
40
41/*******************************************************************************
42 * Variables
43 ******************************************************************************/
44
45const phy_operations_t phylan8720a_ops = {.phyInit = PHY_LAN8720A_Init,
46 .phyWrite = PHY_LAN8720A_Write,
47 .phyRead = PHY_LAN8720A_Read,
48 .getAutoNegoStatus = PHY_LAN8720A_GetAutoNegotiationStatus,
49 .getLinkStatus = PHY_LAN8720A_GetLinkStatus,
50 .getLinkSpeedDuplex = PHY_LAN8720A_GetLinkSpeedDuplex,
51 .setLinkSpeedDuplex = PHY_LAN8720A_SetLinkSpeedDuplex,
52 .enableLoopback = PHY_LAN8720A_EnableLoopback};
53
54/*******************************************************************************
55 * Code
56 ******************************************************************************/
57
58status_t PHY_LAN8720A_Init(phy_handle_t *handle, const phy_config_t *config)
59{
60 uint32_t counter = PHY_TIMEOUT_COUNT;
61 status_t result = kStatus_Success;
62 uint32_t regValue = 0U;
63
64 /* Init MDIO interface. */
65 MDIO_Init(handle->mdioHandle);
66
67 /* Assign phy address. */
68 handle->phyAddr = config->phyAddr;
69
70 /* Check PHY ID. */
71 do
72 {
73 result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_ID1_REG, &regValue);
74 if (result != kStatus_Success)
75 {
76 return result;
77 }
78 counter--;
79 } while ((regValue != PHY_CONTROL_ID1) && (counter != 0U));
80
81 if (counter == 0U)
82 {
83 return kStatus_Fail;
84 }
85 counter = PHY_TIMEOUT_COUNT;
86
87 /* Reset PHY and wait until completion. */
88 result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, PHY_BCTL_RESET_MASK);
89 if (result != kStatus_Success)
90 {
91 return result;
92 }
93 do
94 {
95 result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, &regValue);
96 if (result != kStatus_Success)
97 {
98 return result;
99 }
100 } while ((counter-- != 0U) && (regValue & PHY_BCTL_RESET_MASK) != 0U);
101
102 if (counter == 0U)
103 {
104 return kStatus_Fail;
105 }
106
107 if (config->autoNeg)
108 {
109 /* Set the ability. */
110 result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_AUTONEG_ADVERTISE_REG,
111 (PHY_ALL_CAPABLE_MASK | PHY_IEEE802_3_SELECTOR_MASK));
112 if (result == kStatus_Success)
113 {
114 /* Start Auto negotiation and wait until auto negotiation completion */
115 result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG,
116 (PHY_BCTL_AUTONEG_MASK | PHY_BCTL_RESTART_AUTONEG_MASK));
117 }
118 }
119 else
120 {
121 /* This PHY only supports 10/100M speed. */
122 assert(config->speed <= kPHY_Speed100M);
123
124 /* Disable isolate mode */
125 result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, &regValue);
126 if (result != kStatus_Success)
127 {
128 return result;
129 }
130 regValue &= PHY_BCTL_ISOLATE_MASK;
131 result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue);
132 if (result != kStatus_Success)
133 {
134 return result;
135 }
136
137 /* Disable the auto-negotiation and set user-defined speed/duplex configuration. */
138 result = PHY_LAN8720A_SetLinkSpeedDuplex(handle, config->speed, config->duplex);
139 }
140
141 return result;
142}
143
144status_t PHY_LAN8720A_Write(phy_handle_t *handle, uint32_t phyReg, uint32_t data)
145{
146 return MDIO_Write(handle->mdioHandle, handle->phyAddr, phyReg, data);
147}
148
149status_t PHY_LAN8720A_Read(phy_handle_t *handle, uint32_t phyReg, uint32_t *dataPtr)
150{
151 return MDIO_Read(handle->mdioHandle, handle->phyAddr, phyReg, dataPtr);
152}
153
154status_t PHY_LAN8720A_GetAutoNegotiationStatus(phy_handle_t *handle, bool *status)
155{
156 assert(status);
157
158 status_t result;
159 uint32_t regValue;
160
161 *status = false;
162
163 /* Check auto negotiation complete. */
164 result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_SEPCIAL_CONTROL_REG, &regValue);
165 if (result == kStatus_Success)
166 {
167 if ((regValue & PHY_SPECIALCTL_AUTONEGDONE_MASK) != 0U)
168 {
169 *status = true;
170 }
171 }
172 return result;
173}
174
175status_t PHY_LAN8720A_GetLinkStatus(phy_handle_t *handle, bool *status)
176{
177 assert(status);
178
179 uint32_t regValue;
180 status_t result;
181
182 /* Read the basic status register. */
183 result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICSTATUS_REG, &regValue);
184 if (result == kStatus_Success)
185 {
186 if ((regValue & PHY_BSTATUS_LINKSTATUS_MASK) != 0U)
187 {
188 /* Link up. */
189 *status = true;
190 }
191 else
192 {
193 /* Link down. */
194 *status = false;
195 }
196 }
197 return result;
198}
199
200status_t PHY_LAN8720A_GetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t *speed, phy_duplex_t *duplex)
201{
202 assert(!((speed == NULL) && (duplex == NULL)));
203
204 uint32_t regValue;
205 status_t result;
206
207 /* Read the control register. */
208 result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_SEPCIAL_CONTROL_REG, &regValue);
209 if (result == kStatus_Success)
210 {
211 if (speed != NULL)
212 {
213 if ((regValue & PHY_SPECIALCTL_100SPEED_MASK) != 0U)
214 {
215 *speed = kPHY_Speed100M;
216 }
217 else
218 {
219 *speed = kPHY_Speed10M;
220 }
221 }
222
223 if (duplex != NULL)
224 {
225 if ((regValue & PHY_SPECIALCTL_DUPLEX_MASK) != 0U)
226 {
227 *duplex = kPHY_FullDuplex;
228 }
229 else
230 {
231 *duplex = kPHY_HalfDuplex;
232 }
233 }
234 }
235 return result;
236}
237
238status_t PHY_LAN8720A_SetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t speed, phy_duplex_t duplex)
239{
240 /* This PHY only supports 10/100M speed. */
241 assert(speed <= kPHY_Speed100M);
242
243 status_t result;
244 uint32_t regValue;
245
246 result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, &regValue);
247 if (result == kStatus_Success)
248 {
249 /* Disable the auto-negotiation and set according to user-defined configuration. */
250 regValue &= ~PHY_BCTL_AUTONEG_MASK;
251 if (speed == kPHY_Speed100M)
252 {
253 regValue |= PHY_BCTL_SPEED0_MASK;
254 }
255 else
256 {
257 regValue &= ~PHY_BCTL_SPEED0_MASK;
258 }
259 if (duplex == kPHY_FullDuplex)
260 {
261 regValue |= PHY_BCTL_DUPLEX_MASK;
262 }
263 else
264 {
265 regValue &= ~PHY_BCTL_DUPLEX_MASK;
266 }
267 result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue);
268 }
269 return result;
270}
271
272status_t PHY_LAN8720A_EnableLoopback(phy_handle_t *handle, phy_loop_t mode, phy_speed_t speed, bool enable)
273{
274 /* This PHY only supports local/remote loopback and 10/100M speed. */
275 assert(mode <= kPHY_RemoteLoop);
276 assert(speed <= kPHY_Speed100M);
277
278 status_t result;
279 uint32_t regValue;
280
281 /* Set the loop mode. */
282 if (enable)
283 {
284 if (mode == kPHY_LocalLoop)
285 {
286 if (speed == kPHY_Speed100M)
287 {
288 regValue = PHY_BCTL_SPEED0_MASK | PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK;
289 }
290 else
291 {
292 regValue = PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK;
293 }
294 result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue);
295 }
296 else
297 {
298 result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_CONTROL_REG, &regValue);
299 if (result == kStatus_Success)
300 {
301 result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_CONTROL_REG,
302 (regValue | PHY_CTL_FARLOOPBACK_MASK));
303 }
304 }
305 }
306 else
307 {
308 if (mode == kPHY_LocalLoop)
309 {
310 /* First read the current status in control register. */
311 result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, &regValue);
312 if (result == kStatus_Success)
313 {
314 regValue &= ~PHY_BCTL_LOOP_MASK;
315 result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG,
316 (regValue | PHY_BCTL_RESTART_AUTONEG_MASK));
317 }
318 }
319 else
320 {
321 result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_CONTROL_REG, &regValue);
322 if (result == kStatus_Success)
323 {
324 result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_CONTROL_REG,
325 (regValue & ~PHY_CTL_FARLOOPBACK_MASK));
326 }
327 }
328 }
329 return result;
330}