/*
 *
 * Copyright (C) 2012-2020, Samsung Electronics Co., Ltd.
 *
 * Synaptics touchscreen routines
 */

#include <errno.h>
#include <interrupt.h>
#include <string.h>
#include <tee_internal_api.h>

#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <macros.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <tee_internal_api.h>
#include <tee_spi.h>
#include <time.h>
#include <unistd.h>

#include <driver/mem/phys.h>
#include <driver/spi/spi.h>
#include <sys/ioctl.h>
#include <sys/mman.h>

#include "board.h"
#include "bsp_common.h"
#include "dbg.h"
#include "device.h"
#include "synap_driver.h"
#include "secmap.h"
#include "touch_gpio.h"

#define TOUCH_MAX_FINGER_NUM                    10
#define MESSAGE_PADDING                         0x5a
#define GET_APPLICATION_INFO                    0x20
#define WAIT_TIME                               50
#define BUF_SIZE                                100
#define SPI_PORT                                1
#define SPI_DMA                                 0
#define SPI_FREQ                                7000000
#define SPI_CPOL                                1
#define SPI_CPHA                                1
#define SPI_WORDTYPE                            0
#define SPI_BUFLEN                              40
#define SPI_MANUAL_CLK                          1

bool press_id[TOUCH_MAX_FINGER_NUM];
int press_x[TOUCH_MAX_FINGER_NUM];
int press_y[TOUCH_MAX_FINGER_NUM];

static unsigned char tx_buf[BUF_SIZE];
static unsigned char rx_buf[BUF_SIZE];

static TEES_SPIHandler handler;

/******************************************************************************/

/**
 * Get touch data from controller and push it to the touch queue
 * @return error status
 */
int synap_irq_process(void)
{
    bool release = false;
    int x = 0;
    int y = 0;
    int res = 0;

    TEE_MemFill(rx_buf, 0x00, BUF_SIZE);

    if (get_touch_queue_wsize() < 1) {
        errPrintf("synap get_touch_queue_wsize \n");
        return -1;
    }

    TEES_SPITransfer rx = {
        .bufAddr = rx_buf,
        .bufLen = SPI_BUFLEN,
        .transferredLen = 0
    };

    rx.bufLen = 20;

    TEE_Wait(WAIT_TIME);
    res = TEES_SPIRead(handler, &rx);

    if (res != TEE_SUCCESS) {
        return 0;
    }

    if (rx_buf[2] == 0 && rx_buf[3] == 0) {
        return 0;
    } else if (rx_buf[9] != MESSAGE_PADDING) {
        int temp;
        x = (int) rx_buf[9];
        y = (int) rx_buf[11];
        temp = (int) rx_buf[10];

        x = ((temp & 0x0F) << 8) | x;
        y = ((temp & 0xF0) >> 4) | (y << 4);
    } else {
        if (press_id[0] == false) {
            return 0;
        }
        release = true;
    }

    if (press_id[0] == false) {
        press_id[0] = true;
        press_x[0] = x;
        press_y[0] = y;
        add_touch_event(1, press_x[0], press_y[0], tui_ts_press);
    } else if (press_id[0] == true && release == true) {
        add_touch_event(1, press_x[0], press_y[0], tui_ts_release);
        release = false;
        press_id[0] = false;
        press_x[0] = 0;
        press_y[0] = 0;
    }

    return 1;
}

/**
 * Initialize device driver
 * @return error status
 */
int synap_driver_init(void)
{
    TEES_SPIConfig cfg = {
        .speedHz = SPI_FREQ,
        .CPOL = SPI_CPOL,
        .CPHA = SPI_CPHA,
        .bitsPerWord = SPI_WORDTYPE,
        .isDMAMode = SPI_DMA,
        .manualClockControl = SPI_MANUAL_CLK,
    };

    TEES_SPITransfer tx = {
        .bufAddr = tx_buf,
        .bufLen = SPI_BUFLEN,
        .transferredLen = 0
    };

    TEES_SPITransfer rx = {
        .bufAddr = rx_buf,
        .bufLen = SPI_BUFLEN,
        .transferredLen = 0
    };

    int res = TEES_SPIInit(SPI_PORT, &cfg, &handler);
    if (res != TEE_SUCCESS) {
        errPrintf("Failed to initalize SPI, tee_err=%#x\n", res);
        return res;
    }

    tx.bufLen = 3;
    tx_buf[0] = GET_APPLICATION_INFO;

    res = TEES_SPIWrite(handler, &tx);
    TEE_Wait(WAIT_TIME);

    rx.bufLen = 52;
    res = TEES_SPIRead(handler, &rx);

    if (res != TEE_SUCCESS) {
        errPrintf("TEES_SPIWriteRead() failed, tee_err=%#x\n", res);
        return res;
    }

    unsigned int maxx = (int) rx_buf[37] << 8 | rx_buf[36];
    unsigned int maxy = (int) rx_buf[39] << 8 | rx_buf[38];

    errPrintf("synap get MaxX : %d MaxY : %d \n", maxx, maxy);

    init_touch_queue();

    return res;
}

/**
 * Uninitialize device driver
 * @return error status
 */
int synap_driver_release(void)
{
    if (TEES_SPIExit(handler)) {
        errPrintf("Failed to close SPI device\n");
        TEE_Panic(0);
    }

    return 0;
}
