/* SPDX-License-Identifier: LGPL-2.1-only OR BSD-3-Clause */
/******************************************************************************
 *
 * This file is provided under a dual license.  When you use or
 * distribute this software, you may choose to be licensed under
 * version 2.1 of the GNU Lesser General Public License
 * ("LGPLv2.1 License") or BSD License.
 *
 * LGPLv2.1 License
 *
 * Copyright(C) 2019 MediaTek Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of version 2.1 of the GNU Lesser General Public
 * License as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html for more
 * details.
 *
 * BSD LICENSE
 *
 * Copyright(C) 2019 MediaTek Inc.
 * All rights reserved.
 *
 * 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 the copyright holder 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
 * HOLDER 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.
 *
 *****************************************************************************/

/*-----------------------------------------------------------------------------
 *
 * $Author: dtvbm11 $
 * $Date: 2015/07/28 $
 * $RCSfile: sif_hw_SECM0.c,v $
 * $Revision: #1 $
 *
 *---------------------------------------------------------------------------*/

/** @file sif_hw_secm0.c
 *  This file implement serial interface SIF function.
 */

//---------------------------------------------------------------------------
// Include files
//---------------------------------------------------------------------------
#include "sif_debug.h"
#include "sif_hw.h"
#include "sif_isr.h"
#include "sif_if.h"

#include "drvcust_if.h"
#include "x_assert.h"
#include "x_bim.h"
#include "x_os.h"
#include "x_pinmux.h"
#include "x_hal_arm.h"
#include "x_printf.h"
#include "x_timer.h"

#include "x_pdwnc.h"
#ifndef  CC_DISCARD_SUPPORT_PCMCIA
#include "pcmcia_if.h"
#endif

//---------------------------------------------------------------------------
// Configurations
//---------------------------------------------------------------------------

/// For driver customization options
/// 1. open drain (default use open drain mode)
/// 2. scl stretch (default don't use clock stretch mode)

/// Default use interrupt mode for OSAI mode
#define CC_SIF_USE_INTERRUPT_MODE

/// Use OSAI function option
#if defined (CC_MTK_LOADER)
#define SIF_USE_OSAI            0
#ifdef CC_SIF_USE_INTERRUPT_MODE
#undef CC_SIF_USE_INTERRUPT_MODE
#endif // CC_SIF_USE_INTERRUPT_MODE
#else // defined (CC_MTK_LOADER)
#define SIF_USE_OSAI            1
#endif // defined (CC_MTK_LOADER)

#if defined (USE_NEW_MODE)
UINT32 u4FLAG_Read_Second = 0;
#endif

/// Default use multiple data read/write
#define CC_SIF_MULTIPLE_DATA_BYTE_ACCESS

/// Support delay between TRI for SCL stretch workaround
// #define CC_SIF_TRI_DELAY_SUPPORT

#ifdef CC_SIF_TRI_DELAY_SUPPORT
/// Current slave device to communicate to
static UINT8 _u1CurrDevAddr = 0;
static UINT8 _u1TRIDelayDevAddr = 0;
/// The delay between, in micro seconds.
static UINT32 _u4TRIDelay = 0;
#if SIF_USE_OSAI && defined(CC_SIF_USE_INTERRUPT_MODE)
static HAL_TIME_T _rTriTime = {0, 0}, _rIsrTime = {0, 0};
#endif // SIF_USE_OSAI
void SIF_SetTRIDelay(UINT32 u4Delay)
{
    _u4TRIDelay = u4Delay;
}
#endif // CC_SIF_TRI_DELAY_SUPPORT

//---------------------------------------------------------------------------
// Constant definitions
//---------------------------------------------------------------------------
/// SIF has 9 data port register. Total 36 bytes, so page read/write unit is 36 bytes.
#if SIF_USE_LENGTHER_PAGE
#define SIF_PAGE_SIZE           ((UINT32)36)
#endif

/// Regular timeout checkings for SIF interrupt status, time is in ms.
/// For Nucleus, minimum is 5 ms.
#define SIF_SEMA_TIMEOUT        ((UINT32)10)

#define PINTNO_SIF      PDWNC_INTNO_SIFM			// SIF0 interrupt number inside Pdwnc
#define PINTNO_SIF1      PDWNC_INTNO_SIFM1			// SIF1 interrupt number inside Pdwnc

#define SIF_TIMEOUT_MAX  (2000)

#define  SIF_OK    (0)

#define  SIF_DEGLITCHLEVEL    (0x03)

//---------------------------------------------------------------------------
// Type definitions
//---------------------------------------------------------------------------
typedef struct _SIFDEVPARAM_T
{
    UINT16  u2ClkDiv;        //< parameter of divider to divide 27 Mhz for SCL. 12 bits width.
    UINT8   u1DevAddr;       //< device address: 7 bits width.
    UINT32  u4WordAddrNum;   //< number of word address:  2 bits width, 0, 1, 2, 3.
    UINT32  u4WordAddr;      //< word address:  24 bits width.
    UINT8*   pu1Buf;         //< point to user's buffer.
    UINT16  u2ByteCnt;       //< the data length that user want to read/write.
    UINT16  u2ProcCnt;       //< the data length that SIF read/write completely.
    UINT8 	u1BusNo;		//< I2C Bus No.
    BOOL    fgNoStart;       //< send start bit or not>
    BOOL    fgNoStop;        //< send stop bit or not>
    BOOL    fgOpenDrain;     //< OpenDrain>
    BOOL    fgSclStretch;    //< SCL_STRETCH bit> byte/bit synchronization
} SIFDEVPARAM_T;

#ifndef SIF_CHECK_SDA_LOW
typedef struct _SIF_BUS_STATUS_
{
    UINT8 SIF_BUS_SDA;
    UINT8 SIF_BUS_SCL;
} SIF_BUS_STATUS_T;
#endif

typedef enum
{
    SIF_CTL_NORMAL    =  0,       /* Normal I2C operation         */
    SIF_CTL_NO_START  =  1 << 1,  /* Do not generate start signal */
    SIF_CTL_NO_STOP   =  1 << 2,  /* Do not generate stop signal  */
} SIF_BUS_CONTROL_T;

//---------------------------------------------------------------------------
// Macro definitions
//---------------------------------------------------------------------------
#ifndef CC_MTK_LOADER
#ifndef  CC_DISCARD_SUPPORT_PCMCIA
#ifndef PCMCIA_RawWrite32MSK
#define PCMCIA_RawWrite32MSK(offset, value, msk)  PCMCIA_RawWrite32((offset),((PCMCIA_RawRead32(offset) & ~(msk)) | (value)))
#endif
#endif
#endif


//---------------------------------------------------------------------------
// Global Variables
//---------------------------------------------------------------------------


//---------------------------------------------------------------------------
// Imported variables
//---------------------------------------------------------------------------


//---------------------------------------------------------------------------
// Imported functions
//---------------------------------------------------------------------------


//---------------------------------------------------------------------------
// Forward declarations
//---------------------------------------------------------------------------
#if SIF_USE_OSAI
// static VOID _SIF_AsyncThread(VOID);
#endif
static VOID SIF_SECM0_Init(VOID);
static UINT16 SIF_SECM0_X_Read(UINT8 u1CHannelID, UINT16 u2ClkDiv, UINT8 u1DevAddr, UINT8 u1WordAddrNum, UINT32 u4WordAddr,
                            UINT8* pu1Buf, UINT16 u2ByteCnt);
static UINT16 SIF_SECM0_X_Sp_Read(UINT8 u1CHannelID, UINT16 u2ClkDiv, UINT8 u1DevAddr, UINT8 u1WordAddrNum, UINT32 u4WordAddr,
                               UINT8* pu1Buf, UINT16 u2ByteCnt);
static UINT16 SIF_SECM0_X_Write(UINT8 u1CHannelID, UINT16 u2ClkDiv, UINT8 u1DevAddr, UINT8 u1WordAddrNum, UINT32 u4WordAddr,
                             UINT8* pu1Buf, UINT16 u2ByteCnt);
#ifdef CC_CLI
static VOID SIF_SECM0_Stop(VOID);
#endif
static VOID SIF_SECM0_ISRHandler(UINT16 u2Vector);

//---------------------------------------------------------------------------
// Static variables
//---------------------------------------------------------------------------
static SIFDEVPARAM_T _rSifDevParm;

/// SIF initialized flag.
static BOOL _fgSifInit            = FALSE;
static BOOL _fgSifInitStart       = FALSE;
static BOOL _fgSifInitWait        = FALSE;
static BOOL _fgIsrEnabled         = FALSE;

#if SIF_USE_OSAI
/// SIF multi-task protection semaphore.
static HANDLE_T _hSifUserSema     = NULL_HANDLE;
static HANDLE_T _hSifSecm0IsrSema      = NULL_HANDLE;

static HANDLE_T _hSifAsyncSema     = NULL_HANDLE;
static HANDLE_T _hSifAsyncMsg;
// static HANDLE_T _hSifAsyncThread;
#endif // SIF_USE_OSAI

static BOOL _fgEnableSclStretch   = FALSE;
static BOOL _fgDisableOpenDrain   = FALSE;

static PFN_SIF_CFG_BEFORE_ACTION_FUNC _pfnSifCfgBeforeActionFunc = NULL;
static PFN_SIF_CFG_AFTER_ACTION_FUNC _pfnSifCfgAfterActionFunc = NULL;
static PFN_SIF_CFG_PIN_SET_FUNC _pfnSifCfgPinSetFunc = NULL;

static SIF_STRUCT_T _rSifStruct =
{
    5, // SIF engine secure master0
    {
        SIF_SECM0_Init,
#ifdef CC_CLI
        SIF_SECM0_Stop,
#else
        NULL,
#endif
        SIF_SECM0_X_Read,
        SIF_SECM0_X_Sp_Read,
        SIF_SECM0_X_Write,
        SIF_SECM0_ISRHandler,
    }
};

//---------------------------------------------------------------------------
// Static functions
//---------------------------------------------------------------------------
// Func : Check wheather the sema can be locked immediately.
static INT32 _SIFSECM0_ISR_TryLock(void)
{
#if SIF_USE_OSAI && defined(CC_SIF_USE_INTERRUPT_MODE)
    return x_sema_lock(_hSifSecm0IsrSema, X_SEMA_OPTION_NOWAIT);
#else
    return 0;
#endif
}

static INT32 _SIFSECM0_ISR_Unlock(void)
{
#if SIF_USE_OSAI && defined(CC_SIF_USE_INTERRUPT_MODE)
    return x_sema_unlock(_hSifSecm0IsrSema);
#else
    return 0;
#endif
}

static INT32 _SIFSECM0_ISR_Lock(void)
{
#if SIF_USE_OSAI && defined(CC_SIF_USE_INTERRUPT_MODE)
    return x_sema_lock_timeout(_hSifSecm0IsrSema, SIF_TIMEOUT_MAX);
#else
    return 0;
#endif
}

static void _SIFSECM0_ISR_DeleteSema(void)
{
#if SIF_USE_OSAI && defined(CC_SIF_USE_INTERRUPT_MODE)
        VERIFY(x_sema_delete(_hSifSecm0IsrSema) == OSR_OK);
#endif
}

static void _SIFSECM0_ISR_CreateSema(void)
{
#if SIF_USE_OSAI && defined(CC_SIF_USE_INTERRUPT_MODE)
        VERIFY(x_sema_create(&_hSifSecm0IsrSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_LOCK) == OSR_OK);
#endif
}

#ifdef CC_SIF_TRI_DELAY_SUPPORT
#if SIF_USE_OSAI && defined(CC_SIF_USE_INTERRUPT_MODE)
/** _SIF_GetIsrTime
 *  Get the time stamp when SIF ISR happens
 *  @param  void
 *  @retval void
 */
static VOID _SIF_GetIsrTime(VOID)
{
    if ((_u1CurrDevAddr & 0xFE) == _u1TRIDelayDevAddr)
    {
        HAL_GetTime(&_rIsrTime);
    }
}
#endif // SIF_USE_OSAI && defined(CC_SIF_USE_INTERRUPT_MODE)
/** _SIF_CheckAndDelay
 *  Check time stamp and delay between TRI
 *  @param  void
 *  @retval void
 */
static VOID _SIF_CheckAndDelay(VOID)
{
    UINT32 u4Clk_2 = (_rSifDevParm.u2ClkDiv << 1) / 27;
#if SIF_USE_OSAI && defined(CC_SIF_USE_INTERRUPT_MODE)
    UINT32 u4Delay;
    HAL_TIME_T rDeltaTime;
    if ((_u1CurrDevAddr & 0xFE) == _u1TRIDelayDevAddr)
    {
        HAL_GetTime(&_rTriTime);
        HAL_GetDeltaTime(&rDeltaTime, &_rIsrTime, &_rTriTime);
        // If the delta time between TRI already > TRI_DELAY, extra delay is not needed
        if (rDeltaTime.u4Seconds >= 1 || rDeltaTime.u4Micros >= _u4TRIDelay + u4Clk_2)
        {
            return;
        }
        u4Delay = _u4TRIDelay + u4Clk_2 - rDeltaTime.u4Micros;
        // Busy delay here since the slave device will only stretch SCL in micro second order
        HAL_Delay_us(u4Delay);
    }
#else
    if ((_u1CurrDevAddr & 0xFE) == _u1TRIDelayDevAddr)
    {
        HAL_Delay_us(_u4TRIDelay + u4Clk_2);
    }
#endif // SIF_USE_OSAI && defined(CC_SIF_USE_INTERRUPT_MODE)       
}
#endif // CC_SIF_TRI_DELAY_SUPPORT

