
/******************************************************************************
*@file  : spl_gpio.c
*@brief : GPIO SPL module driver.
******************************************************************************/

#include "acm32g103_spl_conf.h" 

//#ifdef SPL_GPIO_MODULE_ENABLED

/******************************************************************************
*@brief : Initializes the GPIOx peripheral according to the specified parameters
*         in the GPIO_Init.
*@param : GPIOx: where x can be (A..F) to select the GPIO peripheral.
*@param : GPIO_Init: pointer to an GPIO_InitTypeDef structure that contains 
*         the configuration information for the specified GPIO peripheral.
*@return: None
******************************************************************************/
void GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init)
{
    uint32_t position;
    uint32_t currentPin;
    uint32_t temp;
    
    /* Check the parameters */
    assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
    assert_param(IS_GPIO_ALL_PIN(GPIOx, GPIO_Init->Pin));
    assert_param(IS_GPIO_MODE(GPIO_Init->Mode));
    assert_param(IS_GPIO_PULL(GPIO_Init->Pull));

    /* Configure Select pins */
    position = 0;
    while ((GPIO_Init->Pin) >> position != 0) 
    {
        /* Get current pin position */
        currentPin = (GPIO_Init->Pin) & (1U << position);
        
        if (currentPin) 
        {
            if (GPIOx == GPIOC)
            {
                if (currentPin == GPIO_PIN_13)
                {
                    __RCC_PMU_CLK_ENABLE();
                    PMU->IOSEL &= ~PMU_IOSEL_PC13_SEL_Msk;
                }
                if (currentPin == GPIO_PIN_14)
                {
                    __RCC_PMU_CLK_ENABLE();
                    PMU->IOSEL &= ~PMU_IOSEL_PC14_SEL_Msk;
                }
                if (currentPin == GPIO_PIN_15)
                {
                    __RCC_PMU_CLK_ENABLE();
                    PMU->IOSEL &= ~PMU_IOSEL_PC15_SEL_Msk;
                }
            }
            
            
            if (GPIO_Init->Mode == GPIO_MODE_ANALOG)
			{
                GPIOx->OTYP &= ~(0x01U << position);
                GPIOx->PUPD  &= ~(0x3U << (position << 1U));
                GPIOx->SMIT &= ~(0x01U << position);
                if (position < 8U) 
                {
                    GPIOx->AF0 &= ~(0xFU << (position << 2U));
                    GPIOx->DS0 &= ~(0xFU << (position << 2U));
                }
                else
                {
                    GPIOx->AF1 &= ~(0xFU << ((position - 8U) << 2U));
                    GPIOx->DS1 &= ~(0xFU << ((position - 8U) << 2U));
                }
                
				GPIOx->AIEN |= 0x01U << position;
            }
            else
            {
                GPIOx->AIEN &= ~(0x01U << position);
                /* Alternate Function */
                if ((GPIO_Init->Mode == GPIO_MODE_AF_PP) || (GPIO_Init->Mode == GPIO_MODE_AF_OD))
                {
                    /* Check the Alternate function parameters */
                    assert_param(IS_GPIO_FUNCTION(GPIO_Init->Alternate));
           
                    /* Configure Alternate function mapped with the current IO */
                    if (position < 8U) 
                    {
                        temp = GPIOx->AF0;
                        temp &= ~(0xFU << (position << 2U));
                        temp |= GPIO_Init->Alternate << (position << 2U);
                        GPIOx->AF0 = temp;
                    }
                    else 
                    {
                        temp = GPIOx->AF1;
                        temp &= ~(0xFU << ((position - 8U) << 2U));
                        temp |= GPIO_Init->Alternate << ((position - 8U) << 2U);
                        GPIOx->AF1 = temp;
                    }
                }
                else
                {
                    if (position < 8U) 
                        GPIOx->AF0 &= ~(0xFU << (position << 2U));
                    else
                        GPIOx->AF1 &= ~(0xFU << ((position - 8U) << 2U));
                }
                /* In case of Output or Alternate function mode selection */
                if (GPIO_Init->Mode == GPIO_MODE_INPUT)
                {
                    GPIOx->OTYP &= ~(0x01U << position) ;
                    if (position < 8U) 
                        GPIOx->DS0 &= ~(0xFU << (position << 2U));
                    else
                        GPIOx->DS1 &= ~(0xFU << ((position - 8U) << 2U));
                    /* Configure schmitt input */
                    GPIOx->SMIT |= 0x01U << position;
                }
                else
                {
                    /* Configure schmitt input */
                    GPIOx->SMIT &= ~(0x01U << position);
                
                    /* Check the drive parameter */
                    assert_param(IS_GPIO_DRIVE(GPIO_Init->Drive));
                    
                    /* Configure the IO drive capability */
                    if (position < 8U) 
                    {
                        temp = GPIOx->DS0;
                        temp &= ~(0xFU << (position << 2U));
                        temp |= (GPIO_Init->Drive << (position << 2U));
                        GPIOx->DS0 = temp;
                    }
                    else
                    {
                        temp = GPIOx->DS1;
                        temp &= ~(0xFU << ((position - 8U) << 2U));
                        temp |= (GPIO_Init->Drive << ((position - 8U) << 2U));
                        GPIOx->DS1 = temp;
                    }

                    /* Configure the IO Output Type */
                    temp = GPIOx->OTYP;
                    temp &= ~(0x01U << position) ;
                    temp |= (((GPIO_Init->Mode & GPIO_MODE_GPIO_OUTPUT_TYPE_MASK) >> 4U) << position);
                    GPIOx->OTYP = temp;
                }
                
                /* Activate the Pull-up or Pull down resistor for the current IO */
                temp = GPIOx->PUPD;
                temp &= ~(0x3U << (position << 1U));
                temp |= ((GPIO_Init->Pull) << (position << 1U));
                GPIOx->PUPD = temp;
            }
			
            /* Configure IO Direction mode (Input, Output, Alternate or Analog) */
            temp = GPIOx->MD;
            temp &= ~(0x03U << (position << 1U));
            temp |= ((GPIO_Init->Mode & GPIO_MODE_GPIO_MASK) << (position << 1U));
            GPIOx->MD = temp;
        }
        position++;
    }
}

