/* 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 x_gpio.h
 *  x_gpio.h declare all pinmux/gpio related function and parameters.
 */


#ifndef X_GPIO_H
#define X_GPIO_H

#include "x_typedef.h"
#include "hw_ckgen.h"

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

//#define  CC_FIQ_SUPPORT

//-----------------------------------------------------------------------------
// Constant definitions
//-----------------------------------------------------------------------------
#define TOTAL_NORMAL_GPIO_NUM   (NORMAL_GPIO_NUM)
#define NORMAL_GPIO_NUM         167
#define MAX_GPIO_NUM            (409)

#define TOTAL_OPCTRL_NUM        TOTAL_PDWNC_GPIO_NUM

#define TOTAL_GPIO_NUM          (OPCTRL0 + TOTAL_OPCTRL_NUM)//(NORMAL_GPIO_NUM + 8 + TOTAL_OPCTRL_NUM)
#define TOTAL_GPIO_IDX          ((NORMAL_GPIO_NUM + 31) >> 5)
#define GPIO_INDEX_MASK         ((1 << 5) - 1)
#define GPIO_TO_INDEX(gpio)     (((UINT32)(gpio)) >> 5)
#define GPIO_SUPPORT_INT_NUM	147// GPIO0~GPIO146
#define GPIO_EDGE_INTR_NUM      GPIO_SUPPORT_INT_NUM
#define TOTAL_EDGE_IDX          ((GPIO_EDGE_INTR_NUM + 31) >> 5)
#define EDGE_INDEX_MASK         ((1 << 5) - 1)
#define GPIO_INT_INDEX_MAX 		((GPIO_SUPPORT_INT_NUM + 31) >> 5)


#define PINMUX0_WRITE(value)            vIO32Write4B(CKGEN_PMUX0, (value))
#define PINMUX1_WRITE(value)            vIO32Write4B(CKGEN_PMUX1, (value))
#define PINMUX2_WRITE(value)            vIO32Write4B(CKGEN_PMUX2, (value))
#define PINMUX3_WRITE(value)            vIO32Write4B(CKGEN_PMUX3, (value))
#define PINMUX4_WRITE(value)            vIO32Write4B(CKGEN_PMUX4, (value))
#define PINMUX5_WRITE(value)            vIO32Write4B(CKGEN_PMUX5, (value))
#define PINMUX6_WRITE(value)            vIO32Write4B(CKGEN_PMUX6, (value))
#define PINMUX7_WRITE(value)            vIO32Write4B(CKGEN_PMUX7, (value))
#define PINMUX8_WRITE(value)            vIO32Write4B(CKGEN_PMUX8, (value))
#define PINMUX_MISC_WRITE(value)        vIO32Write4B(CKGEN_PMUX_MISC, (value))
#define PINMUX_WRITE(idx, value)        vIO32Write4B((CKGEN_PMUX0+(idx << 2)), (value))

#define PINMUX0_REG()                   u4IO32Read4B(CKGEN_PMUX0)
#define PINMUX1_REG()                   u4IO32Read4B(CKGEN_PMUX1)
#define PINMUX2_REG()                   u4IO32Read4B(CKGEN_PMUX2)
#define PINMUX3_REG()                   u4IO32Read4B(CKGEN_PMUX3)
#define PINMUX4_REG()                   u4IO32Read4B(CKGEN_PMUX4)
#define PINMUX5_REG()                   u4IO32Read4B(CKGEN_PMUX5)
#define PINMUX6_REG()                   u4IO32Read4B(CKGEN_PMUX6)
#define PINMUX7_REG()                   u4IO32Read4B(CKGEN_PMUX7)
#define PINMUX8_REG()                   u4IO32Read4B(CKGEN_PMUX8)
#define PINMUX_MISC_REG()               u4IO32Read4B(CKGEN_PMUX_MISC)
#define PINMUX_REG(idx)                 u4IO32Read4B((CKGEN_PMUX0+(idx << 2)))

#define _GPIO_PMUX_REG(X) 			((X==0)?CKGEN_PMUX0:((X==1)?CKGEN_PMUX1:((X==2)?CKGEN_PMUX2:((X==3)?CKGEN_PMUX3:((X==4)?CKGEN_PMUX4:((X==5)?CKGEN_PMUX5:((X==6)?CKGEN_PMUX6:((X==7)?CKGEN_PMUX7:CKGEN_PMUX8))))))))	

