/*
 *
 * Copyright (C) 2012-2019, Samsung Electronics Co., Ltd.
 *
 * FTS touchscreen routines
 */


#include <tee_internal_api.h>
#include <errno.h>
#include <string.h>
#include "board.h"
#include "bsp_common.h"
#include "dbg.h"
#include "board.h"
#include "device.h"
#include "../../devices/i2c.h"
#include "touch_gpio.h"
#include "secmap.h"
#include "fts_main.h"

#define FTS_RETRY_COUNT             8

int fts_i2c_read(uint8_t cmd, uint8_t *params, int params_len)
{
    TEE_Result ret;
    deviceInfo_t *i2cDev = &board.i2c;
    int try_count = FTS_RETRY_COUNT;

    if (!params || !params_len) {
        return -EINVAL;
    }
    do {
        ret = i2c_send(i2cDev, i2cDev->bus.slave_address, (uint8_t *)&cmd, 1);
        if (ret == TEE_SUCCESS) {
            ret = i2c_receive(i2cDev, i2cDev->bus.slave_address, params, params_len);
        }
        if (ret == TEE_SUCCESS) {
            return 0;
        }
    } while(--try_count);
    return -EIO;
}

int fts_i2c_read_data(uint8_t *params, int params_len)
{
    TEE_Result ret;
    deviceInfo_t *i2cDev = &board.i2c;
    int try_count = FTS_RETRY_COUNT;

    if (!params || !params_len) {
        return -EINVAL;
    }
    do {
        ret = i2c_receive(i2cDev, i2cDev->bus.slave_address, params, params_len);
        if (ret == TEE_SUCCESS) {
            return 0;
        }
    } while(--try_count);
    return -EIO;
}

int fts_i2c_write(uint8_t cmd, uint8_t *params, int params_len)
{
    TEE_Result ret;
    deviceInfo_t *i2cDev = &board.i2c;
    static uint8_t local_buff[256];
    int try_count = FTS_RETRY_COUNT;

    if ((!params && params_len) || (size_t)params_len >= sizeof(local_buff)) {
        return -EINVAL;
    }
    local_buff[0] = cmd;
    if (params_len) {
        TEE_MemMove(local_buff + 1, params, params_len);
    }
    do {
        ret = i2c_send(i2cDev, i2cDev->bus.slave_address, local_buff, params_len + 1);
        if (ret == TEE_SUCCESS) {
            return 0;
        }
    } while(--try_count);
    return -EIO;
}

////////////////////////////////////////////////
//////////    TUI HAL API   ////////////////////
////////////////////////////////////////////////

TEE_Result tuiHalTouchGetInfo(drTouchInfo_ptr touchSize)
{
    touchSize->width = fts_data.max_x;
    touchSize->height = fts_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;

    (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_init_i2c;
    }

    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(&fts_data, 0, sizeof(fts_data));
        fts_data.width = width;
        fts_data.height = height;

        /* Initialize FTS library */
        ret = fts_driver_init();
        if (ret < 0) {
            errPrintf("fts_driver_init() : retval = %d\n", ret);
            retHal = E_TUI_HAL_IO;
            goto err_init_drv;
        }
        touch_dev->state |= DEV_SFR_CONFIGURED;
    }

    sec_release();
    dbgPrintf("<< %s\n", __func__);
    return retHal;

err_init_drv:
err_init_i2c:
    tuiHalTouchClose();
    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;

    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 = fts_driver_release();
        if (ret != TEE_SUCCESS) {
            errPrintf("fts_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)
{
    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, fts_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 = fts_irq_process();
#endif /* USE_TOUCH_INTERRUPT */
    if (retval != 0) {
        return TEE_ERROR_GENERIC;
    }
    return TEE_SUCCESS;
}