/******************************************************************************
*@brief : De-initializes the GPIOx peripheral registers to their default reset values.
*@param : GPIOx: where x can be (A..F) to select the GPIO peripheral.
*@param : GPIO_Pin: specifies the port bit to be written.
*@return: None
******************************************************************************/
void GPIO_DeInit(GPIO_TypeDef *GPIOx, uint32_t GPIO_Pin)
{
    uint32_t position = 0;
    uint32_t currentPin;
    
    /* Check the parameters */
    assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
    assert_param(IS_GPIO_ALL_PIN(GPIOx, GPIO_Pin));
    
    /* Configure Select pins */
    while (GPIO_Pin >> position != 0U) 
    {
        /* Get current pin position */
        currentPin = GPIO_Pin & (1UL << position);
        
        if (currentPin) 
        {
            /* SET GPIO Function */
            if (position < 8U) 
            {
                GPIOx->AF0 &= ~(0xFU << (position << 2U));
                GPIOx->DS0 &= ~(0xFU << (position << 2U));
            }
            else 
            {
                GPIOx->AF1 &= ~(0xFU << ((position - 8U) << 2U));
                GPIOx->DS1 &= ~(0xFU << ((position - 8U) << 2U));
            }

            /* Deactivate the Pull-up and Pull-down resistor for the current IO */
            GPIOx->PUPD &= ~(0x3U << (position << 1U));
            
            /* Configure the default value for output type */
            GPIOx->OTYP &= ~currentPin;
			
            /* Configure the default value for schmitt input */
			GPIOx->SMIT &= ~currentPin;
			
            /* Configure the default value for analog switch */
            GPIOx->AIEN &= ~currentPin;
            
            /* Configure IO Direction mode to Analog*/
            GPIOx->MD |= ((0x03U) << (position << 1U));
        }
        position++;
    }
}

/******************************************************************************
*@brief : Fills each GPIO_InitStruct member with its default value.
*@param : GPIO_InitStruct: pointer to a GPIO_InitTypeDef structure which will be initialized.
*@return: None
******************************************************************************/
void GPIO_StructInit(GPIO_InitTypeDef* GPIO_InitStruct)
{
    /* Check the parameters */
    assert_param(GPIO_InitStruct != NULL);
    
    /* Reset GPIO init structure parameters values */
    GPIO_InitStruct->Pin  = GPIO_ALL_PIN_MASK;
    GPIO_InitStruct->Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct->Pull = GPIO_NOPULL;
    GPIO_InitStruct->Drive = GPIO_DRIVE_LEVEL3;
    GPIO_InitStruct->Alternate = GPIO_FUNCTION_0;
}

/******************************************************************************
*@brief : Reads the specified input port pin.
*@param : GPIOx: where x can be (A..F) to select the GPIO peripheral.
*@param : GPIO_Pin: specifies the port bit to be read.
*@return: The input port pin value.
******************************************************************************/
GPIO_PinState GPIO_ReadPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
{
    /* Check the parameters */
    assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
    assert_param(IS_GPIO_SINGLE_PIN(GPIOx, GPIO_Pin));
    
    if (GPIOx->IDATA & GPIO_Pin) 
        return GPIO_PIN_SET;
    else 
        return GPIO_PIN_RESET;
}

/******************************************************************************
*@brief : Reads the specified input port.
*@param : GPIOx: where x can be (A..F) to select the GPIO peripheral.
*@return: The input port value.
******************************************************************************/
uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx)
{
    /* Check the parameters */
    assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
    
    return ((uint16_t)GPIOx->IDATA);
}

/******************************************************************************
*@brief : Reads the specified output data port bit.
*@param : GPIOx: where x can be (A..F) to select the GPIO peripheral.
*@param : GPIO_Pin: specifies the port bit to be read.
*@return: The output port pin value.
******************************************************************************/
GPIO_PinState GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
    /* Check the parameters */
    assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
    assert_param(IS_GPIO_SINGLE_PIN(GPIOx, GPIO_Pin));
    
    if (GPIOx->ODATA & GPIO_Pin)
        return GPIO_PIN_SET;
    else
        return GPIO_PIN_RESET;
}