#if SIF_USE_OSAI
#ifdef CC_SIF_USE_INTERRUPT_MODE
static VOID _SIF_Control(VOID);
#if defined(CC_FAST_INIT)|| (defined(CC_SUPPORT_STR))
VOID _SIFSECM0_DisableAndClearInterrupt(VOID);
#else
static VOID _SIFSECM0_DisableAndClearInterrupt(VOID);
#endif
static VOID _SIF_TimeOutReset(VOID)
{
    //UINT32 u4Reg;
    UINT32 u4Flag;

    //Enter critical section,
    u4Flag = HalCriticalStart();

    // Disable and clear interrupt
    _SIFSECM0_DisableAndClearInterrupt();

    //SIF HW Reset
    vIO32WriteFldAlign(SIF_PERMISC, 0x1, FLD_SECSM0_SW_RST);        
    vIO32WriteFldAlign(SIF_PERMISC, 0x0, FLD_SECSM0_SW_RST);        
	
    // Enable SIF master
    vIO32WriteFldAlign(SIF_SECSM0CTL0, 0x1, FLD_SECSM0_EN);        
    
    HAL_Delay_us(100);

    //Leave critical section
    HalCriticalEnd(u4Flag);
    // Restore SIF control register value
    _SIF_Control();

    // Protect: If SIF ISR comes after timeout but before timeout reset, we need to reset sema in lock state
    if (_SIFSECM0_ISR_Lock() != OSR_WOULD_BLOCK)
    {
        _SIFSECM0_ISR_DeleteSema();
        _SIFSECM0_ISR_CreateSema();
    }

}
#endif
#endif



// Lock SIF semaphore
static VOID _SIF_UserLock(VOID)
{
    SIF_Init();
#if SIF_USE_OSAI
    // wait semaphore
    VERIFY(x_sema_lock(_hSifUserSema, X_SEMA_OPTION_WAIT) == OSR_OK);
#endif // SIF_USE_OSAI
}

// Unlock SIF semaphore
static VOID _SIF_UserUnlock(VOID)
{
#if SIF_USE_OSAI
    // release semaphore
    VERIFY(x_sema_unlock(_hSifUserSema) == OSR_OK);
#endif //SIF_USE_OSAI
}


// Wait tirgger bit becomes 0
static INT32 _SIF_WaitHwDone(VOID)
{
    UINT32 u4Tri;

#if SIF_USE_OSAI
#ifdef CC_SIF_USE_INTERRUPT_MODE
    if (_SIFSECM0_ISR_Lock() != OSR_OK)
    {
		Printf("_SIF_WaitHwDone isr semaphore lock timeout!\n");
#if 1
		Printf("SIF_SECSM0CTL0(0x%x)=0x%x\n", SIF_SECSM0CTL0, u4IO32Read4B(SIF_SECSM0CTL0));
		Printf("SIF_SECSM0CTL1(0x%x)=0x%x\n", SIF_SECSM0CTL1, u4IO32Read4B(SIF_SECSM0CTL1));
		Printf("SIF_SECSM0CTL2(0x%x)=0x%x\n", SIF_SECSM0CTL2, u4IO32Read4B(SIF_SECSM0CTL2));
		Printf("SIF_SECSM0SDEV(0x%x)=0x%x\n", SIF_SECSM0SDEV, u4IO32Read4B(SIF_SECSM0SDEV));
		Printf("SIF_SECSM0CTL3(0x%x)=0x%x\n", SIF_SECSM0CTL3, u4IO32Read4B(SIF_SECSM0CTL3));
		Printf("SIF_I2CINTEN(0x%x)=0x%x\n", SIF_I2CINTEN, u4IO32Read4B(SIF_I2CINTEN));
		Printf("SIF_I2CINTST(0x%x)=0x%x\n", SIF_I2CINTST, u4IO32Read4B(SIF_I2CINTST));
		Printf("SIF_I2CINTCL(0x%x)=0x%x\n", SIF_I2CINTCL, u4IO32Read4B(SIF_I2CINTCL));
		Printf("SIF_PERMISC(0x%x)=0x%x\n", SIF_PERMISC, u4IO32Read4B(SIF_PERMISC));
#endif
		_SIF_TimeOutReset();
		return SIF_ERROR_TIMEOUT;
    }
#endif // CC_SIF_USE_INTERRUPT_MODE
#endif // SIF_USE_OSAI 
    u4Tri = 1;

    while (u4Tri)
    {
        u4Tri = IO32ReadFldAlign(SIF_SECSM0CTL1, FLD_SECSM0_TRI);
    }

    return SIF_OK;
}


#if defined(CC_FAST_INIT)|| (defined(CC_SUPPORT_STR))
VOID _SIFSECM0_DisableAndClearInterrupt(VOID)
#else
static VOID _SIFSECM0_DisableAndClearInterrupt(VOID)
#endif
{
    if ((!_fgIsrEnabled) && (_fgSifInit))
    {
        return;
    }

    _fgIsrEnabled = FALSE;

    vIO32WriteFldAlign(SIF_I2CINTEN, 0x0, FLD_SECSM0_INT_EN);        
    vIO32WriteFldAlign(SIF_I2CINTCL, 0x1, FLD_SECSM0_INT_CL);        
	VERIFY(BIM_DisableIrq(VECTOR_I2C));
	VERIFY(BIM_ClearIrq(VECTOR_I2C));

}


static VOID _SIF_EnableAndClearInterrupt(VOID)
{
    if ((_fgIsrEnabled) && (_fgSifInit))
    {
        return;
    }

    _fgIsrEnabled = TRUE;

    vIO32WriteFldAlign(SIF_I2CINTCL, 0x1, FLD_SECSM0_INT_CL);        
#if SIF_USE_OSAI
#ifdef CC_SIF_USE_INTERRUPT_MODE
	vIO32WriteFldAlign(SIF_I2CINTEN, 0x1, FLD_SECSM0_INT_EN);		
#endif
#endif
	VERIFY(BIM_ClearIrq(VECTOR_I2C));
	VERIFY(BIM_EnableIrq(VECTOR_I2C));

}


// Send one start bit
static INT32 _SIF_PutStartBit(VOID)
{
    //UINT32 u4Reg, u4Msk;

    _SIF_EnableAndClearInterrupt();

#ifdef CC_SIF_TRI_DELAY_SUPPORT
    _SIF_CheckAndDelay();
#endif // CC_SIF_TRI_DELAY_SUPPORT

	vIO32WriteFldMulti(SIF_SECSM0CTL1, P_Fld(0x1, FLD_SECSM0_TRI) | P_Fld(MODE_START, FLD_SECSM0_MODE));

    return _SIF_WaitHwDone();
}


// Send one stop bit
static INT32 _SIF_PutStopBit(VOID)
{
    //UINT32 u4Reg, u4Msk;

    _SIF_EnableAndClearInterrupt();

#ifdef CC_SIF_TRI_DELAY_SUPPORT
    _SIF_CheckAndDelay();
#endif // CC_SIF_TRI_DELAY_SUPPORT

	vIO32WriteFldMulti(SIF_SECSM0CTL1, P_Fld(0x1, FLD_SECSM0_TRI) | P_Fld(MODE_STOP, FLD_SECSM0_MODE));

    return _SIF_WaitHwDone();
}

#ifdef SIF_CHECK_SDA_LOW
INT32 SIF_SendStopBit(VOID)
{
   _SIF_PutStopBit();
}
#endif

// Send one data byte
// Return: 1 success, 0 fail, <0 error.
static INT32 _SIF_PutByte(UINT8 u1Data)
{
    UINT32 u4Ack;
    INT32 i4Ret = 0;

#if SIF_USE_OSAI
#ifdef CC_SIF_USE_INTERRUPT_MODE
    // Make sure SIF semaphore is in lock state.
    if (_SIFSECM0_ISR_TryLock() != OSR_WOULD_BLOCK)
    {
        Printf("SIF_PutByte ISR lock status error!\n");
        _SIF_TimeOutReset();
        return SIF_ERROR_DATA;
    }
#endif // CC_SIF_USE_INTERRUPT_MODE
#endif // SIF_USE_OSAI

    _SIF_EnableAndClearInterrupt();

    // fill data port
    vIO32Write4B(SIF_SECSM0D0, u1Data);

#ifdef CC_SIF_TRI_DELAY_SUPPORT
    _SIF_CheckAndDelay();
#endif // CC_SIF_TRI_DELAY_SUPPORT

    // fill control word
    // P_Fld(0, FLD_SECSM0_PGLEN) = 1 byte
	vIO32WriteFldMulti(SIF_SECSM0CTL1, P_Fld(0x1, FLD_SECSM0_TRI) | P_Fld(MODE_WR_DATA, FLD_SECSM0_MODE) | P_Fld(0, FLD_SECSM0_PGLEN));

    // wait for hardware
    i4Ret = _SIF_WaitHwDone();
    if (i4Ret != SIF_OK)
    {
        LOG(0, "SIF put byte: sema time out ");
        return i4Ret;
    }

	u4Ack = IO32ReadFldAlign(SIF_SECSM0CTL1, FLD_SECSM0_ACK0);

    return ((u4Ack & 0x01) ? 1 : 0);
}