#define GPIO_IN_REG(idx)                u4IO32Read4B(CKGEN_GPIOIN0+(4*(idx)))
#define GPIO_OUT_REG(idx)               u4IO32Read4B(CKGEN_GPIOOUT0+(4*(idx)))
#define GPIO_OUT_WRITE(idx,val)         vIO32Write4B((CKGEN_GPIOOUT0+(4*(idx))), (val))
#define GPIO_EN_REG(idx)                u4IO32Read4B(CKGEN_GPIOEN0+(4*(idx)))
#define GPIO_EN_WRITE(idx,val)          vIO32Write4B((CKGEN_GPIOEN0+(4*(idx))), (val))
#define GPIO_RISE_REG(num)			    (~ GPIO_ED2INTEN_REG(num)) & (~ GPIO_LEVINTEN_REG(num))	 & (GPIO_ENTPOL_REG(num)) &  (GPIO_EXTINTEN_REG(num))// 				(~u4IO32Read4B(REG_GPIO_ED2INTEN)) & (~u4IO32Read4B(REG_GPIO_LEVINTEN)) & u4IO32Read4B(REG_GPIO_ENTPOL) & u4IO32Read4B(REG_GPIO_EXTINTEN)
#define GPIO_FALL_REG(num)			    (~ GPIO_ED2INTEN_REG(num)) & (~ GPIO_LEVINTEN_REG(num))	 & (~ GPIO_ENTPOL_REG(num)) &  (GPIO_EXTINTEN_REG(num))						//	(~u4IO32Read4B(REG_GPIO_ED2INTEN)) & (~u4IO32Read4B(REG_GPIO_LEVINTEN)) & (~u4IO32Read4B(REG_GPIO_ENTPOL)) & u4IO32Read4B(REG_GPIO_EXTINTEN)

#define _GPIO_ED2INTEN_REG(X) 		((X==0)?CKGEN_ED2INTEN0:((X==1)?CKGEN_ED2INTEN1:((X==2)?CKGEN_ED2INTEN2:((X==3)?CKGEN_ED2INTEN3:CKGEN_ED2INTEN4))))
#define GPIO_ED2INTEN_REG(num) 		u4IO32Read4B(_GPIO_ED2INTEN_REG(GPIO_TO_INDEX(num)))
#define _GPIO_LEVINTEN_REG(X) 		((X==0)?CKGEN_LEVINTEN0:((X==1)?CKGEN_LEVINTEN1:((X==2)?CKGEN_LEVINTEN2:((X==3)?CKGEN_LEVINTEN3:CKGEN_LEVINTEN4))))
#define GPIO_LEVINTEN_REG(num) 		u4IO32Read4B(_GPIO_LEVINTEN_REG(GPIO_TO_INDEX(num)))
#define _GPIO_ENTPOL_REG(X) 		((X==0)?CKGEN_ENTPOL0:((X==1)?CKGEN_ENTPOL1:((X==2)?CKGEN_ENTPOL2:((X==3)?CKGEN_ENTPOL3:CKGEN_ENTPOL4))))
#define GPIO_ENTPOL_REG(num) 		u4IO32Read4B(_GPIO_ENTPOL_REG(GPIO_TO_INDEX(num)))
#ifdef CC_FIQ_SUPPORT
#define _GPIO_EXTINTEN_REG(X)		((X==0)?CKGEN_EXTINTEN0_FIQ:((X==1)?CKGEN_EXTINTEN1_FIQ:((X==2)?CKGEN_EXTINTEN2_FIQ:((X==3)?CKGEN_EXTINTEN3_FIQ:CKGEN_EXTINTEN4_FIQ))))
#else
#define _GPIO_EXTINTEN_REG(X)		((X==0)?CKGEN_EXTINTEN0:((X==1)?CKGEN_EXTINTEN1:((X==2)?CKGEN_EXTINTEN2:((X==3)?CKGEN_EXTINTEN3:CKGEN_EXTINTEN4))))
#endif
#define GPIO_EXTINTEN_REG(num)		u4IO32Read4B(_GPIO_EXTINTEN_REG(GPIO_TO_INDEX(num)))
#ifdef CC_FIQ_SUPPORT
#define _GPIO_EXTINT_REG(X)			((X==0)?CKGEN_EXTINT0_FIQ:((X==1)?CKGEN_EXTINT1_FIQ:((X==2)?CKGEN_EXTINT2_FIQ:((X==3)?CKGEN_EXTINT3_FIQ:CKGEN_EXTINT4_FIQ))))
#else
#define _GPIO_EXTINT_REG(X)			((X==0)?CKGEN_EXTINT0:((X==1)?CKGEN_EXTINT1:((X==2)?CKGEN_EXTINT2:((X==3)?CKGEN_EXTINT3:CKGEN_EXTINT4))))
#endif
//#define GPIO_EXTINT_REG(num)		u4IO32Read4B(_GPIO_EXTINT_REG(GPIO_TO_INDEX(num)))

