/* * Copyright (C) 2013 Realtek Semiconductor Corp. * All Rights Reserved. * * Unless you and Realtek execute a separate written software license * agreement governing use of this software, this software is licensed * to you under the terms of the GNU General Public License version 2, * available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt * * Purpose : RTL8367C switch low-level function for access register * Feature : SMI related functions * */ #include #include #include "rtk_error.h" #if defined(MDC_MDIO_OPERATION) /*******************************************************************************/ /* MDC/MDIO porting */ /*******************************************************************************/ /* define the PHY ID currently used */ /* carlos */ #if 0 #define MDC_MDIO_PHY_ID 0 /* PHY ID 0 or 29 */ #else #define MDC_MDIO_PHY_ID 29 /* PHY ID 0 or 29 */ #endif /* MDC/MDIO, redefine/implement the following Macro */ /*carlos*/ #if 0 #define MDC_MDIO_WRITE(preamableLength, phyID, regID, data) #define MDC_MDIO_READ(preamableLength, phyID, regID, pData) #else #define u32 unsigned int extern u32 mii_mgr_read(u32 phy_addr, u32 phy_register, u32 *read_data); extern u32 mii_mgr_write(u32 phy_addr, u32 phy_register, u32 write_data); #define MDC_MDIO_WRITE(preamableLength, phyID, regID, data) mii_mgr_write(phyID, regID, data) #define MDC_MDIO_READ(preamableLength, phyID, regID, pData) mii_mgr_read(phyID, regID, pData) #endif #elif defined(SPI_OPERATION) /*******************************************************************************/ /* SPI porting */ /*******************************************************************************/ /* SPI, redefine/implement the following Macro */ #define SPI_WRITE(data, length) #define SPI_READ(pData, length) #else /*******************************************************************************/ /* I2C porting */ /*******************************************************************************/ /* Define the GPIO ID for SCK & SDA */ rtk_uint32 smi_SCK = 1; /* GPIO used for SMI Clock Generation */ rtk_uint32 smi_SDA = 2; /* GPIO used for SMI Data signal */ /* I2C, redefine/implement the following Macro */ #define GPIO_DIRECTION_SET(gpioID, direction) #define GPIO_DATA_SET(gpioID, data) #define GPIO_DATA_GET(gpioID, pData) #endif static void rtlglue_drvMutexLock(void) { /* It is empty currently. Implement this function if Lock/Unlock function is needed */ return; } static void rtlglue_drvMutexUnlock(void) { /* It is empty currently. Implement this function if Lock/Unlock function is needed */ return; } #if defined(MDC_MDIO_OPERATION) || defined(SPI_OPERATION) /* No local function in MDC/MDIO & SPI mode */ #else static void _smi_start(void) { /* change GPIO pin to Output only */ GPIO_DIRECTION_SET(smi_SCK, GPIO_DIR_OUT); GPIO_DIRECTION_SET(smi_SDA, GPIO_DIR_OUT); /* Initial state: SCK: 0, SDA: 1 */ GPIO_DATA_SET(smi_SCK, 0); GPIO_DATA_SET(smi_SDA, 1); CLK_DURATION(DELAY); /* CLK 1: 0 -> 1, 1 -> 0 */ GPIO_DATA_SET(smi_SCK, 1); CLK_DURATION(DELAY); GPIO_DATA_SET(smi_SCK, 0); CLK_DURATION(DELAY); /* CLK 2: */ GPIO_DATA_SET(smi_SCK, 1); CLK_DURATION(DELAY); GPIO_DATA_SET(smi_SDA, 0); CLK_DURATION(DELAY); GPIO_DATA_SET(smi_SCK, 0); CLK_DURATION(DELAY); GPIO_DATA_SET(smi_SDA, 1); } static void _smi_writeBit(rtk_uint16 signal, rtk_uint32 bitLen) { for( ; bitLen > 0; bitLen--) { CLK_DURATION(DELAY); /* prepare data */ if ( signal & (1<<(bitLen-1)) ) { GPIO_DATA_SET(smi_SDA, 1); } else { GPIO_DATA_SET(smi_SDA, 0); } CLK_DURATION(DELAY); /* clocking */ GPIO_DATA_SET(smi_SCK, 1); CLK_DURATION(DELAY); GPIO_DATA_SET(smi_SCK, 0); } } static void _smi_readBit(rtk_uint32 bitLen, rtk_uint32 *rData) { rtk_uint32 u = 0; /* change GPIO pin to Input only */ GPIO_DIRECTION_SET(smi_SDA, GPIO_DIR_IN); for (*rData = 0; bitLen > 0; bitLen--) { CLK_DURATION(DELAY); /* clocking */ GPIO_DATA_SET(smi_SCK, 1); CLK_DURATION(DELAY); GPIO_DATA_GET(smi_SDA, &u); GPIO_DATA_SET(smi_SCK, 0); *rData |= (u << (bitLen - 1)); } /* change GPIO pin to Output only */ GPIO_DIRECTION_SET(smi_SDA, GPIO_DIR_OUT); } static void _smi_stop(void) { CLK_DURATION(DELAY); GPIO_DATA_SET(smi_SDA, 0); GPIO_DATA_SET(smi_SCK, 1); CLK_DURATION(DELAY); GPIO_DATA_SET(smi_SDA, 1); CLK_DURATION(DELAY); GPIO_DATA_SET(smi_SCK, 1); CLK_DURATION(DELAY); GPIO_DATA_SET(smi_SCK, 0); CLK_DURATION(DELAY); GPIO_DATA_SET(smi_SCK, 1); /* add a click */ CLK_DURATION(DELAY); GPIO_DATA_SET(smi_SCK, 0); CLK_DURATION(DELAY); GPIO_DATA_SET(smi_SCK, 1); /* change GPIO pin to Input only */ GPIO_DIRECTION_SET(smi_SDA, GPIO_DIR_IN); GPIO_DIRECTION_SET(smi_SCK, GPIO_DIR_IN); } #endif /* End of #if defined(MDC_MDIO_OPERATION) || defined(SPI_OPERATION) */ rtk_int32 smi_read(rtk_uint32 mAddrs, rtk_uint32 *rData) { #if (!defined(MDC_MDIO_OPERATION) && !defined(SPI_OPERATION)) rtk_uint32 rawData=0, ACK; rtk_uint8 con; rtk_uint32 ret = RT_ERR_OK; #endif if(mAddrs > 0xFFFF) return RT_ERR_INPUT; if(rData == NULL) return RT_ERR_NULL_POINTER; #if defined(MDC_MDIO_OPERATION) /* Lock */ rtlglue_drvMutexLock(); /* Write address control code to register 31 */ MDC_MDIO_WRITE(MDC_MDIO_PREAMBLE_LEN, MDC_MDIO_PHY_ID, MDC_MDIO_CTRL0_REG, MDC_MDIO_ADDR_OP); /* Write address to register 23 */ MDC_MDIO_WRITE(MDC_MDIO_PREAMBLE_LEN, MDC_MDIO_PHY_ID, MDC_MDIO_ADDRESS_REG, mAddrs); /* Write read control code to register 21 */ MDC_MDIO_WRITE(MDC_MDIO_PREAMBLE_LEN, MDC_MDIO_PHY_ID, MDC_MDIO_CTRL1_REG, MDC_MDIO_READ_OP); /* Read data from register 25 */ MDC_MDIO_READ(MDC_MDIO_PREAMBLE_LEN, MDC_MDIO_PHY_ID, MDC_MDIO_DATA_READ_REG, rData); /* Unlock */ rtlglue_drvMutexUnlock(); return RT_ERR_OK; #elif defined(SPI_OPERATION) /* Lock */ rtlglue_drvMutexLock(); /* Write 8 bits READ OP_CODE */ SPI_WRITE(SPI_READ_OP, SPI_READ_OP_LEN); /* Write 16 bits register address */ SPI_WRITE(mAddrs, SPI_REG_LEN); /* Read 16 bits data */ SPI_READ(rData, SPI_DATA_LEN); /* Unlock */ rtlglue_drvMutexUnlock(); return RT_ERR_OK; #else /*Disable CPU interrupt to ensure that the SMI operation is atomic. The API is based on RTL865X, rewrite the API if porting to other platform.*/ rtlglue_drvMutexLock(); _smi_start(); /* Start SMI */ _smi_writeBit(0x0b, 4); /* CTRL code: 4'b1011 for RTL8370 */ _smi_writeBit(0x4, 3); /* CTRL code: 3'b100 */ _smi_writeBit(0x1, 1); /* 1: issue READ command */ con = 0; do { con++; _smi_readBit(1, &ACK); /* ACK for issuing READ command*/ } while ((ACK != 0) && (con < ack_timer)); if (ACK != 0) ret = RT_ERR_FAILED; _smi_writeBit((mAddrs&0xff), 8); /* Set reg_addr[7:0] */ con = 0; do { con++; _smi_readBit(1, &ACK); /* ACK for setting reg_addr[7:0] */ } while ((ACK != 0) && (con < ack_timer)); if (ACK != 0) ret = RT_ERR_FAILED; _smi_writeBit((mAddrs>>8), 8); /* Set reg_addr[15:8] */ con = 0; do { con++; _smi_readBit(1, &ACK); /* ACK by RTL8369 */ } while ((ACK != 0) && (con < ack_timer)); if (ACK != 0) ret = RT_ERR_FAILED; _smi_readBit(8, &rawData); /* Read DATA [7:0] */ *rData = rawData&0xff; _smi_writeBit(0x00, 1); /* ACK by CPU */ _smi_readBit(8, &rawData); /* Read DATA [15: 8] */ _smi_writeBit(0x01, 1); /* ACK by CPU */ *rData |= (rawData<<8); _smi_stop(); rtlglue_drvMutexUnlock();/*enable CPU interrupt*/ return ret; #endif /* end of #if defined(MDC_MDIO_OPERATION) */ } rtk_int32 smi_write(rtk_uint32 mAddrs, rtk_uint32 rData) { #if (!defined(MDC_MDIO_OPERATION) && !defined(SPI_OPERATION)) rtk_int8 con; rtk_uint32 ACK; rtk_uint32 ret = RT_ERR_OK; #endif if(mAddrs > 0xFFFF) return RT_ERR_INPUT; if(rData > 0xFFFF) return RT_ERR_INPUT; #if defined(MDC_MDIO_OPERATION) /* Lock */ rtlglue_drvMutexLock(); /* Write address control code to register 31 */ MDC_MDIO_WRITE(MDC_MDIO_PREAMBLE_LEN, MDC_MDIO_PHY_ID, MDC_MDIO_CTRL0_REG, MDC_MDIO_ADDR_OP); /* Write address to register 23 */ MDC_MDIO_WRITE(MDC_MDIO_PREAMBLE_LEN, MDC_MDIO_PHY_ID, MDC_MDIO_ADDRESS_REG, mAddrs); /* Write data to register 24 */ MDC_MDIO_WRITE(MDC_MDIO_PREAMBLE_LEN, MDC_MDIO_PHY_ID, MDC_MDIO_DATA_WRITE_REG, rData); /* Write data control code to register 21 */ MDC_MDIO_WRITE(MDC_MDIO_PREAMBLE_LEN, MDC_MDIO_PHY_ID, MDC_MDIO_CTRL1_REG, MDC_MDIO_WRITE_OP); /* Unlock */ rtlglue_drvMutexUnlock(); return RT_ERR_OK; #elif defined(SPI_OPERATION) /* Lock */ rtlglue_drvMutexLock(); /* Write 8 bits WRITE OP_CODE */ SPI_WRITE(SPI_WRITE_OP, SPI_WRITE_OP_LEN); /* Write 16 bits register address */ SPI_WRITE(mAddrs, SPI_REG_LEN); /* Write 16 bits data */ SPI_WRITE(rData, SPI_DATA_LEN); /* Unlock */ rtlglue_drvMutexUnlock(); return RT_ERR_OK; #else /*Disable CPU interrupt to ensure that the SMI operation is atomic. The API is based on RTL865X, rewrite the API if porting to other platform.*/ rtlglue_drvMutexLock(); _smi_start(); /* Start SMI */ _smi_writeBit(0x0b, 4); /* CTRL code: 4'b1011 for RTL8370*/ _smi_writeBit(0x4, 3); /* CTRL code: 3'b100 */ _smi_writeBit(0x0, 1); /* 0: issue WRITE command */ con = 0; do { con++; _smi_readBit(1, &ACK); /* ACK for issuing WRITE command*/ } while ((ACK != 0) && (con < ack_timer)); if (ACK != 0) ret = RT_ERR_FAILED; _smi_writeBit((mAddrs&0xff), 8); /* Set reg_addr[7:0] */ con = 0; do { con++; _smi_readBit(1, &ACK); /* ACK for setting reg_addr[7:0] */ } while ((ACK != 0) && (con < ack_timer)); if (ACK != 0) ret = RT_ERR_FAILED; _smi_writeBit((mAddrs>>8), 8); /* Set reg_addr[15:8] */ con = 0; do { con++; _smi_readBit(1, &ACK); /* ACK for setting reg_addr[15:8] */ } while ((ACK != 0) && (con < ack_timer)); if (ACK != 0) ret = RT_ERR_FAILED; _smi_writeBit(rData&0xff, 8); /* Write Data [7:0] out */ con = 0; do { con++; _smi_readBit(1, &ACK); /* ACK for writting data [7:0] */ } while ((ACK != 0) && (con < ack_timer)); if (ACK != 0) ret = RT_ERR_FAILED; _smi_writeBit(rData>>8, 8); /* Write Data [15:8] out */ con = 0; do { con++; _smi_readBit(1, &ACK); /* ACK for writting data [15:8] */ } while ((ACK != 0) && (con < ack_timer)); if (ACK != 0) ret = RT_ERR_FAILED; _smi_stop(); rtlglue_drvMutexUnlock();/*enable CPU interrupt*/ return ret; #endif /* end of #if defined(MDC_MDIO_OPERATION) */ }