/* 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$
 * $Date$
 * $RCSfile: pdwnc_gpio.c,v $
 * $Revision$
 *
 *---------------------------------------------------------------------------*/

/** @file pdwnc_gpio.c
 *  pdwnc_gpio.c The PDWNC (Power DoWN Controller) GPIO functions
 */


//-----------------------------------------------------------------------------
// Include files
//-----------------------------------------------------------------------------

#include "x_pinmux.h"
#include "x_pdwnc.h"
#include "x_bim.h"
#include "x_assert.h"
#include "x_os.h"
#include "x_ckgen.h"
#include "x_timer.h"
#include "x_hal_arm.h"
#include "x_gpio.h"
#include "drvcust_if.h"
#include "pdwnc_config.h"
#include "pdwnc_debug.h"
#include "pdwnc_hw.h"
#include "pdwnc_t8032.h"
#include "pdwnc_srvad.h"
#include "pdwnc_if.h"
#include "sif_if.h"


#ifndef CC_MTK_LOADER
#ifdef __KERNEL__
#include <linux/module.h>
#ifdef CONFIG_MT53XX_NATIVE_GPIO
#include <linux/soc/mediatek/mtk_gpio.h>
#else
#include "cb_data.h"
#include "mtperipheral.h"
#endif
#endif
#endif

//-----------------------------------------------------------------------------
// Configuration
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// Constant definitions
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// Macros
//-----------------------------------------------------------------------------


//-----------------------------------------------------------------------------
// Static variables
//-----------------------------------------------------------------------------
/*PDWNC support gpio HW wakeup mode*/
#if defined(CC_MT5886)
static const INT8 _ai1PdwncGpio2Wak[TOTAL_PDWNC_GPIO_NUM] =
{
	  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, //0~9    , OPCTRL 0~22
	 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, //10~19
	 20, 21, 22, -1, -1, -1, -1, -1, -1, -1, //20~29
	 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //30~39
	 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //40~49
	 -1, -1, -1, -1, -1, -1, 23, 24, 25, 26, //50~59  , LED_PWM 0~3, MHL_SENCE
};
#elif defined(CC_MT5863)  
static const INT8 _ai1PdwncGpio2Wak[TOTAL_PDWNC_GPIO_NUM] =
{
	  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, //0~9
	 10, 11, 12, 13, 14, -1, 15, -1, -1, 16, //10~19
	 -1, -1, -1, -1, -1, 17, 18, 19, 20, 21, //20~29
	 22, 23, -1, -1, -1, -1, -1, -1, -1, -1, //30~39
	 -1, -1, -1, 							 //40~42
};
#elif defined(CC_MT5865)
static const INT8 _ai1PdwncGpio2Wak[TOTAL_PDWNC_GPIO_NUM] =
{
	  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, //0~9
	 -1, -1, -1, 10, -1, -1, -1, -1, -1, -1, //10~19
	 -1, 11, 12, 13, 14, 15, 16, 17, -1, -1, //20~29
	 -1, -1, 18, 19, -1, -1, -1, -1, -1,  //30-39
};
#elif defined(CC_MT5891)
static const INT8 _ai1PdwncGpio2Wak[TOTAL_PDWNC_GPIO_NUM] =
{
	  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, //0~9    , OPCTRL 0~24
	 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, //10~19
	 20, 21, 22, 23, 24, -1, -1, -1, -1, -1, //20~29
	 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //30~39
	 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //40~49
	 -1, -1, -1, -1, 25, 26, 27, 28, 29, -1, //50~59  , LED_PWM 0~3, MHL_SENCE
	 -1, -1, -1, -1, -1, -1, -1,     		 //60~69
};
#elif defined(CC_MT5893)
static const INT8 _ai1PdwncGpio2Wak[TOTAL_PDWNC_GPIO_NUM] =
{
	  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, //0~9    , OPCTRL 0~24
	 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, //10~19
	 20, 21, 22, 23, 24, -1, -1, -1, -1, -1, //20~29
	 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //30~39
	 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //40~49
	 -1, -1, -1, -1, 25, 26, 27, 28, 29, -1, //50~59  , LED_PWM 0~3, MHL_SENCE
	 -1, -1, -1, -1, -1, -1,      		 //60~69
};
#elif defined(CC_MT5895)
static const INT8 _ai1PdwncGpio2Wak[TOTAL_PDWNC_GPIO_NUM] =
{
	  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, //0~9    , OPCTRL 0~24
	 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, //10~19
	 20, 21, 22, 23, 24, -1, -1, -1, -1, -1, //20~29
	 -1, -1, -1, 25, 26, 27, 28, -1, -1, -1, //30~39  , LED_PWM 0~3
	 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //40~49
	 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //50~59
	 -1, -1, -1, -1, -1, 
};
#else
static const INT8 _ai1PdwncGpio2Wak[TOTAL_PDWNC_GPIO_NUM] =
{
	  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, //0~9    , OPCTRL 0~7
	 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, //10~19  , OPCTRL 8~20
	 20, -1, -1, -1, -1, -1, -1, -1, -1, -1, //20~29
	 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //30~39
	 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //40~49
	 -1, -1, -1, -1, 21, 22, 23, 24, 25, -1, //50~59  , LED_PWM 0~3, MHL_SENCE
	 -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, //60~69  , TCON 0~12
	 34, 35, 36, 37, 38,                     //70~74
};
#endif