#define GPIO_INTR_RISE_REG(gpio)   	(GPIO_RISE_REG(gpio) & (1U << (gpio & EDGE_INDEX_MASK)))
#define GPIO_INTR_REG(gpio)         (GPIO_EXTINTEN_REG(gpio) & (1U << (gpio & GPIO_INDEX_MASK)))
#define GPIO_INTR_FALL_REG(gpio)    (GPIO_FALL_REG(gpio) & (1U << (gpio & EDGE_INDEX_MASK)))
#define GPIO_INTR_CLR(gpio)         vIO32Write4B(_GPIO_EXTINTEN_REG(GPIO_TO_INDEX(gpio)), GPIO_EXTINTEN_REG(gpio) & (~(1U << (gpio & EDGE_INDEX_MASK))))
#define GPIO_INTR_FALL_SET(gpio)    \
    vIO32Write4B(_GPIO_ED2INTEN_REG(GPIO_TO_INDEX(gpio)), GPIO_ED2INTEN_REG(gpio) & (~(1U << (gpio & EDGE_INDEX_MASK)))); \
    vIO32Write4B(_GPIO_LEVINTEN_REG(GPIO_TO_INDEX(gpio)), GPIO_LEVINTEN_REG(gpio) & (~(1U << (gpio & EDGE_INDEX_MASK)))); \
    vIO32Write4B(_GPIO_ENTPOL_REG(GPIO_TO_INDEX(gpio)), GPIO_ENTPOL_REG(gpio) & (~(1U << (gpio & EDGE_INDEX_MASK)))); \
    vIO32Write4B(_GPIO_EXTINTEN_REG(GPIO_TO_INDEX(gpio)), GPIO_EXTINTEN_REG(gpio) | (1U << (gpio & EDGE_INDEX_MASK)));
#define GPIO_INTR_RISE_SET(gpio)    \
    vIO32Write4B(_GPIO_ED2INTEN_REG(GPIO_TO_INDEX(gpio)), GPIO_ED2INTEN_REG(gpio) & (~(1U << (gpio & EDGE_INDEX_MASK)))); \
    vIO32Write4B(_GPIO_LEVINTEN_REG(GPIO_TO_INDEX(gpio)), GPIO_LEVINTEN_REG(gpio) & (~(1U << (gpio & EDGE_INDEX_MASK)))); \
    vIO32Write4B(_GPIO_ENTPOL_REG(GPIO_TO_INDEX(gpio)), GPIO_ENTPOL_REG(gpio) | (1U << (gpio & EDGE_INDEX_MASK)));    \
    vIO32Write4B(_GPIO_EXTINTEN_REG(GPIO_TO_INDEX(gpio)), GPIO_EXTINTEN_REG(gpio) | (1U << (gpio & EDGE_INDEX_MASK)));
#define GPIO_INTR_BOTH_EDGE_SET(gpio)    \
    vIO32Write4B(_GPIO_ED2INTEN_REG(GPIO_TO_INDEX(gpio)), GPIO_ED2INTEN_REG(gpio) | (1U << (gpio & EDGE_INDEX_MASK)));    \
    vIO32Write4B(_GPIO_LEVINTEN_REG(GPIO_TO_INDEX(gpio)), GPIO_LEVINTEN_REG(gpio) | (1U << (gpio & EDGE_INDEX_MASK)));    \
    vIO32Write4B(_GPIO_ENTPOL_REG(GPIO_TO_INDEX(gpio)), GPIO_ENTPOL_REG(gpio) | (1U << (gpio & EDGE_INDEX_MASK)));    \
    vIO32Write4B(_GPIO_EXTINTEN_REG(GPIO_TO_INDEX(gpio)), GPIO_EXTINTEN_REG(gpio) | (1U << (gpio & EDGE_INDEX_MASK)));
#define GPIO_INTR_LEVEL_LOW_SET(gpio)    \
    vIO32Write4B(_GPIO_ED2INTEN_REG(GPIO_TO_INDEX(gpio)), GPIO_ED2INTEN_REG(gpio) & (~(1U << (gpio & EDGE_INDEX_MASK)))); \
    vIO32Write4B(_GPIO_LEVINTEN_REG(GPIO_TO_INDEX(gpio)), GPIO_LEVINTEN_REG(gpio) | (1U << (gpio & EDGE_INDEX_MASK))); \
    vIO32Write4B(_GPIO_ENTPOL_REG(GPIO_TO_INDEX(gpio)), GPIO_ENTPOL_REG(gpio) & (~(1U << (gpio & EDGE_INDEX_MASK)))); \
    vIO32Write4B(_GPIO_EXTINTEN_REG(GPIO_TO_INDEX(gpio)), GPIO_EXTINTEN_REG(gpio) | (1U << (gpio & EDGE_INDEX_MASK)));
