/*
 *
 * Copyright (C) 2012-2019, Samsung Electronics Co., Ltd.
 *
 * High level RMI4 wrapper for secure touch driver
 */

#include <tee_internal_api.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 "tuiHal.h"
#include "rmi_driver.h"
#include "rmi.h"

static int tsu_i2c_read(uint16_t addr, uint8_t *buff, uint16_t count)
{
    TEE_Result ret;
    deviceInfo_t *i2cDev = &board.i2c;
    int try_count = 8;

    if (!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 tsu_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 = 8;

    if (!count) {
        return -EINVAL;
    }
    local_buff[0] = addr & 0xff;
    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 = tui_ts_dev.max_x;
    touchSize->height = tui_ts_dev.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;

    (void)width;
    (void)height;
    (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");
        tui_ts_dev.max_x = SENSOR_MAX_X_DEFAULT;
        tui_ts_dev.max_y = SENSOR_MAX_Y_DEFAULT;

        /* Setup i2c access functions for RMI4 library */
        tui_ts_dev.i2c_read = tsu_i2c_read;
        tui_ts_dev.i2c_write = tsu_i2c_write;

        /* Initialize RMI4 library */
        ret = rmi_driver_init(&tui_ts_dev);
        if (ret < 0) {
            errPrintf("rmi_driver_init() : retval = %d", ret);
            retHal = E_TUI_HAL_IO;
            goto err_init_rmi;
        }
        touch_dev->state |= DEV_SFR_CONFIGURED;
    }

    sec_release();
    dbgPrintf("<< %s\n", __func__);
    return retHal;

err_init_rmi:
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 = rmi_driver_remove(&tui_ts_dev);
        if (ret != TEE_SUCCESS) {
            errPrintf("rmi_driver_remove 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, rmi_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 = rmi_irq_process();
#endif /* USE_TOUCH_INTERRUPT */
    if (retval != 0) {
        return TEE_ERROR_GENERIC;
    }
    return TEE_SUCCESS;
}
