/*******************************************************************************
 * DISCLAIMER
 * This software is supplied by Renesas Electronics Corporation and is only
 * intended for use with Renesas products. No other uses are authorized. This
 * software is owned by Renesas Electronics Corporation and is protected under
 * all applicable laws, including copyright laws.
 * THIS SOFTWARE IS PROVIDED "AS IS" AND RENESAS MAKES NO WARRANTIES REGARDING
 * THIS SOFTWARE, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING BUT NOT
 * LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
 * AND NON-INFRINGEMENT. ALL SUCH WARRANTIES ARE EXPRESSLY DISCLAIMED.
 * TO THE MAXIMUM EXTENT PERMITTED NOT PROHIBITED BY LAW, NEITHER RENESAS
 * ELECTRONICS CORPORATION NOR ANY OF ITS AFFILIATED COMPANIES SHALL BE LIABLE
 * FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES FOR
 * ANY REASON RELATED TO THIS SOFTWARE, EVEN IF RENESAS OR ITS AFFILIATES HAVE
 * BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 * Renesas reserves the right, without notice, to make changes to this software
 * and to discontinue the availability of this software. By using this software,
 * you agree to the additional terms and conditions found by accessing the
 * following link:
 * http://www.renesas.com/disclaimer
 * Copyright 2021-2022 Renesas Electronics Corporation All rights reserved.
 *******************************************************************************/

/*******************************************************************************
 * DESCRIPTION   : Time wait driver
 ******************************************************************************/
/******************************************************************************
 * @file          micro_wait.c
 * - Version      : 0.03
 * @brief         Wait of micro second
 * .
 *****************************************************************************/
/******************************************************************************
 * History : DD.MM.YYYY Version  Description
 *         : 28.07.2021 0.01     First Release
 *         : 15.10.2021 0.02     modify register access to read modify write.
 *         : 03.12.2021 0.03     fix incorrect configuration process.
 *****************************************************************************/

#include <stdint.h>
#include <micro_wait.h>
#include <mem_io.h>

/************************************************************************************************/
/*  Definitions                                                                                 */
/************************************************************************************************/

#define INTICUOSTM0     (0xFFFEEA14U)
#define INTCR_RF        ((uint16_t)1U << 12U)
#define INTCR_RF_NO_REQ ((uint16_t)0U << 12U)

#define OSTM0_BASE      (0xFFFEE000U)
#define OSTM0CMP        (OSTM0_BASE)
#define OSTM0TS         (OSTM0_BASE + 0x0014U)
#define OSTM0TT         (OSTM0_BASE + 0x0018U)
#define OSTM0CTL        (OSTM0_BASE + 0x0020U)

#define OSTM0TS_TS              (uint8_t)(0x01U)    /* b0:1: Start  */
#define OSTM0TT_TT              (uint8_t)(0x01U)    /* b0:1: Stop   */
#define OSTM0CMP_MICRO_VALUE    (0x00000190U)       /* PCLK=400MHz(400=0x190 = 1us) */

#define OSTM0CTL_MD10           (uint8_t)(0x02U)    /* b1:1: Free-run compare mode(Start:0 Counting Direction:up)   */
                                                    /* b0:0: Interrupts when counting starts are enabled        */

#define MAX_MICRO_WAIT          (10737418U)         /* 0xFFFFFFFF / 400 */

void micro_wait(uint32_t count_us)
{
    uint32_t val;
    uint16_t reg16;
    uint8_t reg8;

    if (count_us != 0U)
    {
        /* When the timer count is an argument that exceeds 0xFFFFFFFF */
        if(MAX_MICRO_WAIT < count_us)
        {
            count_us = MAX_MICRO_WAIT;
        }
        val = count_us * OSTM0CMP_MICRO_VALUE;
        /* timer start */
        reg8 = mem_read8(OSTM0TT);
        reg8 |= OSTM0TT_TT;
        mem_write8(OSTM0TT, reg8);
        mem_write32(OSTM0CMP, val);
        reg8 = mem_read8(OSTM0CTL);
        reg8 |= OSTM0CTL_MD10;
        mem_write8(OSTM0CTL, reg8);
        reg8 = mem_read8(OSTM0TS);
        reg8 |= OSTM0TS_TS;
        mem_write8(OSTM0TS, reg8);

        while (1)
        {
            reg16 = mem_read16(INTICUOSTM0);
            if ((reg16 & (INTCR_RF)) != INTCR_RF_NO_REQ)
            {
                /* timer stop */
                reg16 = (reg16 & (uint16_t)(~(INTCR_RF)));
                mem_write16(INTICUOSTM0, reg16);
                reg8 = mem_read8(OSTM0TT);
                reg8 |= OSTM0TT_TT;
                mem_write8(OSTM0TT, reg8);
                break;
            }
        }
    }
}
/* End of function micro_wait(uint32_t count_us) */