#define GPIO_INTR_LEVEL_HIGH_SET(gpio)    \
    vIO32Write4B(_GPIO_ED2INTEN_REG(GPIO_TO_INDEX(gpio)), GPIO_ED2INTEN_REG(gpio) & (~(1U << (gpio & EDGE_INDEX_MASK)))); \
    vIO32Write4B(_GPIO_LEVINTEN_REG(GPIO_TO_INDEX(gpio)), GPIO_LEVINTEN_REG(gpio) | (1U << (gpio & EDGE_INDEX_MASK))); \
    vIO32Write4B(_GPIO_ENTPOL_REG(GPIO_TO_INDEX(gpio)), GPIO_ENTPOL_REG(gpio) | (1U << (gpio & EDGE_INDEX_MASK)));    \
    vIO32Write4B(_GPIO_EXTINTEN_REG(GPIO_TO_INDEX(gpio)), GPIO_EXTINTEN_REG(gpio) | (1U << (gpio & EDGE_INDEX_MASK)));

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


typedef void (* PFN_GPIO_CALLBACK)(INT32 i4Gpio, BOOL fgStatus);

typedef enum
{
    GPIO_TYPE_NONE = 0,
    GPIO_TYPE_INTR_RISE = 1,        
    GPIO_TYPE_INTR_FALL = 2,
    GPIO_TYPE_INTR_BOTH = 3,
    GPIO_TYPE_INTR_LEVEL_HIGH = 4,    
    GPIO_TYPE_INTR_LEVEL_LOW = 8,
    GPIO_TYPE_LAST
} GPIO_TYPE;

typedef struct
{
    INT32 i4Gpio;
    BOOL fgGpioPolarity;
    UINT8 u1LightPeriod;
    UINT8 u1RoundPeriod;
    UINT8 u1Timer;
} GPIO_LED_BLINKER_T;

typedef enum
{
	GPIO_HANDLER_CKGEN = 0,
	GPIO_HANDLER_PDWNC_GPIO,
	GPIO_HANDLER_PDWNC_SRVAD,
} GPIO_HANDLER;

typedef struct
{
	INT32 (*pfnIsOwner)(INT32);    
    INT32 (*pfnInit)(void);	
    INT32 (*pfnEnable)(INT32, INT32*);    
    INT32 (*pfnInput)(INT32);    
    INT32 (*pfnOutput)(INT32, INT32*);
	INT32 (*pfnIntrq)(INT32, INT32*);
    INT32 (*pfnReg)(INT32, GPIO_TYPE, PFN_GPIO_CALLBACK);    
    INT32 (*pfnStop)(void);
	INT32 (*pfnQuery)(INT32 , INT32 *, INT32 *, INT32 *);
	INT32 (*pfnStatus)(INT32, INT32*, INT32*, INT32*, INT32*);
} GPIO_HANDLER_FUNC_TBL;

//-----------------------------------------------------------------------------
// Public function declaration
//-----------------------------------------------------------------------------

/* GPIO functions. */
EXTERN INT32 GPIO_pm_suspend(void);
EXTERN INT32 GPIO_pm_resume(void);

extern INT32 GPIO_Init(void);
extern INT32 GPIO_Stop(void);

/* Register query/set functions */
EXTERN INT32 GPIO_Output(INT32 i4GpioNum, INT32 *pfgSet);
EXTERN INT32 GPIO_Enable(INT32 i4GpioNum, INT32 *pfgSet);
EXTERN INT32 GPIO_Input(INT32 i4GpioNum);
EXTERN INT32 GPIO_Status(INT32 i4GpioNum, INT32* pi4Pinmux, INT32* pi4Enable, INT32* pi4Output, INT32* pi4Input);
EXTERN INT32 GPIO_Intrq(INT32 i4GpioNum, INT32 *pfgSet);

/* GPIO functions. */
EXTERN INT32 GPIO_Query(INT32 i4Gpio, INT32 *pi4Intr, INT32 *pi4Fall, INT32 *pi4Rise);
EXTERN INT32 GPIO_Reg(INT32 i4Gpio, GPIO_TYPE eType, PFN_GPIO_CALLBACK pfnCallback);
EXTERN INT32 GPIO_SetOut(INT32 i4GpioNum, INT32 i4Val);
EXTERN INT32 GPIO_GetIn(INT32 i4GpioNum);
EXTERN INT32 GPIO_INTEN(INT32 i4Gpio, GPIO_TYPE eType);
EXTERN INT32 GPIO_RegPeriodLevel(INT32 i4Gpio, INT32 i4HighLow, UINT32 u4Period/*mili-second*/, PFN_GPIO_CALLBACK pfnCallback);
EXTERN INT32 GPIO_SetIntExtParam(INT32 i4Gpio, UINT32 u4Arg);
EXTERN INT32 GPIO_GetIntExtParam(INT32 i4Gpio, UINT32 *pu4Arg);

#endif //X_GPIO_H