//-----------------------------------------------------------------------------
// Prototypes
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Static functions
//-----------------------------------------------------------------------------


//-----------------------------------------------------------------------------
/** _PdwncGpioIsr() is the interrupt routine for GPIO pins of PDWNC module.
 *  @param u2IntIndex is the gpio number in PDWNC module to trigger interrupt.
 */
//-----------------------------------------------------------------------------
#ifndef CC_MTK_LOADER
void _PdwncGpioIsr(UINT16 u2IntIndex)
{
	mtk_pdwnc_gpio_isr_func(u2IntIndex);
}
#endif
//-----------------------------------------------------------------------------
// Inter-file functions
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
/** _PDWNC_InitGpio(). Initialize the interrupt routine for GPIO irq.
 *  @param void
 */
//-----------------------------------------------------------------------------
#ifndef CC_MTK_LOADER
INT32 _PDWNC_InitGpio(void)
{
    return 0;
}
#endif
//-----------------------------------------------------------------------------
// Public functions
//-----------------------------------------------------------------------------
#ifdef CC_MTK_LOADER
INT32 PDWNC_GpioRangeCheck(INT32 i4Gpio)
{
	if ((i4Gpio >= OPCTRL(0)) && (i4Gpio <= (TOTAL_PDWNC_GPIO_NUM + OPCTRL(0))))
	{
		return 1;
	}
	else
	{
		return 0;
	}
}
//-----------------------------------------------------------------------------
/** PDWNC_GpioEnable() The GPIO input/output mode setting functions. It will
 *  check the i4Gpio and set to related register bit as 0 or 1.  In this
 *  function, 0 is input mode and 1 is output mode.
 *  @param i4Gpio the gpio number to set or read.
 *  @param pfgSet A integer pointer.  If it's NULL, this function will return
 *  the current mode of gpio number (0 or 1).  If it's not NULL, it must
 *  reference to a integer.  If the integer is 0, this function will set the
 *  mode of the gpio number as input mode, otherwise set as output mode.
 *  @retval If pfgSet is NULL, it return 0 or 1 (0 is input mode, 1 is output
 *          mode.)  Otherwise, return (*pfgSet).
 */
//-----------------------------------------------------------------------------
INT32 PDWNC_GpioEnable(INT32 i4Gpio, INT32 *pfgSet)
{
    UINT32 u4Val = 0;
    INT32 i4Idx;

    if ((i4Gpio < 0) || (i4Gpio >= TOTAL_PDWNC_GPIO_NUM))
    {
        return -1;
    }
    // Translate GPIO number to pad setting register offset
    i4Idx = i4Gpio;

    if (i4Gpio <= 31)
    {
        u4Val = u4IO32Read4B(PDWNC_GPIOEN0);
    }
    else if((i4Gpio>=32) && (i4Gpio<=63))
    {
        u4Val = u4IO32Read4B(PDWNC_GPIOEN1);
    }
	#if !(defined(CC_MT5886) || defined(CC_MT5863) || defined(CC_MT5865))
	else
	{
		u4Val = u4IO32Read4B(PDWNC_GPIOEN2);
	}
	#endif
	i4Idx &= 0x1f;
    if (pfgSet == NULL)
    {
        return ((u4Val & (1U << i4Idx)) ? 1 : 0);
    }
    u4Val = (*pfgSet) ?
            (u4Val | (1U << i4Idx)) :
            (u4Val & ~(1U << i4Idx));

    if (i4Gpio <= 31)
    {
        vIO32Write4B(PDWNC_GPIOEN0, u4Val);
    }
    else if((i4Gpio>=32) && (i4Gpio<=63))
    {
        vIO32Write4B(PDWNC_GPIOEN1, u4Val);
    }
	#if !(defined(CC_MT5886) || defined(CC_MT5863) || defined(CC_MT5865))
	else
	{
		vIO32Write4B(PDWNC_GPIOEN2, u4Val);
	}
	#endif
    return (*pfgSet);
}

