/* 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: weibo.li $
 * $Date: 2015/11/12 $
 * $RCSfile: sif_if.c,v $
 * $Revision: #3 $
 *
 *---------------------------------------------------------------------------*/

/** @file sif_if.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_hal_5381.h"

#include "x_pdwnc.h"

//---------------------------------------------------------------------------
// Configurations
//---------------------------------------------------------------------------
/// 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)
#ifdef CC_S_PLATFORM //for sony board
#ifdef CC_LM_CUST //for sony use Lemur project
#define PANEL_SIF_BUS         0 //panel power off need disable panel i2c
#endif
#endif

//---------------------------------------------------------------------------
// Constant definitions
//---------------------------------------------------------------------------
#define  SIF_OK    (0)


//---------------------------------------------------------------------------
// Type definitions
//---------------------------------------------------------------------------


//---------------------------------------------------------------------------
// Macro definitions
//---------------------------------------------------------------------------


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


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


//---------------------------------------------------------------------------
// Imported functions
//---------------------------------------------------------------------------
//#if defined(CC_MT5883)    //CC_MT5883_SIF_Verifivation
EXTERN SIF_STRUCT_T* SIF_M0_GetStruct(void);
EXTERN SIF_STRUCT_T* SIF_M1_GetStruct(void);
#if defined(CC_MT5891)				
EXTERN SIF_STRUCT_T* SIF_M2_GetStruct(void);
#endif
EXTERN SIF_STRUCT_T* SIF_PDM0_GetStruct(void);
EXTERN SIF_STRUCT_T* SIF_PDM1_GetStruct(void);
#if defined(CC_SIF_IC_VERIFICATION)				
EXTERN SIF_STRUCT_T* SIF_SECM0_GetStruct(void);
#endif
//#endif

//---------------------------------------------------------------------------
// Static function forward declarations
//---------------------------------------------------------------------------


//---------------------------------------------------------------------------
// Static variables
//---------------------------------------------------------------------------
static SIF_STRUCT_T* _aprSifStruct[SIF_MAX_NUM_BUS] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL};
static SIF_STRUCT_T* _prCurrentActiveSifStruct[SIF_MAX_NUM_MASTER] = {NULL, NULL, NULL, NULL, NULL, NULL};
static BOOL _fgInit = FALSE;
static BOOL _fgInitStart       = FALSE;
static BOOL _fgInitWait        = FALSE;

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

static SIF_CONFIG_T* _prSifConfig = NULL;
static PFN_SIF_CFG_GET_CONFIG_FUNC _pfnSifCfgGetConfigFunc = NULL;

// This flag will be set upon standby request to avoid SIF opeartion being interrupted
static BOOL _fgSIFDisabled = FALSE;

#ifdef CC_S_PLATFORM //for sony board
#ifdef CC_LM_CUST //for sony use Lemur project
BOOL _fgPanelI2CDisabled = TRUE;
#endif
#endif

//---------------------------------------------------------------------------
// Static functions
//---------------------------------------------------------------------------
#ifdef CC_SUPPORT_STR
// Lock SIF semaphore
static VOID _SIF_Lock(VOID)
{
    SIF_Init();
#if SIF_USE_OSAI
    // wait semaphore
    VERIFY(x_sema_lock(_hSifLockSema, X_SEMA_OPTION_WAIT) == OSR_OK);
#endif // SIF_USE_OSAI
}
#endif

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

// Lock SIF semaphore
static VOID _SIF_LockTimeout(UINT32 u4Timeout)
{
    SIF_Init();
#if SIF_USE_OSAI
    // wait semaphore
    VERIFY(x_sema_lock_timeout(_hSifLockSema, u4Timeout) == OSR_OK);
#endif // SIF_USE_OSAI
}


//---------------------------------------------------------------------------
// Inter-file functions
//---------------------------------------------------------------------------
SIF_STRUCT_T* _SIF_GetActiveMaster(UINT8 u1MasterID)
{
    return _prCurrentActiveSifStruct[u1MasterID];
}

void _SIF_SetActiveMaster(UINT8 u1MasterID,SIF_STRUCT_T* prStruct)
{
    _prCurrentActiveSifStruct[u1MasterID] = prStruct;
}


#if defined(CC_FAST_INIT)
extern VOID _SIFM0_DisableAndClearInterrupt(VOID);
extern VOID _SIFM1_DisableAndClearInterrupt(VOID);
#if defined(CC_MT5891)				
extern VOID _SIFM2_DisableAndClearInterrupt(VOID);
#endif
extern VOID _SIFPDM0_DisableAndClearInterrupt(VOID);
extern VOID _SIFPDM1_DisableAndClearInterrupt(VOID);
//LH for suspend/resume
void SIF_pm_suspend(void)
{
}
void SIF_pm_resume(void)
{
    Printf("SIF_Master: init\n");
	_SIFM0_DisableAndClearInterrupt();
	_SIFM1_DisableAndClearInterrupt();
#if defined(CC_MT5891)				
	_SIFM2_DisableAndClearInterrupt();
#endif
	VERIFY(BIM_DisableIrq(VECTOR_SERIAL));
	VERIFY(BIM_ClearIrq(VECTOR_SERIAL));
	VERIFY(BIM_EnableIrq(VECTOR_SERIAL));
	if (_SIF_ISR_IsPdwncMasterEnable())
	{
		_SIFPDM0_DisableAndClearInterrupt();
	}

	if (_SIF_ISR_IsPdwncMaster1Enable())
	{
		_SIFPDM1_DisableAndClearInterrupt();
	}

    // Enable SIF masters
    vIO32WriteFldAlign(SIF_SM0CTL0, 0x1, FLD_SM0_EN);        
    vIO32WriteFldAlign(SIF_SM1CTL0, 0x1, FLD_SM1_EN);   
#if defined(CC_MT5891)				
    vIO32WriteFldAlign(SIF_SM2CTL0, 0x1, FLD_SM2_EN);        
#endif
    if (_SIF_ISR_IsPdwncMasterEnable())
    {
		vIO32WriteFldAlign(PDWNC_SM0CTL0, 0x1, FLD_SIFM0_EN);		 
		vIO32WriteFldAlign(PDWNC_ARM_INTEN, 0x1, FLD_SIFM0_INTEN);		 
    }

    if (_SIF_ISR_IsPdwncMaster1Enable())
    {
		vIO32WriteFldAlign(PDWNC_SM1CTL0, 0x1, FLD_SIFM1_EN);		 
		vIO32WriteFldAlign(PDWNC_ARM_INTEN, 0x1, FLD_SIFM1_INTEN);		 
    }

}
#endif

#ifdef SIF_CHECK_SDA_LOW
/*
* 5890(Oryx)    (SIF0, SIF1, SIF2)
*/
void SIF_CheckEachBusSDA(void)
{
    SIF_BUS_STATUS_T Bus_Status;
    UINT32 u4CheckTime;
    UINT32 u4BusIndex;
    UINT32 u4Error;	
	PFN_SIF_CFG_PIN_SET_FUNC SIF_PinSetFunc = NULL;
	
	if (DRVCUST_InitQuery(eSifCfgPinSetFunc, (UINT32*)(void*)&SIF_PinSetFunc) != 0)
	{
		SIF_PinSetFunc = NULL;
	}

    for (u4BusIndex = 0; u4BusIndex < 3; u4BusIndex++)
    {
		if (SIF_PinSetFunc)
		{
			SIF_PinSetFunc(u4BusIndex);//
		}
        Bus_Status = SIF_CheckBusStatus();
        for (u4CheckTime = 0; u4CheckTime < 5; u4CheckTime++)
        {
            if (Bus_Status.SIF_BUS_SDA == 0) //SDA is low
            {
                x_thread_delay(1);// 100KHz means 0.01ms 1T. 20*0.01 = 0.2
                // send a STOP
                SIF_SendStopBit();

                //check the bus again
                Bus_Status = SIF_CheckBusStatus();
                if (Bus_Status.SIF_BUS_SDA == 0) //SDA is still low
                {
                    Printf("[SIF]:SDA is low\n");
                }
                else
                {
                    Printf("[SIF]:SDA is high\n");
                    break;
                }
            }
        }
    }

    Bus_Status = SIF_CheckBusStatus();
    if (Bus_Status.SIF_BUS_SDA == 0) //SDA is low at last
    {
        // Error conditions
    }
}
#endif

