Newer
Older
mbed-os / targets / TARGET_TOSHIBA / TARGET_TMPM4GR / Periph_driver / src / txz_i2c.c
@Jay Sridharan Jay Sridharan on 31 Dec 2022 12 KB Merge upstream changes into mbed-ce (#117)
/**
 *******************************************************************************
 * @file    txz_i2c.c
 * @brief   This file provides API functions for I2C Class.
 * @version V1.0.0
 *
 * DO NOT USE THIS SOFTWARE WITHOUT THE SOFTWARE LICENSE AGREEMENT.
 *
 * Copyright(C) Toshiba Electronic Device Solutions Corporation 2021
  * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *******************************************************************************
 */

#ifdef __cplusplus
extern "C" {
#endif

/*------------------------------------------------------------------------------*/
/*  Includes                                                                    */
/*------------------------------------------------------------------------------*/
#include "txz_i2c.h"

#if defined(__I2C_H)

/**
 *  @addtogroup Example
 *  @{
 */

/**
 *  @addtogroup UTILITIES
 *  @{
 */
/*------------------------------------------------------------------------------*/
/*  Macro Function                                                              */
/*------------------------------------------------------------------------------*/
/**
 *  @addtogroup UTILITIES_Private_macro
 *  @{
 */

/* no define */

/**
 *  @}
 */ /* End of group UTILITIES_Private_macro */

/*------------------------------------------------------------------------------*/
/*  Configuration                                                               */
/*------------------------------------------------------------------------------*/
/**
 *  @addtogroup UTILITIES_Private_define
 *  @{
 */

/* no define */

/**
 *  @}
 */ /* End of group UTILITIES_Private_define */

/*------------------------------------------------------------------------------*/
/*  Macro Definition                                                            */
/*------------------------------------------------------------------------------*/
/**
 *  @addtogroup UTILITIES_Private_define
 *  @{
 */

/**
 *  @}
 */ /* End of group UTILITIES_Private_define */

/*------------------------------------------------------------------------------*/
/*  Enumerated Type Definition                                                  */
/*------------------------------------------------------------------------------*/
/**
 *  @addtogroup UTILITIES_Private_define
 *  @{
 */

/* no define */

/**
 *  @}
 */ /* End of group UTILITIES_Private_define */

/*------------------------------------------------------------------------------*/
/*  Structure Definition                                                        */
/*------------------------------------------------------------------------------*/
/**
 *  @addtogroup UTILITIES_Private_typedef
 *  @{
 */

/* no define */

/**
 *  @}
 */ /* End of group UTILITIES_Private_typedef */

/*------------------------------------------------------------------------------*/
/*  Private Member                                                              */
/*------------------------------------------------------------------------------*/
/**
 *  @addtogroup UTILITIES_Private_variables
 *  @{
 */

/* no define */

/**
 *  @}
 */ /* End of group UTILITIES_Private_variables */

/*------------------------------------------------------------------------------*/
/*  Const Table                                                                 */
/*------------------------------------------------------------------------------*/
/**
 *  @addtogroup UTILITIES_Private_const
 *  @{
 */
/*----------------------------------*/
/**
 * @brief   SCK Divider value table.
 * @details SCK  = b000 - b111.
 * @note    NFSEL=0 (Digital Setting) Divider value.
*/
/*----------------------------------*/
static const uint32_t I2C_SCK_DIVIDER_TBL[8] = { 20, 24, 32, 48, 80, 144, 272, 528 };
static const uint32_t I2C_SCK_LOW_MUL_TBL[8] = { 12, 14, 18, 26, 42, 74, 138, 266 };

/**
 *  @}
 */ /* End of group UTILITIES_Private_const */

/*------------------------------------------------------------------------------*/
/*  Private Function                                                            */
/*------------------------------------------------------------------------------*/
/**
 *  @addtogroup UTILITIES_Private_functions
 *  @{
 */

/* no define */

/**
 *  @}
 */ /* End of group UTILITIES_Private_functions */

/*------------------------------------------------------------------------------*/
/*  Public Function                                                             */
/*------------------------------------------------------------------------------*/
/**
 *  @addtogroup UTILITIES_Private_functions
 *  @{
 */

/*--------------------------------------------------*/
/**
  * @brief     Initializing I2C Regester
  * @param     p_obj       :I2C object.
  * @retval    -
  * @note      -
  */
/*--------------------------------------------------*/
void I2C_init(I2C_t *p_obj)
{
    /*------------------------------*/
    /*  Parameter Check             */
    /*------------------------------*/
#ifdef __DEBUG__
    assert_param(IS_POINTER_NOT_NULL(p_obj));
    assert_param(IS_POINTER_NOT_NULL(p_obj->p_instance));
#endif /* #ifdef __DEBUG__ */
    p_obj->p_instance->CR2 = I2CxCR2_I2CM_ENABLE;
    p_obj->p_instance->OP  = I2CxOP_INIT;
    p_obj->p_instance->CR1 = (I2CxCR1_ACK | I2CxCR1_NOACK | p_obj->init.clock.sck);
    p_obj->p_instance->AR  = I2CxAR_INIT;
    p_obj->p_instance->AR2 = I2CxAR2_INIT;
    p_obj->p_instance->CR2 = I2CxCR2_INIT;
    p_obj->p_instance->PRS = (I2CxPRS_PRCK & p_obj->init.clock.prsck);
    p_obj->p_instance->IE  = I2CxIE_CLEAR;
}

/*--------------------------------------------------*/
/**
  * @brief     Generate start condition
  * @param     p_obj       :I2C object.
  * @param     data        :Slave address.
  * @retval    -
  * @note      -
  */
/*--------------------------------------------------*/
void I2C_start_condition(I2C_t *p_obj, uint32_t data)
{
    __IO uint32_t opreg;

    /*------------------------------*/
    /*  Parameter Check             */
    /*------------------------------*/
#ifdef __DEBUG__
    assert_param(IS_POINTER_NOT_NULL(p_obj));
    assert_param(IS_POINTER_NOT_NULL(p_obj->p_instance));
#endif /* #ifdef __DEBUG__ */

    opreg = p_obj->p_instance->OP;
    opreg &= ~(I2CxOP_RSTA | I2CxOP_SREN);
    if (I2C_master(p_obj)) {
        if ((p_obj->p_instance->SR & I2CxSR_BB)) {
            opreg |= I2CxOP_SREN;
        }
    }
    p_obj->p_instance->CR1 = (I2CxCR1_ACK | I2CxCR1_NOACK | p_obj->init.clock.sck);
    p_obj->p_instance->OP  = opreg;
    p_obj->p_instance->DBR = (data & I2CxDBR_DB_MASK);
    p_obj->p_instance->CR2 = I2CxCR2_START_CONDITION;
}

/*--------------------------------------------------*/
/**
  * @brief     Return the I2c clock setting
  * @param     p_obj       :I2C object.
  * @param     frequency   :Maximum frequency.
  * @param     fsys        :SystemCoreClock.
  * @param     p_setting   :Clock data pointer.
  * @retval    Non-zero    :Scl frequency.
  * @retval    0           :Error.
  * @note      -
  */
/*--------------------------------------------------*/
uint32_t I2C_get_clock_setting(I2C_t *p_obj, uint32_t frequency, uint32_t fsys, I2C_clock_setting_t *p_setting)
{
    uint32_t result = 0;

    /*------------------------------*/
    /*  Parameter Check             */
    /*------------------------------*/
#ifdef __DEBUG__
    assert_param(IS_POINTER_NOT_NULL(p_obj));
    assert_param(IS_POINTER_NOT_NULL(p_obj->p_instance));
    assert_param(IS_POINTER_NOT_NULL(p_setting));
#endif /* #ifdef __DEBUG__ */

    if (frequency <= 1000000) {
        uint64_t sck, tmp_sck;
        uint64_t prsck, tmp_prsck;
        uint64_t fscl, tmp_fscl;
        uint64_t fx;
        uint64_t max_fx, min_fx;
        uint64_t low_width, low_width_min;

        sck   = tmp_sck   = 0;
        prsck = tmp_prsck = 1;
        fscl  = tmp_fscl  = 0;

        if (frequency <= 400000) {
            max_fx = 11428572U;     /* Tpresck: 87.5ns 1/87.5 = 0.0114285714 */
            min_fx =  6666666U;     /* Tpresck:150.0ns 1/150  = 0.0066666667 */
            low_width_min = 1600;
        } else {
            max_fx = 26666667U;     /* Tpresck:37.5ns 1/37.5  = 0.0266666667 */
            min_fx = 15384615U;     /* Tpresck:65.0ns 1/65    = 0.0153846154 */
            low_width_min = 675;
        }
        for (prsck = 1; prsck <= 32; prsck++) {
            fx = ((uint64_t)fsys / prsck);

            if ((fx < max_fx) && (fx >= min_fx)) {
                for (sck = 0; sck <= 7; sck++) {
                    low_width = (uint64_t)(1000000000 * prsck * I2C_SCK_LOW_MUL_TBL[sck]) / fsys;
                    if (low_width < low_width_min) {
                        continue;
                    }
                    fscl = (fx / (uint64_t)I2C_SCK_DIVIDER_TBL[sck]);

                    if ((fscl <= frequency) && (fscl > tmp_fscl)) {
                        tmp_fscl = fscl;
                        tmp_sck = sck;
                        tmp_prsck = (prsck < 32) ? prsck : 0;
                    }
                }
            }
        }
        result = (uint32_t)tmp_fscl;
        p_setting->sck = (uint32_t)tmp_sck;
        p_setting->prsck = (tmp_prsck < 32) ? (uint32_t)tmp_prsck : 0;
    } else {
        result = 0;
    }
    return (result);
}

/*--------------------------------------------------*/
/**
  * @brief     Slave mode setting.
  * @param     p_obj       :I2C object.
  * @retval    -
  * @note      -
  */
/*--------------------------------------------------*/
void I2C_slave_init(I2C_t *p_obj)
{
    /*------------------------------*/
    /*  Parameter Check             */
    /*------------------------------*/
#ifdef __DEBUG__
    assert_param(IS_POINTER_NOT_NULL(p_obj));
    assert_param(IS_POINTER_NOT_NULL(p_obj->p_instance));
#endif /* #ifdef __DEBUG__ */

    p_obj->p_instance->OP  = I2CxOP_SLAVE_INIT;
    p_obj->p_instance->CR1 = (I2CxCR1_ACK | p_obj->init.clock.sck);
    p_obj->p_instance->CR2 = (I2CxCR2_INIT | I2CxCR2_PIN_CLEAR);
    p_obj->p_instance->CR2 = I2CxCR2_INIT;
    p_obj->p_instance->PRS = (I2CxPRS_PRCK & p_obj->init.clock.prsck);
}
#if defined(I2CSxWUP_EN)
/*--------------------------------------------------*/
/**
  * @brief     I2C Wakeup Control setting.
  * @param     p_obj       :I2CS object.
  * @retval    -
  * @note      -
  */
/*--------------------------------------------------*/
void I2CS_init(I2CS_t *p_obj)
{
    /*------------------------------*/
    /*  Parameter Check             */
    /*------------------------------*/
#ifdef __DEBUG__
    assert_param(IS_POINTER_NOT_NULL(p_obj));
    assert_param(IS_POINTER_NOT_NULL(p_obj->p_instance));
#endif /* #ifdef __DEBUG__ */

    p_obj->p_instance->WUPCR1 = (p_obj->init.wup.sgcdi | p_obj->init.wup.ack | p_obj->init.wup.reset | p_obj->init.wup.intend);
}

/*--------------------------------------------------*/
/**
  * @brief     Primary Slave Address setting.
  * @param     p_obj       :I2CS object.
  * @param     addr        :Primary Slave Address.
  * @retval    -
  * @note      -
  */
/*--------------------------------------------------*/
void I2CS_Primary_slave_adr_set(I2CS_t *p_obj, uint32_t adr)
{
    /*------------------------------*/
    /*  Parameter Check             */
    /*------------------------------*/
#ifdef __DEBUG__
    assert_param(IS_POINTER_NOT_NULL(p_obj));
    assert_param(IS_POINTER_NOT_NULL(p_obj->p_instance));
#endif /* #ifdef __DEBUG__ */

    p_obj->p_instance->WUPCR2 = (0x0000000E & adr);
}

/*--------------------------------------------------*/
/**
  * @brief     Secondary Slave Address setting.
  * @param     p_obj       :I2CS object.
  * @param     addr        :Secondary Slave Address.
  * @retval    -
  * @note      -
  */
/*--------------------------------------------------*/
void I2CS_Secondary_slave_adr_set(I2CS_t *p_obj, uint32_t adr)
{
    /*------------------------------*/
    /*  Parameter Check             */
    /*------------------------------*/
#ifdef __DEBUG__
    assert_param(IS_POINTER_NOT_NULL(p_obj));
    assert_param(IS_POINTER_NOT_NULL(p_obj->p_instance));
#endif /* #ifdef __DEBUG__ */

    p_obj->p_instance->WUPCR3 = (0x0000000E & adr);
    p_obj->p_instance->WUPCR3 |= 0x00000001;        /* WUPSA2EN: Secondary Slave Address Use Setting */
}
#endif
/**
 *  @}
 */ /* End of group UTILITIES_Private_functions */

/**
 *  @}
 */ /* End of group UTILITIES */

/**
 *  @}
 */ /* End of group Example */

#endif /* defined(__I2C_H)  */

#ifdef __cplusplus
}
#endif /* __cplusplus */