//-----------------------------------------------------------------------------
/** PDWNC_GpioOutput() The GPIO output value setting functions. It will check
 *  the i4Gpio and set to related register bit as 0 or 1.
 *  @param i4Gpio the gpio number to set or read.
 *  @param pfgSet A integer pointer.  If it's NULL, this function will return
 *          the bit of gpio number (0 or 1).  If it's not NULL, it must
 *          reference to a integer.  If the integer is 0, this function
 *          will set the bit of the gpio number as 0, otherwise set as 1.
 *  @retval If pfgSet is NULL, it return 0 or 1 (the bit value of the gpio
 *          number of output mode.  Otherwise, return (*pfgSet).
 */
//-----------------------------------------------------------------------------
INT32 PDWNC_GpioOutput(INT32 i4Gpio, INT32 *pfgSet)
{
    UINT32 u4Val,u4Val1;
    INT32 i4Idx,i4Val;

    if ((i4Gpio < 0) || (i4Gpio >= TOTAL_PDWNC_GPIO_NUM))
    {
        return -1;
    }

    // Translate GPIO number to pad setting register offset
    i4Idx = i4Gpio;
	u4Val = 0;
	u4Val1 = 0;
	BSP_PinGpioSel(i4Gpio +  OPCTRL(0));

	i4Idx &= 0x1f;

    if (pfgSet == NULL)	//NULL: for query gpio status, must be GPIO output , but not change pin level
    {
		//if input mode, get input value and set the value for output valeu ,then change to be output
		if(PDWNC_GpioEnable(i4Gpio, NULL) == 0)
		{
			//get pin level
		    if (i4Gpio <= 31)
		    {
		        u4Val1 = IO32ReadFldAlign(PDWNC_GPIOIN0, FLD_PD_GPIO_IN0);
		    }
		    else if((i4Gpio>=32) && (i4Gpio<=63))
		    {
		        u4Val1 = IO32ReadFldAlign(PDWNC_GPIOIN1, FLD_PD_GPIO_IN1);
		    }
			#if !(defined(CC_MT5886) || defined(CC_MT5863) || defined(CC_MT5865))
			else
			{
				u4Val1 = IO32ReadFldAlign(PDWNC_GPIOIN2, FLD_PD_GPIO_IN2);
			}
			#endif
			//get current out register setting
			if (i4Gpio <= 31)
			{
				u4Val = u4IO32Read4B(PDWNC_GPIOOUT0);
			}
			else if((i4Gpio>=32) && (i4Gpio<=63))
			{
				u4Val = u4IO32Read4B(PDWNC_GPIOOUT1);
			}
			#if !(defined(CC_MT5886) || defined(CC_MT5863) || defined(CC_MT5865))
			else
			{

				u4Val = u4IO32Read4B(PDWNC_GPIOOUT2);
			}
			#endif
			u4Val = (u4Val1 & (1U << i4Idx)) ?
						(u4Val | (1U << i4Idx)) :
						(u4Val & ~(1U << i4Idx));
			if (i4Gpio <= 31)
			{
				vIO32Write4B(PDWNC_GPIOOUT0, u4Val);
			}
			else if((i4Gpio>=32) && (i4Gpio<=63))
			{
				vIO32Write4B(PDWNC_GPIOOUT1, u4Val);
			}
			#if !(defined(CC_MT5886) || defined(CC_MT5863) || defined(CC_MT5865))
			else
			{
				vIO32Write4B(PDWNC_GPIOOUT2, u4Val);
			}
			#endif
			// Set the output mode.
			i4Val = 1;
			VERIFY(1 == PDWNC_GpioEnable(i4Gpio, &i4Val));

		}

	//get out value
		if (i4Gpio <= 31)
		{
			u4Val = u4IO32Read4B(PDWNC_GPIOOUT0);
		}
		else if((i4Gpio>=32) && (i4Gpio<=63))
		{
			u4Val = u4IO32Read4B(PDWNC_GPIOOUT1);
		}
		#if !(defined(CC_MT5886) || defined(CC_MT5863) || defined(CC_MT5865))
		else
		{
			u4Val = u4IO32Read4B(PDWNC_GPIOOUT2);
		}
		#endif
        return ((u4Val & (1U << i4Idx)) ? 1 : 0);
    }

//get out value
	if (i4Gpio <= 31)
	{
		u4Val = u4IO32Read4B(PDWNC_GPIOOUT0);
	}
	else if((i4Gpio>=32) && (i4Gpio<=63))
	{
		u4Val = u4IO32Read4B(PDWNC_GPIOOUT1);
	}
	#if !(defined(CC_MT5886) || defined(CC_MT5863) || defined(CC_MT5865))
	else
	{
		u4Val = u4IO32Read4B(PDWNC_GPIOOUT2);
	}
	#endif
    u4Val = (*pfgSet) ?
                (u4Val | (1U << i4Idx)) :
                (u4Val & ~(1U << i4Idx));

    if (i4Gpio <= 31)
    {
        vIO32Write4B(PDWNC_GPIOOUT0, u4Val);
    }
    else if((i4Gpio>=32) && (i4Gpio<=63))
    {
        vIO32Write4B(PDWNC_GPIOOUT1, u4Val);
    }
	#if !(defined(CC_MT5886) || defined(CC_MT5863) || defined(CC_MT5865))
	else
	{
		vIO32Write4B(PDWNC_GPIOOUT2, u4Val);
	}
	#endif
    // Set the output mode.
    i4Val = 1;
    VERIFY(1 == PDWNC_GpioEnable(i4Gpio, &i4Val));

    return (*pfgSet);
}