//---------------------------------------------------------------------------
// Public functions
//---------------------------------------------------------------------------
//-------------------------------------------------------------------------
/** SIF_Init
 *  Initialize SIF module.
 *  @param  VOID
 *  @return  VOID
 */
//-------------------------------------------------------------------------
VOID SIF_Init(VOID)
{
    //    UINT16 u2Ret = 0;
    UINT32 i;
    UINT32 u4Reg;

    u4Reg = HalCriticalStart();

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

    if (!_fgInitStart)
    {
        _fgInitStart = TRUE;
    }
    else
    {
        _fgInitWait = TRUE;
    }
    HalCriticalEnd(u4Reg);
    /*cobra eco IC master0 new mode will use 0xf0029284 bit31:24 & 22:16 ,so this register must be 0 at first*/
    //if(BSP_GetIcVersion() == IC_VER_5398_AB)
    //{
    //    IO_WRITE32MSK(BIM_BASE, RW_SM0_DEV_REG, 0x0, 0xffffffff);
    //}
    //vIO32WriteFldAlign(SIF_SM0SDEV, 0, FLD_SM0_EN);        
    vIO32Write4B(SIF_SM0SDEV, 0);
    vIO32Write4B(SIF_SM1SDEV, 0);
#if defined(CC_MT5891)				
    vIO32Write4B(SIF_SM2SDEV, 0);
#endif

    if (!_fgInitWait)
    {
#if SIF_USE_OSAI
        // create semaphore
        VERIFY(x_sema_create(&_hSifLockSema, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK) == OSR_OK);
#endif // SIF_USE_OSAI

        // TODO: Query Bus Configuration and save to u4Numbus & au4BusVer
        if ((DRVCUST_InitQuery(eSifCfgGetConfigFunc, (UINT32*)(void*)&_pfnSifCfgGetConfigFunc) == 0) &&
            (_pfnSifCfgGetConfigFunc != NULL) )
        {
            _prSifConfig = _pfnSifCfgGetConfigFunc();
        }

        _SIF_ISR_Init();

        for (i = 0; i < (_prSifConfig->u1NumBus > SIF_MAX_NUM_BUS ? SIF_MAX_NUM_BUS : _prSifConfig->u1NumBus); i++)
        {
			if (_prSifConfig->au1Master[i] == 0)
			{
				_aprSifStruct[i] = SIF_M0_GetStruct();
				_aprSifStruct[i]->rSifOps.pfn_Init();
			}
			else if (_prSifConfig->au1Master[i] == 1)
			{
				_aprSifStruct[i] = SIF_M1_GetStruct();
				_aprSifStruct[i]->rSifOps.pfn_Init();
			}
			else if (_prSifConfig->au1Master[i] == 2)
			{
#if defined(CC_MT5891)				
				_aprSifStruct[i] = SIF_M2_GetStruct();
				_aprSifStruct[i]->rSifOps.pfn_Init();
#else
				Printf("Master2 not Used!\n");
#endif
			}
			else if (_prSifConfig->au1Master[i] == 3)
			{
				_aprSifStruct[i] = SIF_PDM0_GetStruct();
				_aprSifStruct[i]->rSifOps.pfn_Init();
			}
			else if (_prSifConfig->au1Master[i] == 4)
			{
				_aprSifStruct[i] = SIF_PDM1_GetStruct();
				_aprSifStruct[i]->rSifOps.pfn_Init();
			}
			else if (_prSifConfig->au1Master[i] == 5)
			{
#if defined(CC_SIF_IC_VERIFICATION)				
				_aprSifStruct[i] = SIF_SECM0_GetStruct();
				_aprSifStruct[i]->rSifOps.pfn_Init();
#else
				Printf("Master5 only Used in secure mode!\n");
#endif
			}
			else
			{
				Printf("Un-recognized NumBus=%d, Master num: 0x%x\n", i, _prSifConfig->au1Master[i]);
				//VERIFY(0);
			}			
        }
        _fgInit = TRUE;

    }
    else
    {
        /* Wait until SIF_Init() finish */
        while (!_fgInit)
        {
            static UINT32 u4Count = 0;
            x_thread_delay(10);
            u4Count++;
            ASSERT(u4Count < 1000);
        }
    }
#ifdef CC_SIF_OUTPUT_LOW_WAITING
    //change the output level L when SIF master in waiting state
    {
        UINT32 u4Tmp;
        u4Tmp = *((volatile unsigned int*)0xF0029240);
        u4Tmp &= ~(1 << 6); //clear bit6
        *((volatile unsigned int*)0xF0029240) = u4Tmp;
    }
#endif

#ifdef SIF_CHECK_SDA_LOW
    SIF_CheckEachBusSDA();
#endif

}


