/*
*************************************************************
 Copyright (C), 2016-2020 smartlinkMicro. Co., Ltd.  All rights reserved.
 Filename:
 Complier:      ARM-MDK 5.xx
 Target OS:
 Target HW:
 Author:        rpliu
 Version :      V1.0.0
 Date:          2019.4.12
 Description:
 History:
     <author>     <time>     <version >   <desc>

*************************************************************
*/
#include "utilities.h"
#include "iic.h"

//#include "slm_type.h"
//#include "sl2x23.h"

volatile uint32_t SL2x23_Timeout;

/**
  * @brief  DeInitializes peripherals used by the I2C driver.
  * @param  None
  * @retval None
  */
void SL2x23_I2C_DeInit(void)
{
  SL2x23_I2C_LowLevel_DeInit(); 
}

void SL2x23_I2C_Init(void)
{
    I2C_InitTypeDef I2C_InitStructure;

    SL2x23_I2C_LowLevel_Init();

    /* SL2x23_I2C configuration */
    I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
    I2C_InitStructure.I2C_AnalogFilter = I2C_AnalogFilter_Enable;
    I2C_InitStructure.I2C_DigitalFilter = 0x00;
    I2C_InitStructure.I2C_OwnAddress1 = 0x00;
    I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
    I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
    I2C_InitStructure.I2C_Timing = SL2x23_I2C_TIMING;

    /* Apply SL2x23_I2C configuration after enabling it */
    I2C_Init(SL2x23_I2C, &I2C_InitStructure);

    /* SL2x23_I2C Peripheral Enable */
    I2C_Cmd(SL2x23_I2C, ENABLE);
}
 
/**
  * @brief  DeInitializes peripherals used by the I2C driver.
  * @param  None
  * @retval None
  */
void SL2x23_I2C_LowLevel_DeInit(void)
{
  GPIO_InitTypeDef  GPIO_InitStructure; 
   
  /* SL2x23_I2C Peripheral Disable */
  I2C_Cmd(SL2x23_I2C, DISABLE);
 
  /* SL2x23_I2C DeInit */
  I2C_DeInit(SL2x23_I2C);

  /* SL2x23_I2C Periph clock disable */
  RCC_APB1PeriphClockCmd(SL2x23_I2C_CLK, DISABLE);
    
  /* GPIO configuration */  
  /* Configure SL2x23_I2C pins: SCL */
  GPIO_InitStructure.GPIO_Pin = SL2x23_I2C_SCL_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_Init(SL2x23_I2C_SCL_GPIO_PORT, &GPIO_InitStructure);

  /* Configure SL2x23_I2C pins: SDA */
  GPIO_InitStructure.GPIO_Pin = SL2x23_I2C_SDA_PIN;
  GPIO_Init(SL2x23_I2C_SDA_GPIO_PORT, &GPIO_InitStructure);
}

/**
  * @brief  Initializes the I2C source clock and IOs used to drive the SL2x23.
  * @param  None
  * @retval None
  */
void SL2x23_I2C_LowLevel_Init(void)
{
  GPIO_InitTypeDef  GPIO_InitStructure;
  
  /* Configure the I2C clock source. The clock is derived from the HSI */
  RCC_I2CCLKConfig(RCC_I2C1CLK_HSI);
    
  /* SL2x23_I2C_SCL_GPIO_CLK and SL2x23_I2C_SDA_GPIO_CLK Periph clock enable */
  RCC_AHBPeriphClockCmd(SL2x23_I2C_SCL_GPIO_CLK | SL2x23_I2C_SDA_GPIO_CLK, ENABLE);
  
  /* SL2x23_I2C Periph clock enable */
  RCC_APB1PeriphClockCmd(SL2x23_I2C_CLK, ENABLE);
  
  /* Connect PXx to I2C_SCL*/
  GPIO_PinAFConfig(SL2x23_I2C_SCL_GPIO_PORT, SL2x23_I2C_SCL_SOURCE, SL2x23_I2C_SCL_AF);
  
  /* Connect PXx to I2C_SDA*/
  GPIO_PinAFConfig(SL2x23_I2C_SDA_GPIO_PORT, SL2x23_I2C_SDA_SOURCE, SL2x23_I2C_SDA_AF);
  
  /* GPIO configuration */  
  /* Configure SL2x23_I2C pins: SCL */
  GPIO_InitStructure.GPIO_Pin = SL2x23_I2C_SCL_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_Init(SL2x23_I2C_SCL_GPIO_PORT, &GPIO_InitStructure);
  
  /* Configure SL2x23_I2C pins: SDA */
  GPIO_InitStructure.GPIO_Pin = SL2x23_I2C_SDA_PIN;
  GPIO_Init(SL2x23_I2C_SDA_GPIO_PORT, &GPIO_InitStructure);
}