#ifdef CC_SIF_MULTIPLE_DATA_BYTE_ACCESS
// Send multiple data bytes
// Return: how many bytes were written, 0 fail, <1 error
static INT32 _SIF_PutMultipleBytes(UINT8* pu1Data, INT32 i4Bytes)
{
    UINT32 u4Ack, u4D0, u4D1;
    INT32 i4Ret, i4RetTimeout, i, j, i4SplitBytes, i4TotalLoops;
#if SIF_USE_LENGTHER_PAGE
    UINT32 u4AckH, u4AckL, u4D2, u4D3, u4D4, u4D5, u4D6, u4D7, u4D8;
#endif
    ASSERT(pu1Data);
#if SIF_USE_OSAI
#ifdef CC_SIF_USE_INTERRUPT_MODE
    // Make sure SIF semaphore is in lock state.
    if (_SIFSECM0_ISR_TryLock() != OSR_WOULD_BLOCK)
    {
        Printf("SIF_PutMultipleBytes ISR lock status error!\n");
        _SIF_TimeOutReset();
        return SIF_ERROR_DATA;
    }
#endif // CC_SIF_USE_INTERRUPT_MODE
#endif // SIF_USE_OSAI

    i4Ret = 0;
    i4RetTimeout = 0;


    i4TotalLoops = (i4Bytes + SIF_PAGE_SIZE - 1) / SIF_PAGE_SIZE;
    for (i = 0; i < i4TotalLoops; i++)
    {
        // Last <= SIF_PAGE_SIZE bytes
        if (i == (i4TotalLoops - 1))
        {
            i4SplitBytes = i4Bytes % SIF_PAGE_SIZE;
        }
        else
        {
            i4SplitBytes = (INT32)SIF_PAGE_SIZE;
        }

        if (i4SplitBytes == 0)
        {
            i4SplitBytes = (INT32)SIF_PAGE_SIZE;
        }

        u4D0 = 0;
        u4D1 = 0;
#if SIF_USE_LENGTHER_PAGE
        u4D2 = 0;
        u4D3 = 0;
        u4D4 = 0;
        u4D5 = 0;
        u4D6 = 0;
        u4D7 = 0;
        u4D8 = 0;
#endif
        // setup data bytes
#if SIF_USE_LENGTHER_PAGE
        for (j = 0; j < ((i4SplitBytes > 4) ? 4 : i4SplitBytes); j++)
        {
            u4D0 |= ((*(pu1Data + j) << (8 * j)) & (0xFF << (8 * j)));
        }

        if (i4SplitBytes > 4)
        {
            for (j = 0; j < ((i4SplitBytes > 8) ? 4 : (i4SplitBytes - 4)); j++)
            {
                u4D1 |= ((*(pu1Data + 4 + j) << (8 * j)) & (0xFF << (8 * j)));
            }
        }

        if (i4SplitBytes > 8)
        {
            for (j = 0; j < ((i4SplitBytes > 12) ? 4 : (i4SplitBytes - 8)); j++)
            {
                u4D2 |= ((*(pu1Data + 8 + j) << (8 * j)) & (0xFF << (8 * j)));
            }
        }

        if (i4SplitBytes > 12)
        {
            for (j = 0; j < ((i4SplitBytes > 16) ? 4 : (i4SplitBytes - 12)); j++)
            {
                u4D3 |= ((*(pu1Data + 12 + j) << (8 * j)) & (0xFF << (8 * j)));
            }
        }

        if (i4SplitBytes > 16)
        {
            for (j = 0; j < ((i4SplitBytes > 20) ? 4 : (i4SplitBytes - 16)); j++)
            {
                u4D4 |= ((*(pu1Data + 16 + j) << (8 * j)) & (0xFF << (8 * j)));
            }
        }

        if (i4SplitBytes > 20)
        {
            for (j = 0; j < ((i4SplitBytes > 24) ? 4 : (i4SplitBytes - 20)); j++)
            {
                u4D5 |= ((*(pu1Data + 20 + j) << (8 * j)) & (0xFF << (8 * j)));
            }
        }

        if (i4SplitBytes > 24)
        {
            for (j = 0; j < ((i4SplitBytes > 28) ? 4 : (i4SplitBytes - 24)); j++)
            {
                u4D6 |= ((*(pu1Data + 24 + j) << (8 * j)) & (0xFF << (8 * j)));
            }
        }

        if (i4SplitBytes > 28)
        {
            for (j = 0; j < ((i4SplitBytes > 32) ? 4 : (i4SplitBytes - 28)); j++)
            {
                u4D7 |= ((*(pu1Data + 28 + j) << (8 * j)) & (0xFF << (8 * j)));
            }
        }

        if (i4SplitBytes > 32)
        {
            for (j = 0; j < (i4SplitBytes - 32); j++)
            {
                u4D8 |= ((*(pu1Data + 32 + j) << (8 * j)) & (0xFF << (8 * j)));
            }
        }
#else
        for (j = 0; j < ((i4SplitBytes > 4) ? 4 : i4SplitBytes); j++)
        {
            u4D0 |= ((*(pu1Data + j) << (8 * j)) & (0xFF << (8 * j)));
        }
        if (i4SplitBytes > 4)
        {
            for (j = 0; j < (i4SplitBytes - 4); j++)
            {
                u4D1 |= ((*(pu1Data + 4 + j) << (8 * j)) & (0xFF << (8 * j)));
            }
        }
#endif
        pu1Data += i4SplitBytes;

        _SIF_EnableAndClearInterrupt();

        // fill data port
		vIO32Write4B(SIF_SECSM0D0, u4D0);		
		vIO32Write4B(SIF_SECSM0D1, u4D1);		

#if SIF_USE_LENGTHER_PAGE
		vIO32Write4B(SIF_SECSM0D2, u4D2);		
		vIO32Write4B(SIF_SECSM0D3, u4D3);		
		vIO32Write4B(SIF_SECSM0D4, u4D4);		
		vIO32Write4B(SIF_SECSM0D5, u4D5);		
		vIO32Write4B(SIF_SECSM0D6, u4D6);		
		vIO32Write4B(SIF_SECSM0D7, u4D7);		
		vIO32Write4B(SIF_SECSM0D8, u4D8);		
#endif

#ifdef CC_SIF_TRI_DELAY_SUPPORT
        _SIF_CheckAndDelay();
#endif // CC_SIF_TRI_DELAY_SUPPORT

        // fill control word, use old mode
#if defined (USE_NEW_MODE)
        if (i4Bytes > 8)
        {
			vIO32WriteFldMulti(SIF_SECSM0CTL1, P_Fld(0x1, FLD_SECSM0_TRI) | P_Fld(MODE_WR_DATA, FLD_SECSM0_MODE) | P_Fld(i4SplitBytes - 1, FLD_SECSM0_PGLEN));
        }
        //use new mode
        else
        {
			vIO32WriteFldMulti(SIF_SECSM0CTL1, P_Fld(0x1, FLD_SECSM0_TRI) | P_Fld(i4SplitBytes - 1, FLD_SECSM0_PGLEN));
        }
#else
		vIO32WriteFldMulti(SIF_SECSM0CTL1, P_Fld(0x1, FLD_SECSM0_TRI) | P_Fld(MODE_WR_DATA, FLD_SECSM0_MODE) | P_Fld(i4SplitBytes - 1, FLD_SECSM0_PGLEN));
#endif

        // wait for hardware
        i4RetTimeout = _SIF_WaitHwDone();
        if (i4RetTimeout != SIF_OK)
        {
            LOG(0, "SIF put mutiple byte: sema time out ");
            return i4RetTimeout;
        }
#if SIF_USE_LENGTHER_PAGE
		u4AckL = IO32ReadFldAlign(SIF_SECSM0CTL1, FLD_SECSM0_ACK0);//from 0x0 ~ 0x0ffff
		u4AckH = IO32ReadFldAlign(SIF_SECSM0CTL3, FLD_SECSM0_ACK1);//from 0x0 ~ 0x0fffff
        u4Ack =  (u4AckH << 16) | u4AckL;					//from 0x0 ~ 0x0ffffffff

        if (u4AckH > 0x0FFFF)							//u4Ack > 32
        {
            if (u4AckL != 0x0FFFF)
            {
                LOG(0, "SIF put mutiple byte: Abnormal device ack sequence 0x%x.\n ", u4Ack);
                u4Ack = 0;
                ASSERT(0);
            }
            else
            {
                switch (u4AckH)
                {
                    case 0x01FFFF:
                        u4Ack = 33;
                        break;

                    case 0x03FFFF:
                        u4Ack = 34;
                        break;

                    case 0x07FFFF:
                        u4Ack = 35;
                        break;

                    case 0xFFFFF:
                        u4Ack = 36;
                        break;

                    default:
                        LOG(0, "SIF put mutiple byte: Abnormal device ack sequence 0x%x.\n ", u4Ack);
                        u4Ack = 0;
                        ASSERT(0);

                }
            }
        }

        if (u4AckH <= 0x0FFFF)
        {

            switch (u4Ack)
            {
                case 0x00:
                    u4Ack = 0;
                    break;

                case 0x01:
                    u4Ack = 1;
                    break;

                case 0x03:
                    u4Ack = 2;
                    break;

                case 0x07:
                    u4Ack = 3;
                    break;

                case 0x0F:
                    u4Ack = 4;
                    break;

                case 0x1F:
                    u4Ack = 5;
                    break;

                case 0x3F:
                    u4Ack = 6;
                    break;

                case 0x7F:
                    u4Ack = 7;
                    break;

                case 0xFF:
                    u4Ack = 8;
                    break;

                case 0x1FF:
                    u4Ack = 9;
                    break;

                case 0x3FF:
                    u4Ack = 10;
                    break;

                case 0x7FF:
                    u4Ack = 11;
                    break;

                case 0xFFF:
                    u4Ack = 12;
                    break;

                case 0x1FFF:
                    u4Ack = 13;
                    break;

                case 0x3FFF:
                    u4Ack = 14;
                    break;

                case 0x7FFF:
                    u4Ack = 15;
                    break;

                case 0xFFFF:
                    u4Ack = 16;
                    break;

                case 0x1FFFF:
                    u4Ack = 17;
                    break;

                case 0x3FFFF:
                    u4Ack = 18;
                    break;

                case 0x7FFFF:
                    u4Ack = 19;
                    break;

                case 0xFFFFF:
                    u4Ack = 20;
                    break;

                case 0x1FFFFF:
                    u4Ack = 21;
                    break;

                case 0x3FFFFF:
                    u4Ack = 22;
                    break;

                case 0x7FFFFF:
                    u4Ack = 23;
                    break;

                case 0xFFFFFF:
                    u4Ack = 24;
                    break;

                case 0x1FFFFFF:
                    u4Ack = 25;
                    break;

                case 0x3FFFFFF:
                    u4Ack = 26;
                    break;

                case 0x7FFFFFF:
                    u4Ack = 27;
                    break;

                case 0xFFFFFFF:
                    u4Ack = 28;
                    break;

                case 0x1FFFFFFF:
                    u4Ack = 29;
                    break;

                case 0x3FFFFFFF:
                    u4Ack = 30;
                    break;

                case 0x7FFFFFFF:
                    u4Ack = 31;
                    break;

                case 0xFFFFFFFF:
                    u4Ack = 32;
                    break;


                default:
                    LOG(0, "SIF put mutiple byte: Abnormal device ack sequence 0x%x.\n ", u4Ack);
                    u4Ack = 0;
                    ASSERT(0);
            }
        }
#else
		u4Ack = IO32ReadFldAlign(SIF_SECSM0CTL1, FLD_SECSM0_ACK0);
        u4Ack &= 0xFF;
        // count how many acks
        switch (u4Ack)
        {
            case 0x00:
                u4Ack = 0;
                break;

            case 0x01:
                u4Ack = 1;
                break;

            case 0x03:
                u4Ack = 2;
                break;

            case 0x07:
                u4Ack = 3;
                break;

            case 0x0F:
                u4Ack = 4;
                break;

            case 0x1F:
                u4Ack = 5;
                break;

            case 0x3F:
                u4Ack = 6;
                break;

            case 0x7F:
                u4Ack = 7;
                break;

            case 0xFF:
                u4Ack = 8;
                break;

            default:
                LOG(0, "SIF put mutiple byte: Abnormal device ack sequence 0x%x.\n ", u4Ack);
                u4Ack = 0;
                ASSERT(0);
        }
#endif


        i4Ret += u4Ack;

        if (u4Ack == 0)
        {
            return ((i4Ret > i4Bytes) ? i4Bytes : i4Ret);
        }
    }

    return ((i4Ret > i4Bytes) ? i4Bytes : i4Ret);
}
#endif // CC_SIF_MULTIPLE_DATA_BYTE_ACCESS


#ifdef CC_SIF_MULTIPLE_DATA_BYTE_ACCESS
// Read multiple data bytes
// Return: how many bytes were read, 0 fail
static INT32 _SIF_GetMultipleBytes(UINT8* pu1Data, INT32 i4Bytes)
{
    UINT32 u4D0, u4D1;
    INT32 i4Ret, i4RetTimeout, i, j, i4SplitBytes, i4TotalLoops;
#if SIF_USE_LENGTHER_PAGE
    UINT32 u4D2, u4D3, u4D4, u4D5, u4D6, u4D7, u4D8;
#endif

    ASSERT(pu1Data);

#if SIF_USE_OSAI
#ifdef CC_SIF_USE_INTERRUPT_MODE
    // Make sure SIF semaphore is in lock state.
    if (_SIFSECM0_ISR_TryLock() != OSR_WOULD_BLOCK)
    {
        Printf("SIF_GetMultipleBytes ISR lock status error!\n");
        _SIF_TimeOutReset();
        return SIF_ERROR_DATA;
    }
#endif // CC_SIF_USE_INTERRUPT_MODE
#endif // SIF_USE_OSAI

    i4Ret = 0;
    i4RetTimeout = 0;


    i4TotalLoops = (i4Bytes + SIF_PAGE_SIZE - 1) / SIF_PAGE_SIZE;

    for (i = 0; i < i4TotalLoops; i++)
    {
        // Last <= SIF_PAGE_SIZE bytes
        if (i == (i4TotalLoops - 1))
        {
            i4SplitBytes = i4Bytes % SIF_PAGE_SIZE;
        }
        else
        {
            i4SplitBytes = (INT32) SIF_PAGE_SIZE;
        }

        if (i4SplitBytes == 0)
        {
            i4SplitBytes = (INT32) SIF_PAGE_SIZE;
        }

		
		_SIF_EnableAndClearInterrupt();

#ifdef CC_SIF_TRI_DELAY_SUPPORT
		_SIF_CheckAndDelay();
#endif // CC_SIF_TRI_DELAY_SUPPORT

		// fill control word
        if (i == (i4TotalLoops - 1))
        {
#if defined (USE_NEW_MODE)
            //use old mode
            if (i4Bytes > 8)
            {
				vIO32WriteFldMulti(SIF_SECSM0CTL1, P_Fld(0x1, FLD_SECSM0_TRI) | P_Fld(MODE_RD_DATA_LAST, FLD_SECSM0_MODE) | P_Fld(i4SplitBytes - 1, FLD_SECSM0_PGLEN));
            }
            //use new mode
            else
            {
				vIO32WriteFldMulti(SIF_SECSM0CTL1, P_Fld(0x1, FLD_SECSM0_TRI) | P_Fld(i4SplitBytes - 1, FLD_SECSM0_PGLEN));
            }
#else
			vIO32WriteFldMulti(SIF_SECSM0CTL1, P_Fld(0x1, FLD_SECSM0_TRI) | P_Fld(MODE_RD_DATA_LAST, FLD_SECSM0_MODE) | P_Fld(i4SplitBytes - 1, FLD_SECSM0_PGLEN));
#endif
        }
        else
        {
			vIO32WriteFldMulti(SIF_SECSM0CTL1, P_Fld(0x1, FLD_SECSM0_TRI) | P_Fld(MODE_RD_DATA, FLD_SECSM0_MODE) | P_Fld(i4SplitBytes - 1, FLD_SECSM0_PGLEN));
        }

        // wait for hardware
        i4RetTimeout = _SIF_WaitHwDone();
        if (i4RetTimeout != SIF_OK)
        {
            LOG(0, "SIF get mutiple byte: sema time out ");
            return i4RetTimeout;
        }

        u4D0 = u4IO32Read4B(SIF_SECSM0D0);
        u4D1 = u4IO32Read4B(SIF_SECSM0D1);

#if SIF_USE_LENGTHER_PAGE
        u4D2 = u4IO32Read4B(SIF_SECSM0D2);
        u4D3 = u4IO32Read4B(SIF_SECSM0D3);
        u4D4 = u4IO32Read4B(SIF_SECSM0D4);
        u4D5 = u4IO32Read4B(SIF_SECSM0D5);
        u4D6 = u4IO32Read4B(SIF_SECSM0D6);
        u4D7 = u4IO32Read4B(SIF_SECSM0D7);
        u4D8 = u4IO32Read4B(SIF_SECSM0D8);
#endif

        // save to buffer
#if defined (USE_NEW_MODE)
        if (u4FLAG_Read_Second == 1)
        {
            for (j = 0; j < ((i4SplitBytes > 4) ? 4 : i4SplitBytes); j++)
            {
                *(pu1Data + 8) = (UINT8) (u4D0 & 0xFF);
                u4D0 >>= 8;
                pu1Data++;
                i4Ret++;
            }

            if (i4SplitBytes > 4)
            {
                for (j = 0; j < (i4SplitBytes - 4); j++)
                {
                    *(pu1Data + 8)  = (UINT8) (u4D1 & 0xFF);
                    u4D1 >>= 8;
                    pu1Data++;
                    i4Ret++;
                }
            }
        }
        else
        {
            for (j = 0; j < ((i4SplitBytes > 4) ? 4 : i4SplitBytes); j++)
            {
                *pu1Data = (UINT8) (u4D0 & 0xFF);
                u4D0 >>= 8;
                pu1Data++;
                i4Ret++;
            }

            if (i4SplitBytes > 4)
            {
                for (j = 0; j < (i4SplitBytes - 4); j++)
                {
                    *pu1Data = (UINT8) (u4D1 & 0xFF);
                    u4D1 >>= 8;
                    pu1Data++;
                    i4Ret++;
                }
            }

        }
#else

#if SIF_USE_LENGTHER_PAGE
        for (j = 0; j < ((i4SplitBytes > 4) ? 4 : i4SplitBytes); j++)
        {
            *pu1Data = (UINT8) (u4D0 & 0xFF);
            u4D0 >>= 8;
            pu1Data++;
            i4Ret++;
        }
        if (i4SplitBytes > 4)
        {
            for (j = 0; j < ((i4SplitBytes > 8) ? 4 : (i4SplitBytes - 4)); j++)
            {
                *pu1Data = (UINT8) (u4D1 & 0xFF);
                u4D1 >>= 8;
                pu1Data++;
                i4Ret++;
            }
        }

        if (i4SplitBytes > 8)
        {
            for (j = 0; j < ((i4SplitBytes > 12) ? 4 : (i4SplitBytes - 8)); j++)
            {
                *pu1Data = (UINT8) (u4D2 & 0xFF);
                u4D2 >>= 8;
                pu1Data++;
                i4Ret++;

            }
        }
        if (i4SplitBytes > 12)
        {
            for (j = 0; j < ((i4SplitBytes > 16) ? 4 : (i4SplitBytes - 12)); j++)
            {
                *pu1Data = (UINT8) (u4D3 & 0xFF);
                u4D3 >>= 8;
                pu1Data++;
                i4Ret++;

            }
        }
        if (i4SplitBytes > 16)
        {
            for (j = 0; j < ((i4SplitBytes > 20) ? 4 : (i4SplitBytes - 16)); j++)
            {
                *pu1Data = (UINT8) (u4D4 & 0xFF);
                u4D4 >>= 8;
                pu1Data++;
                i4Ret++;

            }
        }
        if (i4SplitBytes > 20)
        {
            for (j = 0; j < ((i4SplitBytes > 24) ? 4 : (i4SplitBytes - 20)); j++)
            {
                *pu1Data = (UINT8) (u4D5 & 0xFF);
                u4D5 >>= 8;
                pu1Data++;
                i4Ret++;

            }
        }
        if (i4SplitBytes > 24)
        {
            for (j = 0; j < ((i4SplitBytes > 28) ? 4 : (i4SplitBytes - 24)); j++)
            {
                *pu1Data = (UINT8) (u4D6 & 0xFF);
                u4D6 >>= 8;
                pu1Data++;
                i4Ret++;

            }
        }
        if (i4SplitBytes > 28)
        {
            for (j = 0; j < ((i4SplitBytes > 32) ? 4 : (i4SplitBytes - 28)); j++)
            {
                *pu1Data = (UINT8) (u4D7 & 0xFF);
                u4D7 >>= 8;
                pu1Data++;
                i4Ret++;

            }
        }

        if (i4SplitBytes > 32)
        {
            for (j = 0; j < (i4SplitBytes - 32); j++)
            {
                *pu1Data = (UINT8) (u4D8 & 0xFF);
                u4D8 >>= 8;
                pu1Data++;
                i4Ret++;
            }
        }

#else
        for (j = 0; j < ((i4SplitBytes > 4) ? 4 : i4SplitBytes); j++)
        {
            *pu1Data = (UINT8) (u4D0 & 0xFF);
            u4D0 >>= 8;
            pu1Data++;
            i4Ret++;
        }

        if (i4SplitBytes > 4)
        {
            for (j = 0; j < (i4SplitBytes - 4); j++)
            {
                *pu1Data = (UINT8) (u4D1 & 0xFF);
                u4D1 >>= 8;
                pu1Data++;
                i4Ret++;
            }
        }
#endif
#endif

    }

    return i4Ret;
}
#else // CC_SIF_MULTIPLE_DATA_BYTE_ACCESS
// Get one data byte from SIF
static INT32 _SIF_GetByte(UINT8* pu1Data, BOOL fgLast)
{
    INT32 i4Ret = 0;

#if SIF_USE_OSAI
#ifdef CC_SIF_USE_INTERRUPT_MODE
    // Make sure SIF semaphore is in lock state.
    if (_SIFSECM0_ISR_TryLock() != OSR_WOULD_BLOCK)
    {
        Printf("SIF_GetByte ISR lock status error!\n");
        _SIF_TimeOutReset();
        return SIF_ERROR_DATA;
    }
#endif // CC_SIF_USE_INTERRUPT_MODE
#endif // SIF_USE_OSAI

    ASSERT(pu1Data);

    _SIF_EnableAndClearInterrupt();

#ifdef CC_SIF_TRI_DELAY_SUPPORT
    _SIF_CheckAndDelay();
#endif // CC_SIF_TRI_DELAY_SUPPORT

    // fill control word
    if (fgLast == TRUE) //last byte
    {
		vIO32WriteFldMulti(SIF_SECSM0CTL1, P_Fld(0x1, FLD_SECSM0_TRI) | P_Fld(MODE_RD_DATA_LAST, FLD_SECSM0_MODE) | P_Fld(0, FLD_SECSM0_PGLEN));
    }
    else
    {
		vIO32WriteFldMulti(SIF_SECSM0CTL1, P_Fld(0x1, FLD_SECSM0_TRI) | P_Fld(MODE_RD_DATA, FLD_SECSM0_MODE) | P_Fld(0, FLD_SECSM0_PGLEN));
    }

    // wait for hardware
    i4Ret = _SIF_WaitHwDone();
    if (i4Ret != SIF_OK)
    {
        LOG(0, "SIF get byte: sema time out ");
        return i4Ret;
    }

    *pu1Data = u4IO32Read4B(SIF_SECSM0D0) & 0xff;
    return i4Ret;
}
#endif // CC_SIF_MULTIPLE_DATA_BYTE_ACCESS