//-------------------------------------------------------------------------
/** SIF_Stop
 *  terminate SIF module.
 *  @param  VOID
 *  @return  VOID
 */
//-------------------------------------------------------------------------
#ifdef CC_CLI
VOID SIF_Stop(VOID)
{
    UINT32 i;

    // TODO: Query Bus Configuration and save to u4Numbus & au4BusVer
    if ((DRVCUST_InitQuery(eSifCfgGetConfigFunc, (UINT32*)(void*)&_pfnSifCfgGetConfigFunc) == 0) &&
        (_pfnSifCfgGetConfigFunc != NULL) )
    {
        _prSifConfig = _pfnSifCfgGetConfigFunc();
    }

    for (i = 0; i < (_prSifConfig->u1NumBus > SIF_MAX_NUM_BUS ? SIF_MAX_NUM_BUS : _prSifConfig->u1NumBus); i++)
    {
        _aprSifStruct[i]->rSifOps.pfn_Stop();
    }
}
#endif

UINT16 SIF_Read(UINT16 u2ClkDiv, UINT8 u1DevAddr, UINT8 u1WordAddr,
                UINT8* pu1Buf, UINT16 u2ByteCnt)
{
    UINT16 u2Ret = 0;

    u2Ret = SIF_X_Read(SIF_BUS_SYSTEM_I2C, u2ClkDiv, u1DevAddr, 1, u1WordAddr,
                       pu1Buf, u2ByteCnt);
    return u2Ret;
}


/** SIF_ReadNoSubAddr
 *  Read data without word address from SIF module from SIF_BUS_SYSTEM_I2C.
 *  @param  u2ClkDiv    Parameter of divider to divide 27Mhz for SCL.
 *  @param  u1DevAddr   Serial interface device address.
 *  @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
 */
UINT16 SIF_ReadNoSubAddr(UINT16 u2ClkDiv, UINT8 u1DevAddr, UINT8* pu1Buf,
                         UINT16 u2ByteCnt)
{
    UINT16 u2Ret = 0;
    u2Ret = SIF_X_Read(SIF_BUS_SYSTEM_I2C, u2ClkDiv, u1DevAddr, 0, 0,
                       pu1Buf, u2ByteCnt);
    return u2Ret;
}


