/*
 *
 * Copyright (C) 2012-2019, Samsung Electronics Co., Ltd.
 *
 * High level wrapper for SEC touchscreen
 */

#include <tee_internal_api.h>
#include <errno.h>
#include <string.h>
#include "board.h"
#include "bsp_common.h"
#include "dbg.h"
#include "device.h"
#include "i2c.h"
#include "touch_gpio.h"
#include "secmap.h"
#include "sec_driver.h"

#define SEC_RETRY_COUNT       3

static int sec_i2c_read(uint16_t addr, uint8_t *buff, uint16_t count)
{
    TEE_Result ret;
    deviceInfo_t *i2cDev = &board.i2c;
    int try_count = SEC_RETRY_COUNT;

    if (!buff || !count) {
        return -EINVAL;
    }
    do {
        ret = i2c_send(i2cDev, i2cDev->bus.slave_address, (uint8_t *)&addr, 1);
        if (ret == TEE_SUCCESS) {
            ret = i2c_receive(i2cDev, i2cDev->bus.slave_address, buff, count);
        }
        if (ret == TEE_SUCCESS) {
            return count;
        }
    } while(--try_count);
    return -EIO;
}

static int sec_i2c_write(uint16_t addr, uint8_t *buff, uint16_t count)
{
    TEE_Result ret;
    deviceInfo_t *i2cDev = &board.i2c;
    static uint8_t local_buff[256];
    int try_count = SEC_RETRY_COUNT;

    if ((!buff && count) || (size_t)count >= sizeof(local_buff)) {
        return -EINVAL;
    }
    local_buff[0] = addr;
    if (count) {
        TEE_MemMove(local_buff+1, buff, count);
    }
    do {
        ret = i2c_send(i2cDev, i2cDev->bus.slave_address, local_buff, count+1);
        if (ret == TEE_SUCCESS) {
            return count;
        }
    } while(--try_count);
    return -EIO;
}

////////////////////////////////////////////////
//////////    TUI HAL API   ////////////////////
////////////////////////////////////////////////

TEE_Result tuiHalTouchGetInfo(drTouchInfo_ptr touchSize)
{
    touchSize->width = ts_data.max_x;
    touchSize->height = ts_data.max_y;
    return TEE_SUCCESS;
}

TEE_Result tuiHalTouchOpen(uint32_t width, uint32_t height, uint32_t touch_type)
{
    deviceInfo_t *touch_dev = &board.touch;
    deviceInfo_t *i2c_dev = &board.i2c;
    deviceInfo_t *gpio_dev = &board.gpio;
    TEE_Result retHal = TEE_ERROR_GENERIC;
    int ret = TEE_ERROR_GENERIC;
    ts_data.initialized = 0;

    (void)touch_type;

    dbgPrintf(">> %s\n", __func__);

    /* Initialization */
    retHal = touch_gpio_init(gpio_dev);
    if (retHal != TEE_SUCCESS) {
        errPrintf("touch_gpio_init() Failed\n");
        goto err_gpio_init;
    }

    retHal = i2c_init(i2c_dev);
    if (retHal != TEE_SUCCESS) {
        errPrintf("i2c_init() Failed\n");
        goto err_init_i2c;
    }

    if (touch_dev->state == DEV_UNCONFIGURED) {
        /* Init touch module */
        dbgPrintf("Touch Init Start\n");
        TEE_MemFill(&ts_data, 0, sizeof(ts_data));

        /* Setup i2c access functions */
        ts_data.i2c_read = sec_i2c_read;
        ts_data.i2c_write = sec_i2c_write;

        ts_data.width = width;
        ts_data.height = height;

        /* Initialize SEC touchscreen */
        ret = sec_driver_init(&ts_data);
        if (ret < 0) {
            errPrintf("sec_driver_init() : retval = %d\n", ret);
            retHal = E_TUI_HAL_IO;
            goto err_init_sec;
        }
        ts_data.initialized = 1;
        touch_dev->state |= DEV_SFR_CONFIGURED;
    }

    sec_release();
    dbgPrintf("<< %s\n", __func__);
    return retHal;

err_init_sec:
    ret = i2c_release(i2c_dev);
    if (ret != TEE_SUCCESS) {
        errPrintf("i2c_release Failed!\n");
    }
err_init_i2c:
    ret = touch_gpio_release(gpio_dev);
    if (ret != TEE_SUCCESS) {
        errPrintf("touch_gpio_unregister_int Failed!\n");
    }
err_gpio_init:
    sec_release();
    dbgPrintf("<< %s\n", __func__);
    return retHal;
}

TEE_Result tuiHalTouchClose(void)
{
    dbgPrintf(">> %s\n", __func__);
    deviceInfo_t *i2c_dev = &board.i2c;
    deviceInfo_t *touch_dev = &board.touch;
    deviceInfo_t *gpio_dev = &board.gpio;
    TEE_Result ret;

    if (touch_dev->state == DEV_UNCONFIGURED)
        return TEE_SUCCESS;

    ts_data.initialized = 0;
    ret = touch_gpio_unregister_int(gpio_dev);
    if (ret != TEE_SUCCESS) {
        errPrintf("touch_gpio_unregister_int Failed!\n");
    }
    if (touch_dev->state & DEV_SFR_CONFIGURED) {
        ret = sec_driver_release(&ts_data);
        if (ret != TEE_SUCCESS) {
            errPrintf("sec_driver_release Failed!\n");
        } else {
            touch_dev->state &= ~DEV_SFR_CONFIGURED;
        }
    }
    ret = i2c_release(i2c_dev);
    if (ret != TEE_SUCCESS) {
        errPrintf("i2c_release Failed!\n");
    }
    ret = touch_gpio_release(gpio_dev);
    if (ret != TEE_SUCCESS) {
        errPrintf("touch_gpio_release Failed!\n");
    }

    sec_release();
    touch_dev->state = DEV_UNCONFIGURED;
    dbgPrintf("<< %s\n", __func__);
    return TEE_SUCCESS;
}

TEE_Result tuiHalTouchProcess(void)
{
    dbgPrintf(">> %s\n", __func__);

    int retval = 0;
    deviceInfo_t *touch_dev = &board.touch;

    if (touch_dev->state != DEV_SFR_CONFIGURED && touch_dev->state != DEV_CONFIGURED) {
        return TEE_ERROR_GENERIC;
    }

#ifdef USE_TOUCH_INTERRUPT
    deviceInfo_t *gpio_dev = &board.gpio;

    if (touch_dev->state == DEV_SFR_CONFIGURED) {
        retval = touch_gpio_register_int(gpio_dev, sec_irq_process);
        if (retval != TEE_SUCCESS) {
            errPrintf("touch_gpio_register_int() : retval = %d\n", retval);
            return TEE_ERROR_GENERIC;
        }
        touch_dev->state = DEV_CONFIGURED;
    }
    gpio_wait_touch_irq();
#else /* USE_TOUCH_INTERRUPT */
    retval = sec_irq_process();
#endif /* USE_TOUCH_INTERRUPT */
    if (retval != 0) {
        return TEE_ERROR_GENERIC;
    }
    return TEE_SUCCESS;
}