//-----------------------------------------------------------------------------
/** PDWNC_GpioInput()  The GPIO input reading functions. It will check the
 *  i4Gpio and read related register bit to return.
 *  @param i4Gpio the gpio number to read.
 *  @retval 0 or 1.  (GPIO input value.)
 */
//-----------------------------------------------------------------------------
INT32 PDWNC_GpioInput(INT32 i4Gpio)
{
    UINT32 u4Val;
    INT32 i4Idx = 0;

    if ((i4Gpio < 0) || (i4Gpio >= TOTAL_PDWNC_GPIO_NUM))
    {
        return -1;
    }
    // Translate GPIO number to pad setting register offset
    i4Idx = i4Gpio;
//    _PdwncSetGpioPin(i4Gpio);
    BSP_PinGpioSel(i4Gpio +  OPCTRL(0));

	i4Idx &= 0x1f;
    if (i4Gpio <= 31)
    {
        u4Val = IO32ReadFldAlign(PDWNC_GPIOIN0, FLD_PD_GPIO_IN0);
		return ((u4Val & (1U << i4Idx)) ? 1U : 0);
    }
    else if((i4Gpio>=32) && (i4Gpio<=63))
    {
        u4Val = IO32ReadFldAlign(PDWNC_GPIOIN1, FLD_PD_GPIO_IN1);
		return ((u4Val & (1U << i4Idx)) ? 1U : 0);
    }
	#if !(defined(CC_MT5886) || defined(CC_MT5863) || defined(CC_MT5865))
	else
	{
		u4Val = IO32ReadFldAlign(PDWNC_GPIOIN2, FLD_PD_GPIO_IN2);
		return ((u4Val & (1U << i4Idx)) ? 1U : 0);
	}
	#endif

	//return -1;
}