/** SIF_TunerReadNoSubAddr
 *  NIM module api: read data without word address from SIF module from SIF_BUS_TUNER_I2C.
 *  @param  u2ClkDiv    Parameter of divider to divide 27Mhz for SCL.
 *  @param  u1DevAddr   Serial interface device address.
 *  @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
 */
UINT16 SIF_TunerReadNoSubAddr(UINT16 u2ClkDiv, UINT8 u1DevAddr, UINT8* pu1Buf,
                              UINT16 u2ByteCnt)
{
    UINT16 u2Ret = 0;
    u2Ret = SIF_X_Read(SIF_BUS_TUNER_I2C, u2ClkDiv, u1DevAddr, 0, 0,
                       pu1Buf, u2ByteCnt);
    return u2Ret;
}


/** SIF_Write
 *  Write data with word address to SIF module on SIF_BUS_SYSTEM_I2C.
 *  @param  u2ClkDiv    Parameter of divider to divide 27Mhz for SCL.
 *  @param  u1DevAddr   Serial interface device address.
 *  @param  u1WordAddr  Serial interface word address.
 *  @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
 */
UINT16 SIF_Write(UINT16 u2ClkDiv, UINT8 u1DevAddr, UINT8 u1WordAddr,
                 UINT8* pu1Buf, UINT16 u2ByteCnt)
{
    UINT16 u2Ret = 0;
    u2Ret = SIF_X_Write(SIF_BUS_SYSTEM_I2C, u2ClkDiv, u1DevAddr, 1, u1WordAddr,
                        pu1Buf, u2ByteCnt);
    return u2Ret;
}


/** SIF_WriteNoSubAddr
 *  Write data without word address to SIF module on SIF_BUS_SYSTEM_I2C.
 *  @param  u2ClkDiv    Parameter of divider to divide 27Mhz for SCL.
 *  @param  u1DevAddr   Serial interface device address.
 *  @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
 */
UINT16 SIF_WriteNoSubAddr(UINT16 u2ClkDiv, UINT8 u1DevAddr, UINT8* pu1Buf,
                          UINT16 u2ByteCnt)
{
    UINT16 u2Ret = 0;
    u2Ret = SIF_X_Write(SIF_BUS_SYSTEM_I2C, u2ClkDiv, u1DevAddr, 0, 0,
                        pu1Buf, u2ByteCnt);
    return u2Ret;
}


/** SIF_TunerWriteNoSubAddr
 *  NIM module api: write data without word address to SIF module on SIF_BUS_TUNER_I2C.
 *  @param  u2ClkDiv    Parameter of divider to divide 27Mhz for SCL.
 *  @param  u1DevAddr   Serial interface device address.
 *  @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
 */
UINT16 SIF_TunerWriteNoSubAddr(UINT16 u2ClkDiv, UINT8 u1DevAddr, UINT8* pu1Buf,
                               UINT16 u2ByteCnt)
{
    UINT16 u2Ret = 0;
    u2Ret = SIF_X_Write(SIF_BUS_TUNER_I2C, u2ClkDiv, u1DevAddr, 0, 0,
                        pu1Buf, u2ByteCnt);
    return u2Ret;
}


/** SIF_ReadMultipleSubAddress
 *  Read data with word address, of which length up to three, from SIF module from SIF_BUS_SYSTEM_I2C.
 *  @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
 */
UINT16 SIF_ReadMultipleSubAddr(UINT16 u2ClkDiv, UINT8 u1DevAddr, UINT8 u1WordAddrNum, UINT32 u4WordAddr,
                               UINT8* pu1Buf, UINT16 u2ByteCnt)
{
    UINT16 u2Ret = 0;
    u2Ret = SIF_X_Read(SIF_BUS_SYSTEM_I2C, u2ClkDiv, u1DevAddr, u1WordAddrNum, u4WordAddr,
                       pu1Buf, u2ByteCnt);
    return u2Ret;
}


/** SIF_WriteMultipleSubAddress
 *  Write data with word address, of which length up to three, to SIF module on SIF_BUS_SYSTEM_I2C.
 *  @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 written.
 *  @retval = 0             Error
 */
UINT16 SIF_WriteMultipleSubAddr(UINT16 u2ClkDiv, UINT8 u1DevAddr, UINT8 u1WordAddrNum, UINT32 u4WordAddr,
                                UINT8* pu1Buf, UINT16 u2ByteCnt)
{
    UINT16 u2Ret = 0;
    u2Ret = SIF_X_Write(SIF_BUS_SYSTEM_I2C, u2ClkDiv, u1DevAddr, u1WordAddrNum, u4WordAddr,
                        pu1Buf, u2ByteCnt);
    return u2Ret;
}


/** 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
 */