// Check SIF bus status
static SIF_BUS_STATUS_T _SIF_CheckBus (VOID)
{
    SIF_BUS_STATUS_T tRet;

    x_memset((VOID*)(&tRet), 0, sizeof(SIF_BUS_STATUS_T));

	tRet.SIF_BUS_SDA = (UINT8) (IO32ReadFldAlign(SIF_SECSM0CTL0, FLD_SECSM0_SDA_STATE));
    tRet.SIF_BUS_SCL = (UINT8) (IO32ReadFldAlign(SIF_SECSM0CTL0, FLD_SECSM0_SCL_STATE));

    return tRet;
};

#ifdef SIF_CHECK_SDA_LOW
SIF_BUS_STATUS_T SIF_CheckBusStatus (VOID)
{
    return _SIF_CheckBus();
}
#endif

/** _SIF_OptRead
 *  Read data with options
 *  @param  u2ClkDiv    Parameter of divider to divide 27Mhz for SCL.
 *  @param  u1DevAddr   Serial interface device address.
 *  @param  pu1DataBuf  Pointer to user's buffer.
 *  @param  u4DataLen   Number of bytes to read.
 *  @param  bus_ctrl    Options for read
 *  @retval > 0         Actual number of bytes read.
 *  @retval = 0         Device acked
 *  @retval < 0         Error
 */
static INT32 _SIF_OptRead(UINT16 u2ClkDiv, UINT8 u1DevAddr, UINT8* pu1DataBuf, UINT32 u4DataLen,
                          SIF_BUS_CONTROL_T bus_ctrl)
{
#ifndef CC_SIF_MULTIPLE_DATA_BYTE_ACCESS
    BOOL fgLastByte = FALSE;
#endif
    INT32 i4Cnt = 0, i4Ret = 0;

    if (!(bus_ctrl & SIF_CTL_NO_START))
    {
        i4Ret = _SIF_PutStartBit();
        if (i4Ret != SIF_OK)                 // start
        {
            LOG(0, "_SIF_OptRead: Start Bit error, %d.\n", i4Ret);
            return i4Ret;
        }
        if (_SIF_PutByte(u1DevAddr) != 1)   // dev addr
        {
            LOG(3, "_SIF_OptRead: dev addr 0x%x does not ack.\n", u1DevAddr);

            // stop
            if (!(bus_ctrl & SIF_CTL_NO_STOP))
            {
                i4Ret = _SIF_PutStopBit();
                if ( i4Ret != SIF_OK)
                {
                    LOG(0, "_SIF_OptRead: Stop Bit error, %d.\n", i4Ret);
                    return i4Ret;
                }
            }

            return SIF_ERROR_NODEV;
        }
    }


    // data
#ifdef CC_SIF_MULTIPLE_DATA_BYTE_ACCESS
    i4Cnt = _SIF_GetMultipleBytes(pu1DataBuf, (INT32) u4DataLen);
    if (i4Cnt != (INT32) u4DataLen)
    {
        LOG(0, "_SIF_OptRead: only %d byte were read, expected %d.\n", i4Cnt, u4DataLen);
    }
#else // CC_SIF_MULTIPLE_DATA_BYTE_ACCESS
    while (i4Cnt < u4DataLen)
    {
        if (i4Cnt == (u4DataLen - 1))
        {
            fgLastByte = TRUE;
        }
        i4Ret = _SIF_GetByte((pu1DataBuf + i4Cnt), fgLastByte);
        if (i4Ret != SIF_OK)
        {
            LOG(0, "_SIF_OptRead: terminated at %d byte due to no ACK. return %d\n", i4Cnt, i4Ret);
            break;
        }
        // i4Cnt == Number of data bytes sent on bus
        i4Cnt += 1;
    }
#endif // CC_SIF_MULTIPLE_DATA_BYTE_ACCESS

    // stop
    if (!(bus_ctrl & SIF_CTL_NO_STOP))
    {
        i4Ret = _SIF_PutStopBit();
        if (i4Ret != SIF_OK)
        {
            LOG(0, "_SIF_OptRead: Stop Bit error, %d.\n", i4Ret);
            return i4Ret;
        }
    }

    return i4Cnt;
}


/** _SIF_OptWrite
 *  Write data with options
 *  @param  u2ClkDiv    Parameter of divider to divide 27Mhz for SCL.
 *  @param  u1DevAddr   Serial interface device address.
 *  @param  pu1DataBuf  Pointer to user's buffer.
 *  @param  u4DataLen   Number of bytes to read.
 *  @param  bus_ctrl    Options for read
 *  @retval > 0         Actual number of bytes (sub-address + data) written.
 *  @retval = 0         Device acked
 *  @retval < 0         Error
 */
static INT32 _SIF_OptWrite(UINT16 u2ClkDiv, UINT8 u1DevAddr, UINT8* pu1DataBuf, UINT32 u4DataLen,
                           SIF_BUS_CONTROL_T bus_ctrl)
{
    INT32 i4Cnt = 0, i4Ret = 0;

    if (!(bus_ctrl & SIF_CTL_NO_START))
    {
        i4Ret = _SIF_PutStartBit();
        if (i4Ret != SIF_OK)                 // start
        {
            LOG(0, "_SIF_OptWrite: Start Bit error, %d.\n", i4Ret);
            return i4Ret;
        }

        if (_SIF_PutByte(u1DevAddr) != 1)   // dev addr
        {
            LOG(3, "_SIF_OptWrite: dev addr 0x%x does not ack.\n", u1DevAddr);

            // stop
            if (!(bus_ctrl & SIF_CTL_NO_STOP))
            {
                i4Ret = _SIF_PutStopBit();
                if (i4Ret != SIF_OK)
                {
                    LOG(0, "_SIF_OptWrite: Stop Bit error, %d.\n", i4Ret);
                    return i4Ret;
                }
            }

            return SIF_ERROR_NODEV;
        }
    }

#ifdef CC_SIF_MULTIPLE_DATA_BYTE_ACCESS
    // data
    i4Cnt = _SIF_PutMultipleBytes(pu1DataBuf, (INT32) u4DataLen);
    if (i4Cnt != (INT32) u4DataLen)
    {
        LOG(0, "_SIF_OptWrite: only %d byte were written, expected %d.\n", i4Cnt, u4DataLen);
    }
#else // CC_SIF_MULTIPLE_DATA_BYTE_ACCESS
    // data
    for (i4Cnt = 0; i4Cnt < u4DataLen; i4Cnt++)
    {
        if (_SIF_PutByte(*(pu1DataBuf + i4Cnt)) != 1)
        {
            LOG(0, "_SIF_OptWrite: terminated at %d byte due to no ACK.\n", i4Cnt);
            break;
        }
    }
#endif // CC_SIF_MULTIPLE_DATA_BYTE_ACCESS

    // stop
    if (!(bus_ctrl & SIF_CTL_NO_STOP))
    {
        i4Ret = _SIF_PutStopBit();
        if (i4Ret != SIF_OK)
        {
            LOG(0, "_SIF_OptWrite: Stop Bit error, %d.\n", i4Ret);
            return i4Ret;
        }
    }

    return i4Cnt;
}

#if defined (USE_NEW_MODE)
/** _SIF_Read
 *  Read data with options
 *  @param  u2ClkDiv    Parameter of divider to divide 27Mhz for SCL.
 *  @param  u1DevAddr   Serial interface device address.
 *  @param  pu1DataBuf  Pointer to user's buffer.
 *  @param  u4DataLen   Number of bytes to read.
 *  @param  bus_ctrl    Options for read
 *  @retval > 0         Actual number of bytes read.
 *  @retval = 0         Device acked
 *  @retval < 0         Error
 */
