/*
 *
 * Copyright (C) 2012-2019, Samsung Electronics Co., Ltd.
 *
 * Novatek touchscreen routines
 */

#include <errno.h>
#include <driver/interrupt/interrupt.h>
#include <string.h>
#include <tee_internal_api.h>

#include "board.h"
#include "bsp_common.h"
#include "dbg.h"
#include "device.h"
#include "i2c.h"
#include "novatek_driver.h"
#include "secmap.h"
#include "touch_gpio.h"

#define NVT_EVENT_BUF_ADDR                      0x21C00
#define NVT_I2C_FW_Address                      0x01
#define NVT_EVENT_MAP_FWINFO                    0x78
#define NVT_POINT_DATA_LEN                      65
#define NVT_TOUCH_MAX_FINGER_NUM                10
#define NVT_RELEASE_CLIENT_ID                   0x1F
#define NVT_MAX_TOUCH_COUNT                     10

#define NVT_FINGER_ENTER                        0x01
#define NVT_FINGER_MOVING                       0x02
#define NVT_GLOVE_TOUCH                         0x06
#define NVT_RELEASE                             0xFF


struct novatek_ts_info novatek_data;

bool press_id[NVT_TOUCH_MAX_FINGER_NUM];
int press_x[NVT_TOUCH_MAX_FINGER_NUM];
int press_y[NVT_TOUCH_MAX_FINGER_NUM];
/******************************************************************************/

/**
 * Get touch data from controller and push it to the touch queue
 * @return error status
 */
int nvt_irq_process(void)
{
    int ret = 0;
    uint8_t point_data[NVT_POINT_DATA_LEN + 1] = {0, };
    int finger_cnt;
    int i;
    struct nvt_ts_event_coord *p_event_coord;
    int x = 0, y = 0;
    uint8_t id, status;
    bool release = false;

    if (get_touch_queue_wsize() < 1) {
        return -1;
    }

    ret = novatek_data.i2c_read(point_data, NVT_POINT_DATA_LEN + 1);
    if (ret < 0) {
        errPrintf("nvt_ts_i2c_read failed.(%d)\n", ret);
        return -1;
    }

    for (i = 0, finger_cnt = 0; i < NVT_MAX_TOUCH_COUNT; i++) {
        p_event_coord = (struct nvt_ts_event_coord *)&point_data[1 + 6 * i];
        id = p_event_coord->id;
        release = ((p_event_coord->id << 3 | p_event_coord->reserved_1 << 2 | p_event_coord->status) == NVT_RELEASE);
        if (!id || (id > 10 && id != NVT_RELEASE_CLIENT_ID)) {
            continue;
        }

        id = id - 1;
        status = p_event_coord->status;

        if ((status == NVT_FINGER_ENTER) || (status == NVT_FINGER_MOVING) || (status == NVT_GLOVE_TOUCH)) {
            x = (uint32_t)(p_event_coord->x_11_4 << 4) + (uint32_t)(p_event_coord->x_3_0);
            y = (uint32_t)(p_event_coord->y_11_4 << 4) + (uint32_t)(p_event_coord->y_3_0);
            if (x < 0 || y < 0) {
                errPrintf("%s: invaild coordinate (%d, %d)\n", __func__, x, y);
                continue;
            }
            press_id[id] = true;
            press_x[id] = x;
            press_y[id] = y;
            add_touch_event(id, x, y, tui_ts_press);
            finger_cnt++;
        } else {
            if (release && press_id[i]) {
                add_touch_event(i, press_x[i], press_y[i], tui_ts_release);
                press_id[i] = false;
                press_x[i] = 0;
                press_y[i] = 0;
            }
        }
    }

    return ret;
}

/**
 * Initialize NVT device driver
 * @param[in] nvt_dev nvy device pointer
 * @return error status
 */
int nvt_driver_init(struct novatek_ts_info *nvt_dev)
{
    int ret;
    uint8_t resp_buff[10] = {0, };
    uint8_t cmd_buff[10] = {0, };

    /* get resolution info */
    cmd_buff[0] = 0xFF;
    cmd_buff[1] = (NVT_EVENT_BUF_ADDR >> 16) & 0xFF;
    cmd_buff[2] = (NVT_EVENT_BUF_ADDR >> 8) & 0xFF;

    ret = novatek_data.i2c_write(cmd_buff, 3);
    if (ret < 0) {
        errPrintf("write xdata index fail %d\n", ret);
        return ret;
    }

    /* read fw info */
    resp_buff[0] = NVT_EVENT_MAP_FWINFO;
    ret = novatek_data.i2c_read(resp_buff, 9);
    if (ret < 0) {
        errPrintf("get resolution info fail %d\n", ret);
        return ret;
    }

    dbgPrintf("%s fw_ver=%s\n", __func__, resp_buff[1]);

    nvt_dev->max_x = (uint16_t) ((resp_buff[5] << 8) | resp_buff[6]);
    nvt_dev->max_y = (uint16_t) ((resp_buff[7] << 8) | resp_buff[8]);
    dbgPrintf("%s resolution info x=%d y=%d\n",
              __func__, nvt_dev->max_x, nvt_dev->max_y);

    init_touch_queue();

    return ret;
}

/**
 * Uninitialize NVT device driver
 * @return error status
 */
int nvt_driver_release(void)
{
    return 0;
}