UINT16 SIF_X_Read(UINT8 u1CHannelID, UINT16 u2ClkDiv, UINT8 u1DevAddr, UINT8 u1WordAddrNum, UINT32 u4WordAddr,
                  UINT8* pu1Buf, UINT16 u2ByteCnt)
{
    UINT16 u2Ret = 0;
#ifdef CC_FIXED_SIF_CLK_DIV
    UINT32 u4FixClkDiv;
    u4FixClkDiv = DRVCUST_InitGet(eSifcfgFixClkDiv);
    u2ClkDiv = u4FixClkDiv;
#endif
#if defined(CC_S_PLATFORM) && defined(CC_LM_CUST)
	if((_fgPanelI2CDisabled == TRUE) && (u1CHannelID == PANEL_SIF_BUS))
	{
        goto X_READ_ERROR;
    }
#endif
    if ((u1CHannelID>=SIF_MAX_NUM_BUS) || (_aprSifStruct[u1CHannelID]==NULL))
    {
        goto X_READ_ERROR;
    }
    if (_aprSifStruct[u1CHannelID]->rSifOps.pfn_X_Read == NULL)
    {
        goto X_READ_ERROR;
    }
    //_SIF_Lock();

    if (_fgSIFDisabled)
    {
        //_SIF_Unlock();
        return u2ByteCnt;
    }
	LOG(1, "[SIF_Read]Channle(%d)Device_Addr(0x%x) want read(%d) bytes. \n", u1CHannelID, u1DevAddr, u2ByteCnt);
	
    _SIF_SetActiveMaster(_aprSifStruct[u1CHannelID]->u1SifMaster, _aprSifStruct[u1CHannelID]);
    u2Ret = _aprSifStruct[u1CHannelID]->rSifOps.pfn_X_Read(u1CHannelID, u2ClkDiv, u1DevAddr, u1WordAddrNum, u4WordAddr, pu1Buf, u2ByteCnt);
    //_SIF_Unlock();

    if (u2Ret != u2ByteCnt)
    {
        LOG(1, "[SIF][Read_Error]Channle(%d)Device_Addr(0x%x) want read(%d) bytes. Actually read(%d) bytes\n", u1CHannelID, u1DevAddr, u2ByteCnt, u2Ret);
    }

X_READ_ERROR:
    return u2Ret;
}

/** SIF_X_SpecialRead
 *  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
 *   start + slave address + w +tnflg + target address + w +  register address
 *
 restart + slave address + w +tnflg + target address + r
 *    restart + slave address + r +data ... +stop
 */
UINT16 SIF_X_SpecialRead(UINT8 u1CHannelID, UINT16 u2ClkDiv, UINT8 u1DevAddr, UINT8 u1WordAddrNum, UINT32 u4WordAddr,
                         UINT8* pu1Buf, UINT16 u2ByteCnt)
{
    UINT16 u2Ret = 0;


#ifdef CC_FIXED_SIF_CLK_DIV
    UINT32 u4FixClkDiv;
    u4FixClkDiv = DRVCUST_InitGet(eSifcfgFixClkDiv);
    u2ClkDiv = u4FixClkDiv;
#endif
#if defined(CC_S_PLATFORM) && defined(CC_LM_CUST)
	if((_fgPanelI2CDisabled == TRUE) && (u1CHannelID == PANEL_SIF_BUS))
	{
        goto X_READ_ERROR;
    }
#endif
    if ((u1CHannelID>=SIF_MAX_NUM_BUS) || (_aprSifStruct[u1CHannelID]==NULL))
    {
        goto X_READ_ERROR;
    }
    if (_aprSifStruct[u1CHannelID]->rSifOps.pfn_X_Sp_Read == NULL)
    {
        goto X_READ_ERROR;
    }
    //_SIF_Lock();

    if (_fgSIFDisabled)
    {
        //_SIF_Unlock();
        Printf("SIF_X_Read _fgSIFDisabled:\n");
        return u2ByteCnt;
    }

    _SIF_SetActiveMaster(_aprSifStruct[u1CHannelID]->u1SifMaster, _aprSifStruct[u1CHannelID]);
    u2Ret = _aprSifStruct[u1CHannelID]->rSifOps.pfn_X_Sp_Read(u1CHannelID, u2ClkDiv, u1DevAddr, u1WordAddrNum, u4WordAddr, pu1Buf, u2ByteCnt);
    //_SIF_Unlock();
X_READ_ERROR:
    return u2Ret;
}

/** 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
 */
UINT16 SIF_X_Write(UINT8 u1CHannelID, UINT16 u2ClkDiv, UINT8 u1DevAddr, UINT8 u1WordAddrNum, UINT32 u4WordAddr,
                   UINT8* pu1Buf, UINT16 u2ByteCnt)
{
    UINT16 u2Ret = 0;
#ifdef CC_FIXED_SIF_CLK_DIV
    UINT32 u4FixClkDiv;
    u4FixClkDiv = DRVCUST_InitGet(eSifcfgFixClkDiv);
    u2ClkDiv = u4FixClkDiv;
#endif
#if defined(CC_S_PLATFORM) && defined(CC_LM_CUST)
	if((_fgPanelI2CDisabled == TRUE) && (u1CHannelID == PANEL_SIF_BUS))
	{
        goto X_WRITE_ERROR;
    }
#endif
    if ((u1CHannelID>=SIF_MAX_NUM_BUS) || (_aprSifStruct[u1CHannelID]==NULL))
    {
        goto X_WRITE_ERROR;
    }
    if (_aprSifStruct[u1CHannelID]->rSifOps.pfn_X_Write == NULL)
    {
        goto X_WRITE_ERROR;
    }
    //_SIF_Lock();

    if (_fgSIFDisabled)
    {
        //_SIF_Unlock();
        return u2ByteCnt;
    }

    _SIF_SetActiveMaster(_aprSifStruct[u1CHannelID]->u1SifMaster, _aprSifStruct[u1CHannelID]);
    u2Ret = _aprSifStruct[u1CHannelID]->rSifOps.pfn_X_Write(u1CHannelID, u2ClkDiv, u1DevAddr, u1WordAddrNum, u4WordAddr, pu1Buf, u2ByteCnt);
    //_SIF_Unlock();

    if (u2Ret != u2ByteCnt)
    {
        LOG(1, "[SIF][Write_Error]Channle(%d)Device_Addr(0x%x) want write(%d) bytes. Actually write(%d) bytes\n", u1CHannelID, u1DevAddr, u2ByteCnt, u2Ret);
    }

X_WRITE_ERROR:
    return u2Ret;
}