/**
  * @brief  Basic management of the timeout situation.
  * @param  None.
  * @retval 0.
  */
uint32_t SL2x23_TIMEOUT_UserCallback(void)
{
    /* The following code allows I2C error recovery and return to normal communication
       if the error source doesnĄ¯t still exist (ie. hardware issue..) */
    
    /* Reinitialize all resources */
    SL2x23_I2C_DeInit();
    SL2x23_I2C_Init();

    /* At this stage the I2C error should be recovered and device can communicate
       again (except if the error source still exist).
       User can implement mechanism (ex. test on max trial number) to manage situation
       when the I2C can't recover from current error. */
    
    return 0;
}

uint32_t i2c_write_word(uint8_t i2c_dev_addr, uint8_t reg_addr, uint8_t reg_value)
{
    I2C_TransferHandling(SL2x23_I2C, i2c_dev_addr, 2, I2C_AutoEnd_Mode, I2C_Generate_Start_Write);

    /* Wait until TXIS flag is set */
    SL2x23_Timeout = SL2x23_LONG_TIMEOUT;
    while(I2C_GetFlagStatus(SL2x23_I2C, I2C_ISR_TXIS) == RESET)
    {
        if((SL2x23_Timeout--) == 0) return SL2x23_TIMEOUT_UserCallback();
    }
    
    /* Send register address */
    I2C_SendData(SL2x23_I2C, reg_addr);  
    
    /* Wait until TXIS flag is set */
    SL2x23_Timeout = SL2x23_LONG_TIMEOUT;
    while(I2C_GetFlagStatus(SL2x23_I2C, I2C_ISR_TXIS) == RESET)
    {
        if((SL2x23_Timeout--) == 0) return SL2x23_TIMEOUT_UserCallback();
    }
    
    /* Send register value  */
    I2C_SendData(SL2x23_I2C, reg_value);
  
    /* Wait until STOPF flag is set */
    SL2x23_Timeout = SL2x23_LONG_TIMEOUT;
    while(I2C_GetFlagStatus(SL2x23_I2C, I2C_ISR_STOPF) == RESET)
    {
        if((SL2x23_Timeout--) == 0) return SL2x23_TIMEOUT_UserCallback();
    }   
    
    /* Clear STOPF flag */
    I2C_ClearFlag(SL2x23_I2C, I2C_ICR_STOPCF);
    
    /* If all operations OK, return (0) */
    return 0;
}

uint8_t i2c_read_word(uint8_t i2c_dev_addr, uint8_t reg_addr, uint8_t *reg_value)
{
    I2C_TransferHandling(SL2x23_I2C, i2c_dev_addr, 1, I2C_SoftEnd_Mode, I2C_Generate_Start_Write);

    /* Wait until TXIS flag is set */
    SL2x23_Timeout = SL2x23_LONG_TIMEOUT;
    while(I2C_GetFlagStatus(SL2x23_I2C, I2C_ISR_TXIS) == RESET)
    {
        if((SL2x23_Timeout--) == 0) return SL2x23_TIMEOUT_UserCallback();
    }
    
    /* Send register address */
    I2C_SendData(SL2x23_I2C, reg_addr);  

    /* Wait until TC flag is set */
    SL2x23_Timeout = SL2x23_LONG_TIMEOUT;
    while(I2C_GetFlagStatus(SL2x23_I2C, I2C_ISR_TC) == RESET)
    {
        if((SL2x23_Timeout--) == 0) return SL2x23_TIMEOUT_UserCallback();
    }  
    
    /* Configure slave address, end mode and start condition */
    I2C_TransferHandling(SL2x23_I2C, i2c_dev_addr, 1, I2C_AutoEnd_Mode, I2C_Generate_Start_Read);

    /* Wait until RXNE flag is set */
    SL2x23_Timeout = SL2x23_LONG_TIMEOUT;
    while(I2C_GetFlagStatus(SL2x23_I2C, I2C_ISR_RXNE) == RESET)
    {
        if((SL2x23_Timeout--) == 0) return SL2x23_TIMEOUT_UserCallback();
    }
    
    /* Read data from RXDR */
    *reg_value = I2C_ReceiveData(SL2x23_I2C);

    /* If all operations OK, return (0) */
    return 0;
}

//endfile