static INT32 _SIF_Read(UINT16 u2ClkDiv, UINT8 u1DevAddr, UINT8* pu1DataBuf, UINT32 u4DataLen,
                       UINT8 Bus_Mode)
{
#ifndef CC_SIF_MULTIPLE_DATA_BYTE_ACCESS
    BOOL fgLastByte = FALSE;
#endif
    UINT32 i4Cnt = 0;
    //INT32 i4Ret = 0;
    //UINT32 u4Reg, u4Msk;
    if (Bus_Mode == 2)
    {
        //u4Reg = (0x03 << 16);
        //u4Msk = 0x7f0000;
        //_SIF_WRITE32MSK(RW_SECSM0_CTRL3_REG, u4Reg, u4Msk);  //284
		vIO32WriteFldMulti(SIF_SECSM0CTL3, P_Fld(0x1, FLD_SECSM0_SDEV_MODE) 
										| P_Fld(0X1, FLD_SECSM0_STR_RDNACK_STOP_MODE) 
										| P_Fld(0, FLD_SECSM0_STR_RDACK_MODE) 
										| P_Fld(0, FLD_SECSM0_RDNACK_STOP_MODE) 
										| P_Fld(0, FLD_SECSM0_STR_WD_STOP_MODE) 
										| P_Fld(0, FLD_SECSM0_STR_WD_MODE) 
										| P_Fld(0, FLD_SECSM0_WD_STOP_MODE));
        LOG(3, "dd	_SIF_Write RW_SECSM0_CTRL1_REG = 0x%x \n", u4IO32Read4B(SIF_SECSM0CTL1));
        LOG(3, "dd	_SIF_Write RW_SECSM0_CTRL3_REG = 0x%x \n", u4IO32Read4B(SIF_SECSM0CTL3));

    }
    else if (Bus_Mode == 3)
    {
        //u4Reg = (0x05 << 16);
        //u4Msk = 0x7f0000;
        //_SIF_WRITE32MSK(RW_SECSM0_CTRL3_REG, u4Reg, u4Msk);  //284
		vIO32WriteFldMulti(SIF_SECSM0CTL3, P_Fld(0x1, FLD_SECSM0_SDEV_MODE) 
										| P_Fld(0, FLD_SECSM0_STR_RDNACK_STOP_MODE) 
										| P_Fld(0X1, FLD_SECSM0_STR_RDACK_MODE) 
										| P_Fld(0, FLD_SECSM0_RDNACK_STOP_MODE) 
										| P_Fld(0, FLD_SECSM0_STR_WD_STOP_MODE) 
										| P_Fld(0, FLD_SECSM0_STR_WD_MODE) 
										| P_Fld(0, FLD_SECSM0_WD_STOP_MODE));
        LOG(3, "dd	_SIF_Write RW_SECSM0_CTRL1_REG = 0x%x \n", u4IO32Read4B(SIF_SECSM0CTL1));
        LOG(3, "dd	_SIF_Write RW_SECSM0_CTRL3_REG = 0x%x \n", u4IO32Read4B(SIF_SECSM0CTL3));

    }
    else if (Bus_Mode == 4)
    {
        //u4Reg = (0x09 << 16);
        //u4Msk = 0x7f0000;
        //_SIF_WRITE32MSK(RW_SECSM0_CTRL3_REG, u4Reg, u4Msk);  //284
		vIO32WriteFldMulti(SIF_SECSM0CTL3, P_Fld(0x1, FLD_SECSM0_SDEV_MODE) 
										| P_Fld(0, FLD_SECSM0_STR_RDNACK_STOP_MODE) 
										| P_Fld(0, FLD_SECSM0_STR_RDACK_MODE) 
										| P_Fld(0X1, FLD_SECSM0_RDNACK_STOP_MODE) 
										| P_Fld(0, FLD_SECSM0_STR_WD_STOP_MODE) 
										| P_Fld(0, FLD_SECSM0_STR_WD_MODE) 
										| P_Fld(0, FLD_SECSM0_WD_STOP_MODE));
        LOG(3, "dd	_SIF_Write RW_SECSM0_CTRL1_REG = 0x%x \n", u4IO32Read4B(SIF_SECSM0CTL1));
        LOG(3, "dd	_SIF_Write RW_SECSM0_CTRL3_REG = 0x%x \n", u4IO32Read4B(SIF_SECSM0CTL3));

    }
    else	//other mode
    {
        //u4Reg = (0x00 << 16);
        //u4Msk = 0x7f0000;
        //_SIF_WRITE32MSK(RW_SECSM0_CTRL3_REG, u4Reg, u4Msk);  //284
		vIO32WriteFldMulti(SIF_SECSM0CTL3, P_Fld(0, FLD_SECSM0_SDEV_MODE) 
										| P_Fld(0, FLD_SECSM0_STR_RDNACK_STOP_MODE) 
										| P_Fld(0, FLD_SECSM0_STR_RDACK_MODE) 
										| P_Fld(0, FLD_SECSM0_RDNACK_STOP_MODE) 
										| P_Fld(0, FLD_SECSM0_STR_WD_STOP_MODE) 
										| P_Fld(0, FLD_SECSM0_STR_WD_MODE) 
										| P_Fld(0, FLD_SECSM0_WD_STOP_MODE));
    }
    // data
#ifdef CC_SIF_MULTIPLE_DATA_BYTE_ACCESS
    i4Cnt = _SIF_GetMultipleBytes(pu1DataBuf, (INT32) u4DataLen);
    if (i4Cnt != (INT32) u4DataLen)
    {
        LOG(0, "_SIF_OptRead: only %d byte were read, expected %d.\n", i4Cnt, u4DataLen);
    }
#else // CC_SIF_MULTIPLE_DATA_BYTE_ACCESS
    while (i4Cnt < u4DataLen)
    {
        LOG(3, "dd	3_SIF_Read CC_SIF_NOT_MULTIPLE_DATA_BYTE_ACCESS \n");
        if (i4Cnt == (u4DataLen - 1))
        {
            fgLastByte = TRUE;
        }
        i4Ret = _SIF_GetByte((pu1DataBuf + i4Cnt), fgLastByte);
        if (i4Ret != SIF_OK)
        {
            LOG(0, "_SIF_OptRead: terminated at %d byte due to no ACK. return %d\n", i4Cnt, i4Ret);
            break;
        }
        // i4Cnt == Number of data bytes sent on bus
        i4Cnt += 1;
    }
#endif // CC_SIF_MULTIPLE_DATA_BYTE_ACCESS

    // stop
#if 0
    if (!(bus_ctrl & SIF_CTL_NO_STOP))
    {
        i4Ret = _SIF_PutStopBit();
        if (i4Ret != SIF_OK)
        {
            LOG(0, "_SIF_OptRead: Stop Bit error, %d.\n", i4Ret);
            return i4Ret;
        }
    }
#endif


    return i4Cnt;

}

/** _SIF_Write
 *  Write data with options
 *  @param  u2ClkDiv    Parameter of divider to divide 27Mhz for SCL.
 *  @param  u1DevAddr   Serial interface device address.
 *  @param  pu1DataBuf  Pointer to user's buffer.
 *  @param  u4DataLen   Number of bytes to read.
 *  @param  Bus_Mode    Options mode for bus
 *  @retval > 0         Actual number of bytes (sub-address + data) written.
 *  @retval = 0         Device acked
 *  @retval < 0         Error
 */
static INT32 _SIF_Write(UINT16 u2ClkDiv, UINT8 u1DevAddr, UINT8* pu1DataBuf, UINT32 u4DataLen,
                        UINT8 Bus_Mode)
{
    INT32 i4Cnt = 0;
    //INT32 i4Ret = 0;
    UINT32 u4Reg;
    if (Bus_Mode == 5)
    {
        //u4Reg = (0x11 << 16);
        //u4Msk = 0x7f0000;
        //_SIF_WRITE32MSK(RW_SECSM0_CTRL3_REG, u4Reg, u4Msk);  //284
		vIO32WriteFldMulti(SIF_SECSM0CTL3, P_Fld(0x1, FLD_SECSM0_SDEV_MODE) 
										| P_Fld(0, FLD_SECSM0_STR_RDNACK_STOP_MODE) 
										| P_Fld(0, FLD_SECSM0_STR_RDACK_MODE) 
										| P_Fld(0, FLD_SECSM0_RDNACK_STOP_MODE) 
										| P_Fld(0X1, FLD_SECSM0_STR_WD_STOP_MODE) 
										| P_Fld(0, FLD_SECSM0_STR_WD_MODE) 
										| P_Fld(0, FLD_SECSM0_WD_STOP_MODE));
        LOG(3, "dd	_SIF_Write RW_SECSM0_CTRL1_REG = 0x%x \n", u4IO32Read4B(SIF_SECSM0CTL1));
        LOG(3, "dd	_SIF_Write RW_SECSM0_CTRL3_REG = 0x%x \n", u4IO32Read4B(SIF_SECSM0CTL3));

    }
    else if (Bus_Mode == 6)
    {
        //u4Reg = (0x21 << 16);
        //u4Msk = 0x7f0000;
        //_SIF_WRITE32MSK(RW_SECSM0_CTRL3_REG, u4Reg, u4Msk);  //284
		vIO32WriteFldMulti(SIF_SECSM0CTL3, P_Fld(0x1, FLD_SECSM0_SDEV_MODE) 
										| P_Fld(0, FLD_SECSM0_STR_RDNACK_STOP_MODE) 
										| P_Fld(0, FLD_SECSM0_STR_RDACK_MODE) 
										| P_Fld(0, FLD_SECSM0_RDNACK_STOP_MODE) 
										| P_Fld(0, FLD_SECSM0_STR_WD_STOP_MODE) 
										| P_Fld(0X1, FLD_SECSM0_STR_WD_MODE) 
										| P_Fld(0, FLD_SECSM0_WD_STOP_MODE));
        LOG(3, "dd	_SIF_Write RW_SECSM0_CTRL1_REG = 0x%x \n", u4IO32Read4B(SIF_SECSM0CTL1));
        LOG(3, "dd	_SIF_Write RW_SECSM0_CTRL3_REG = 0x%x \n", u4IO32Read4B(SIF_SECSM0CTL3));

    }
    else if (Bus_Mode == 7)
    {
        //u4Reg = (0x41 << 16);
        //u4Msk = 0x7f0000;
        //_SIF_WRITE32MSK(RW_SECSM0_CTRL3_REG, u4Reg, u4Msk);  //284
		vIO32WriteFldMulti(SIF_SECSM0CTL3, P_Fld(0x1, FLD_SECSM0_SDEV_MODE) 
										| P_Fld(0, FLD_SECSM0_STR_RDNACK_STOP_MODE) 
										| P_Fld(0, FLD_SECSM0_STR_RDACK_MODE) 
										| P_Fld(0, FLD_SECSM0_RDNACK_STOP_MODE) 
										| P_Fld(0, FLD_SECSM0_STR_WD_STOP_MODE) 
										| P_Fld(0, FLD_SECSM0_STR_WD_MODE) 
										| P_Fld(0X1, FLD_SECSM0_WD_STOP_MODE));
    }
    else	//other mode
    {
        //u4Reg = (0x00 << 16);
        //u4Msk = 0x7f0000;
        //_SIF_WRITE32MSK(RW_SECSM0_CTRL3_REG, u4Reg, u4Msk);  //284
		vIO32WriteFldMulti(SIF_SECSM0CTL3, P_Fld(0, FLD_SECSM0_SDEV_MODE) 
										| P_Fld(0, FLD_SECSM0_STR_RDNACK_STOP_MODE) 
										| P_Fld(0, FLD_SECSM0_STR_RDACK_MODE) 
										| P_Fld(0, FLD_SECSM0_RDNACK_STOP_MODE) 
										| P_Fld(0, FLD_SECSM0_STR_WD_STOP_MODE) 
										| P_Fld(0, FLD_SECSM0_STR_WD_MODE) 
										| P_Fld(0, FLD_SECSM0_WD_STOP_MODE));
    }

#ifdef CC_SIF_MULTIPLE_DATA_BYTE_ACCESS
    // data
    u4Reg = u4IO32Read4B(SIF_SECSM0CTL3);
    LOG(5, "dd SIF_Write_CC_SIF_MULTIPLE_DATA_BYTE_ACCESS: u4regval = 0x%x ,Bus_Mode = %d , DataLented = %d.\n", u4Reg, Bus_Mode, u4DataLen);
    i4Cnt = _SIF_PutMultipleBytes(pu1DataBuf, (INT32) u4DataLen);
    LOG(5, "dd 2_SIF_Write: i4Cnt = %d ,DataLented = %d.\n", i4Cnt, u4DataLen);
    if (i4Cnt != (INT32) u4DataLen)
    {
        LOG(0, "_SIF_Write: only %d byte were written, expected %d.\n", i4Cnt, u4DataLen);
    }
#else // CC_SIF_MULTIPLE_DATA_BYTE_ACCESS
    // data
    u4Reg = u4IO32Read4B(SIF_SECSM0CTL3);
    LOG(5, "dd SIF_Write_NOT_CC_SIF_MULTIPLE_DATA_BYTE_ACCESS: u4regval = 0x%x ,Bus_Mode = %d , DataLented = %d.\n", u4Reg, Bus_Mode, u4DataLen);
    for (i4Cnt = 0; i4Cnt < u4DataLen; i4Cnt++)
    {
        if (_SIF_PutByte(*(pu1DataBuf + i4Cnt)) != 1)
        {
            LOG(0, "_SIF_Write: terminated at %d byte due to no ACK.\n", i4Cnt);
            break;
        }
    }
#endif // CC_SIF_MULTIPLE_DATA_BYTE_ACCESS
    return i4Cnt;
}
#endif


// Fill control register
static VOID _SIF_Control(VOID)
{
    UINT32 u4RiseValue, u4Odrain, u4ClkDiv, u4SclStrect, u4Deglitch ;

    ASSERT(_rSifDevParm.u2ClkDiv);
    if(_rSifDevParm.u2ClkDiv < 0x80)// Fast Mode
    {
        u4RiseValue = _rSifDevParm.u2ClkDiv * 3 / 5;
		vIO32WriteFldMulti(SIF_SECSM0CTL2, P_Fld(u4RiseValue, FLD_SECSM0_SCL_RISE_VALUE) | P_Fld(0x1, FLD_SECSM0_SCL_MODE));
    }
	else  // Standard Mode
	{
		vIO32WriteFldAlign(SIF_SECSM0CTL2, 0, FLD_SECSM0_SCL_MODE);		
	}

    if (_fgEnableSclStretch)
    {
        _rSifDevParm.u2ClkDiv -= ((SIF_DEGLITCHLEVEL) << 1);
		u4SclStrect = 0x1;
    }
    else
    {
		u4SclStrect = 0;
    }
	u4ClkDiv = (UINT32)(_rSifDevParm.u2ClkDiv);


    if (_fgDisableOpenDrain)
    {
		u4Odrain = 0x1;
    }
	else
	{
		u4Odrain = 0;
	}

    u4Deglitch = SIF_DEGLITCHLEVEL;
	//Printf("function======>%s: line=========>%d, SIF_SECSM0CTL0=0x%x\n", __FUNCTION__, __LINE__, u4IO32Read4B(SIF_SECSM0CTL0));
	vIO32WriteFldMulti(SIF_SECSM0CTL0, P_Fld(u4Odrain, FLD_SECSM0_ODRAIN) 
									| P_Fld(u4ClkDiv, FLD_SECSM0_CLK_DIV) 
									| P_Fld(u4Deglitch, FLD_SECSM0_DEG_CNT) 
									| P_Fld(0x1, FLD_SECSM0_DEG_EN) 
									| P_Fld(0x1, FLD_SECSM0_EN) 
									| P_Fld(u4SclStrect, FLD_SECSM0_SCL_STRECH));

}


/** _SIF_DrvRawRead
 *  Raw read SIF data
 *  @param  u2ClkDiv    Parameter of divider to divide 27Mhz for SCL.
 *  @param  u1DevAddr   Serial interface device address.
 *  @param  pSUbAddr    Pointer to sub addresses
 *  @param  u4SubAddrLen  Sub address length
 *  @param  pData       Pointer to user's buffer.
 *  @param  u4DataLen   Number of bytes to read.
 *  @retval > 0         Actual number of data bytes read.
 *  @retval <= 0        Error
 */