UINT16 SIF_X_Write_SpecialDemod(UINT8 u1CHannelID, UINT16 u2ClkDiv, UINT8 u1DevAddr, UINT8 u1WordAddrNum, UINT32 u4WordAddr, UINT8* pu1Buf, UINT16 u2ByteCnt)
{
    UINT16 u2Ret = 0;
    UINT8 au1Data[4];
#if defined(CC_S_PLATFORM) && defined(CC_LM_CUST)
	if((_fgPanelI2CDisabled == TRUE) && (u1CHannelID == PANEL_SIF_BUS))
	{
        goto X_WRITE_SD_ERROR;
    }
#endif
    if ((u1CHannelID>=SIF_MAX_NUM_BUS) || (_aprSifStruct[u1CHannelID]==NULL))
    {
        goto X_WRITE_SD_ERROR;
    }
    if (_aprSifStruct[u1CHannelID]->rSifOps.pfn_X_Write == NULL)
    {
        goto X_WRITE_SD_ERROR;
    }
    //_SIF_Lock();

    if (_fgSIFDisabled)
    {
        //_SIF_Unlock();
        return u2ByteCnt;
    }

    _SIF_SetActiveMaster(_aprSifStruct[u1CHannelID]->u1SifMaster, _aprSifStruct[u1CHannelID]);
    if (u1WordAddrNum == 1)
    {
        au1Data[0] = (UINT8)(u4WordAddr & 0xFF);
    }
    if (u1WordAddrNum == 2)
    {
        au1Data[0] = (UINT8)((u4WordAddr >> 8) & 0xFF);
        au1Data[1] = (UINT8)(u4WordAddr & 0xFF);
    }
    else if (u1WordAddrNum == 3)
    {
        au1Data[0] = (UINT8)((u4WordAddr >> 16) & 0xFF);
        au1Data[1] = (UINT8)((u4WordAddr >> 8) & 0xFF);
        au1Data[2] = (UINT8)(u4WordAddr & 0xFF);
    }
    else
    {
        //_SIF_Unlock();
        goto X_WRITE_SD_ERROR;
    }
    u2Ret = _aprSifStruct[u1CHannelID]->rSifOps.pfn_X_Write(u1CHannelID, u2ClkDiv, u1DevAddr, 0, 0, au1Data, (UINT16)u1WordAddrNum);
    if (u2Ret != (UINT16)u1WordAddrNum)
    {
        //_SIF_Unlock();
        goto X_WRITE_SD_ERROR;
    }
    u2Ret = _aprSifStruct[u1CHannelID]->rSifOps.pfn_X_Write(u1CHannelID, u2ClkDiv, u1DevAddr, 0, 0, pu1Buf, u2ByteCnt);
    //_SIF_Unlock();
X_WRITE_SD_ERROR:
    return u2Ret;
}


#if 0
#if SIF_USE_OSAI
//-------------------------------------------------------------------------
/** _SIF_AsyncThread
 *  Dedicated thread for async read/write requests.
 *  @param  VOID
 *  @return   VOID
 */
//-------------------------------------------------------------------------
static VOID _SIF_AsyncThread(VOID)
{

    UINT16 u2MsgQIdx, u2Result = 0;
    SIZE_T zMsgSize;
    SIF_ASYNC_REQ_T rReq;

    while (1)
    {
        zMsgSize = sizeof(SIF_ASYNC_REQ_T);

        // receive request message.
        VERIFY(x_msg_q_receive(&u2MsgQIdx, &rReq, &zMsgSize, &_hSifAsyncMsg, 1, X_MSGQ_OPTION_WAIT) == OSR_OK);
        ASSERT(zMsgSize == sizeof(SIF_ASYNC_REQ_T));

        VERIFY(x_sema_lock(_hSifAsyncSema, X_SEMA_OPTION_WAIT) == OSR_OK);

        if (rReq.u1RequestType == SIF_ASYNC_REQ_READ)
        {
            LOG(7, "AsyncThread call SIF_X_Read: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", rReq.u1CHannelID, rReq.u2ClkDiv,
                rReq.u1DevAddr, rReq.u1WordAddrNum, rReq.u4WordAddr, rReq.u2ByteCnt);

            u2Result = SIF_X_Read(rReq.u1CHannelID, rReq.u2ClkDiv, rReq.u1DevAddr, rReq.u1WordAddrNum,
                                  rReq.u4WordAddr, rReq.pu1Buf, rReq.u2ByteCnt);
        }
        else if (rReq.u1RequestType == SIF_ASYNC_REQ_WRITE)
        {
            LOG(7, "AsyncThread call SIF_X_Write: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", rReq.u1CHannelID, rReq.u2ClkDiv,
                rReq.u1DevAddr, rReq.u1WordAddrNum, rReq.u4WordAddr, rReq.u2ByteCnt);

            u2Result = SIF_X_Write(rReq.u1CHannelID, rReq.u2ClkDiv, rReq.u1DevAddr, rReq.u1WordAddrNum,
                                   rReq.u4WordAddr, rReq.pu1Buf, rReq.u2ByteCnt);
        }

        VERIFY(x_sema_unlock(_hSifAsyncSema) == OSR_OK);

        if (rReq.pfnNfy)
        {
            // call user defined callback function
            rReq.pfnNfy(rReq.pvNfyData, u2Result);
        }
    }

}

