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


/**
 * @file HDMI customization file
 *
 *
 * @author chiachi_chiang@mtk.com.tw
 * @author darren_weng@mtk.com.tw
 * @author daniel_hsiao@mtk.com.tw
 */
//Change the following definition for gpio customization



#include "x_gpio.h"
#include "x_printf.h"

#include "hw_vdoin.h"
#include "hw_hdmi.h"
#include "drv_hdmi.h"
#include "drv_video.h"
#include "sv_const.h"
#include "source_table.h"
#include "sif_if.h"
#include "x_timer.h"

#define HDMI_PORT_LARGEST HDMI_SWITCH_4

/*Main chip I2C define*/
#define Chip_I2C_ChannelId  0		//It CANNOT be changed
#define I2C_TIMING	0x100
#define I2C_AddrNum 				0
//#define Switch_Slave_Addr	0xAE
UINT8 Switch_Slave_Addr;

/*
@para: 1 is success , 0 is fail   
if I2C_AddrNum=1, I2C will send out wordaddr
if I2C_AddrNum=0, I2C will not  send out wordaddr
*/
UINT8 u1SwitchI2CRead(UINT8 u1SlaveAddr, UINT32 u1WordAddr,UINT8 *pu1Buffer, UINT16 u2ByteCount)
{
  
    INT32 i4ReturnValue;
    i4ReturnValue = SIF_X_Read(Chip_I2C_ChannelId,I2C_TIMING, u1SlaveAddr, I2C_AddrNum , u1WordAddr, pu1Buffer, u2ByteCount);

    if (i4ReturnValue>0)
    {
		return 1;
    }
    else
    {
	  return 0;
    }

}
/*
@para: 1 is success , 0 is fail   
*/ 
UINT8 u1SwitchI2CWrite(UINT8 u1SlaveAddr, UINT32 u1WordAddr, UINT8 *pu1Buffer, UINT16 u2ByteCount)
{
    INT32 i4ReturnValue;
   
    i4ReturnValue = SIF_X_Write(Chip_I2C_ChannelId, I2C_TIMING, u1SlaveAddr, I2C_AddrNum ,u1WordAddr, (UINT8 *)pu1Buffer, u2ByteCount);

    if (i4ReturnValue > 0)
    {

    		return 1;
    }
    else
    {
       //LOG(1,"Sil9187 write fail\n");
        return 0;
    }
}

static void vSwitchI2CInit(void)
{
    	UINT8 data[2];
    	if(u1SwitchI2CRead(0xAE,0,data,1))
    	{
    			Switch_Slave_Addr=0xAE;
    			data[0]=0x3f;
    			printf("2410 A....\n");
    	}	
    	else
    	{
    			Switch_Slave_Addr=0xAC;
    			data[0]=0x1f;
    			printf("2410 ....\n");
    	}
    	
    	data[1]=0xc2;
  	u1SwitchI2CWrite(Switch_Slave_Addr,0,data,2);
  	u1SwitchI2CRead(Switch_Slave_Addr,0,data,2);
  	printf("data[0]=%x data[1]=%x\n",data[0],data[1]);
}

void vHDMIHPDHigh(UINT8 bSwitch)
{
    	UINT8 data[2];
    	
  	 u1SwitchI2CRead(Switch_Slave_Addr,0,data,2);  	 
	switch(bSwitch) 
	{
		case HDMI_SWITCH_1:
			  	 data[0]=data[0]&0xfe;
			  	 data[0]=data[0]|0x01;
				break;
		case HDMI_SWITCH_2:
				data[0]=data[0]&0xfd;
			  	data[0]=data[0]|0x02;
				break;
		case HDMI_SWITCH_3:
				data[0]=data[0]&0xfb;
			  	data[0]=data[0]|0x04;
				break;
		case HDMI_SWITCH_4: // SIDE
				data[0]=data[0]&0xf7;
			  	data[0]=data[0]|0x08;
				break;
		default:
				break;
				
	}	
	u1SwitchI2CWrite(Switch_Slave_Addr,0,data,2);
}