INT32 PDWNC_GpioStatus(INT32 i4Gpio, INT32* pi4Pinmux, INT32* pi4Enable, INT32* pi4Output, INT32* pi4Input)
{
    UINT32 u4Val;
    INT32 i4Idx = 0;


    if ((i4Gpio < 0) || (i4Gpio >= TOTAL_PDWNC_GPIO_NUM))
    {
        return -1;
    }

    *pi4Pinmux = BSP_PinGpioGet(i4Gpio +  OPCTRL(0), &u4Val);

    // Translate GPIO number to pad setting register offset
    i4Idx = i4Gpio;
	i4Idx &= 0x1f;

    if (i4Gpio <= 31)
    {
        u4Val = u4IO32Read4B(PDWNC_GPIOEN0);
    }
    else if((i4Gpio>=32) && (i4Gpio<=63))
    {
        u4Val = u4IO32Read4B(PDWNC_GPIOEN1);
    }
	#if !(defined(CC_MT5886) || defined(CC_MT5863) || defined(CC_MT5865))
	else
	{
		u4Val = u4IO32Read4B(PDWNC_GPIOEN2);
	}
	#endif
    *pi4Enable = ((u4Val & (1U << i4Idx)) ? 1 : 0);

    if (i4Gpio <= 31)
    {
        u4Val = u4IO32Read4B(PDWNC_GPIOOUT0);
    }
    else if((i4Gpio>=32) && (i4Gpio<=63))
    {
        u4Val = u4IO32Read4B(PDWNC_GPIOOUT1);
    }
	#if !(defined(CC_MT5886) || defined(CC_MT5863) || defined(CC_MT5865))
	else
	{
		u4Val = u4IO32Read4B(PDWNC_GPIOOUT2);
	}
	#endif
    *pi4Output = ((u4Val & (1U << i4Idx)) ? 1 : 0);

    if (i4Gpio <= 31)
    {
        u4Val = IO32ReadFldAlign(PDWNC_GPIOIN0, FLD_PD_GPIO_IN0);
    }
    else if((i4Gpio>=32) && (i4Gpio<=63))
    {
        u4Val = IO32ReadFldAlign(PDWNC_GPIOIN1, FLD_PD_GPIO_IN1);
    }
	#if !(defined(CC_MT5886) || defined(CC_MT5863) || defined(CC_MT5865))
	else
	{
		u4Val = IO32ReadFldAlign(PDWNC_GPIOIN2, FLD_PD_GPIO_IN2);
	}
	#endif
    *pi4Input = ((u4Val & (1U << i4Idx)) ? 1U : 0);

    return 0;
}
#endif

//-----------------------------------------------------------------------------
/** _PdwncSetupGPIO() to setup PDWNC module GPIO wakeup settings
 *  @param pu4PowerDownEn is the power down wakeup enable register value.
 */