/** SIF_AsyncRead
 *  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.
 *  @param  pfnNfy       Callback function pointer.
 *  @param  pvNfyData       Callback function parameter
 *  @retval > 0             Success
 *  @retval = 0             Error
 */
UINT16 SIF_X_AsyncRead(UINT8 u1CHannelID, UINT16 u2ClkDiv, UINT8 u1DevAddr, UINT8 u1WordAddrNum, UINT32 u4WordAddr,
                       UINT8* pu1Buf, UINT16 u2ByteCnt, SIF_ASYNC_NFY_FCT pfnNfy, VOID* pvNfyData)
{
    SIF_ASYNC_REQ_T rReq;

    if ( (u1WordAddrNum >= 4) || (!pu1Buf) || (u2ByteCnt <= 0) || (u1CHannelID > 2) )
    {
        Printf("Incorrect parameter!\n");
        return 0;
    }

    rReq.u1RequestType = SIF_ASYNC_REQ_READ;
    rReq.u1CHannelID = u1CHannelID;
    rReq.u2ClkDiv = u2ClkDiv;
    rReq.u1DevAddr = u1DevAddr;
    rReq.u1WordAddrNum = u1WordAddrNum;
    rReq.u4WordAddr = u4WordAddr;
    rReq.pu1Buf = pu1Buf;
    rReq.u2ByteCnt = u2ByteCnt;
    rReq.pfnNfy = pfnNfy;
    rReq.pvNfyData = pvNfyData;

    LOG(7, "Send request to AsyncThread for read: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", rReq.u1CHannelID, rReq.u2ClkDiv,
        rReq.u1DevAddr, rReq.u1WordAddrNum, rReq.u4WordAddr, rReq.u2ByteCnt);

    // Send request to aync thread
    if (x_msg_q_send(_hSifAsyncMsg, &rReq, sizeof(SIF_ASYNC_REQ_T), 1) != OSR_OK)
    {
        Printf("SIF_X_AsyncRead fail!\n");
        return 0;
    }

    return 1;
}

/** SIF_X_AsyncWrite
 *  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.
 *  @param  pfnNfy       Callback function pointer.
 *  @param  pvNfyData       Callback function parameter
 *  @retval > 0             Success
 *  @retval = 0             Error
 */
UINT16 SIF_X_AsyncWrite(UINT8 u1CHannelID, UINT16 u2ClkDiv, UINT8 u1DevAddr, UINT8 u1WordAddrNum, UINT32 u4WordAddr,
                        UINT8* pu1Buf, UINT16 u2ByteCnt, SIF_ASYNC_NFY_FCT pfnNfy, VOID* pvNfyData)
{
    SIF_ASYNC_REQ_T rReq;

    if ( (u1WordAddrNum >= 4) || (!pu1Buf) || (u2ByteCnt <= 0) || (u1CHannelID > 2) )
    {
        Printf("Incorrect parameter!\n");
        return 0;
    }

    rReq.u1RequestType = SIF_ASYNC_REQ_WRITE;
    rReq.u1CHannelID = u1CHannelID;
    rReq.u2ClkDiv = u2ClkDiv;
    rReq.u1DevAddr = u1DevAddr;
    rReq.u1WordAddrNum = u1WordAddrNum;
    rReq.u4WordAddr = u4WordAddr;
    rReq.pu1Buf = pu1Buf;
    rReq.u2ByteCnt = u2ByteCnt;
    rReq.pfnNfy = pfnNfy;
    rReq.pvNfyData = pvNfyData;

    LOG(7, "Send request to AsyncThread for write: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", rReq.u1CHannelID, rReq.u2ClkDiv,
        rReq.u1DevAddr, rReq.u1WordAddrNum, rReq.u4WordAddr, rReq.u2ByteCnt);

    // Send request to aync thread
    if (x_msg_q_send(_hSifAsyncMsg, &rReq, sizeof(SIF_ASYNC_REQ_T), 1) != OSR_OK)
    {
        Printf("SIF_X_AsyncWrite fail!\n");
        return 0;
    }

    return 1;
}
#endif  // SIF_USE_OSAI
#endif