void vHDMIHPDLow(UINT8 bSwitch)
{
    	UINT8 data[2];
    	
  	 u1SwitchI2CRead(Switch_Slave_Addr,0,data,2);  	 
	switch(bSwitch) 
	{
		case HDMI_SWITCH_1:
			  	 data[0]=data[0]&0xfe;
				break;
		case HDMI_SWITCH_2:
				data[0]=data[0]&0xfd;
				break;
		case HDMI_SWITCH_3:
				data[0]=data[0]&0xfb;
				break;
		case HDMI_SWITCH_4: // SIDE
				data[0]=data[0]&0xf7;
				break;
		default:
				break;
				
	}	
	u1SwitchI2CWrite(Switch_Slave_Addr,0,data,2);
}

//====================//
UINT8 bHDMIPort5VStatus(UINT8 port)
{

UINT8 data[2];
	if(u1SwitchI2CRead(Switch_Slave_Addr,0,data,2))
	{
		//if(data[1]&0x2==0x2)
		{
			switch(port)
			{
			       case HDMI_SWITCH_1: 
			       	return (data[1]&0x4)>>2;
			       case HDMI_SWITCH_2: 
			       	return (data[1]&0x8)>>3;
			       case HDMI_SWITCH_3: 
			       	return (data[1]&0x10)>>4;
			       case HDMI_SWITCH_4: 
			       	return (data[1]&0x20)>>5;          
				default: 
					return 0;
			}
			//u1SwitchI2CWrite(Switch_Slave_Addr,0,);	
		}		
	}
	else
	{
		return 0;
	}

}

//====================//
void vHDMISwitchInit(void)
{    
	vSwitchI2CInit();
}

//====================//
void vHDMISetSwitch(UINT8 bSwitch)
{
    UINT8 i = 0;
    
    UINT8 data[2];
   u1SwitchI2CRead(Switch_Slave_Addr,0,data,2);
    	
	if (_bHDMICurrSwitch != bSwitch)
	{	
		_bHDMICurrSwitch = bSwitch;
		
		vHDMIHPDLow(bSwitch);
		data[0]=data[0]&0x3f;

		switch(bSwitch)
		{				
			case HDMI_SWITCH_1:				
				data[0]=data[0]|0x0;
				vRegWriteFldAlign(HDMI_DDC_PAD,0x0,HDMI_DDC_MUX_MASK);  //DDC pad select
				break;			
			case HDMI_SWITCH_2:
				data[0]=data[0]|0x40;
				vRegWriteFldAlign(HDMI_DDC_PAD,0x1,HDMI_DDC_MUX_MASK);
				break;
			case HDMI_SWITCH_3:		
				data[0]=data[0]|0x80;
				vRegWriteFldAlign(HDMI_DDC_PAD,0x2,HDMI_DDC_MUX_MASK);  //DDC pad select
				break;			
			case HDMI_SWITCH_4:
				data[0]=data[0]|0xc0;
				vRegWriteFldAlign(HDMI_DDC_PAD,0x3,HDMI_DDC_MUX_MASK);
				break;
				
			default: /* disable all */
				//vRegWriteFldAlign(ANA_INTF_2,0x0,RG_HDMI_SW_EN);
				vRegWriteFldAlign(HDMI_DDC_PAD,0x0,HDMI_DDC_MUX_MASK);
				break;
			 
		}
		u1SwitchI2CWrite(Switch_Slave_Addr,0,data,2);
		
		// HPD high for unselected ports, support CEC feature.
		for ( i = HDMI_SWITCH_1 ; i <= HDMI_PORT_LARGEST ; i++) 
		{
			if (i != bSwitch)
			{
				vHDMIHPDHigh(i);
			}
		}
		
		#if MUTE_TEMP
		vHDMIVideoOutOff();
		#endif
		
		_bHDMIState = HDMI_STATE_INIT;
	}
}