static INT32 _SIF_DrvRawRead(UINT16 u2ClkDiv, UINT8 u1DevAddr, UINT8* pSubAddr, UINT32 u4SubAddrLen,
                             UINT8* pData, UINT32 u4DataLen)
{
    INT32 i4Ret = SIF_ERROR_BUS_BUSY;
    SIF_BUS_STATUS_T BusSts;
    UINT8 u1BusNo = _rSifDevParm.u1BusNo;
#if defined (USE_NEW_MODE)
    INT32 i4RetFirst, i4RetSecond;
    UINT32 u4Dev;
    //UINT32 u4Reg, u4Msk;
#endif

    if (_pfnSifCfgBeforeActionFunc != NULL)
    {

        _pfnSifCfgBeforeActionFunc(u1BusNo, u2ClkDiv, u1DevAddr, pSubAddr, u4SubAddrLen, pData, u4DataLen, 1);
    }
    else
    {
        LOG(7, "_pfnSifCfgBeforeActionFunc is NULL\n");
    }

    _rSifDevParm.u2ClkDiv = u2ClkDiv;

    _SIF_Control();
#ifdef TRI_DELAY
    _u1CurrDevAddr = u1DevAddr;
#endif

    // Set Pin mux
    if (_pfnSifCfgPinSetFunc)
    {
        _pfnSifCfgPinSetFunc(u1BusNo);
    }

    // check bus status
    BusSts = _SIF_CheckBus();
    if ((BusSts.SIF_BUS_SCL == 0) || (BusSts.SIF_BUS_SDA == 0))// bus is busy
    {
        i4Ret = _SIF_PutStopBit();
        if (i4Ret != SIF_OK)
        {
            LOG(0, "_SIF_DrvRawRead: Stop Bit error, %d.\n", i4Ret);
            //can't return,because of after callback.
        }
        BusSts = _SIF_CheckBus();                                   // check bus status, again.
        if ((BusSts.SIF_BUS_SCL == 0) || (BusSts.SIF_BUS_SDA == 0)) // bus is still busy...
        {
            LOG(0, "[SIF]Bus is too busy to read\n");
            i4Ret = SIF_ERROR_BUS_BUSY;                             // let's return error
        }
    }
#if defined (USE_NEW_MODE)

    // do ...
    if ((BusSts.SIF_BUS_SCL == 1) && (BusSts.SIF_BUS_SDA == 1)) 	// bus free
    {
        //u4DataLen > 16,use normal mode
        if (u4DataLen > 16)
        {
            //make sure new feasure mode can't be trig
            //u4Reg = (0x0000 << 16);
            //u4Msk = 0xff7f0000;
            //_SIF_WRITE32MSK(RW_SECSM0_CTRL3_REG, u4Reg, u4Msk);  //284
			vIO32WriteFldMulti(SIF_SECSM0CTL3, P_Fld(0, FLD_SECSM0_SDEV_MODE) 
											| P_Fld(0, FLD_SECSM0_STR_RDNACK_STOP_MODE) 
											| P_Fld(0, FLD_SECSM0_STR_RDACK_MODE) 
											| P_Fld(0, FLD_SECSM0_RDNACK_STOP_MODE) 
											| P_Fld(0, FLD_SECSM0_STR_WD_STOP_MODE) 
											| P_Fld(0, FLD_SECSM0_STR_WD_MODE) 
											| P_Fld(0, FLD_SECSM0_WD_STOP_MODE));
            if (u4SubAddrLen)											  // sub-addr
            {
                i4Ret = _SIF_OptWrite(u2ClkDiv, u1DevAddr, pSubAddr, u4SubAddrLen, SIF_CTL_NO_STOP);
                if (i4Ret == (INT32) u4SubAddrLen)
                {
                    i4Ret = _SIF_OptRead(u2ClkDiv, u1DevAddr | 0x1, pData, u4DataLen, SIF_CTL_NORMAL);
                    if (u4DataLen != (UINT32) i4Ret)
                    {
                        i4Ret = SIF_ERROR_DATA;
                    }
                }
                else													// status != SIF_OK
                {
                    i4Ret = _SIF_PutStopBit();
                    if (i4Ret != SIF_OK)
                    {
                        LOG(0, "_SIF_DrvRawRead: Stop Bit error, %d.\n", i4Ret);
                        //can't return,because of after callback.
                    }
                    i4Ret = SIF_ERROR_SUBADDR;
                }
            }
            else														// No sub-addr
            {
                i4Ret = _SIF_OptRead(u2ClkDiv, u1DevAddr | 0x1, pData, u4DataLen, SIF_CTL_NORMAL);
                if (u4DataLen != (UINT32) i4Ret)
                {
                    i4Ret = SIF_ERROR_DATA;
                }
            }
        }
        else
        {
            //dev device address put in register RW_SECSM0_DEV_REG bit[31:24],read bit 24 is 1
            u4Dev = (UINT32)u1DevAddr | 0x1;
            //u4Dev = (u4Dev) << 24 ;
            //_SIF_WRITE32(RW_SECSM0_DEV_REG, u4Dev);
			vIO32WriteFldAlign(SIF_SECSM0SDEV, u4Dev, FLD_SECSM0_DEV_ADDR);		
            if (u4SubAddrLen)											  // sub-addr
            {
                i4Ret = _SIF_OptWrite(u2ClkDiv, u1DevAddr, pSubAddr, u4SubAddrLen, SIF_CTL_NO_STOP);
                if (i4Ret == (INT32) u4SubAddrLen)
                {
                    i4Ret = _SIF_Read(u2ClkDiv, u1DevAddr | 0x1, pData, u4DataLen, 2);
                    if (u4DataLen != (INT32) i4Ret)
                    {
                        i4Ret = SIF_ERROR_DATA;
                    }
                }
                else													// status != SIF_OK
                {
                    i4Ret = _SIF_PutStopBit();
                    if (i4Ret != SIF_OK)
                    {
                        LOG(0, "_SIF_DrvRawRead: Stop Bit error, %d.\n", i4Ret);
                        //can't return,because of after callback.
                    }
                    i4Ret = SIF_ERROR_SUBADDR;
                }
            }
            else														// No sub-addr
            {
                //u4DataLen > 8 use mode 3 & 4 ,SECSM0C3[2] = 1,SECSM0C3[3] = 1
                if (u4DataLen > 8)
                {

                    i4RetFirst = _SIF_Read(u2ClkDiv, u1DevAddr | 0x1, pData, SIF_PAGE_SIZE, 3);
                    if (SIF_PAGE_SIZE != (UINT32) i4RetFirst)
                    {
                        i4Ret = SIF_ERROR_DATA;
                    }
                    u4FLAG_Read_Second = 1;
                    i4RetSecond = _SIF_Read(u2ClkDiv, u1DevAddr | 0x1, pData, u4DataLen - SIF_PAGE_SIZE, 4);
                    if ((u4DataLen - SIF_PAGE_SIZE) != (UINT32) i4RetSecond)
                    {
                        i4Ret = SIF_ERROR_DATA;
                    }
                    i4Ret = i4RetFirst + i4RetSecond;
                    u4FLAG_Read_Second = 0;
                }
                //u4DataLen < 8 use mode 2 ,SECSM0C3[1] = 1
                else
                {
                    i4Ret = _SIF_Read(u2ClkDiv, u1DevAddr | 0x1, pData, u4DataLen, 2);
                    if (u4DataLen != (UINT32) i4Ret)
                    {
                        i4Ret = SIF_ERROR_DATA;
                    }
                }
            }
        }
    }
#else
    //do
    if ((BusSts.SIF_BUS_SCL == 1) && (BusSts.SIF_BUS_SDA == 1)) 	// bus free
    {
        if (u4SubAddrLen)											  // sub-addr
        {
            i4Ret = _SIF_OptWrite(u2ClkDiv, u1DevAddr, pSubAddr, u4SubAddrLen, SIF_CTL_NO_STOP);
            if (i4Ret == (INT32) u4SubAddrLen)
            {
                i4Ret = _SIF_OptRead(u2ClkDiv, u1DevAddr | 0x1, pData, u4DataLen, SIF_CTL_NORMAL);
                if (u4DataLen != (UINT32) i4Ret)
                {
                    i4Ret = SIF_ERROR_DATA;
                }
            }
            else													// status != SIF_OK
            {
                i4Ret = _SIF_PutStopBit();
                if (i4Ret != SIF_OK)
                {
                    LOG(0, "_SIF_DrvRawRead: Stop Bit error, %d.\n", i4Ret);
                    //can't return,because of after callback.
                }
                i4Ret = SIF_ERROR_SUBADDR;
            }
        }
        else														// No sub-addr
        {
            i4Ret = _SIF_OptRead(u2ClkDiv, u1DevAddr | 0x1, pData, u4DataLen, SIF_CTL_NORMAL);
            if (u4DataLen != (UINT32) i4Ret)
            {
                i4Ret = SIF_ERROR_DATA;
            }
        }
    }

#endif
    if (_pfnSifCfgAfterActionFunc != NULL)
    {
        _pfnSifCfgAfterActionFunc(u1BusNo, u2ClkDiv, u1DevAddr, pSubAddr, u4SubAddrLen, pData,  u4DataLen, 1);
    }
    else
    {
        LOG(7, "_pfnSifCfgAfterActionFunc is NULL\n");
    }
    return i4Ret;
}


/** _SIF_DrvRawSpRead
 *  Raw read SIF data
 *  @param  u2ClkDiv    Parameter of divider to divide 27Mhz for SCL.
 *  @param  u1DevAddr   Serial interface device address.
 *  @param  pSUbAddr    Pointer to sub addresses
 *  @param  u4SubAddrLen  Sub address length     fe+c0+register_address+30+fe+c1+31 = 7
 *  @param  pData       Pointer to user's buffer.
 *  @param  u4DataLen   Number of bytes to read.
 *  @retval > 0         Actual number of data bytes read.
 *  @retval <= 0        Error
 */

static INT32 _SIF_DrvRawSpRead(UINT16 u2ClkDiv, UINT8 u1DevAddr, UINT8* pSubAddr, UINT32 u4SubAddrLen,
                               UINT8* pData, UINT32 u4DataLen)
{
    INT32 i4Ret = SIF_ERROR_BUS_BUSY;
    SIF_BUS_STATUS_T BusSts;
    UINT8 u1BusNo = _rSifDevParm.u1BusNo;

    if (_pfnSifCfgBeforeActionFunc != NULL)
    {

        _pfnSifCfgBeforeActionFunc(u1BusNo, u2ClkDiv, u1DevAddr, pSubAddr, u4SubAddrLen, pData, u4DataLen, 1);
    }
    else
    {
        LOG(7, "_pfnSifCfgBeforeActionFunc is NULL\n");
    }

    _rSifDevParm.u2ClkDiv = u2ClkDiv;

    _SIF_Control();
#ifdef TRI_DELAY
    _u1CurrDevAddr = u1DevAddr;
#endif

    // Set Pin mux
    if (_pfnSifCfgPinSetFunc)
    {
        _pfnSifCfgPinSetFunc(u1BusNo);
    }

    // check bus status
    BusSts = _SIF_CheckBus();
    if ((BusSts.SIF_BUS_SCL == 0) || (BusSts.SIF_BUS_SDA == 0))
    {
        i4Ret = _SIF_PutStopBit();
        if (i4Ret != SIF_OK)
        {
            LOG(3, "_SIF_DrvRawSpRead: Stop Bit error, %d.\n", i4Ret);
            //can't return,because of after callback.
        }
        BusSts = _SIF_CheckBus();                                   // check bus status, again.
        if ((BusSts.SIF_BUS_SCL == 0) || (BusSts.SIF_BUS_SDA == 0)) // still bus busy...
        {
            i4Ret = SIF_ERROR_BUS_BUSY;                             // let's return error
        }
    }

    // do ...
    if ((BusSts.SIF_BUS_SCL == 1) && (BusSts.SIF_BUS_SDA == 1))     // bus free
    {

        i4Ret = _SIF_OptWrite(u2ClkDiv, u1DevAddr, pSubAddr, u4SubAddrLen, SIF_CTL_NO_STOP);
        *(pSubAddr + 1) = (*(pSubAddr + 1) | 0x1);
        if (i4Ret == (INT32) u4SubAddrLen)
        {
            i4Ret = _SIF_OptWrite(u2ClkDiv, u1DevAddr, pSubAddr, u4SubAddrLen - 1, SIF_CTL_NO_STOP);
            if (i4Ret == (INT32) u4SubAddrLen - 1)
            {
                i4Ret = _SIF_OptRead(u2ClkDiv, u1DevAddr | 0x1, pData, u4DataLen, SIF_CTL_NORMAL);
                if (u4DataLen != (UINT32) i4Ret)
                {
                    i4Ret = SIF_ERROR_DATA;
                }

            }
        }
        else                                                    // status != SIF_OK
        {
            i4Ret = _SIF_PutStopBit();
            if (i4Ret != SIF_OK)
            {
                LOG(3, "_SIF_DrvRawSpRead: Stop Bit error, %d.\n", i4Ret);
                //can't return,because of after callback.
            }
            i4Ret = SIF_ERROR_SUBADDR;
        }

    }

    if (_pfnSifCfgAfterActionFunc != NULL)
    {
        _pfnSifCfgAfterActionFunc(u1BusNo, u2ClkDiv, u1DevAddr, pSubAddr, u4SubAddrLen, pData,  u4DataLen, 1);
    }
    else
    {
        LOG(7, "_pfnSifCfgAfterActionFunc is NULL\n");
    }
    return i4Ret;
}

/** _SIF_DrvRawWrite
 *  Raw write SIF data
 *  @param  u2ClkDiv    Parameter of divider to divide 27Mhz for SCL.
 *  @param  u1DevAddr   Serial interface device address.
 *  @param  pSUbAddr    Pointer to sub addresses
 *  @param  u4SubAddrLen  Sub address length
 *  @param  pData       Pointer to user's buffer.
 *  @param  u4DataLen   Number of bytes to read.
 *  @retval > 0         Actual number of data bytes written.
 *  @retval <= 0        Error
 */