/******************************************************************************
*@brief : Reads the specified GPIO output data port.
*@param : GPIOx: where x can be (A..F) to select the GPIO peripheral.
*@return: The output port value.
******************************************************************************/
uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx)
{
    /* Check the parameters */
    assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
    
    return ((uint16_t)GPIOx->ODATA);
}

/******************************************************************************
*@brief : Sets the selected data port bits.
*@param : GPIOx: where x can be (A..F) to select the GPIO peripheral.
*@param : GPIO_Pin: specifies the port bit to be written.
*@return: None.
******************************************************************************/
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
    /* Check the parameters */
    assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
    assert_param(IS_GPIO_ALL_PIN(GPIOx, GPIO_Pin));
    
    GPIOx->BSC = GPIO_Pin;
}

/******************************************************************************
*@brief : Clears the selected data port bits.
*@param : GPIOx: where x can be (A..F) to select the GPIO peripheral.
*@param : GPIO_Pin: specifies the port bit to be written.
*@return: None.
******************************************************************************/
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
    /* Check the parameters */
    assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
    assert_param(IS_GPIO_ALL_PIN(GPIOx, GPIO_Pin));
    
    GPIOx->BSC = GPIO_Pin << 16U;
}


/******************************************************************************
*@brief : Set or clear the selected data port bit.
*@param : GPIOx: where x can be (A..F) to select the GPIO peripheral.
*@param : GPIO_Pin: specifies the port bit to be written.
*@param : PinState: specifies the value to be written to the selected bit.
*         This parameter must be a value of @ref GPIO_PinState.
*             @arg GPIO_PIN_RESET: clear the port pin.
*             @arg GPIO_PIN_SET: set the port pin.
*@return: None
******************************************************************************/
void GPIO_WriteBit(GPIO_TypeDef *GPIOx, uint32_t GPIO_Pin, GPIO_PinState PinState)
{
    /* Check the parameters */
    assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
    assert_param(IS_GPIO_ALL_PIN(GPIOx, GPIO_Pin));
    assert_param(IS_GPIO_PIN_STATE(PinState));

    if (GPIO_PIN_RESET == PinState)
        GPIOx->BSC = GPIO_Pin << 16U;
    else
        GPIOx->BSC = GPIO_Pin;
}


/******************************************************************************
*@brief : Writes data to the specified GPIO data port.
*@param : GPIOx: where x can be (A..F) to select the GPIO peripheral.
*@param : PortVal: specifies the value to be written to the port output data register.
*@return: None
******************************************************************************/
void GPIO_Write(GPIO_TypeDef *GPIOx, uint16_t PortVal)
{
    /* Check the parameters */
    assert_param(IS_GPIO_ALL_PERIPH(GPIOx));

    GPIOx->ODATA = PortVal;
}


/******************************************************************************
*@brief : Toggle the specified GPIO pin.
*@param : GPIOx: where x can be (A..F) to select the GPIO peripheral.
*@param : GPIO_Pin: specifies the port bit to be written.
*@return: None.
******************************************************************************/
void GPIO_ToggleBits(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
{
    /* Check the parameters */
    assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
    assert_param(IS_GPIO_ALL_PIN(GPIOx, GPIO_Pin));

    if (GPIOx->ODATA & GPIO_Pin)
        GPIOx->BSC = (uint32_t)GPIO_Pin << 16;
    else
        GPIOx->BSC = GPIO_Pin;
}

/******************************************************************************
*@brief : Lock GPIO Pins configuration registers.
*@param : GPIOx: where x can be (A..F) to select the GPIO peripheral.
*@param : GPIO_Pin: specifies the port bit to be written.
*@return: None.
******************************************************************************/
void GPIO_PinLockConfig(GPIO_TypeDef *GPIOx, uint32_t GPIO_Pin)
{
    __IO uint32_t temp = GPIO_LOCK_LOCKKEY;
    
    /* Check the parameters */
    assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
    assert_param(IS_GPIO_ALL_PIN(GPIOx, GPIO_Pin));

    /* Apply lock key write sequence */
    temp |= GPIO_Pin;
    
    /* Set LOCKx bit(s): LOCKK='1' + LOCK[15-0] */
    GPIOx->LOCK = temp;
    
    /* Reset LOCKx bit(s): LOCKK='0' + LOCK[15-0] */
    GPIOx->LOCK = GPIO_Pin;
    
    /* Set LOCKx bit(s): LOCKK='1' + LOCK[15-0] */
    GPIOx->LOCK = temp;
    
    /* Read LOCK register. This read is mandatory to complete key lock sequence */
    temp = GPIOx->LOCK;
    
    temp = GPIOx->LOCK;
}

//#endif /* HAL_GPIO_MODULE_ENABLED */

/************************ (C) COPYRIGHT AISINOCHIP *****END OF FILE****/

