Sergey Pastor / 1

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lan8742.c Source File

lan8742.c

Go to the documentation of this file.
00001 /**
00002  * @file lan8742.c
00003  * @brief LAN8742 Ethernet PHY transceiver
00004  *
00005  * @section License
00006  *
00007  * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved.
00008  *
00009  * This file is part of CycloneTCP Open.
00010  *
00011  * This program is free software; you can redistribute it and/or
00012  * modify it under the terms of the GNU General Public License
00013  * as published by the Free Software Foundation; either version 2
00014  * of the License, or (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software Foundation,
00023  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00024  *
00025  * @author Oryx Embedded SARL (www.oryx-embedded.com)
00026  * @version 1.7.6
00027  **/
00028 
00029 //Switch to the appropriate trace level
00030 #define TRACE_LEVEL NIC_TRACE_LEVEL
00031 
00032 //Dependencies
00033 #include "core/net.h"
00034 #include "drivers/lan8742.h"
00035 #include "debug.h"
00036 
00037 
00038 /**
00039  * @brief LAN8742 Ethernet PHY driver
00040  **/
00041 
00042 const PhyDriver lan8742PhyDriver =
00043 {
00044    lan8742Init,
00045    lan8742Tick,
00046    lan8742EnableIrq,
00047    lan8742DisableIrq,
00048    lan8742EventHandler,
00049 };
00050 
00051 
00052 /**
00053  * @brief LAN8742 PHY transceiver initialization
00054  * @param[in] interface Underlying network interface
00055  * @return Error code
00056  **/
00057 
00058 error_t lan8742Init(NetInterface *interface)
00059 {
00060    //Debug message
00061    TRACE_INFO("Initializing LAN8742...\r\n");
00062 
00063    //Initialize external interrupt line driver
00064    if(interface->extIntDriver != NULL)
00065       interface->extIntDriver->init();
00066 
00067    //Reset PHY transceiver (soft reset)
00068    lan8742WritePhyReg(interface, LAN8742_PHY_REG_BMCR, BMCR_RESET);
00069    //Wait for the reset to complete
00070    while(lan8742ReadPhyReg(interface, LAN8742_PHY_REG_BMCR) & BMCR_RESET);
00071 
00072    //Restore default auto-negotiation advertisement parameters
00073    lan8742WritePhyReg(interface, LAN8742_PHY_REG_ANAR, ANAR_100BTX_FD |
00074       ANAR_100BTX | ANAR_10BT_FD | ANAR_10BT | ANAR_SELECTOR0);
00075 
00076    //Enable auto-negotiation
00077    lan8742WritePhyReg(interface, LAN8742_PHY_REG_BMCR, BMCR_AN_EN);
00078 
00079    //Dump PHY registers for debugging purpose
00080    lan8742DumpPhyReg(interface);
00081 
00082    //The PHY will generate interrupts when link status changes are detected
00083    lan8742WritePhyReg(interface, LAN8742_PHY_REG_IMR,
00084       IMR_AN_COMPLETE | IMR_LINK_DOWN);
00085 
00086    //Force the TCP/IP stack to poll the link state at startup
00087    interface->phyEvent = TRUE;
00088    //Notify the TCP/IP stack of the event
00089    osSetEvent(&netEvent);
00090 
00091    //Successful initialization
00092    return NO_ERROR;
00093 }
00094 
00095 
00096 /**
00097  * @brief LAN8742 timer handler
00098  * @param[in] interface Underlying network interface
00099  **/
00100 
00101 void lan8742Tick(NetInterface *interface)
00102 {
00103    uint16_t value;
00104    bool_t linkState;
00105 
00106    //No external interrupt line driver?
00107    if(interface->extIntDriver == NULL)
00108    {
00109       //Read basic status register
00110       value = lan8742ReadPhyReg(interface, LAN8742_PHY_REG_BMSR);
00111       //Retrieve current link state
00112       linkState = (value & BMSR_LINK_STATUS) ? TRUE : FALSE;
00113 
00114       //Link up event?
00115       if(linkState && !interface->linkState)
00116       {
00117          //Set event flag
00118          interface->phyEvent = TRUE;
00119          //Notify the TCP/IP stack of the event
00120          osSetEvent(&netEvent);
00121       }
00122       //Link down event?
00123       else if(!linkState && interface->linkState)
00124       {
00125          //Set event flag
00126          interface->phyEvent = TRUE;
00127          //Notify the TCP/IP stack of the event
00128          osSetEvent(&netEvent);
00129       }
00130    }
00131 }
00132 
00133 
00134 /**
00135  * @brief Enable interrupts
00136  * @param[in] interface Underlying network interface
00137  **/
00138 
00139 void lan8742EnableIrq(NetInterface *interface)
00140 {
00141    //Enable PHY transceiver interrupts
00142    if(interface->extIntDriver != NULL)
00143       interface->extIntDriver->enableIrq();
00144 }
00145 
00146 
00147 /**
00148  * @brief Disable interrupts
00149  * @param[in] interface Underlying network interface
00150  **/
00151 
00152 void lan8742DisableIrq(NetInterface *interface)
00153 {
00154    //Disable PHY transceiver interrupts
00155    if(interface->extIntDriver != NULL)
00156       interface->extIntDriver->disableIrq();
00157 }
00158 
00159 
00160 /**
00161  * @brief LAN8742 event handler
00162  * @param[in] interface Underlying network interface
00163  **/
00164 
00165 void lan8742EventHandler(NetInterface *interface)
00166 {
00167    uint16_t value;
00168 
00169    //Read status register to acknowledge the interrupt
00170    value = lan8742ReadPhyReg(interface, LAN8742_PHY_REG_ISR);
00171 
00172    //Link status change?
00173    if(value & (IMR_AN_COMPLETE | IMR_LINK_DOWN))
00174    {
00175       //Any link failure condition is latched in the BMSR register... Reading
00176       //the register twice will always return the actual link status
00177       value = lan8742ReadPhyReg(interface, LAN8742_PHY_REG_BMSR);
00178       value = lan8742ReadPhyReg(interface, LAN8742_PHY_REG_BMSR);
00179 
00180       //Link is up?
00181       if(value & BMSR_LINK_STATUS)
00182       {
00183          //Read PHY special control/status register
00184          value = lan8742ReadPhyReg(interface, LAN8742_PHY_REG_PSCSR);
00185 
00186          //Check current operation mode
00187          switch(value & PSCSR_HCDSPEED_MASK)
00188          {
00189          //10BASE-T
00190          case PSCSR_HCDSPEED_10BT:
00191             interface->linkSpeed = NIC_LINK_SPEED_10MBPS;
00192             interface->duplexMode = NIC_HALF_DUPLEX_MODE;
00193             break;
00194          //10BASE-T full-duplex
00195          case PSCSR_HCDSPEED_10BT_FD:
00196             interface->linkSpeed = NIC_LINK_SPEED_10MBPS;
00197             interface->duplexMode = NIC_FULL_DUPLEX_MODE;
00198             break;
00199          //100BASE-TX
00200          case PSCSR_HCDSPEED_100BTX:
00201             interface->linkSpeed = NIC_LINK_SPEED_100MBPS;
00202             interface->duplexMode = NIC_HALF_DUPLEX_MODE;
00203             break;
00204          //100BASE-TX full-duplex
00205          case PSCSR_HCDSPEED_100BTX_FD:
00206             interface->linkSpeed = NIC_LINK_SPEED_100MBPS;
00207             interface->duplexMode = NIC_FULL_DUPLEX_MODE;
00208             break;
00209          //Unknown operation mode
00210          default:
00211             //Debug message
00212             TRACE_WARNING("Invalid Duplex mode\r\n");
00213             break;
00214          }
00215 
00216          //Update link state
00217          interface->linkState = TRUE;
00218 
00219          //Adjust MAC configuration parameters for proper operation
00220          interface->nicDriver->updateMacConfig(interface);
00221       }
00222       else
00223       {
00224          //Update link state
00225          interface->linkState = FALSE;
00226       }
00227 
00228       //Process link state change event
00229       nicNotifyLinkChange(interface);
00230    }
00231 }
00232 
00233 
00234 /**
00235  * @brief Write PHY register
00236  * @param[in] interface Underlying network interface
00237  * @param[in] address PHY register address
00238  * @param[in] data Register value
00239  **/
00240 
00241 void lan8742WritePhyReg(NetInterface *interface, uint8_t address, uint16_t data)
00242 {
00243    uint8_t phyAddr;
00244 
00245    //Get the address of the PHY transceiver
00246    if(interface->phyAddr < 32)
00247       phyAddr = interface->phyAddr;
00248    else
00249       phyAddr = LAN8742_PHY_ADDR;
00250 
00251    //Write the specified PHY register
00252    interface->nicDriver->writePhyReg(phyAddr, address, data);
00253 }
00254 
00255 
00256 /**
00257  * @brief Read PHY register
00258  * @param[in] interface Underlying network interface
00259  * @param[in] address PHY register address
00260  * @return Register value
00261  **/
00262 
00263 uint16_t lan8742ReadPhyReg(NetInterface *interface, uint8_t address)
00264 {
00265    uint8_t phyAddr;
00266 
00267    //Get the address of the PHY transceiver
00268    if(interface->phyAddr < 32)
00269       phyAddr = interface->phyAddr;
00270    else
00271       phyAddr = LAN8742_PHY_ADDR;
00272 
00273    //Read the specified PHY register
00274    return interface->nicDriver->readPhyReg(phyAddr, address);
00275 }
00276 
00277 
00278 /**
00279  * @brief Dump PHY registers for debugging purpose
00280  * @param[in] interface Underlying network interface
00281  **/
00282 
00283 void lan8742DumpPhyReg(NetInterface *interface)
00284 {
00285    uint8_t i;
00286 
00287    //Loop through PHY registers
00288    for(i = 0; i < 32; i++)
00289    {
00290       //Display current PHY register
00291       TRACE_DEBUG("%02" PRIu8 ": 0x%04" PRIX16 "\r\n", i, lan8742ReadPhyReg(interface, i));
00292    }
00293 
00294    //Terminate with a line feed
00295    TRACE_DEBUG("\r\n");
00296 }
00297