/**************************************************************************
 * @file     pan_gpio.h
 * @version  V1.00
 * $Revision: 3 $
 * $Date: 2023/11/08  $  
 * @brief    Panchip series GPIO driver header file
 *
 * @note
 * Copyright (C) 2023 Panchip Technology Corp. All rights reserved.
 *****************************************************************************/

#ifndef __PAN_GPIO_H__
#define __PAN_GPIO_H__

/**
 * @brief Gpio Interface
 * @defgroup gpio_interface Gpio Interface
 * @{
 */

#include <stdint.h>

#ifdef __cplusplus
extern "C"
{
#endif


#define GPIO_PIN_MAX    8   /*!< Specify Maximum Pins of Each GPIO Port */

/**@defgroup GPIO_MODE_FLAG Gpio mode
 * @brief       Gpio mode definitions
 * @{ */
 
typedef enum _GPIO_ModeDef
{
    GPIO_MODE_INPUT         = 0x0,  /*!< Input Mode */
    GPIO_MODE_OUTPUT        = 0x1,  /*!< Output Mode */
    GPIO_MODE_OPEN_DRAIN    = 0x2,  /*!< Open-Drain Mode */
    GPIO_MODE_QUASI         = 0x3   /*!< Quasi-bidirectional Mode */
} GPIO_ModeDef;
/**@} */

/**@defgroup GPIO_INT_FLAG Gpio interrupt type
 * @brief       Gpio interrupt type definitions
 * @{ */

typedef enum _GPIO_IntAttrDef
{
    GPIO_INT_RISING         = 0x00010000UL, /*!< Interrupt enable by Input Rising Edge */
    GPIO_INT_FALLING        = 0x00000001UL, /*!< Interrupt enable by Input Falling Edge */
    GPIO_INT_BOTH_EDGE      = 0x00010001UL, /*!< Interrupt enable by both Rising Edge and Falling Edge */
    GPIO_INT_HIGH           = 0x01010000UL, /*!< Interrupt enable by Level-High */    
    GPIO_INT_LOW            = 0x01000001UL  /*!< Interrupt enable by Level-Low */
} GPIO_IntAttrDef;

/**@} */

/**@defgroup GPIO_DB_SRC_FLAG Gpio debounce src
 * @brief       Gpio debouce src definitions
 * @{ */

typedef enum _GPIO_ClkSrcDef
{
    GPIO_DBCTL_DBCLKSRC_RCL     = 0x00000010UL, /*!< DBCTL setting for de-bounce counter clock source is the internal 32 kHz */ 
    GPIO_DBCTL_DBCLKSRC_HCLK    = 0x00000000UL  /*!< DBCTL setting for de-bounce counter clock source is the internal HCLK */ 
} GPIO_ClkSrcDef;
/**@} */


/**@defgroup GPIO_DRIVER_ABILITY Gpio driver ability selection
 * @brief       Gpio driver ability definitions
 * @{ */

typedef enum _GPIO_DriverAbilityDef
{
	DRIVER_ABILITY_MINIMUM		= 0x00UL,  /*!< dirver ability minimum */ 
	DRIVER_ABILITY_SUB_MINOR	= 0x01UL,  /*!< dirver ability sub-minor */ 
	DRIVER_ABILITY_BIG			= 0x02UL,  /*!< dirver ability big */ 
	DRIVER_ABILITY_MAX			= 0x03UL,  /*!< dirver ability max */ 
} GPIO_DriverAbilityDef;
/**@} */


/**@defgroup GPIO_DB_CNT_FLAG Gpio debounce count
 * @brief       Gpio debouce count definitions
 * @{ */

typedef enum _GPIO_ClkSelDef
{
    GPIO_DBCTL_DBCLKSEL_1       = 0x00000000UL, /*!< DBCTL setting for sampling cycle = 1 clocks */
    GPIO_DBCTL_DBCLKSEL_2       = 0x00000001UL, /*!< DBCTL setting for sampling cycle = 2 clocks */
    GPIO_DBCTL_DBCLKSEL_4       = 0x00000002UL, /*!< DBCTL setting for sampling cycle = 4 clocks */
    GPIO_DBCTL_DBCLKSEL_8       = 0x00000003UL, /*!< DBCTL setting for sampling cycle = 8 clocks */
    GPIO_DBCTL_DBCLKSEL_16      = 0x00000004UL, /*!< DBCTL setting for sampling cycle = 16 clocks */
    GPIO_DBCTL_DBCLKSEL_32      = 0x00000005UL, /*!< DBCTL setting for sampling cycle = 32 clocks */
    GPIO_DBCTL_DBCLKSEL_64      = 0x00000006UL, /*!< DBCTL setting for sampling cycle = 64 clocks */
    GPIO_DBCTL_DBCLKSEL_128     = 0x00000007UL, /*!< DBCTL setting for sampling cycle = 128 clocks */
    GPIO_DBCTL_DBCLKSEL_256     = 0x00000008UL, /*!< DBCTL setting for sampling cycle = 256 clocks */
    GPIO_DBCTL_DBCLKSEL_512     = 0x00000009UL, /*!< DBCTL setting for sampling cycle = 512 clocks */
    GPIO_DBCTL_DBCLKSEL_1024    = 0x0000000AUL, /*!< DBCTL setting for sampling cycle = 1024 clocks */
    GPIO_DBCTL_DBCLKSEL_2048    = 0x0000000BUL, /*!< DBCTL setting for sampling cycle = 2048 clocks */
    GPIO_DBCTL_DBCLKSEL_4096    = 0x0000000CUL, /*!< DBCTL setting for sampling cycle = 4096 clocks */
    GPIO_DBCTL_DBCLKSEL_8192    = 0x0000000DUL, /*!< DBCTL setting for sampling cycle = 8192 clocks */
    GPIO_DBCTL_DBCLKSEL_16384   = 0x0000000EUL, /*!< DBCTL setting for sampling cycle = 16384 clocks */
    GPIO_DBCTL_DBCLKSEL_32768   = 0x0000000FUL  /*!< DBCTL setting for sampling cycle = 32768 clocks */
} GPIO_ClkSelDef;
/**@} */


/**@defgroup GPIO_ADDR_FLAG Gpio address map
 * @{ */

/** 
 * @brief       Define gpio pin Data input/output. It could be used to control each \n
 *							- I/O pin by pin address mapping.
 *
 * @param[in]   Port GPIO port number. It could be \ref 0, \ref 1, \ref 2, \ref 3, \ref 4 or \ref 5.
 * @param[in]   Pin  The single or multiple pins of specified gpio port. \ref 0, \ref 1, \ref 2,.. \ref 7
 *
 * @code:
 *      GPIO_WritePin(0, 0, 1);
 *  
 * @endcode
 * @details		It is used to set P0.0 to high;
 *
 * @code:
 *  
 *      if (GPIO_ReadPin(0, 0))
 *          GPIO_WritePin(0, 0, 0);
 * @endcode
 * @details		If P0.0 pin status is high, then set P0.0 data output to low.
 */
 #define GPIO_WritePin(port, pin, pin_val)	(pin_val)? (((GPIO_T *)(GPIO_BASE+0x40*port))->DOUT |= (0x1 << pin)):\
			(((GPIO_T *)(GPIO_BASE+0x40*port))->DOUT &= ~(0x1 << pin))
 #define GPIO_ReadPin(port, pin)	((((GPIO_T *)(GPIO_BASE+0x40*port))->PIN >> pin) & 0x1)

/**@} */



/**
 * @brief       Clear GPIO Pin Interrupt Flag
 *
 * @param[in]   gpio        GPIO port. It could be \ref P0, \ref P1, \ref P2.
 * @param[in]   u32PinMask  The single or multiple pins of specified GPIO port. \ref BIT0, \ref BIT1, \ref BIT2,.. \ref BIT7
 *
 * @return      None
 *
 * @details     Clear the interrupt status of specified GPIO pin.
 */
__STATIC_INLINE void GPIO_ClrIntFlag(GPIO_T *gpio, uint32_t u32PinMask)
{
    if (GPIO_DB->DBCTL & GP_DBCTL_DBCLKSRC_Msk) {
        // Set gpio db clock src to ahb to speed up internal clearing flow
        GPIO_DB->DBCTL &= ~GP_DBCTL_DBCLKSRC_Msk;
        // Clear specified gpio int source flag
        gpio->INTSRC = u32PinMask;
        // Set gpio db clock src back to 32k
        GPIO_DB->DBCTL |= GP_DBCTL_DBCLKSRC_Msk;
    } else {
        // Clear specified gpio int source flag
        gpio->INTSRC = u32PinMask;
    }
}

/**
 * @brief       Clear GPIO Pin Interrupt Flag
 *
 * @param[in]   gpio        GPIO port. It could be \ref P0, \ref P1, \ref P2.
 *
 * @return      None
 *
 * @details     Clear the interrupt status of All GPIO pin.
 */
 
__STATIC_INLINE void GPIO_ClrAllIntFlag(GPIO_T *gpio)
{
    if (GPIO_DB->DBCTL & GP_DBCTL_DBCLKSRC_Msk) {
        // Set gpio db clock src to ahb to speed up internal clearing flow
        GPIO_DB->DBCTL &= ~GP_DBCTL_DBCLKSRC_Msk;
        // Clear gpio int source flags
        gpio->INTSRC = gpio->INTSRC;
        // Set gpio db clock src back to 32k
        GPIO_DB->DBCTL |= GP_DBCTL_DBCLKSRC_Msk;
    } else {
        // Clear gpio int source flags
        gpio->INTSRC = gpio->INTSRC;
    }
}

/**
 * @brief       Disable Pin De-bounce Function
 *
 * @param[in]   gpio        GPIO port. It could be \ref P0, \ref P1, \ref P2.
 * @param[in]   u32PinMask  The single or multiple pins of specified GPIO port. \ref BIT0, \ref BIT1, \ref BIT2,.. \ref BIT7
 *
 * @return      None
 *
 * @details     Disable the interrupt de-bounce function of specified GPIO pin.
 */
__STATIC_INLINE void GPIO_DisableDebounce(GPIO_T *gpio, uint32_t u32PinMask)
{
    gpio->DBEN &= ~u32PinMask;
}

/**
 * @brief       Enable Pin De-bounce Function
 *
 * @param[in]   gpio        GPIO port. It could be \ref P0, \ref P1, \ref P2.
 * @param[in]   u32PinMask  The single or multiple pins of specified GPIO port. \ref BIT0, \ref BIT1, \ref BIT2,.. \ref BIT7
 *
 * @return      None
 *
 * @details     Enable the interrupt de-bounce function of specified GPIO pin.
 */
__STATIC_INLINE void GPIO_EnableDebounce(GPIO_T *gpio, uint32_t u32PinMask)
{
    gpio->DBEN |= u32PinMask;
}

/**
 * @brief       Disable I/O Digital Input Path
 *
 * @param[in]   gpio        GPIO port. It could be \ref P0, \ref P1, \ref P2.
 * @param[in]   u32PinMask  The single or multiple pins of specified GPIO port. \ref BIT0, \ref BIT1, \ref BIT2,.. \ref BIT7
 *
 * @return      None
 *
 * @details     Disable I/O digital input path of specified GPIO pin.
 */
__STATIC_INLINE void GPIO_DisableDigitalPath(GPIO_T *gpio, uint32_t u32PinMask)
{
    gpio->DINOFF |= (u32PinMask << 16);
}

/**
 * @brief       Enable I/O Digital Input Path
 *
 * @param[in]   gpio        GPIO port. It could be \ref P0, \ref P1, \ref P2.
 * @param[in]   u32PinMask  The single or multiple pins of specified GPIO port. \ref BIT0, \ref BIT1, \ref BIT2,.. \ref BIT7
 *
 * @return      None
 *
 * @details     Enable I/O digital input path of specified GPIO pin.
 */
__STATIC_INLINE void GPIO_EnableDigitalPath(GPIO_T *gpio, uint32_t u32PinMask)
{
    gpio->DINOFF &= ~(u32PinMask << 16);
}

/**
 * @brief       Disable I/O Digital pull up Path
 *
 * @param[in]   gpio        GPIO port. It could be \ref P0, \ref P1, \ref P2.
 * @param[in]   u32PinMask  The single or multiple pins of specified GPIO port. \ref BIT0, \ref BIT1, \ref BIT2,.. \ref BIT7
 *
 * @return      None
 *
 * @details     Disable I/O Digital pull up Path of specified GPIO pin.
 */
 __STATIC_INLINE void GPIO_DisablePullupPath(GPIO_T *gpio, uint32_t u32PinMask)
{
    gpio->DINOFF &= ~u32PinMask;
}

 /**
 * @brief       Enable I/O Digital pull up Path
 *
 * @param[in]   gpio        GPIO port. It could be \ref P0, \ref P1, \ref P2.
 * @param[in]   u32PinMask  The single or multiple pins of specified GPIO port. \ref BIT0, \ref BIT1, \ref BIT2,.. \ref BIT7
 *
 * @return      None
 *
 * @details     Enable I/O Digital pull up Path of specified GPIO pin.
 */
 __STATIC_INLINE void GPIO_EnablePullupPath(GPIO_T *gpio, uint32_t u32PinMask)
{
    gpio->DINOFF |= u32PinMask;
}

/**
 * @brief       Disable I/O Digital pull down Path
 *
 * @param[in]   gpio        GPIO port. It could be \ref P0, \ref P1, \ref P2.
 * @param[in]   u32PinMask  The single or multiple pins of specified GPIO port. \ref BIT0, \ref BIT1, \ref BIT2,.. \ref BIT7
 *
 * @return      None
 *
 * @details     Disable I/O Digital pull down Path of specified GPIO pin.
 */
 __STATIC_INLINE void GPIO_DisablePulldownPath(GPIO_T *gpio, uint32_t u32PinMask)
{
    gpio->DINOFF &= ~(u32PinMask << 8);
}

 /**
 * @brief       Enable I/O Digital pull down Path
 *
 * @param[in]   gpio        GPIO port. It could be \ref P0, \ref P1, \ref P2.
 * @param[in]   u32PinMask  The single or multiple pins of specified GPIO port. \ref BIT0, \ref BIT1, \ref BIT2,.. \ref BIT7
 *
 * @return      None
 *
 * @details     Enable I/O Digital pull down Path of specified GPIO pin.
 */
 __STATIC_INLINE void GPIO_EnablePulldownPath(GPIO_T *gpio, uint32_t u32PinMask)
{
    gpio->DINOFF |= (u32PinMask << 8);
}


/**
 * @brief       Get GPIO Pin Interrupt Flag
 *
 * @param[in]   gpio        GPIO port. It could be \ref P0, \ref P1, \ref P2.
 * @param[in]   u32PinMask  The single or multiple pins of specified GPIO port. \ref BIT0, \ref BIT1, \ref BIT2,.. \ref BIT7
 *
 * @retval      false           No interrupt at specified GPIO pin
 * @retval      true            The specified GPIO pin generate an interrupt
 *
 * @details     Get the interrupt status of specified GPIO pin.
 */
__STATIC_INLINE bool GPIO_GetIntFlag(GPIO_T *gpio, uint32_t u32PinMask)
{
    return (bool)(gpio->INTSRC & u32PinMask);
}

/**
 * @brief       Set De-bounce Sampling Cycle Time
 *
 * @param[in]   clksrc      The de-bounce counter clock source. It could be GPIO_DBCTL_DBCLKSRC_HCLK or GPIO_DBCTL_DBCLKSRC_RCL.
 * @param[in]   clksel      The de-bounce sampling cycle selection. It could be \n
 *                              - \ref GPIO_DBCTL_DBCLKSEL_1, \ref GPIO_DBCTL_DBCLKSEL_2, \ref GPIO_DBCTL_DBCLKSEL_4, \ref GPIO_DBCTL_DBCLKSEL_8, \n
 *                              - \ref GPIO_DBCTL_DBCLKSEL_16, \ref GPIO_DBCTL_DBCLKSEL_32, \ref GPIO_DBCTL_DBCLKSEL_64, \ref GPIO_DBCTL_DBCLKSEL_128, \n
 *                              - \ref GPIO_DBCTL_DBCLKSEL_256, \ref GPIO_DBCTL_DBCLKSEL_512, \ref GPIO_DBCTL_DBCLKSEL_1024, \ref GPIO_DBCTL_DBCLKSEL_2048, \n
 *                              - \ref GPIO_DBCTL_DBCLKSEL_4096, \ref GPIO_DBCTL_DBCLKSEL_8192, \ref GPIO_DBCTL_DBCLKSEL_16384, \ref GPIO_DBCTL_DBCLKSEL_32768.
 *
 * @return      None
 *
 * @details     Set the interrupt de-bounce sampling cycle time based on the debounce counter clock source. \n
 *              Example: GPIO_SET_DEBOUNCE_TIME(GPIO_DBCTL_DBCLKSRC_RCL, GPIO_DBCTL_DBCLKSEL_4). \n
 *              It's meaning the De-debounce counter clock source is internal 10 KHz and sampling cycle selection is 4. \n
 *              Then the target de-bounce sampling cycle time is (2^4)*(1/(10*1000)) s = 16*0.0001 s = 1600 us,
 *              and system will sampling interrupt input once per 1600 us.
 */
__STATIC_INLINE void GPIO_SetDebounceTime(GPIO_ClkSrcDef clksrc, GPIO_ClkSelDef clksel)
{
	GPIO_DB->DBCTL =  (GPIO_DB->DBCTL & ~(GP_DBCTL_DBCLKSRC_Msk | 0xf)) | (clksrc | clksel);
}

/**
 * @brief       Get GPIO Port IN Data
 *
 * @param[in]   gpio        GPIO port. It could be \ref P0, \ref P1, \ref P2.
 *
 * @retval      The specified port data
 *
 * @details     Get the PIN register of specified GPIO port.
 */
__STATIC_INLINE uint32_t GPIO_GetInData(GPIO_T *gpio)
{
    return gpio->PIN;
}

/**
 * @brief       Set GPIO Port OUT Data
 *
 * @param[in]   gpio        GPIO port. It could be \ref P0, \ref P1, \ref P2.
 * @param[in]   data        GPIO port data.
 *
 * @retval      None
 *
 * @details     Set the Data into specified GPIO port.
 */
__STATIC_INLINE void GPIO_SetOutData(GPIO_T *gpio, uint32_t data)
{
    gpio->DOUT = data;
}

/**
 * @brief       Get GPIO Port OUT Data
 *
 * @param[in]   gpio        GPIO port. It could be \ref P0, \ref P1, \ref P2.
 *
 * @retval      The specified port data
 *
 * @details     Get the DOUT register of specified GPIO port.
 */
__STATIC_INLINE uint32_t GPIO_GetOutData(GPIO_T *gpio)
{
    return gpio->DOUT;
}

/**
 * @brief       Toggle Specified GPIO pin
 *
 * @param[in]   gpio        GPIO port. It could be \ref P0, \ref P1, \ref P2.
 * @param[in]   u32PinMask  The single or multiple pins of specified GPIO port. \ref BIT0, \ref BIT1, \ref BIT2,.. \ref BIT7
 *
 * @retval      None
 *
 * @details     Toggle the specified GPIO pin output.
 */
__STATIC_INLINE void GPIO_Toggle(GPIO_T *gpio, uint32_t u32PinMask)
{
    GPIO_SetOutData(gpio, GPIO_GetOutData(gpio) ^ u32PinMask);
}

/**
 * @brief       Enable GPIO interrupt
 *
 * @param[in]   gpio            GPIO port. It could be \ref P0, \ref P1, \ref P2.
 * @param[in]   u32Pin          The pin of specified GPIO port. It could be 0 ~ 2.
 * @param[in]   IntAttribs      The interrupt attribute of specified GPIO pin. It could be \n
 *                              - \ref GPIO_INT_RISING,
 *                              - \ref GPIO_INT_FALLING,
 *                              - \ref GPIO_INT_BOTH_EDGE,
 *                              - \ref GPIO_INT_HIGH,
 *                              - \ref GPIO_INT_LOW.
 *
 * @return      None
 *
 * @details     This function is used to enable specified GPIO pin interrupt.
 */
__STATIC_INLINE void GPIO_EnableInt(GPIO_T *gpio, uint32_t u32Pin, GPIO_IntAttrDef IntAttribs)
{
    gpio->INTTYPE |= (((IntAttribs >> 24) & 0xFFUL) << u32Pin);
    gpio->INTEN |= ((IntAttribs & 0xFFFFFFUL) << u32Pin);
}

/**
 * @brief       Disable GPIO interrupt
 *
 * @param[in]   gpio        GPIO port. It could be \ref P0, \ref P1, \ref P2.
 * @param[in]   u32Pin      The pin of specified GPIO port. It could be 0 ~ 2.
 *
 * @return      None
 *
 * @details     This function is used to enable specified GPIO pin interrupt.
 */
__STATIC_INLINE void GPIO_DisableInt(GPIO_T *gpio, uint32_t u32Pin)
{
    gpio->INTTYPE &= ~(1UL << u32Pin);
    gpio->INTEN &= ~((0x00010001UL) << u32Pin);
}

/**
 * @brief       Set GPIO dirver ability
 *
 * @param[in]   gpio        GPIO port. It could be \ref P0, \ref P1, \ref P2.
 * @param[in]   port        The pin of specified GPIO port. It could be 0 ~ 2.
 * @param[in]   driverAbility  Driver ability selection. \ref GPIO_DRIVER_ABILITY
 *
 * @return      None
 *
 * @details     This function is used to set gpio dirver ability.
 */
__STATIC_INLINE void GPIO_SetDriverAbility(GPIO_T *gpio, uint8_t port, GPIO_DriverAbilityDef driverAbility)
{
	GPIO_DB->DBCTL = (GPIO_DB->DBCTL & ~(0x3 << (16 + (port << 1)))) | (driverAbility << (16 + (port << 1)));
}


/**
 * @brief       Enable External GPIO interrupt 0
 *
 * @param[in]   gpio            GPIO port. It could be \ref P0, \ref P1, \ref P2.
 * @param[in]   u32Pin          The pin of specified GPIO port.
 * @param[in]   u32IntAttribs   The interrupt attribute of specified GPIO pin. It could be \n
 *                              - \ref GPIO_INT_RISING, \ref GPIO_INT_FALLING, \ref GPIO_INT_BOTH_EDGE, \ref GPIO_INT_HIGH, \ref GPIO_INT_LOW.
 *
 * @return      None
 *
 * @details     This function is used to enable specified GPIO pin interrupt.
 */
#define GPIO_EnableEINT0    GPIO_EnableInt


/**
 * @brief       Disable External GPIO interrupt 0
 *
 * @param[in]   gpio        GPIO port. It could be \ref P0, \ref P1, \ref P2.
 * @param[in]   u32Pin      The pin of specified GPIO port. It could be 0 ~ 2.
 *
 * @return      None
 *
 * @details     This function is used to enable specified GPIO pin interrupt.
 */
#define GPIO_DisableEINT0   GPIO_DisableInt


/**
 * @brief       Enable External GPIO interrupt 1
 *
 * @param[in]   gpio            GPIO port. It could \ref P0, \ref P1, \ref P2.
 * @param[in]   u32Pin          The pin of specified GPIO port.
 * @param[in]   u32IntAttribs   The interrupt attribute of specified GPIO pin. It could be \n
 *                              - \ref GPIO_INT_RISING, \ref GPIO_INT_FALLING, \ref GPIO_INT_BOTH_EDGE, \ref GPIO_INT_HIGH, \ref GPIO_INT_LOW.
 *
 * @return      None
 *
 * @details     This function is used to enable specified GPIO pin interrupt.
 */
#define GPIO_EnableEINT1    GPIO_EnableInt


/**
 * @brief       Disable External GPIO interrupt 1
 *
 * @param[in]   gpio        GPIO port. It could be \ref P0, \ref P1, \ref P2.
 * @param[in]   u32Pin      The pin of specified GPIO port. It could be 0 ~ 2.
 *
 * @return      None
 *
 * @details     This function is used to enable specified GPIO pin interrupt.
 */
#define GPIO_DisableEINT1   GPIO_DisableInt


/**
 * @brief       Set GPIO Work Mode
 *
 * @param[in]   gpio        GPIO port. It could be \ref P0, \ref P1, \ref P2.
 * @param[in]   PinMask  		The single or multiple pins of specified GPIO port. \ref BIT0, \ref BIT1, \ref BIT2,.. \ref BIT7.
 * @param[in]   Mode        Gpio mode definitions (see @ref GPIO_ModeDef).
 *
 * @retval      None
 *
 * @details     Set the GPIO pin work mode.
 */
extern void GPIO_SetMode(GPIO_T *gpio, uint32_t PinMask, GPIO_ModeDef Mode);

/**@} */


#ifdef __cplusplus
}
#endif

#endif //__PAN_GPIO_H__

/*** (C) COPYRIGHT 2023 Panchip Technology Corp. ***/