//-----------------------------------------------------------------------------
void _PDWNC_SetupGPIO(UINT32 *pu4PowerDownEn)
{
    INT32 i, i4Val;
    UINT32 u4Val, u4Gpio, u4DkBit;
    SGL_GPIO_T   *prSingleGpioKeyList = NULL;
    GREED_KEY_T  *prGreedGpioKeyList = NULL;

    ASSERT(pu4PowerDownEn != NULL);

	// Do the special GPIO wakeup initialization
    if ((DRVCUST_InitQuery(eSpecialWakeupGpio, (UINT32 *)&u4Gpio) == 0) && (DRVCUST_InitQuery(eSpecialWakeupOnVal, (UINT32 *)&u4Val) == 0))
    {
        PDWNC_SetupGpioWakeup(u4Gpio,TRUE,(BOOL)u4Val,FALSE);
    }
	// Do the BT GPIO wakeup initialization
    if ((DRVCUST_InitQuery(eBTWakeupGpio, (UINT32 *)&u4Gpio) == 0) && (DRVCUST_InitQuery(eBTWakeupOnVal, (UINT32 *)&u4Val) == 0))
    {
		#ifdef CC_SUPPORT_SHUT_DOWN_ECO
		if(PDWNC_IsSuspend())
		{
		   PDWNC_SetupGpioWakeup(u4Gpio,TRUE,(BOOL)u4Val,FALSE);
		   LOG(0,"[Sony power]only hot boot will enable BT wake up\n");
		}
		#else
		   PDWNC_SetupGpioWakeup(u4Gpio,TRUE,(BOOL)u4Val,FALSE);
		#endif
    }

    if (!PDWNC_SetupFpWakeup(NULL))
    {
        LOG(1,"FP wakeup disable\n");
        return;
    }

    u4DkBit = DRVCUST_InitGet(eKeyPadWakeupBit);
    if (DRVCUST_InitQueryUptr(eSingleGpioKeyList, (UPTR *)&prSingleGpioKeyList) < 0)
    {
        return;
    }
    if (!((*pu4PowerDownEn) & WAK_IRRX))
    {
        u4DkBit = DKBIT_POWER;
    }

    // Do the GPIO wakeup initialization
    i = 0;
    while ((prSingleGpioKeyList) &&
            (prSingleGpioKeyList[i].u4Key != 0) &&
            (prSingleGpioKeyList[i].u4Key != DKBIT_NONE))
    {
        if (prSingleGpioKeyList[i].u4Key & u4DkBit)
        {
			PDWNC_SetupGpioWakeup(prSingleGpioKeyList[i].u4Gpio,TRUE,(BOOL)prSingleGpioKeyList[i].u4Val,FALSE);
        }
        i++;
    }
    if (DRVCUST_InitQueryUptr(eGreedGpioKeyList, (UPTR *)&prGreedGpioKeyList) < 0)
    {
        return;
    }

    // Do the GPIO wakeup initialization
    i = 0;
    while ((prGreedGpioKeyList) &&
            (prGreedGpioKeyList[i].u4Key != 0) &&
            (prGreedGpioKeyList[i].u4Key != DKBIT_NONE))
    {
        if (prGreedGpioKeyList[i].u4Key & u4DkBit)
        {
            u4Gpio = prGreedGpioKeyList[i].u4GpioOut;
            i4Val = (INT32)prGreedGpioKeyList[i].u4Val;
            UNUSED(GPIO_Output((INT32)u4Gpio, &i4Val));
            u4Gpio = prGreedGpioKeyList[i].u4GpioIn - OPCTRL(0);
            if (u4Gpio > TOTAL_PDWNC_DEDICATE_GPI_NUM)
            {
                LOG(1, "Error Power button setting\n");
                i++;
                continue;
            }
            u4Val = u4IO32Read4B(PDWNC_PDIO_CFG0);
            if (prGreedGpioKeyList[i].u4Val)
            {
                u4Val |= (GPIOX_POL(u4Gpio));
            }
            else
            {
                u4Val &= ~(GPIOX_POL(u4Gpio));
            }
            vIO32Write4B(PDWNC_PDIO_CFG0, u4Val);
            *pu4PowerDownEn |= GPIO_WAKEN(WAK_GPIOX(u4Gpio));
        }
        i++;
    }
}

//-----------------------------------------------------------------------------
/** PDWNC_SetupGpioWakeup() to setup PDWNC module GPIO wakeup settings
 *  @param fgEnable,fgPolarity,fgStonly is the power down wakeup enable register value.
 */
