| /******************************************************************************* |
| Copyright (C) Marvell International Ltd. and its affiliates |
| |
| This software file (the "File") is owned and distributed by Marvell |
| International Ltd. and/or its affiliates ("Marvell") under the following |
| alternative licensing terms. Once you have made an election to distribute the |
| File under one of the following license alternatives, please (i) delete this |
| introductory statement regarding license alternatives, (ii) delete the two |
| license alternatives that you have not elected to use and (iii) preserve the |
| Marvell copyright notice above. |
| |
| ******************************************************************************** |
| Marvell Commercial License Option |
| |
| If you received this File from Marvell and you have entered into a commercial |
| license agreement (a "Commercial License") with Marvell, the File is licensed |
| to you under the terms of the applicable Commercial License. |
| |
| ******************************************************************************** |
| Marvell GPL License Option |
| |
| If you received this File from Marvell, you may opt to use, redistribute and/or |
| modify this File in accordance with the terms and conditions of the General |
| Public License Version 2, June 1991 (the "GPL License"), a copy of which is |
| available along with the File in the license.txt file or by writing to the Free |
| Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or |
| on the worldwide web at http://www.gnu.org/licenses/gpl.txt. |
| |
| THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED |
| WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY |
| DISCLAIMED. The GPL License provides additional details about this warranty |
| disclaimer. |
| ******************************************************************************** |
| Marvell BSD License Option |
| |
| If you received this File from Marvell, you may opt to use, redistribute and/or |
| modify this File under the following licensing terms. |
| Redistribution and use in source and binary forms, with or without modification, |
| are permitted provided that the following conditions are met: |
| |
| * Redistributions of source code must retain the above copyright notice, |
| this list of conditions and the following disclaimer. |
| |
| * Redistributions in binary form must reproduce the above copyright |
| notice, this list of conditions and the following disclaimer in the |
| documentation and/or other materials provided with the distribution. |
| |
| * Neither the name of Marvell nor the names of its contributors may be |
| used to endorse or promote products derived from this software without |
| specific prior written permission. |
| |
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
| ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR |
| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
| ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| *******************************************************************************/ |
| |
| #include "mvCommon.h" |
| #include "mvOs.h" |
| #include "ctrlEnv/mvCtrlEnvSpec.h" |
| #include "mvTwsi.h" |
| #include "mvTwsiSpec.h" |
| |
| /*#define MV_DEBUG*/ |
| #ifdef MV_DEBUG |
| #define DB(x) x |
| #else |
| #define DB(x) |
| #endif |
| |
| static MV_VOID twsiIntFlgClr(MV_U8 chanNum); |
| static MV_BOOL twsiMainIntGet(MV_U8 chanNum); |
| static MV_VOID twsiAckBitSet(MV_U8 chanNum); |
| static MV_U32 twsiStsGet(MV_U8 chanNum); |
| static MV_VOID twsiReset(MV_U8 chanNum); |
| static MV_STATUS twsiAddr7BitSet(MV_U8 chanNum, MV_U32 deviceAddress, MV_TWSI_CMD command); |
| static MV_STATUS twsiAddr10BitSet(MV_U8 chanNum, MV_U32 deviceAddress, MV_TWSI_CMD command); |
| static MV_STATUS twsiDataTransmit(MV_U8 chanNum, MV_U8 *pBlock, MV_U32 blockSize); |
| static MV_STATUS twsiDataReceive(MV_U8 chanNum, MV_U8 *pBlock, MV_U32 blockSize); |
| static MV_STATUS twsiTargetOffsSet(MV_U8 chanNum, MV_U32 offset, MV_BOOL moreThen256); |
| |
| static MV_BOOL twsiTimeoutChk(MV_U32 timeout, const MV_8 *pString) |
| { |
| if (timeout >= TWSI_TIMEOUT_VALUE) { |
| DB(mvOsPrintf("%s", pString)); |
| return MV_TRUE; |
| } |
| return MV_FALSE; |
| |
| } |
| |
| /******************************************************************************* |
| * mvTwsiStartBitSet - Set start bit on the bus |
| * |
| * DESCRIPTION: |
| * This routine sets the start bit on the TWSI bus. |
| * The routine first checks for interrupt flag condition, then it sets |
| * the start bit in the TWSI Control register. |
| * If the interrupt flag condition check previously was set, the function |
| * will clear it. |
| * The function then wait for the start bit to be cleared by the HW. |
| * Then it waits for the interrupt flag to be set and eventually, the |
| * TWSI status is checked to be 0x8 or 0x10(repeated start bit). |
| * |
| * INPUT: |
| * chanNum - TWSI channel. |
| * |
| * OUTPUT: |
| * None. |
| * |
| * RETURN: |
| * MV_OK is start bit was set successfuly on the bus. |
| * MV_FAIL if interrupt flag was set before setting start bit. |
| * |
| *******************************************************************************/ |
| MV_STATUS mvTwsiStartBitSet(MV_U8 chanNum) |
| { |
| MV_BOOL isIntFlag = MV_FALSE; |
| MV_U32 timeout, temp; |
| |
| DB(mvOsPrintf("TWSI: mvTwsiStartBitSet \n")); |
| /* check Int flag */ |
| if (twsiMainIntGet(chanNum)) |
| isIntFlag = MV_TRUE; |
| /* set start Bit */ |
| temp = MV_REG_READ(TWSI_CONTROL_REG(chanNum)); |
| MV_REG_WRITE(TWSI_CONTROL_REG(chanNum), temp | TWSI_CONTROL_START_BIT); |
| |
| /* in case that the int flag was set before i.e. repeated start bit */ |
| if (isIntFlag) { |
| DB(mvOsPrintf("TWSI: mvTwsiStartBitSet repeated start Bit\n")); |
| twsiIntFlgClr(chanNum); |
| } |
| |
| /* wait for interrupt */ |
| timeout = 0; |
| while (!twsiMainIntGet(chanNum) && (timeout++ < TWSI_TIMEOUT_VALUE)) |
| ; |
| |
| /* check for timeout */ |
| if (MV_TRUE == twsiTimeoutChk(timeout, |
| (const MV_8 *)"TWSI: mvTwsiStartBitSet ERROR - Start Clear bit TimeOut .\n")) |
| return MV_TIMEOUT; |
| |
| /* check that start bit went down */ |
| if ((MV_REG_READ(TWSI_CONTROL_REG(chanNum)) & TWSI_CONTROL_START_BIT) != 0) { |
| mvOsPrintf("TWSI: mvTwsiStartBitSet ERROR - start bit didn't went down\n"); |
| return MV_FAIL; |
| } |
| |
| /* check the status */ |
| temp = twsiStsGet(chanNum); |
| if ((temp != TWSI_START_CON_TRA) && (temp != TWSI_REPEATED_START_CON_TRA)) { |
| mvOsPrintf("TWSI: mvTwsiStartBitSet ERROR - status %x after Set Start Bit. \n", temp); |
| return MV_FAIL; |
| } |
| |
| return MV_OK; |
| |
| } |
| |
| /******************************************************************************* |
| * mvTwsiStopBitSet - Set stop bit on the bus |
| * |
| * DESCRIPTION: |
| * This routine set the stop bit on the TWSI bus. |
| * The function then wait for the stop bit to be cleared by the HW. |
| * Finally the function checks for status of 0xF8. |
| * |
| * INPUT: |
| * chanNum - TWSI channel |
| * |
| * OUTPUT: |
| * None. |
| * |
| * RETURN: |
| * MV_TRUE is stop bit was set successfuly on the bus. |
| * |
| *******************************************************************************/ |
| MV_STATUS mvTwsiStopBitSet(MV_U8 chanNum) |
| { |
| MV_U32 timeout, temp; |
| |
| /* Generate stop bit */ |
| temp = MV_REG_READ(TWSI_CONTROL_REG(chanNum)); |
| MV_REG_WRITE(TWSI_CONTROL_REG(chanNum), temp | TWSI_CONTROL_STOP_BIT); |
| |
| twsiIntFlgClr(chanNum); |
| |
| /* wait for stop bit to come down */ |
| timeout = 0; |
| while (((MV_REG_READ(TWSI_CONTROL_REG(chanNum)) & TWSI_CONTROL_STOP_BIT) != 0) |
| && (timeout++ < TWSI_TIMEOUT_VALUE)) |
| ; |
| |
| /* check for timeout */ |
| if (MV_TRUE == twsiTimeoutChk(timeout, (const MV_8 *)"TWSI: mvTwsiStopBitSet ERROR - Stop bit TimeOut .\n")) |
| return MV_TIMEOUT; |
| |
| /* check that the stop bit went down */ |
| if ((MV_REG_READ(TWSI_CONTROL_REG(chanNum)) & TWSI_CONTROL_STOP_BIT) != 0) { |
| mvOsPrintf("TWSI: mvTwsiStopBitSet ERROR - stop bit didn't went down. \n"); |
| return MV_FAIL; |
| } |
| |
| /* check the status */ |
| temp = twsiStsGet(chanNum); |
| if (temp != TWSI_NO_REL_STS_INT_FLAG_IS_KEPT_0) { |
| mvOsPrintf("TWSI: mvTwsiStopBitSet ERROR - status %x after Stop Bit. \n", temp); |
| return MV_FAIL; |
| } |
| |
| return MV_OK; |
| } |
| |
| /******************************************************************************* |
| * twsiMainIntGet - Get twsi bit from main Interrupt cause. |
| * |
| * DESCRIPTION: |
| * This routine returns the twsi interrupt flag value. |
| * |
| * INPUT: |
| * None. |
| * |
| * OUTPUT: |
| * None. |
| * |
| * RETURN: |
| * MV_TRUE is interrupt flag is set, MV_FALSE otherwise. |
| * |
| *******************************************************************************/ |
| static MV_BOOL twsiMainIntGet(MV_U8 chanNum) |
| { |
| MV_U32 temp; |
| |
| /* get the int flag bit */ |
| |
| temp = MV_REG_READ(MV_TWSI_CPU_MAIN_INT_CASUE(chanNum)); |
| if (temp & (TWSI0_CPU_MAIN_INT_BIT(chanNum))) |
| return MV_TRUE; |
| |
| return MV_FALSE; |
| } |
| |
| /******************************************************************************* |
| * twsiIntFlgClr - Clear Interrupt flag. |
| * |
| * DESCRIPTION: |
| * This routine clears the interrupt flag. It does NOT poll the interrupt |
| * to make sure the clear. After clearing the interrupt, it waits for at |
| * least 1 miliseconds. |
| * |
| * INPUT: |
| * chanNum - TWSI channel |
| * |
| * OUTPUT: |
| * None. |
| * |
| * RETURN: |
| * None. |
| * |
| *******************************************************************************/ |
| static MV_VOID twsiIntFlgClr(MV_U8 chanNum) |
| { |
| MV_U32 temp; |
| |
| /* wait for 1 mili to prevent TWSI register write after write problems */ |
| mvOsDelay(1); |
| /* clear the int flag bit */ |
| temp = MV_REG_READ(TWSI_CONTROL_REG(chanNum)); |
| MV_REG_WRITE(TWSI_CONTROL_REG(chanNum), temp & ~(TWSI_CONTROL_INT_FLAG_SET)); |
| |
| /* wait for 1 mili sec for the clear to take effect */ |
| mvOsDelay(1); |
| |
| return; |
| } |
| |
| /******************************************************************************* |
| * twsiAckBitSet - Set acknowledge bit on the bus |
| * |
| * DESCRIPTION: |
| * This routine set the acknowledge bit on the TWSI bus. |
| * |
| * INPUT: |
| * None. |
| * |
| * OUTPUT: |
| * None. |
| * |
| * RETURN: |
| * None. |
| * |
| *******************************************************************************/ |
| static MV_VOID twsiAckBitSet(MV_U8 chanNum) |
| { |
| MV_U32 temp; |
| |
| /*Set the Ack bit */ |
| temp = MV_REG_READ(TWSI_CONTROL_REG(chanNum)); |
| MV_REG_WRITE(TWSI_CONTROL_REG(chanNum), temp | TWSI_CONTROL_ACK); |
| |
| /* Add delay of 1ms */ |
| mvOsDelay(1); |
| return; |
| } |
| |
| /******************************************************************************* |
| * twsiInit - Initialize TWSI interface |
| * |
| * DESCRIPTION: |
| * This routine: |
| * -Reset the TWSI. |
| * -Initialize the TWSI clock baud rate according to given frequancy |
| * parameter based on Tclk frequancy and enables TWSI slave. |
| * -Set the ack bit. |
| * -Assign the TWSI slave address according to the TWSI address Type. |
| * |
| * INPUT: |
| * chanNum - TWSI channel |
| * frequancy - TWSI frequancy in KHz. (up to 100KHZ) |
| * |
| * OUTPUT: |
| * None. |
| * |
| * RETURN: |
| * Actual frequancy. |
| * |
| *******************************************************************************/ |
| MV_U32 mvTwsiInit(MV_U8 chanNum, MV_HZ frequancy, MV_U32 Tclk, MV_TWSI_ADDR *pTwsiAddr, MV_BOOL generalCallEnable) |
| { |
| MV_U32 n, m, freq, margin, minMargin = 0xffffffff; |
| MV_U32 power; |
| MV_U32 actualFreq = 0, actualN = 0, actualM = 0, val; |
| |
| if (frequancy > 100000) |
| mvOsPrintf("Warning TWSI frequancy is too high, please use up tp 100Khz. \n"); |
| |
| DB(mvOsPrintf("TWSI: mvTwsiInit - Tclk = %d freq = %d\n", Tclk, frequancy)); |
| /* Calucalte N and M for the TWSI clock baud rate */ |
| for (n = 0; n < 8; n++) { |
| for (m = 0; m < 16; m++) { |
| power = 2 << n; /* power = 2^(n+1) */ |
| freq = Tclk / (10 * (m + 1) * power); |
| margin = MV_ABS(frequancy - freq); |
| |
| if ((freq <= frequancy) && (margin < minMargin)) { |
| minMargin = margin; |
| actualFreq = freq; |
| actualN = n; |
| actualM = m; |
| } |
| } |
| } |
| DB(mvOsPrintf("TWSI: mvTwsiInit - actN %d actM %d actFreq %d\n", actualN, actualM, actualFreq)); |
| /* Reset the TWSI logic */ |
| twsiReset(chanNum); |
| |
| /* Set the baud rate */ |
| val = ((actualM << TWSI_BAUD_RATE_M_OFFS) | actualN << TWSI_BAUD_RATE_N_OFFS); |
| MV_REG_WRITE(TWSI_STATUS_BAUDE_RATE_REG(chanNum), val); |
| |
| /* Enable the TWSI and slave */ |
| MV_REG_WRITE(TWSI_CONTROL_REG(chanNum), TWSI_CONTROL_ENA | TWSI_CONTROL_ACK); |
| |
| /* set the TWSI slave address */ |
| if (pTwsiAddr->type == ADDR10_BIT) { /* 10 Bit deviceAddress */ |
| /* writing the 2 most significant bits of the 10 bit address */ |
| val = ((pTwsiAddr->address & TWSI_SLAVE_ADDR_10BIT_MASK) >> TWSI_SLAVE_ADDR_10BIT_OFFS); |
| /* bits 7:3 must be 0x11110 */ |
| val |= TWSI_SLAVE_ADDR_10BIT_CONST; |
| /* set GCE bit */ |
| if (generalCallEnable) |
| val |= TWSI_SLAVE_ADDR_GCE_ENA; |
| /* write slave address */ |
| MV_REG_WRITE(TWSI_SLAVE_ADDR_REG(chanNum), val); |
| |
| /* writing the 8 least significant bits of the 10 bit address */ |
| val = (pTwsiAddr->address << TWSI_EXTENDED_SLAVE_OFFS) & TWSI_EXTENDED_SLAVE_MASK; |
| MV_REG_WRITE(TWSI_EXTENDED_SLAVE_ADDR_REG(chanNum), val); |
| } else { /*7 bit address */ |
| |
| /* set the 7 Bits address */ |
| MV_REG_WRITE(TWSI_EXTENDED_SLAVE_ADDR_REG(chanNum), 0x0); |
| val = (pTwsiAddr->address << TWSI_SLAVE_ADDR_7BIT_OFFS) & TWSI_SLAVE_ADDR_7BIT_MASK; |
| MV_REG_WRITE(TWSI_SLAVE_ADDR_REG(chanNum), val); |
| } |
| |
| /* unmask twsi int */ |
| val = MV_REG_READ(TWSI_CONTROL_REG(chanNum)); |
| MV_REG_WRITE(TWSI_CONTROL_REG(chanNum), val | TWSI_CONTROL_INT_ENA); |
| /* Add delay of 1ms */ |
| mvOsDelay(1); |
| |
| return actualFreq; |
| } |
| |
| /******************************************************************************* |
| * twsiStsGet - Get the TWSI status value. |
| * |
| * DESCRIPTION: |
| * This routine returns the TWSI status value. |
| * |
| * INPUT: |
| * chanNum - TWSI channel |
| * |
| * OUTPUT: |
| * None. |
| * |
| * RETURN: |
| * MV_U32 - the TWSI status. |
| * |
| *******************************************************************************/ |
| static MV_U32 twsiStsGet(MV_U8 chanNum) |
| { |
| return MV_REG_READ(TWSI_STATUS_BAUDE_RATE_REG(chanNum)); |
| |
| } |
| |
| /******************************************************************************* |
| * twsiReset - Reset the TWSI. |
| * |
| * DESCRIPTION: |
| * Resets the TWSI logic and sets all TWSI registers to their reset values. |
| * |
| * INPUT: |
| * chanNum - TWSI channel |
| * |
| * OUTPUT: |
| * None. |
| * |
| * RETURN: |
| * None |
| * |
| *******************************************************************************/ |
| static MV_VOID twsiReset(MV_U8 chanNum) |
| { |
| /* Reset the TWSI logic */ |
| MV_REG_WRITE(TWSI_SOFT_RESET_REG(chanNum), 0); |
| |
| /* wait for 2 mili sec */ |
| mvOsDelay(2); |
| |
| return; |
| } |
| |
| /******************************* POLICY ****************************************/ |
| |
| /******************************************************************************* |
| * mvTwsiAddrSet - Set address on TWSI bus. |
| * |
| * DESCRIPTION: |
| * This function Set address (7 or 10 Bit address) on the Twsi Bus. |
| * |
| * INPUT: |
| * chanNum - TWSI channel |
| * pTwsiAddr - twsi address. |
| * command - read / write . |
| * |
| * OUTPUT: |
| * None. |
| * |
| * RETURN: |
| * MV_OK - if setting the address completed succesfully. |
| * MV_FAIL otherwmise. |
| * |
| *******************************************************************************/ |
| MV_STATUS mvTwsiAddrSet(MV_U8 chanNum, MV_TWSI_ADDR *pTwsiAddr, MV_TWSI_CMD command) |
| { |
| DB(mvOsPrintf("TWSI: mvTwsiAddr7BitSet addr %x , type %d, cmd is %s\n", pTwsiAddr->address, |
| pTwsiAddr->type, ((command == MV_TWSI_WRITE) ? "Write" : "Read"))); |
| /* 10 Bit address */ |
| if (pTwsiAddr->type == ADDR10_BIT) |
| return twsiAddr10BitSet(chanNum, pTwsiAddr->address, command); |
| /* 7 Bit address */ |
| else |
| return twsiAddr7BitSet(chanNum, pTwsiAddr->address, command); |
| } |
| |
| /******************************************************************************* |
| * twsiAddr10BitSet - Set 10 Bit address on TWSI bus. |
| * |
| * DESCRIPTION: |
| * There are two address phases: |
| * 1) Write '11110' to data register bits [7:3] and 10-bit address MSB |
| * (bits [9:8]) to data register bits [2:1] plus a write(0) or read(1) bit |
| * to the Data register. Then it clears interrupt flag which drive |
| * the address on the TWSI bus. The function then waits for interrupt |
| * flag to be active and status 0x18 (write) or 0x40 (read) to be set. |
| * 2) write the rest of 10-bit address to data register and clears |
| * interrupt flag which drive the address on the TWSI bus. The |
| * function then waits for interrupt flag to be active and status |
| * 0xD0 (write) or 0xE0 (read) to be set. |
| * |
| * INPUT: |
| * chanNum - TWSI channel |
| * deviceAddress - twsi address. |
| * command - read / write . |
| * |
| * OUTPUT: |
| * None. |
| * |
| * RETURN: |
| * MV_OK - if setting the address completed succesfully. |
| * MV_FAIL otherwmise. |
| * |
| *******************************************************************************/ |
| static MV_STATUS twsiAddr10BitSet(MV_U8 chanNum, MV_U32 deviceAddress, MV_TWSI_CMD command) |
| { |
| MV_U32 val, timeout; |
| |
| /* writing the 2 most significant bits of the 10 bit address */ |
| val = ((deviceAddress & TWSI_DATA_ADDR_10BIT_MASK) >> TWSI_DATA_ADDR_10BIT_OFFS); |
| /* bits 7:3 must be 0x11110 */ |
| val |= TWSI_DATA_ADDR_10BIT_CONST; |
| /* set command */ |
| val |= command; |
| MV_REG_WRITE(TWSI_DATA_REG(chanNum), val); |
| /* WA add a delay */ |
| mvOsDelay(1); |
| |
| /* clear Int flag */ |
| twsiIntFlgClr(chanNum); |
| |
| /* wait for Int to be Set */ |
| timeout = 0; |
| while (!twsiMainIntGet(chanNum) && (timeout++ < TWSI_TIMEOUT_VALUE)) |
| ; |
| |
| /* check for timeout */ |
| if (MV_TRUE == |
| twsiTimeoutChk(timeout, (const MV_8 *)"TWSI: twsiAddr10BitSet ERROR - 1st addr (10Bit) Int TimeOut.\n")) |
| return MV_TIMEOUT; |
| |
| /* check the status */ |
| val = twsiStsGet(chanNum); |
| if (((val != TWSI_AD_PLS_RD_BIT_TRA_ACK_REC) && (command == MV_TWSI_READ)) || |
| ((val != TWSI_AD_PLS_WR_BIT_TRA_ACK_REC) && (command == MV_TWSI_WRITE))) { |
| mvOsPrintf("TWSI: twsiAddr10BitSet ERROR - status %x 1st addr (10 Bit) in %s mode.\n", val, |
| ((command == MV_TWSI_WRITE) ? "Write" : "Read")); |
| return MV_FAIL; |
| } |
| |
| /* set 8 LSB of the address */ |
| val = (deviceAddress << TWSI_DATA_ADDR_7BIT_OFFS) & TWSI_DATA_ADDR_7BIT_MASK; |
| MV_REG_WRITE(TWSI_DATA_REG(chanNum), val); |
| |
| /* clear Int flag */ |
| twsiIntFlgClr(chanNum); |
| |
| /* wait for Int to be Set */ |
| timeout = 0; |
| while (!twsiMainIntGet(chanNum) && (timeout++ < TWSI_TIMEOUT_VALUE)) |
| ; |
| |
| /* check for timeout */ |
| if (MV_TRUE == |
| twsiTimeoutChk(timeout, (const MV_8 *)"TWSI: twsiAddr10BitSet ERROR - 2nd (10 Bit) Int TimOut.\n")) |
| return MV_TIMEOUT; |
| |
| /* check the status */ |
| val = twsiStsGet(chanNum); |
| if (((val != TWSI_SEC_AD_PLS_RD_BIT_TRA_ACK_REC) && (command == MV_TWSI_READ)) || |
| ((val != TWSI_SEC_AD_PLS_WR_BIT_TRA_ACK_REC) && (command == MV_TWSI_WRITE))) { |
| mvOsPrintf("TWSI: twsiAddr10BitSet ERROR - status %x 2nd addr(10 Bit) in %s mode.\n", val, |
| ((command == MV_TWSI_WRITE) ? "Write" : "Read")); |
| return MV_FAIL; |
| } |
| |
| return MV_OK; |
| } |
| |
| /******************************************************************************* |
| * twsiAddr7BitSet - Set 7 Bit address on TWSI bus. |
| * |
| * DESCRIPTION: |
| * This function writes 7 bit address plus a write or read bit to the |
| * Data register. Then it clears interrupt flag which drive the address on |
| * the TWSI bus. The function then waits for interrupt flag to be active |
| * and status 0x18 (write) or 0x40 (read) to be set. |
| * |
| * INPUT: |
| * chanNum - TWSI channel |
| * deviceAddress - twsi address. |
| * command - read / write . |
| * |
| * OUTPUT: |
| * None. |
| * |
| * RETURN: |
| * MV_OK - if setting the address completed succesfully. |
| * MV_FAIL otherwmise. |
| * |
| *******************************************************************************/ |
| static MV_STATUS twsiAddr7BitSet(MV_U8 chanNum, MV_U32 deviceAddress, MV_TWSI_CMD command) |
| { |
| MV_U32 val, timeout; |
| |
| /* set the address */ |
| val = (deviceAddress << TWSI_DATA_ADDR_7BIT_OFFS) & TWSI_DATA_ADDR_7BIT_MASK; |
| /* set command */ |
| val |= command; |
| MV_REG_WRITE(TWSI_DATA_REG(chanNum), val); |
| /* WA add a delay */ |
| mvOsDelay(1); |
| |
| /* clear Int flag */ |
| twsiIntFlgClr(chanNum); |
| |
| /* wait for Int to be Set */ |
| timeout = 0; |
| while (!twsiMainIntGet(chanNum) && (timeout++ < TWSI_TIMEOUT_VALUE)) |
| ; |
| |
| /* check for timeout */ |
| if (MV_TRUE == |
| twsiTimeoutChk(timeout, (const MV_8 *)"TWSI: twsiAddr7BitSet ERROR - Addr (7 Bit) int TimeOut.\n")) |
| return MV_TIMEOUT; |
| |
| /* check the status */ |
| val = twsiStsGet(chanNum); |
| if (((val != TWSI_AD_PLS_RD_BIT_TRA_ACK_REC) && (command == MV_TWSI_READ)) || |
| ((val != TWSI_AD_PLS_WR_BIT_TRA_ACK_REC) && (command == MV_TWSI_WRITE))) { |
| /* only in debug, since in boot we try to read the SPD of both DRAM, and we don't |
| want error messeges in case DIMM doesn't exist. */ |
| DB(mvOsPrintf |
| ("TWSI: twsiAddr7BitSet ERROR - status %x addr (7 Bit) in %s mode.\n", val, |
| ((command == MV_TWSI_WRITE) ? "Write" : "Read"))); |
| return MV_FAIL; |
| } |
| |
| return MV_OK; |
| } |
| |
| /******************************************************************************* |
| * twsiDataWrite - Trnasmit a data block over TWSI bus. |
| * |
| * DESCRIPTION: |
| * This function writes a given data block to TWSI bus in 8 bit granularity. |
| * first The function waits for interrupt flag to be active then |
| * For each 8-bit data: |
| * The function writes data to data register. It then clears |
| * interrupt flag which drives the data on the TWSI bus. |
| * The function then waits for interrupt flag to be active and status |
| * 0x28 to be set. |
| * |
| * |
| * INPUT: |
| * chanNum - TWSI channel |
| * pBlock - Data block. |
| * blockSize - number of chars in pBlock. |
| * |
| * OUTPUT: |
| * None. |
| * |
| * RETURN: |
| * MV_OK - if transmiting the block completed succesfully, |
| * MV_BAD_PARAM - if pBlock is NULL, |
| * MV_FAIL otherwmise. |
| * |
| *******************************************************************************/ |
| static MV_STATUS twsiDataTransmit(MV_U8 chanNum, MV_U8 *pBlock, MV_U32 blockSize) |
| { |
| MV_U32 timeout, temp, blockSizeWr = blockSize; |
| |
| if (NULL == pBlock) |
| return MV_BAD_PARAM; |
| |
| /* wait for Int to be Set */ |
| timeout = 0; |
| while (!twsiMainIntGet(chanNum) && (timeout++ < TWSI_TIMEOUT_VALUE)) |
| ; |
| |
| /* check for timeout */ |
| if (MV_TRUE == |
| twsiTimeoutChk(timeout, (const MV_8 *)"TWSI: twsiDataTransmit ERROR - Read Data Int TimeOut.\n")) |
| return MV_TIMEOUT; |
| |
| while (blockSizeWr) { |
| /* write the data */ |
| MV_REG_WRITE(TWSI_DATA_REG(chanNum), (MV_U32) *pBlock); |
| DB(mvOsPrintf("TWSI: twsiDataTransmit place = %d write %x \n", blockSize - blockSizeWr, *pBlock)); |
| pBlock++; |
| blockSizeWr--; |
| |
| twsiIntFlgClr(chanNum); |
| |
| /* wait for Int to be Set */ |
| timeout = 0; |
| while (!twsiMainIntGet(chanNum) && (timeout++ < TWSI_TIMEOUT_VALUE)) |
| ; |
| |
| /* check for timeout */ |
| if (MV_TRUE == |
| twsiTimeoutChk(timeout, (const MV_8 *)"TWSI: twsiDataTransmit ERROR - Read Data Int TimeOut.\n")) |
| return MV_TIMEOUT; |
| |
| /* check the status */ |
| temp = twsiStsGet(chanNum); |
| if (temp != TWSI_M_TRAN_DATA_BYTE_ACK_REC) { |
| mvOsPrintf("TWSI: twsiDataTransmit ERROR - status %x in write trans\n", temp); |
| return MV_FAIL; |
| } |
| |
| } |
| |
| return MV_OK; |
| } |
| |
| /******************************************************************************* |
| * twsiDataReceive - Receive data block from TWSI bus. |
| * |
| * DESCRIPTION: |
| * This function receive data block from TWSI bus in 8bit granularity |
| * into pBlock buffer. |
| * first The function waits for interrupt flag to be active then |
| * For each 8-bit data: |
| * It clears the interrupt flag which allows the next data to be |
| * received from TWSI bus. |
| * The function waits for interrupt flag to be active, |
| * and status reg is 0x50. |
| * Then the function reads data from data register, and copies it to |
| * the given buffer. |
| * |
| * INPUT: |
| * chanNum - TWSI channel |
| * blockSize - number of bytes to read. |
| * |
| * OUTPUT: |
| * pBlock - Data block. |
| * |
| * RETURN: |
| * MV_OK - if receive transaction completed succesfully, |
| * MV_BAD_PARAM - if pBlock is NULL, |
| * MV_FAIL otherwmise. |
| * |
| *******************************************************************************/ |
| static MV_STATUS twsiDataReceive(MV_U8 chanNum, MV_U8 *pBlock, MV_U32 blockSize) |
| { |
| MV_U32 timeout, temp, blockSizeRd = blockSize; |
| |
| if (NULL == pBlock) |
| return MV_BAD_PARAM; |
| |
| /* wait for Int to be Set */ |
| timeout = 0; |
| while (!twsiMainIntGet(chanNum) && (timeout++ < TWSI_TIMEOUT_VALUE)) |
| ; |
| |
| /* check for timeout */ |
| if (MV_TRUE == |
| twsiTimeoutChk(timeout, (const MV_8 *)"TWSI: twsiDataReceive ERROR - Read Data int Time out .\n")) |
| return MV_TIMEOUT; |
| |
| while (blockSizeRd) { |
| if (blockSizeRd == 1) { |
| /* clear ack and Int flag */ |
| temp = MV_REG_READ(TWSI_CONTROL_REG(chanNum)); |
| temp &= ~(TWSI_CONTROL_ACK); |
| MV_REG_WRITE(TWSI_CONTROL_REG(chanNum), temp); |
| } |
| twsiIntFlgClr(chanNum); |
| /* wait for Int to be Set */ |
| timeout = 0; |
| while ((!twsiMainIntGet(chanNum)) && (timeout++ < TWSI_TIMEOUT_VALUE)) |
| ; |
| |
| /* check for timeout */ |
| if (MV_TRUE == |
| twsiTimeoutChk(timeout, (const MV_8 *)"TWSI: twsiDataReceive ERROR - Read Data Int Time out .\n")) |
| return MV_TIMEOUT; |
| |
| /* check the status */ |
| temp = twsiStsGet(chanNum); |
| if ((temp != TWSI_M_REC_RD_DATA_ACK_TRA) && (blockSizeRd != 1)) { |
| mvOsPrintf("TWSI: twsiDataReceive ERROR - status %x in read trans \n", temp); |
| return MV_FAIL; |
| } else if ((temp != TWSI_M_REC_RD_DATA_ACK_NOT_TRA) && (blockSizeRd == 1)) { |
| mvOsPrintf("TWSI: twsiDataReceive ERROR - status %x in Rd Terminate\n", temp); |
| return MV_FAIL; |
| } |
| |
| /* read the data */ |
| *pBlock = (MV_U8) MV_REG_READ(TWSI_DATA_REG(chanNum)); |
| DB(mvOsPrintf("TWSI: twsiDataReceive place %d read %x \n", blockSize - blockSizeRd, *pBlock)); |
| pBlock++; |
| blockSizeRd--; |
| } |
| |
| return MV_OK; |
| } |
| |
| /******************************************************************************* |
| * twsiTargetOffsSet - Set TWST target offset on TWSI bus. |
| * |
| * DESCRIPTION: |
| * The function support TWSI targets that have inside address space (for |
| * example EEPROMs). The function: |
| * 1) Convert the given offset into pBlock and size. |
| * in case the offset should be set to a TWSI slave which support |
| * more then 256 bytes offset, the offset setting will be done |
| * in 2 transactions. |
| * 2) Use twsiDataTransmit to place those on the bus. |
| * |
| * INPUT: |
| * chanNum - TWSI channel |
| * offset - offset to be set on the EEPROM device. |
| * moreThen256 - whether the EEPROM device support more then 256 byte offset. |
| * |
| * OUTPUT: |
| * None. |
| * |
| * RETURN: |
| * MV_OK - if setting the offset completed succesfully. |
| * MV_FAIL otherwmise. |
| * |
| *******************************************************************************/ |
| static MV_STATUS twsiTargetOffsSet(MV_U8 chanNum, MV_U32 offset, MV_BOOL moreThen256) |
| { |
| MV_U8 offBlock[2]; |
| MV_U32 offSize; |
| |
| if (moreThen256 == MV_TRUE) { |
| offBlock[0] = (offset >> 8) & 0xff; |
| offBlock[1] = offset & 0xff; |
| offSize = 2; |
| } else { |
| offBlock[0] = offset & 0xff; |
| offSize = 1; |
| } |
| DB(mvOsPrintf("TWSI: twsiTargetOffsSet offSize = %x addr1 = %x addr2 = %x\n", |
| offSize, offBlock[0], offBlock[1])); |
| return twsiDataTransmit(chanNum, offBlock, offSize); |
| |
| } |
| |
| /******************************************************************************* |
| * mvTwsiRead - Read data block from a TWSI Slave. |
| * |
| * DESCRIPTION: |
| * The function calls the following functions: |
| * -) mvTwsiStartBitSet(); |
| * if(EEPROM device) |
| * -) mvTwsiAddrSet(w); |
| * -) twsiTargetOffsSet(); |
| * -) mvTwsiStartBitSet(); |
| * -) mvTwsiAddrSet(r); |
| * -) twsiDataReceive(); |
| * -) mvTwsiStopBitSet(); |
| * |
| * INPUT: |
| * chanNum - TWSI channel |
| * pTwsiSlave - Twsi Slave structure. |
| * blockSize - number of bytes to read. |
| * |
| * OUTPUT: |
| * pBlock - Data block. |
| * |
| * RETURN: |
| * MV_OK - if EEPROM read transaction completed succesfully, |
| * MV_BAD_PARAM - if pBlock is NULL, |
| * MV_FAIL otherwmise. |
| * |
| *******************************************************************************/ |
| MV_STATUS mvTwsiRead(MV_U8 chanNum, MV_TWSI_SLAVE *pTwsiSlave, MV_U8 *pBlock, MV_U32 blockSize) |
| { |
| if ((NULL == pBlock) || (NULL == pTwsiSlave)) |
| return MV_BAD_PARAM; |
| if (MV_OK != mvTwsiStartBitSet(chanNum)) { |
| mvTwsiStopBitSet(chanNum); |
| return MV_FAIL; |
| } |
| |
| DB(mvOsPrintf("TWSI: mvTwsiEepromRead after mvTwsiStartBitSet\n")); |
| |
| /* in case offset exsist (i.e. eeprom ) */ |
| if (MV_TRUE == pTwsiSlave->validOffset) { |
| if (MV_OK != mvTwsiAddrSet(chanNum, &(pTwsiSlave->slaveAddr), MV_TWSI_WRITE)) { |
| mvTwsiStopBitSet(chanNum); |
| return MV_FAIL; |
| } |
| DB(mvOsPrintf("TWSI: mvTwsiEepromRead after mvTwsiAddrSet\n")); |
| if (MV_OK != twsiTargetOffsSet(chanNum, pTwsiSlave->offset, pTwsiSlave->moreThen256)) { |
| mvTwsiStopBitSet(chanNum); |
| return MV_FAIL; |
| } |
| DB(mvOsPrintf("TWSI: mvTwsiEepromRead after twsiTargetOffsSet\n")); |
| if (MV_OK != mvTwsiStartBitSet(chanNum)) { |
| mvTwsiStopBitSet(chanNum); |
| return MV_FAIL; |
| } |
| DB(mvOsPrintf("TWSI: mvTwsiEepromRead after mvTwsiStartBitSet\n")); |
| } |
| if (MV_OK != mvTwsiAddrSet(chanNum, &(pTwsiSlave->slaveAddr), MV_TWSI_READ)) { |
| mvTwsiStopBitSet(chanNum); |
| return MV_FAIL; |
| } |
| DB(mvOsPrintf("TWSI: mvTwsiEepromRead after mvTwsiAddrSet\n")); |
| if (MV_OK != twsiDataReceive(chanNum, pBlock, blockSize)) { |
| mvTwsiStopBitSet(chanNum); |
| return MV_FAIL; |
| } |
| DB(mvOsPrintf("TWSI: mvTwsiEepromRead after twsiDataReceive\n")); |
| |
| if (MV_OK != mvTwsiStopBitSet(chanNum)) |
| return MV_FAIL; |
| |
| twsiAckBitSet(chanNum); |
| |
| DB(mvOsPrintf("TWSI: mvTwsiEepromRead after mvTwsiStopBitSet\n")); |
| |
| return MV_OK; |
| } |
| |
| /******************************************************************************* |
| * mvTwsiWrite - Write data block to a TWSI Slave. |
| * |
| * DESCRIPTION: |
| * The function calls the following functions: |
| * -) mvTwsiStartBitSet(); |
| * -) mvTwsiAddrSet(); |
| * -)if(EEPROM device) |
| * -) twsiTargetOffsSet(); |
| * -) twsiDataTransmit(); |
| * -) mvTwsiStopBitSet(); |
| * |
| * INPUT: |
| * chanNum - TWSI channel |
| * eepromAddress - eeprom address. |
| * blockSize - number of bytes to write. |
| * pBlock - Data block. |
| * |
| * OUTPUT: |
| * None |
| * |
| * RETURN: |
| * MV_OK - if EEPROM read transaction completed succesfully. |
| * MV_BAD_PARAM - if pBlock is NULL, |
| * MV_FAIL otherwmise. |
| * |
| * NOTE: Part of the EEPROM, required that the offset will be aligned to the |
| * max write burst supported. |
| *******************************************************************************/ |
| MV_STATUS mvTwsiWrite(MV_U8 chanNum, MV_TWSI_SLAVE *pTwsiSlave, MV_U8 *pBlock, MV_U32 blockSize) |
| { |
| if ((NULL == pBlock) || (NULL == pTwsiSlave)) |
| return MV_BAD_PARAM; |
| |
| if (MV_OK != mvTwsiStartBitSet(chanNum)) { |
| mvTwsiStopBitSet(chanNum); |
| return MV_FAIL; |
| } |
| |
| DB(mvOsPrintf("TWSI: mvTwsiEepromWrite after mvTwsiStartBitSet\n")); |
| if (MV_OK != mvTwsiAddrSet(chanNum, &(pTwsiSlave->slaveAddr), MV_TWSI_WRITE)) { |
| mvTwsiStopBitSet(chanNum); |
| return MV_FAIL; |
| } |
| DB(mvOsPrintf("TWSI :mvTwsiEepromWrite after mvTwsiAddrSet\n")); |
| |
| /* in case offset exsist (i.e. eeprom ) */ |
| if (MV_TRUE == pTwsiSlave->validOffset) { |
| if (MV_OK != twsiTargetOffsSet(chanNum, pTwsiSlave->offset, pTwsiSlave->moreThen256)) { |
| mvTwsiStopBitSet(chanNum); |
| return MV_FAIL; |
| } |
| DB(mvOsPrintf("TWSI: mvTwsiEepromWrite after twsiTargetOffsSet\n")); |
| } |
| if (MV_OK != twsiDataTransmit(chanNum, pBlock, blockSize)) { |
| mvTwsiStopBitSet(chanNum); |
| return MV_FAIL; |
| } |
| DB(mvOsPrintf("TWSI: mvTwsiEepromWrite after twsiDataTransmit\n")); |
| if (MV_OK != mvTwsiStopBitSet(chanNum)) |
| return MV_FAIL; |
| |
| DB(mvOsPrintf("TWSI: mvTwsiEepromWrite after mvTwsiStopBitSet\n")); |
| |
| return MV_OK; |
| } |