Newer
Older
mbed-os / targets / TARGET_Samsung / TARGET_SIDK_S5JS100 / us_ticker.c
/****************************************************************************
 *
 * Copyright 2020 Samsung Electronics All Rights Reserved.
 * 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.
 *
 ****************************************************************************/

#if DEVICE_USTICKER

#include <stddef.h>
#include "cmsis.h"
#include "us_ticker_api.h"
#include "us_ticker.h"
#include "PeripheralNames.h"

#define TIMER_TARGET_COUNT_DEFAULT    0xFFFFFFFF

uint32_t us_ticker_initialized = 0;
uint32_t g_us_last_return = 0;

void us_ticker_enable_interrupt(void);
void us_ticker_disable_interrupt(void);

const ticker_info_t *us_ticker_get_info()
{
    static const ticker_info_t info = {
        26000000,        //26Mhz
        32              //32bit counter
    };
    return &info;
}

static void enable_timer0(void)
{
    putreg32(0, S5JS100_TIMER0_BASE + S5JS100_TIMER_UP_DOWN_SEL); // Set Up count
    putreg32(TIMER_TARGET_COUNT_DEFAULT, S5JS100_TIMER0_BASE + S5JS100_TIMER_LOAD_VALUE);
    putreg32(0x1, S5JS100_TIMER0_BASE + S5JS100_TIMER_CDC_ENABLE);
    putreg32(TIMER_TARGET_COUNT_DEFAULT, S5JS100_TIMER0_BASE + S5JS100_TIMER_CDC_COUNT_VALUE);
    putreg32(0, S5JS100_TIMER0_BASE + S5JS100_TIMER_INT_SEL);
    putreg32(0, S5JS100_TIMER0_BASE + S5JS100_TIMER_INT_ENABLE);
    putreg32(3, S5JS100_TIMER0_BASE + S5JS100_TIMER_CONTROL);
}

static void disable_timer0(void)
{
    putreg32(0, S5JS100_TIMER0_BASE + S5JS100_TIMER_CONTROL);
    putreg32(0, S5JS100_TIMER0_BASE + S5JS100_TIMER_UP_DOWN_SEL);
    putreg32(TIMER_TARGET_COUNT_DEFAULT, S5JS100_TIMER0_BASE + S5JS100_TIMER_LOAD_VALUE);
    putreg32(TIMER_TARGET_COUNT_DEFAULT, S5JS100_TIMER0_BASE + S5JS100_TIMER_INT_SEL);
    putreg32(0, S5JS100_TIMER0_BASE + S5JS100_TIMER_INT_ENABLE);
    putreg32(0x0, S5JS100_TIMER0_BASE + S5JS100_TIMER_CDC_ENABLE);
    putreg32(TIMER_TARGET_COUNT_DEFAULT, S5JS100_TIMER0_BASE + S5JS100_TIMER_CDC_COUNT_VALUE);
}

static void enable_timer1(void)
{
    putreg32(0, S5JS100_TIMER1_BASE + S5JS100_TIMER_UP_DOWN_SEL); // Set Up count
    putreg32(TIMER_TARGET_COUNT_DEFAULT, S5JS100_TIMER1_BASE + S5JS100_TIMER_LOAD_VALUE);
    putreg32(0, S5JS100_TIMER1_BASE + S5JS100_TIMER_INT_SEL);
    putreg32(0, S5JS100_TIMER1_BASE + S5JS100_TIMER_INT_ENABLE);
    putreg32(3, S5JS100_TIMER1_BASE + S5JS100_TIMER_CONTROL);
}

static void disable_timer1(void)
{
    putreg32(0, S5JS100_TIMER1_BASE + S5JS100_TIMER_UP_DOWN_SEL);
    putreg32(TIMER_TARGET_COUNT_DEFAULT, S5JS100_TIMER1_BASE + S5JS100_TIMER_LOAD_VALUE);
    putreg32(0, S5JS100_TIMER1_BASE + S5JS100_TIMER_INT_SEL);
    putreg32(0, S5JS100_TIMER1_BASE + S5JS100_TIMER_CONTROL);
    putreg32(0, S5JS100_TIMER1_BASE + S5JS100_TIMER_INT_ENABLE);
}

void __us_ticker_irq_handler(void)
{
    us_ticker_disable_interrupt();
    us_ticker_clear_interrupt();
    us_ticker_irq_handler();
}

void us_ticker_init(void)
{
    /**
     ** We use two timer, timer0 channel to be used timer and timer1 to be used compare timer
     **/

    if (!us_ticker_initialized) {
        us_ticker_initialized = 1;
        /* Enable timer0 to timer */
        enable_timer0();
        /* Enable timer1 to compare and Disable timer1 interrupt */
        enable_timer1();
        /* Install the interrupt handler(timer0) */
        NVIC_SetVector((IRQn_Type)S5JS100_IRQ_TINT1, (uint32_t)__us_ticker_irq_handler);
        NVIC_EnableIRQ((IRQn_Type)S5JS100_IRQ_TINT1);
        return;
    }
    /* Re_init should Disable timer1(compare) interrupt */
    us_ticker_disable_interrupt();
    us_ticker_clear_interrupt();
}

uint32_t us_ticker_read()
{
    /* from timer0 read count value */
    if (!us_ticker_initialized) {
        us_ticker_init();
    }
    uint32_t current_count = TIMER_TARGET_COUNT_DEFAULT - getreg32(S5JS100_TIMER0_BASE + S5JS100_TIMER_CDC_COUNT_VALUE);
    g_us_last_return = current_count;
    return current_count;
}

void us_ticker_set_interrupt(timestamp_t timestamp)
{
    uint32_t past_tick = TIMER_TARGET_COUNT_DEFAULT - getreg32(S5JS100_TIMER0_BASE + S5JS100_TIMER_CDC_COUNT_VALUE) - g_us_last_return;
    putreg32(timestamp - g_us_last_return - past_tick, S5JS100_TIMER1_BASE + S5JS100_TIMER_LOAD_CON_VALUE);
    us_ticker_enable_interrupt();
}

void us_ticker_fire_interrupt(void)
{
    NVIC_SetPendingIRQ((IRQn_Type)S5JS100_IRQ_TINT1);
}

void us_ticker_disable_interrupt(void)
{
    putreg32(0, S5JS100_TIMER1_BASE + S5JS100_TIMER_INT_ENABLE);
}

void us_ticker_enable_interrupt(void)
{
    putreg32(1, S5JS100_TIMER1_BASE + S5JS100_TIMER_INT_ENABLE);
}

void us_ticker_clear_interrupt(void)
{
    putreg32(1, S5JS100_TIMER1_BASE + S5JS100_TIMER_INT_CLEAR);
    NVIC_ClearPendingIRQ((IRQn_Type)S5JS100_IRQ_TINT1);
}

void us_ticker_free(void)
{
    us_ticker_initialized = 0;
    disable_timer1();
    NVIC_DisableIRQ((IRQn_Type)S5JS100_IRQ_TINT1);
    disable_timer0();
}

#endif // DEVICE_USTICKER