//-----------------------------------------------------------------------------
INT32 PDWNC_SetupGpioWakeup(INT32 i4GpioNum, BOOL fgEnable, BOOL fgPolarity, BOOL fgStonly)
{
	INT32 i4Int,i4Val;
	UINT32 u4Val;
    if ((i4GpioNum < OPCTRL0) || (i4GpioNum >= (OPCTRL0 + TOTAL_PDWNC_GPIO_NUM)))
    {
    	LOG(0,"gpio num error , OPCTRL .\n");
        return -1;
    }
	if((i4Int = _ai1PdwncGpio2Wak[i4GpioNum - OPCTRL0]) < 0)
    {
    	LOG(0,"gpio[%d] can't support wakeup.\n",i4GpioNum);
        return -1;
    }
	// Set to input mode.
    i4Val = 0;
    UNUSED(GPIO_Enable((INT32)i4GpioNum, &i4Val));
	//set enable bit
	#if defined(CC_MT5893) || defined(CC_MT5891) || defined(CC_MT5886) || defined(CC_MT5863) || defined(CC_MT5865) || defined(CC_MT5895)
	u4Val = IO32ReadFldAlign(PDWNC_WAKEN1,FLD_EXTIO_WAKEN1);
	#else
	u4Val = IO32ReadFldAlign((i4Int<8)?PDWNC_WAKEN:PDWNC_WAKEN1,(i4Int<8)?FLD_EXTIO_WAKEN:FLD_EXTIO_WAKEN1);
	#endif
	if(fgEnable){
		#if defined(CC_MT5893) || defined(CC_MT5891) || defined(CC_MT5886) || defined(CC_MT5863) || defined(CC_MT5865) || defined(CC_MT5895)
		u4Val |= (GPIO_WAKEN_1(WAK_GPIOX(i4Int)));
		#else
		u4Val |= ((i4Int<8)?GPIO_WAKEN(WAK_GPIOX(i4Int)):GPIO_WAKEN_1(WAK_GPIOX(i4Int-8)));
		#endif
	}
	else{
		#if defined(CC_MT5893) || defined(CC_MT5891) || defined(CC_MT5886) || defined(CC_MT5863) || defined(CC_MT5865) || defined(CC_MT5895)
		u4Val &= ~(GPIO_WAKEN_1(WAK_GPIOX(i4Int)));
		#else
		u4Val &= ~((i4Int<8)?GPIO_WAKEN(WAK_GPIOX(i4Int)):GPIO_WAKEN_1(WAK_GPIOX(i4Int-8)));
		#endif
	}
	#if defined(CC_MT5893) || defined(CC_MT5891) || defined(CC_MT5886) || defined(CC_MT5863) || defined(CC_MT5865) || defined(CC_MT5895)
	vIO32WriteFldAlign(PDWNC_WAKEN1,u4Val,FLD_EXTIO_WAKEN1);
	#else
	vIO32WriteFldAlign((i4Int<=7)?PDWNC_WAKEN:PDWNC_WAKEN1,u4Val,(i4Int<8)?FLD_EXTIO_WAKEN:FLD_EXTIO_WAKEN1);
	#endif
	//set polarity bit
	#if defined(CC_MT5893) || defined(CC_MT5891) || defined(CC_MT5886) || defined(CC_MT5895)
	u4Val = IO32ReadFldAlign(PDWNC_PDIO_CFG1,FLD_EXTIO_POL1);
	#elif defined(CC_MT5863) || defined(CC_MT5865)
	u4Val = IO32ReadFldAlign(PDWNC_PDIO_CFG0,FLD_EXTIO_POL0);
	#else
	u4Val = IO32ReadFldAlign((i4Int<16)?PDWNC_PDIO_CFG0:PDWNC_PDIO_CFG1,(i4Int<16)?FLD_EXTIO_POL0:FLD_EXTIO_POL1);
	#endif
    if (fgPolarity){
		#if defined(CC_MT5893) || defined(CC_MT5891) || defined(CC_MT5886) || defined(CC_MT5863) || defined(CC_MT5865) || defined(CC_MT5895)
		u4Val |= ((GPIOX_POL(i4Int)));
		#else
        u4Val |= ((i4Int<16)?(GPIOX_POL(i4Int)):(GPIOX_POL(i4Int-16)));
		#endif
    }
    else{
		#if defined(CC_MT5893) || defined(CC_MT5891) || defined(CC_MT5886) || defined(CC_MT5863) || defined(CC_MT5865) || defined(CC_MT5895)
		u4Val &= ~((GPIOX_POL(i4Int)));
		#else
        u4Val &= ~((i4Int<16)?(GPIOX_POL(i4Int)):(GPIOX_POL(i4Int-16)));
		#endif
    }
	#if defined(CC_MT5893) || defined(CC_MT5891) || defined(CC_MT5886) || defined(CC_MT5895)
	vIO32WriteFldAlign(PDWNC_PDIO_CFG1,u4Val,FLD_EXTIO_POL1);
	#elif defined(CC_MT5863) || defined(CC_MT5865)
	vIO32WriteFldAlign(PDWNC_PDIO_CFG0,u4Val,FLD_EXTIO_POL0);
	#else
	vIO32WriteFldAlign((i4Int<16)?PDWNC_PDIO_CFG0:PDWNC_PDIO_CFG1,u4Val,(i4Int<16)?FLD_EXTIO_POL0:FLD_EXTIO_POL1);
	#endif
	//set stonly bit
	#if defined(CC_MT5893) || defined(CC_MT5891) || defined(CC_MT5886) || defined(CC_MT5863) || defined(CC_MT5865) || defined(CC_MT5895)
	u4Val = IO32ReadFldAlign(PDWNC_WAKE_STONLY1,FLD_WAK_STON1_EN);
	#else
	u4Val = IO32ReadFldAlign((i4Int<8)?PDWNC_WAKE_STONLY0:PDWNC_WAKE_STONLY1,(i4Int<8)?FLD_EXTIO_WAK_STON0_EN:FLD_WAK_STON1_EN);
	#endif
	if(fgStonly){
		#if defined(CC_MT5893) || defined(CC_MT5891) || defined(CC_MT5886) || defined(CC_MT5863) || defined(CC_MT5865) || defined(CC_MT5895)
		u4Val |= (GPIO_WAKEN_1(WAK_GPIOX(i4Int)));
		#else
		u4Val |= ((i4Int<8)?GPIO_WAKEN(WAK_GPIOX(i4Int)):GPIO_WAKEN_1(WAK_GPIOX(i4Int-8)));
		#endif
	}
	else{
		#if defined(CC_MT5893) || defined(CC_MT5891) || defined(CC_MT5886) || defined(CC_MT5863) || defined(CC_MT5865) || defined(CC_MT5895)
		u4Val &= ~(GPIO_WAKEN_1(WAK_GPIOX(i4Int)));
		#else
		u4Val &= ~((i4Int<8)?GPIO_WAKEN(WAK_GPIOX(i4Int)):GPIO_WAKEN_1(WAK_GPIOX(i4Int-8)));
		#endif
	}
	#if defined(CC_MT5893) || defined(CC_MT5891) || defined(CC_MT5886) || defined(CC_MT5863) || defined(CC_MT5865) || defined(CC_MT5895)
	vIO32WriteFldAlign(PDWNC_WAKE_STONLY1,u4Val,FLD_WAK_STON1_EN);
	#else
	vIO32WriteFldAlign((i4Int<8)?PDWNC_WAKE_STONLY0:PDWNC_WAKE_STONLY1,u4Val,(i4Int<8)?FLD_EXTIO_WAK_STON0_EN:FLD_WAK_STON1_EN);
	#endif

	return 0;
}

