/*
 *
 * Copyright (C) 2021, Samsung Electronics Co., Ltd.
 *
 * GPIO interface, local implementation
 */

#include <errno.h>
#include "dbg.h"
#include "device.h"
#include "secmap.h"
#include "touch_gpio.h"

#ifdef USE_TOUCH_INTERRUPT
static uint32_t gpioa_stored_data[3];

static void gpio_write_mask(uint32_t reg_id, uint32_t val, uint32_t mask)
{
    uint32_t old = GPA_REG(reg_id);

    val = (val & mask) | (old & ~mask);
    GPA_REG(reg_id) = val;
}

/* Get pending touch attention interrupt */
static bool gpio_get_pend_irq(void)
{
    return (GPA_REG(WEINT_GPA0_PEND_OFFSET) & WEINT_GPA0_3_PEND);
}

static void gpio_save_state(void)
{
    /* Save GPA0_3 settings */
    gpioa_stored_data[0] = GPA_REG(GPA0_CON_OFFSET) & GPA0_3_CONF_MASK;
    gpioa_stored_data[1] = GPA_REG(WEINT_GPA0_CON_OFFSET) & GPA0_EINT3_MASK;
    gpioa_stored_data[2] = GPA_REG(WEINT_GPA0_MASK_OFFSET) & WEINT_GPA0_3_PEND;

#ifdef DR_DBGLOG
    int i;
    for(i=0; i<3; i++) {
        dbgPrintf("%s, gpioa_stored_data: 0x%x\n", __func__, gpioa_stored_data[i]);
    }
#endif
}

int map_gpio_sfr(void)
{
    return sec_map(DEV_GPA, GPIO_PA_BASE, SIZE_4KB);
}

void gpio_restore_state(void)
{
    /* Restore GPA0_3 settings */
    gpio_write_mask(GPA0_CON_OFFSET, gpioa_stored_data[0], GPA0_3_CONF_MASK);
    gpio_write_mask(WEINT_GPA0_CON_OFFSET, gpioa_stored_data[1], GPA0_EINT3_MASK);
    gpio_write_mask(WEINT_GPA0_MASK_OFFSET, gpioa_stored_data[2], WEINT_GPA0_3_PEND);
}

void gpio_config(void)
{
    gpio_save_state();

    /* Configure GPA0_3 for EINT */
    gpio_write_mask(GPA0_CON_OFFSET, GPA0_3_CONF_EINT, GPA0_3_CONF_MASK);

    /* Configure GPA0_3 trigger type */
    gpio_write_mask(WEINT_GPA0_CON_OFFSET, gpioa_stored_data[1], GPA0_EINT3_MASK);
}

/* Enable/disable touch attention interrupt from gpio */
void gpio_enable_touch_irq(bool enable)
{
    if (map_gpio_sfr()) {
        TEE_Panic(0xDEADBEEF);
        return;
    }

    if (enable) {
        gpio_write_mask(WEINT_GPA0_MASK_OFFSET, ~WEINT_GPA0_3_PEND, WEINT_GPA0_3_PEND);
    } else {
        gpio_write_mask(WEINT_GPA0_MASK_OFFSET, WEINT_GPA0_3_PEND, WEINT_GPA0_3_PEND);
    }
}

/* Clear pending touch attention interrupt */
void gpio_clear_pend_irq(void)
{
    if (map_gpio_sfr()) {
        TEE_Panic(0xDEADBEEF);
        return;
    }

    if (gpio_get_pend_irq()) {
        GPA_REG(WEINT_GPA0_PEND_OFFSET) |= WEINT_GPA0_3_PEND;
    }
}
#endif /* USE_TOUCH_INTERRUPT */