static INT32 _SIF_DrvRawWrite(UINT16 u2ClkDiv, UINT8 u1DevAddr, UINT8* pSubAddr, UINT32 u4SubAddrLen,
                              UINT8* pData, UINT32 u4DataLen)
{
    INT32 i4Ret = SIF_ERROR_PARAM;
    SIF_BUS_STATUS_T BusSts;
    UINT8 u1BusNo = _rSifDevParm.u1BusNo;
#if defined (USE_NEW_MODE)
    UINT32 u4Dev;
    //UINT32 u4Reg, u4Msk;
#endif
    ASSERT(u4DataLen > 0);

    if (_pfnSifCfgBeforeActionFunc != NULL)
    {
        _pfnSifCfgBeforeActionFunc(u1BusNo, u2ClkDiv, u1DevAddr, pSubAddr, u4SubAddrLen, pData,  u4DataLen, 0);
    }
    else
    {
        LOG(7, "_pfnSifCfgBeforeActionFunc is NULL\n");
    }

    _rSifDevParm.u2ClkDiv = u2ClkDiv;

    _SIF_Control();
#ifdef TRI_DELAY
    _u1CurrDevAddr = u1DevAddr;
#endif

    // Set Pin mux
    if (_pfnSifCfgPinSetFunc)
    {
        _pfnSifCfgPinSetFunc(u1BusNo);
    }

    // check bus status
    BusSts = _SIF_CheckBus();
    if ((BusSts.SIF_BUS_SCL == 0) || (BusSts.SIF_BUS_SDA == 0))
    {
        i4Ret = _SIF_PutStopBit();
        if (i4Ret != SIF_OK)
        {
            LOG(0, "_SIF_DrvRawWrite: Stop Bit error, %d.\n", i4Ret);
            //can't return,because of after callback.
        }
        BusSts = _SIF_CheckBus();                                   // check bus status, again.
        if ((BusSts.SIF_BUS_SCL == 0) || (BusSts.SIF_BUS_SDA == 0)) // still bus busy...
        {
            i4Ret = SIF_ERROR_BUS_BUSY;                             // let's return error
        }
    }
#if defined (USE_NEW_MODE)
    if ((BusSts.SIF_BUS_SCL == 1) && (BusSts.SIF_BUS_SDA == 1)) 	// bus free
    {
        if (u4DataLen > 16) //nor right
        {
            //make sure new feasure mode can't be trig
            //u4Reg = (0x0000 << 16);
            //u4Msk = 0xff7f0000;
            //_SIF_WRITE32MSK(RW_SECSM0_CTRL3_REG, u4Reg, u4Msk);  //284
			vIO32WriteFldMulti(SIF_SECSM0CTL3, P_Fld(0, FLD_SECSM0_SDEV_MODE) 
											| P_Fld(0, FLD_SECSM0_STR_RDNACK_STOP_MODE) 
											| P_Fld(0, FLD_SECSM0_STR_RDACK_MODE) 
											| P_Fld(0, FLD_SECSM0_RDNACK_STOP_MODE) 
											| P_Fld(0, FLD_SECSM0_STR_WD_STOP_MODE) 
											| P_Fld(0, FLD_SECSM0_STR_WD_MODE) 
											| P_Fld(0, FLD_SECSM0_WD_STOP_MODE));
            // sub address
            if (u4SubAddrLen)
            {
                //i4Ret = _SIF_OptWrite(u2ClkDiv, u1DevAddr, pSubAddr, u4SubAddrLen, SIF_CTL_NO_STOP);
                i4Ret = _SIF_Write(u2ClkDiv, u1DevAddr, pSubAddr, u4SubAddrLen, 6);
                if (i4Ret != (INT32) u4SubAddrLen)
                {
                    i4Ret = _SIF_PutStopBit();
                    if (i4Ret != SIF_OK)
                    {
                        LOG(0, "_SIF_DrvRawWrite: Stop Bit error, %d.\n", i4Ret);
                        //can't return,because of after callback.
                    }
                    i4Ret = SIF_ERROR_SUBADDR;
                }
                else
                {
                    i4Ret = _SIF_OptWrite(u2ClkDiv, u1DevAddr, pData, u4DataLen, SIF_CTL_NO_START);
                    if (i4Ret != (INT32) u4DataLen)
                    {
                        i4Ret = SIF_ERROR_DATA;
                    }
                }
            }
            else
            {
                i4Ret = _SIF_OptWrite(u2ClkDiv, u1DevAddr, pData, u4DataLen, SIF_CTL_NORMAL);
                if (i4Ret != (INT32) u4DataLen)
                {
                    i4Ret = SIF_ERROR_DATA;
                }
            }

        }
        else
        {
            //dev device address put in register RW_SECSM0_DEV_REG bit[7:0]
            u4Dev = (UINT32)u1DevAddr;
			vIO32WriteFldAlign(SIF_SECSM0SDEV, u4Dev, FLD_SECSM0_DEV_ADDR);		
            // sub address
            if (u4SubAddrLen)
            {
                LOG(3, "dd _SIF_DrvRawWrite RW_SECSM0_DEV_REG = 0x%x \n", u4IO32Read4B(SIF_SECSM0SDEV));
                i4Ret = _SIF_Write(u2ClkDiv, u1DevAddr, pSubAddr, u4SubAddrLen, 6);
                if (i4Ret != (INT32) u4SubAddrLen)
                {
                    i4Ret = _SIF_PutStopBit();
                    if (i4Ret != SIF_OK)
                    {
                        LOG(0, "_SIF_DrvRawWrite: Stop Bit error, %d.\n", i4Ret);
                        //can't return,because of after callback.
                    }
                    i4Ret = SIF_ERROR_SUBADDR;
                }
                else
                {
                    i4Ret = _SIF_Write(u2ClkDiv, u1DevAddr, pData, u4DataLen, 7);
                    if (i4Ret != (INT32) u4DataLen)
                    {
                        i4Ret = SIF_ERROR_DATA;
                    }
                }
            }
            else
            {

                //device address is at RW_SECSM0_DEV_REG bit[7:0]
                LOG(3, "dd	_SIF_DrvRawWrite no address RW_SECSM0_DEV_REG = 0x%x \n", u4IO32Read4B(SIF_SECSM0SDEV));

                i4Ret = _SIF_Write(u2ClkDiv, u1DevAddr, pData, u4DataLen, 5);
                if (i4Ret != (INT32) u4DataLen)
                {
                    i4Ret = SIF_ERROR_DATA;
                }
            }

        }

    }
#else
    if ((BusSts.SIF_BUS_SCL == 1) && (BusSts.SIF_BUS_SDA == 1)) 	// bus free
    {
        if (u4SubAddrLen)
        {
            i4Ret = _SIF_OptWrite(u2ClkDiv, u1DevAddr, pSubAddr, u4SubAddrLen, SIF_CTL_NO_STOP);
            if (i4Ret != (INT32) u4SubAddrLen)
            {
                i4Ret = _SIF_PutStopBit();
                if (i4Ret != SIF_OK)
                {
                    LOG(0, "_SIF_DrvRawWrite: Stop Bit error, %d.\n", i4Ret);
                    //can't return,because of after callback.
                }
                i4Ret = SIF_ERROR_SUBADDR;
            }
            else
            {
                i4Ret = _SIF_OptWrite(u2ClkDiv, u1DevAddr, pData, u4DataLen, SIF_CTL_NO_START);
                if (i4Ret != (INT32) u4DataLen)
                {
                    i4Ret = SIF_ERROR_DATA;
                }
            }
        }
        else
        {
            i4Ret = _SIF_OptWrite(u2ClkDiv, u1DevAddr, pData, u4DataLen, SIF_CTL_NORMAL);
            if (i4Ret != (INT32) u4DataLen)
            {
                i4Ret = SIF_ERROR_DATA;
            }
        }
    }
#endif

    if (_pfnSifCfgAfterActionFunc != NULL)
    {
        _pfnSifCfgAfterActionFunc(u1BusNo, u2ClkDiv, u1DevAddr, pSubAddr, u4SubAddrLen, pData, u4DataLen, 0);
    }
    else
    {
        LOG(7, "_pfnSifCfgAfterActionFunc is NULL\n");
    }

    return i4Ret;
}


static INT32 _SIF_RawReadMultipleSubAddr(UINT16 u2ClkDiv, UINT8 u1DevAddr, UINT8 u1WordAddrNum, UINT32 u4WordAddr,
                                         UINT8* pu1Buf, UINT16 u2ByteCnt)
{
    UINT8 pu1SubAddr[36] = {0, 0, 0, 0, 0, 0, 0, 0};

    ASSERT(u1WordAddrNum <= 3);

    if (u1WordAddrNum == 1)
    {
        pu1SubAddr[0] = (UINT8) ((u4WordAddr & 0x000000FF));
    }
    else if (u1WordAddrNum == 2)
    {
        pu1SubAddr[0] = (UINT8) ((u4WordAddr & 0x0000FF00) >> 8);
        pu1SubAddr[1] = (UINT8) ((u4WordAddr & 0x000000FF));
    }
    else
    {
        pu1SubAddr[0] = (UINT8) ((u4WordAddr & 0x00FF0000) >> 16);
        pu1SubAddr[1] = (UINT8) ((u4WordAddr & 0x0000FF00) >> 8);
        pu1SubAddr[2] = (UINT8) ((u4WordAddr & 0x000000FF));
    }

    return _SIF_DrvRawRead(u2ClkDiv, u1DevAddr, (UINT8*)pu1SubAddr, u1WordAddrNum, pu1Buf, u2ByteCnt);
}


static INT32 _SIF_RawSpReadMultipleSubAddr(UINT16 u2ClkDiv, UINT8 u1DevAddr, UINT8 u1WordAddrNum, UINT32 u4WordAddr,
                                           UINT8* pu1Buf, UINT16 u2ByteCnt)
{

    UINT8 pu1SubAddr[36] = {0, 0, 0, 0, 0, 0, 0, 0};

    ASSERT(u1WordAddrNum <= 3);

    if (u1WordAddrNum == 1)
    {
        pu1SubAddr[0] = (UINT8) ((u4WordAddr & 0x000000FF));
    }
    else if (u1WordAddrNum == 2)
    {
        pu1SubAddr[0] = (UINT8) ((u4WordAddr & 0x0000FF00) >> 8);
        pu1SubAddr[1] = (UINT8) ((u4WordAddr & 0x000000FF));
    }
    else
    {
        pu1SubAddr[0] = (UINT8) ((u4WordAddr & 0x00FF0000) >> 16);
        pu1SubAddr[1] = (UINT8) ((u4WordAddr & 0x0000FF00) >> 8);
        pu1SubAddr[2] = (UINT8) ((u4WordAddr & 0x000000FF));
    }

    return _SIF_DrvRawSpRead(u2ClkDiv, u1DevAddr, (UINT8*)pu1SubAddr, u1WordAddrNum, pu1Buf, u2ByteCnt);
}

static INT32 _SIF_RawWriteMultipleSubAddr(UINT16 u2ClkDiv, UINT8 u1DevAddr, UINT8 u1WordAddrNum,
                                          UINT32 u4WordAddr, UINT8* pu1Buf, UINT16 u2ByteCnt)
{
    UINT8 pu1SubAddr[36] = {0, 0, 0, 0, 0, 0, 0, 0};

    ASSERT(u1WordAddrNum <= 3);

    if (u1WordAddrNum == 1)
    {
        pu1SubAddr[0] = (UINT8) ((u4WordAddr & 0x000000FF));
    }
    else if (u1WordAddrNum == 2)
    {
        pu1SubAddr[0] = (UINT8) ((u4WordAddr & 0x0000FF00) >> 8);
        pu1SubAddr[1] = (UINT8) ((u4WordAddr & 0x000000FF));
    }
    else
    {
        pu1SubAddr[0] = (UINT8) ((u4WordAddr & 0x00FF0000) >> 16);
        pu1SubAddr[1] = (UINT8) ((u4WordAddr & 0x0000FF00) >> 8);
        pu1SubAddr[2] = (UINT8) ((u4WordAddr & 0x000000FF));
    }

    return _SIF_DrvRawWrite(u2ClkDiv, u1DevAddr, (UINT8*)pu1SubAddr, u1WordAddrNum, pu1Buf, u2ByteCnt);
}

/** _SIF_X_RawRead
 *  Raw read data with channel ID, word address, of which length up to three, from SIF module.
 *  @param  u1ChannelID     SIF bus ID.
 *  @param  u2ClkDiv        Parameter of divider to divide 27Mhz for SCL.
 *  @param  u1DevAddr       Serial interface device address.
 *  @param  u1WordAddrNum   Serial interface word address length.
 *  @param  u4WordAddr      Serial interface word address. Format XX B2 B1 B0. B2 is sent on SIF bus first.
 *  @param  pu1Buf          Pointer to user's buffer.
 *  @param  u2ByteCnt       Number of byte to read. Max = 256 bytes.
 *  @retval > 0             Actual number of bytes read.
 *  @retval < 0             Error
 */
static INT32 _SIF_X_RawRead(UINT8 u1CHannelID, UINT16 u2ClkDiv, UINT8 u1DevAddr, UINT8 u1WordAddrNum,
                            UINT32 u4WordAddr, UINT8* pu1Buf, UINT16 u2ByteCnt)
{
    INT32 i4Ret = SIF_ERROR_PARAM;

    ASSERT(u1WordAddrNum < 4);
    ASSERT(pu1Buf);
    ASSERT(u2ByteCnt > 0);
	
    _rSifDevParm.u1BusNo= u1CHannelID;
    i4Ret = _SIF_RawReadMultipleSubAddr(u2ClkDiv, u1DevAddr, u1WordAddrNum, u4WordAddr,
                                        pu1Buf, u2ByteCnt);
    
    return i4Ret;
}