INT32 PDWNC_GetWakeupGpioNum(UINT32 *u4GpioNum)
{
	INT32 i;
	INT32 u4Wak = -1;
	UINT32 u4Val;

	VERIFY(u4GpioNum != NULL);
#if defined(CC_MT5893) || defined(CC_MT5891) || defined(CC_MT5886) || defined(CC_MT5863) || defined(CC_MT5865) || defined(CC_MT5895)
    u4Val = _PDWNC_ReadWakeupStatus(1);
	if(u4Val & 0x3FFFFFFF)
	{
		for(i=0;i<30;i++) //0~29
		{
			if(u4Val & 0x01)
			{
				u4Wak = i;
				break;
			}
			u4Val = u4Val >> 1;
		}
	}
#else
	u4Val = _PDWNC_ReadWakeupStatus(0);
	if(u4Val & 0xFF) //OPCTRL0 ~ OPCTRL7.
	{

		for(i=0;i<8;i++)
		{
			if(u4Val & 0x01)
			{
				u4Wak = i;
				break;
			}
			u4Val = u4Val >> 1;
		}
	}else{
		u4Val = _PDWNC_ReadWakeupStatus(1);
		if(u4Val & 0x7FFFFFFF)
		{
			for(i=0;i<31;i++) //0~30
			{
				if(u4Val & 0x01)
				{
					u4Wak = i + 8;
					break;
				}
				u4Val = u4Val >> 1;
			}
		}
	}
#endif
	if(u4Wak != -1)
	{
		//LOG(1, "GPIO wakeup status, u4Wak = %d.\n",u4Wak);
		for(i=0;i<TOTAL_PDWNC_GPIO_NUM;i++)
		{
			if(_ai1PdwncGpio2Wak[i] == u4Wak)
			{
				//LOG(1, "Trigger wakeup GPIO num: %d .\n",OPCTRL0+i);
				*u4GpioNum = (OPCTRL0+i);
				return 0;
			}
		}
	}

	return -1;
}