#ifdef __MODEL_slt
extern INT32 SIF_M0_Diag(VOID);
extern INT32 SIF_M1_Diag(VOID);
#if defined(CC_MT5891)				
extern INT32 SIF_M2_Diag(VOID);
#endif
extern INT32 SIF_PDM0_Diag(VOID);
extern INT32 SIF_PDM1_Diag(VOID);
#if defined(CC_SIF_IC_VERIFICATION)				
extern INT32 SIF_SECM0_Diag(VOID);
#endif

INT32 SIF_Diag(VOID)
{
	SIF_M0_Diag();
	SIF_M1_Diag();	
#if defined(CC_MT5891)				
	SIF_M2_Diag();
#endif
	if (_SIF_ISR_IsPdwncMasterEnable())
	{
		SIF_PDM0_Diag();
	}
	if (_SIF_ISR_IsPdwncMaster1Enable())
	{
		SIF_PDM1_Diag();
	}
#if defined(CC_SIF_IC_VERIFICATION)				
	SIF_SECM0_Diag();
#endif	
    return 0;
}
#endif

/** SIF_WaitLastTransaction
 *  Signal SIF driver to stop issueing any SIF read/write and wait the completion of the last SIF transaction
 *  @param  u4Timeout     Safety guard to avoid wait forever.
 *  @retval void
 */
void SIF_WaitLastTransaction(UINT32 u4Timeout)
{
    _SIF_LockTimeout(u4Timeout);
    _fgSIFDisabled = TRUE;
    _SIF_Unlock();
}

#ifdef CC_SUPPORT_STR
extern VOID _SIFM0_DisableAndClearInterrupt(VOID);
extern VOID _SIFM1_DisableAndClearInterrupt(VOID);
#if defined(CC_MT5891)				
extern VOID _SIFM2_DisableAndClearInterrupt(VOID);
#endif
extern VOID _SIFPDM0_DisableAndClearInterrupt(VOID);
extern VOID _SIFPDM1_DisableAndClearInterrupt(VOID);
//-----------------------------------------------------------------------------
/**SIF_pm_str_suspend
 */
//-----------------------------------------------------------------------------
void SIF_pm_str_suspend(void)
{
    _SIF_Lock();

    // power off
    CKGEN_WRITE32(0x1CC, CKGEN_READ32(0x1CC) & ~(1U << 11));

    _SIF_Unlock();
}


//-----------------------------------------------------------------------------
/** SIF_pm_str_resume
 */
//-----------------------------------------------------------------------------
void SIF_pm_str_resume(void)
{
    _SIF_Lock();

    CKGEN_WRITE32(0x1CC, CKGEN_READ32(0x1CC) | (1U << 11));
    _fgSIFDisabled = FALSE;

	_SIFM0_DisableAndClearInterrupt();
	_SIFM1_DisableAndClearInterrupt();	
#if defined(CC_MT5891)				
	_SIFM2_DisableAndClearInterrupt();
#endif
	VERIFY(BIM_DisableIrq(VECTOR_SERIAL));
	VERIFY(BIM_ClearIrq(VECTOR_SERIAL));
    VERIFY(BIM_EnableIrq(VECTOR_SERIAL));
	
	if (_SIF_ISR_IsPdwncMasterEnable())
	{
		_SIFPDM0_DisableAndClearInterrupt();
	}

	if (_SIF_ISR_IsPdwncMaster1Enable())
	{
		_SIFPDM1_DisableAndClearInterrupt();
	}
    // Enable SIF masters
    vIO32WriteFldAlign(SIF_SM0CTL0, 0x1, FLD_SM0_EN);        
    vIO32WriteFldAlign(SIF_SM1CTL0, 0x1, FLD_SM1_EN); 
#if defined(CC_MT5891)				
    vIO32WriteFldAlign(SIF_SM2CTL0, 0x1, FLD_SM2_EN);        
#endif
	if (_SIF_ISR_IsPdwncMasterEnable())
	{
		vIO32WriteFldAlign(PDWNC_SM0CTL0, 0x1, FLD_SIFM0_EN);		 
		vIO32WriteFldAlign(PDWNC_ARM_INTEN, 0x1, FLD_SIFM0_INTEN);		 
	}

	if (_SIF_ISR_IsPdwncMaster1Enable())
	{
		vIO32WriteFldAlign(PDWNC_SM1CTL0, 0x1, FLD_SIFM1_EN);		 
		vIO32WriteFldAlign(PDWNC_ARM_INTEN, 0x1, FLD_SIFM1_INTEN);		 
	}

#ifdef CC_SIF_OUTPUT_LOW_WAITING
    //change the output level L when SIF master in waiting state
    UINT32 u4Tmp;
    u4Tmp = *((volatile unsigned int*)0xF0029240);
    u4Tmp &= ~(1 << 6); //clear bit6
    *((volatile unsigned int*)0xF0029240) = u4Tmp;
#endif

    _SIF_Unlock();
}
#endif // CC_SUPPORT_STR

#if !defined (CC_MTK_LOADER) && defined (__KERNEL__)
EXPORT_SYMBOL(SIF_X_Read);
EXPORT_SYMBOL(SIF_X_Write);
#endif