static INT32 _SIF_X_RawSpRead(UINT8 u1CHannelID, UINT16 u2ClkDiv, UINT8 u1DevAddr, UINT8 u1WordAddrNum,
                              UINT32 u4WordAddr, UINT8* pu1Buf, UINT16 u2ByteCnt)
{
    INT32 i4Ret = SIF_ERROR_PARAM;

    ASSERT(u1WordAddrNum < 4);
    ASSERT(pu1Buf);
    ASSERT(u2ByteCnt > 0);
	
	_rSifDevParm.u1BusNo= u1CHannelID;
    i4Ret = _SIF_RawSpReadMultipleSubAddr(u2ClkDiv, u1DevAddr, u1WordAddrNum, u4WordAddr,
                                          pu1Buf, u2ByteCnt);
    return i4Ret;
}

static INT32 _SIF_X_RawWrite(UINT8 u1CHannelID, UINT16 u2ClkDiv, UINT8 u1DevAddr, UINT8 u1WordAddrNum,
                             UINT32 u4WordAddr, UINT8* pu1Buf, UINT16 u2ByteCnt)
{
    INT32 i4Ret = SIF_ERROR_PARAM;

    ASSERT(u1WordAddrNum < 4);
    ASSERT(pu1Buf);
    ASSERT(u2ByteCnt > 0);

	_rSifDevParm.u1BusNo= u1CHannelID;
    i4Ret = _SIF_RawWriteMultipleSubAddr(u2ClkDiv, u1DevAddr, u1WordAddrNum, u4WordAddr,
                                         pu1Buf, u2ByteCnt);

    return i4Ret;
}


#if SIF_USE_OSAI
#ifdef CC_SIF_USE_INTERRUPT_MODE
static VOID _SIF_HandleISR(UINT16 u2Vector)
{
#ifdef CC_SIF_TRI_DELAY_SUPPORT
    _SIF_GetIsrTime();
#endif // CC_SIF_TRI_DELAY_SUPPORT
    if (u2Vector == VECTOR_I2C)
    {
		vIO32WriteFldAlign(SIF_I2CINTCL, 0x1, FLD_SECSM0_INT_CL);		

        // release semaphore
        VERIFY(_SIFSECM0_ISR_Unlock() == OSR_OK);
    }    
}
#endif // CC_SIF_USE_INTERRUPT_MODE
#endif // SIF_USE_OSAI


//---------------------------------------------------------------------------
// Inter-file functions
//---------------------------------------------------------------------------


//---------------------------------------------------------------------------
// Public functions
//---------------------------------------------------------------------------
SIF_STRUCT_T* SIF_SECM0_GetStruct(void)
{
    return &_rSifStruct;
}

//-------------------------------------------------------------------------
/** SIF_Init
 *  Initialize SIF module.
 *  @param  VOID
 *  @return  VOID
 */
//-------------------------------------------------------------------------
static VOID SIF_SECM0_Init(VOID)
{
    UINT32 u4Reg, u4Var;
#if defined(CC_MTK_LOADER)
#else
    UINT32 u4Ret;
#endif

    u4Reg = HalCriticalStart();

    if (_fgSifInit)
    {
        HalCriticalEnd(u4Reg);
        return;
    }

    if (!_fgSifInitStart)
    {
        _fgSifInitStart = TRUE;
    }
    else
    {
        _fgSifInitWait = TRUE;
    }
    HalCriticalEnd(u4Reg);

    if (!_fgSifInitWait)
    {
        _pfnSifCfgBeforeActionFunc = NULL;
        _pfnSifCfgAfterActionFunc = NULL;
#if defined(CC_MTK_LOADER)
        u4Var = DRVCUST_InitGet(eSifEnableSclStretch);
        _fgEnableSclStretch = u4Var;

        u4Var = DRVCUST_InitGet(eSifDisableOpenDrain);
        _fgDisableOpenDrain = u4Var;

        if (DRVCUST_InitQuery(eSifCfgBeforeAction, (UINT32*)(void*)&_pfnSifCfgBeforeActionFunc) != 0)
        {
            _pfnSifCfgBeforeActionFunc = NULL;
        }

        if (DRVCUST_InitQuery(eSifCfgAfterAction, (UINT32*)(void*)&_pfnSifCfgAfterActionFunc) != 0)
        {
            _pfnSifCfgAfterActionFunc = NULL;
        }
#else
        u4Ret = (UINT32) DRVCUST_OptQuery(eSifEnableSclStretch, &u4Var);
        if (u4Ret == 0)
        {
            _fgEnableSclStretch = u4Var;
        }

        u4Ret = (UINT32) DRVCUST_OptQuery(eSifDisableOpenDrain, &u4Var);
        if (u4Ret == 0)
        {
            _fgDisableOpenDrain = u4Var;
        }

        if (DRVCUST_OptQuery(eSifCfgBeforeAction, (UINT32*)(void*)&_pfnSifCfgBeforeActionFunc) != 0)
        {
            _pfnSifCfgBeforeActionFunc = NULL;
        }

        if (DRVCUST_OptQuery(eSifCfgAfterAction, (UINT32*)(void*)&_pfnSifCfgAfterActionFunc) != 0)
        {
            _pfnSifCfgAfterActionFunc = NULL;
        }
#endif // defined(CC_MTK_LOADER)

#ifdef CC_SIF_TRI_DELAY_SUPPORT
        if (DRVCUST_InitQuery(eSifCfgTRIDelay, (UINT32*)(void*)&u4Var) == 0)
        {
            _u4TRIDelay = u4Var; // Stored in micro seconds
        }

        if (DRVCUST_InitQuery(eSifCfgTRIDelayDevAddr, (UINT32*)(void*)&u4Var) == 0)
        {
            _u1TRIDelayDevAddr = (UINT8)u4Var;
        }
#endif
        if (DRVCUST_InitQuery(eSifCfgPinSetFunc, (UINT32*)(void*)&_pfnSifCfgPinSetFunc) != 0)
        {
            _pfnSifCfgPinSetFunc = NULL;
        }

        if (_fgEnableSclStretch && _fgDisableOpenDrain)
        {
            LOG(0, "SIF_Init: error, SCL stretch and non open-drain functions are both enabled!\n");
            LOG(0, "SIF_Init: disable SCL stretch!\n");
            ASSERT(0);
            _fgEnableSclStretch = FALSE;
        }

        LOG(0, "SIF_Init: SCL stretch enabled %d, open drain mode %d.\n",
            _fgEnableSclStretch, _fgDisableOpenDrain ? 0 : 1);

        _SIFSECM0_DisableAndClearInterrupt();

#if SIF_USE_OSAI
        // Create ISR semaphore
        _SIFSECM0_ISR_CreateSema();
        // create semaphore
        VERIFY(x_sema_create(&_hSifUserSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK) == OSR_OK);
#endif

        Printf("SIF Secure Master0: V2 design\n");

        // Enable SIF masters
		vIO32WriteFldAlign(SIF_SECSM0CTL0, 0x1, FLD_SECSM0_EN);		

#if SIF_USE_OSAI

        // Create thread semaphore
        VERIFY(x_sema_create(&_hSifAsyncSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK) == OSR_OK);

        // Create request message queue
        VERIFY(x_msg_q_create(&_hSifAsyncMsg, "SIFSECM0_MsgQ", sizeof(SIF_ASYNC_REQ_T), 64) == OSR_OK);

        // Create thread for async read/write.
        /*
                VERIFY(x_thread_create(&_hSifAsyncThread, "SIF_ASYNC", 1024, 20,
                    (x_os_thread_main_fct)_SIF_AsyncThread, 0, NULL) == OSR_OK);
        */

#endif // SIF_USE_OSAI

        // init local variable
        _fgSifInit = TRUE;

    }
    else
    {
        /* Wait until SIF_Init() finish */
        while (!_fgSifInit)
        {
            static UINT32 u4Count = 0;
            x_thread_delay(10);
            u4Count++;
            ASSERT(u4Count < 1000);
        }
    }
}


//-------------------------------------------------------------------------
/** SIF_Stop
 *  terminate SIF module.
 *  @param  VOID
 *  @return  VOID
 */
//-------------------------------------------------------------------------
#ifdef CC_CLI
static VOID SIF_SECM0_Stop(VOID)
{
    UINT32 u4Reg;
#if SIF_USE_OSAI
#ifdef CC_SIF_USE_INTERRUPT_MODE
    x_os_isr_fct pfnOldIsr;
#endif // CC_SIF_USE_INTERRUPT_MODE
#endif // SIF_USE_OSAI

    u4Reg = HalCriticalStart();

    ASSERT(_fgSifInit);

    if (_fgSifInit)
    {
        _SIFSECM0_DisableAndClearInterrupt();

        // Disable SIF masters
		vIO32WriteFldAlign(SIF_SECSM0CTL0, 0, FLD_SECSM0_EN);		

#if SIF_USE_OSAI
        // Delete semaphore
        VERIFY(x_sema_delete(_hSifUserSema) == OSR_OK);
#ifdef CC_SIF_USE_INTERRUPT_MODE
        // Unregister ISR
        VERIFY(x_reg_isr(VECTOR_I2C, NULL, &pfnOldIsr) == OSR_OK);
        // Delete semaphore
        _SIFSECM0_ISR_DeleteSema();
#endif // CC_SIF_USE_INTERRUPT_MODE
#endif // SIF_USE_OSAI

        _fgSifInit = FALSE;
    }

    HalCriticalEnd(u4Reg);
}
#endif


/** SIF_X_Read
 *  Read data with channel ID, word address, of which length up to three, from SIF module.
 *  @param  u1ChannelID     SIF bus ID.
 *  @param  u2ClkDiv        Parameter of divider to divide 27Mhz for SCL.
 *  @param  u1DevAddr       Serial interface device address.
 *  @param  u1WordAddrNum   Serial interface word address length.
 *  @param  u4WordAddr      Serial interface word address. Format XX B2 B1 B0. B2 is sent on SIF bus first.
 *  @param  pu1Buf          Pointer to user's buffer.
 *  @param  u2ByteCnt       Number of byte to read. Max = 256 bytes.
 *  @retval > 0             Actual number of bytes read.
 *  @retval = 0             Error
 */
static UINT16 SIF_SECM0_X_Read(UINT8 u1CHannelID, UINT16 u2ClkDiv, UINT8 u1DevAddr, UINT8 u1WordAddrNum, UINT32 u4WordAddr,
                            UINT8* pu1Buf, UINT16 u2ByteCnt)
{
    INT32 i4Ret;
    _SIF_UserLock();
    i4Ret = _SIF_X_RawRead(u1CHannelID, u2ClkDiv, u1DevAddr, u1WordAddrNum, u4WordAddr,
                           pu1Buf, u2ByteCnt);
    _SIF_UserUnlock();
    if (i4Ret > 0)
    {
        return (UINT16) i4Ret;
    }
    else
    {
        return 0;
    }
}

static UINT16 SIF_SECM0_X_Sp_Read(UINT8 u1CHannelID, UINT16 u2ClkDiv, UINT8 u1DevAddr, UINT8 u1WordAddrNum, UINT32 u4WordAddr,
                               UINT8* pu1Buf, UINT16 u2ByteCnt)
{
    INT32 i4Ret;
    _SIF_UserLock();
    i4Ret = _SIF_X_RawSpRead(u1CHannelID, u2ClkDiv, u1DevAddr, u1WordAddrNum, u4WordAddr,
                             pu1Buf, u2ByteCnt);
    _SIF_UserUnlock();
    if (i4Ret > 0)
    {
        return (UINT16) i4Ret;
    }
    else
    {
        return 0;
    }
}


/** SIF_X_Write
 *  Write data with channel ID, word address, of which length up to three, to SIF module.
 *  @param  u1ChannelID     SIF bus ID.
 *  @param  u2ClkDiv        Parameter of divider to divide 27Mhz for SCL.
 *  @param  u1DevAddr       Serial interface device address.
 *  @param  u1WordAddrNum   Serial interface word address length.
 *  @param  u4WordAddr      Serial interface word address. Format XX B2 B1 B0. B2 is sent on SIF bus first.
 *  @param  pu1Buf          Pointer to user's buffer.
 *  @param  u2ByteCnt       Number of byte to write. Max = 256 bytes.
 *  @retval > 0             Actual number of bytes written.
 *  @retval = 0             Error
 */
static UINT16 SIF_SECM0_X_Write(UINT8 u1CHannelID, UINT16 u2ClkDiv, UINT8 u1DevAddr, UINT8 u1WordAddrNum, UINT32 u4WordAddr,
                             UINT8* pu1Buf, UINT16 u2ByteCnt)
{
    INT32 i4Ret;

    _SIF_UserLock();
    i4Ret = _SIF_X_RawWrite(u1CHannelID, u2ClkDiv, u1DevAddr, u1WordAddrNum, u4WordAddr,
                            pu1Buf, u2ByteCnt);
    _SIF_UserUnlock();

    if (i4Ret > 0)
    {
        return (UINT16) i4Ret;
    }
    else
    {
        return 0;
    }
}

static VOID SIF_SECM0_ISRHandler(UINT16 u2Vector)
{
#if SIF_USE_OSAI
#ifdef CC_SIF_USE_INTERRUPT_MODE
    _SIF_HandleISR(u2Vector);
#endif
#endif
}

#ifdef __MODEL_slt
INT32 SIF_SECM0_Diag(VOID)
{
    UINT32 u4Reg;

    u4Reg = u4IO32Read4B(SIF_SECSM0CTL0);

    Printf("Secure Master 0 %s\n", IO32ReadFldAlign(SIF_SECSM0CTL0, FLD_SECSM0_EN) ? "Enable" : "Disable");

    Printf("Bus clock pull high by: %s \n",
           IO32ReadFldAlign(SIF_SECSM0CTL0, FLD_SECSM0_ODRAIN) ? "Master" : "Open Drain (pull-high register");

    Printf("SCL-Stretch %s\n", IO32ReadFldAlign(SIF_SECSM0CTL0, FLD_SECSM0_SCL_STRECH) ? "On" : "Off");

    Printf("SCL= %s, SDA= %s\n", IO32ReadFldAlign(SIF_SECSM0CTL0, FLD_SECSM0_SCL_STATE) ? "High" : "Low",
           IO32ReadFldAlign(SIF_SECSM0CTL0, FLD_SECSM0_SDA_STATE) ? "High" : "Low");

    return 0;
}
#endif

