/* 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.
 *
 *****************************************************************************/

#ifndef MTK_SIF_CFG_H
#define MTK_SIF_CFG_H

#include "x_gpio.h"

#include "x_timer.h"
#include "x_pinmux.h"
#include "x_os.h"
#include "x_assert.h"
#include "drvcust_if.h"
#include "pcmcia_if.h"

static SIF_CONFIG_T _rSifConfig =
{
    5, // Total 7 buses
    {
        2, // SystemI2C uses V2 engine
        2, // TunerI2C uses V2 engine
        2, // SecondI2C uses V2 engine
        2, // PdwncI2C uses V2 engine
        2, // PdwncI2C1 uses V2 engine
        0, // 8295BI2C0
        0  // 8295BI2C1
    }
};



//#define SIF_CFG_BEFORE_ACTION_FUNC      (SIF_MtkCfgBeforeActionFunc)
//#define SIF_CFG_AFTER_ACTION_FUNC     (SIF_MtkCfgAfterActionFunc)
#define SIF_CFG_PIN_SET_FUNC     (SIF_MtkCfgPinSetFunc)
#define SIF_CFG_GET_CONFIG_FUNC     (SIF_MtkCfgGetConfigFunc)
//#define SIF_CFG_TRI_DELAY (0)
//#define SIF_CFG_TRI_DELAY_DEV_ADDR (0)
EXTERN BOOL _SIF_ISR_IsPdwncMasterEnable(void);
EXTERN BOOL _SIF_ISR_IsPdwncMaster1Enable(void);

static void SIF_MtkCfgPinSetFunc(UINT8 u1Channel)
{
    UINT32 u4Reg = 0;
#ifndef CC_MTK_LOADER
    CRIT_STATE_T rCrit;
    rCrit = x_crit_start();
#endif
    if (u1Channel == 0)	//osda0/oscl0, use V2 engine
    {
        //PMUX1 [1:0] != 1
		u4Reg = CKGEN_READ32(0x604);
        if ((u4Reg & 0x00000003) == 0x00000001)
        {
            u4Reg &= ~(0x00000003);
        }		
        CKGEN_WRITE32(0x604, u4Reg);
		
        if (IS_IC_5861())
        {
            // PMUX2[5:3] != 2;            
            u4Reg = CKGEN_READ32(0x608);
            if ((u4Reg & 0x00000038) == 0x00000010)
            {
                u4Reg &= ~(0x00000038);
            }
            CKGEN_WRITE32(0x608, u4Reg); 
			
            // PMUX0[19:18]  = 1
            u4Reg = CKGEN_READ32(0x600);
		    u4Reg &= ~(0x000C0000);
		    u4Reg |= 0x00040000;
            CKGEN_WRITE32(0x600, u4Reg);
        }
		else
		{
			u4Reg = CKGEN_READ32(0x600);
		    //  [21:20]  != 2; [19:18] = 1
		    if ((u4Reg & 0x00300000) == 0x00200000)
		    {
		        u4Reg &= ~(0x00300000);
		    }
		    u4Reg &= ~(0x000C0000);
		    u4Reg |= 0x00040000;
		    CKGEN_WRITE32(0x600, u4Reg);
		}
    }
    else if (u1Channel == 1)	//osda2/oscl2 for tuner, use V2 engine
    {
        if (IS_IC_5861())
        {
            // PMUX0[19:18]  != 1
            u4Reg = CKGEN_READ32(0x600);
            if ((u4Reg & 0x000C0000) == 0x00040000)
            {
                u4Reg &= ~(0x000C0000);
            }
            CKGEN_WRITE32(0x600, u4Reg);
            // PMUX2[5:3] != 2;            
            u4Reg = CKGEN_READ32(0x608);
            if ((u4Reg & 0x00000038) == 0x00000010)
            {
                u4Reg &= ~(0x00000038);
            }
            CKGEN_WRITE32(0x608, u4Reg);            
        }
		else
		{
		    u4Reg = CKGEN_READ32(0x600);
		    // [21:20] != 2 ; [19:18]  != 1
		    if ((u4Reg & 0x00300000) == 0x00200000)
		    {
		        u4Reg &= ~(0x00300000);
		    }
		    if ((u4Reg & 0x000C0000) == 0x00040000)
		    {
		        u4Reg &= ~(0x000C0000);
		    }
		    CKGEN_WRITE32(0x600, u4Reg);
		}
	    u4Reg = CKGEN_READ32(0x604);
	    // PMUX1 [1:0] = 1
	    u4Reg &= ~(0x00000003);
	    u4Reg |= 0x00000001;
	    CKGEN_WRITE32(0x604, u4Reg);
    }
    else if (u1Channel == 2)	//osda1/oscl1, use V2 engine
    {
        if (IS_IC_5861())
        {
            // PMUX0[19:18]  != 1
            u4Reg = CKGEN_READ32(0x600);
            if ((u4Reg & 0x000C0000) == 0x00040000)
            {
                u4Reg &= ~(0x000C0000);
            }
            CKGEN_WRITE32(0x600, u4Reg);
            // PMUX1[1:0]  != 1
            u4Reg = CKGEN_READ32(0x604);
            if ((u4Reg & 0x00000003) == 0x00000001)
            {
                u4Reg &= ~(0x00000003);
            }
            CKGEN_WRITE32(0x604, u4Reg);
            // PMUX2[5:3] = 2;            
            u4Reg = CKGEN_READ32(0x608);
            u4Reg &= ~(0x38);
            u4Reg |= 0x10;
            CKGEN_WRITE32(0x608, u4Reg);            
        }
        else
        {
            u4Reg = CKGEN_READ32(0x600);
            // [21:20] = 2; [19:18]  != 1
            u4Reg &= ~(0x00300000);
            u4Reg |= 0x00200000;
            if ((u4Reg & 0x000C0000) == 0x00040000)
            {
                u4Reg &= ~(0x000C0000);
            }
            CKGEN_WRITE32(0x600, u4Reg);
            u4Reg = CKGEN_READ32(0x604);
            // [1:0]  != 1
            if ((u4Reg & 0x00000003) == 0x00000001)
            {
                u4Reg &= ~(0x00000003);
            }
            CKGEN_WRITE32(0x604, u4Reg);
        }
    }
    else if (_SIF_ISR_IsPdwncMasterEnable() && u1Channel == 3) // PDWNC SIF0
    {
        u4Reg = IO_READ32(PDWNC_BASE, 0x684);
        // pdmux0 [3:2] = 0x1, [1:0] = 0x1
        u4Reg &= ~(0x0000000F);
        u4Reg |= 0x00000005;
        IO_WRITE32(PDWNC_BASE, 0x684, u4Reg);
    }
    else if (_SIF_ISR_IsPdwncMaster1Enable() && u1Channel == 4) // PDWNC SIF1
    {
        u4Reg = IO_READ32(PDWNC_BASE, 0x684);
        // pdmux0 [27:26] = 0x1
        u4Reg &= ~(0x0c000000);
        u4Reg |= 0x04000000;
        IO_WRITE32(PDWNC_BASE, 0x684, u4Reg);
    }
#ifndef CC_MTK_LOADER
    x_crit_end(rCrit);
#endif
}


static SIF_CONFIG_T* SIF_MtkCfgGetConfigFunc(void)
{
    return &_rSifConfig;
}

#if 0
/** SIF_MtkCfgBeforeActionFunc
 *  do cfg BeforeAction
 *  @param  u1BusNo       sif bus no.
 *  @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.
 *  @param  u1IsRead     is in read function or write function. 1: read, 0: write

 */
static void SIF_MtkCfgBeforeActionFunc(UINT8 u1BusNo, UINT16 u2ClkDiv, UINT8 u1DevAddr, UINT8* pSubAddr, UINT32 u4SubAddrLen, UINT8* pData, UINT32
                                       u4DataLen, UINT8 u1IsRead)
{

}
/** SIF_MtkCfgAfterActionFunc
 *  do cfg AfterAction
 *  @param  u1BusNo       sif bus no.
 *  @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.
 *  @param  u1IsRead     is in read function or write function. 1: read, 0: write

 */
static void SIF_MtkCfgAfterActionFunc(UINT8 u1BusNo, UINT16 u2ClkDiv, UINT8 u1DevAddr, UINT8* pSubAddr, UINT32 u4SubAddrLen, UINT8* pData, UINT32
                                      u4DataLen, UINT8 u1IsRead)
{

}
#endif

#endif /* MTK_SIF_CFG */
