/*
 * Copyright (C) 2019 SAMSUNG S.LSI
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifdef ESE_U_BOOT_BUILD
#include <common.h>
#else
#include <stdio.h>
#endif

#include <ese_log.h>
#include <ese_hal.h>

#include "ese_device.h"

#include "sec_spi_info.h"
//#include "debug.h"

#define LOG_TAG "ESE_HAL"
#define MAX_RETRY_CNT 10

#if 1 //def RELEASE_BUILD
#define API
#else
#define API __attribute__((visibility("default")))
#endif

static void _print_buffer(const char *buf_tag, uint8_t *buffer, uint32_t buffer_size)
{
	char tmp_buffer[49] = { 0 };
	char *tmp_p = tmp_buffer;
	uint32_t i = 0;
	ESELOG_D("%s : ", buf_tag);

	for (i = 0; i < buffer_size; i ++) {
		if (i != 0 && (i % 16) == 0) {
			ESELOG_D("%s", tmp_buffer);
			tmp_p = tmp_buffer;
		}
		snprintf(tmp_p, 4, " %02x", buffer[i]);
		tmp_p += 3;
	}
	ESELOG_D("%s", tmp_buffer);
}

void grdmSetSpiConfiguration(qsee_spi_config_t* spi_config) {
    /**< SPI clock frequency */
    spi_config->max_freq = GRDM_SPI_MAX_FREQ;
    /**< Clock polarity  type to be used for the SPI core. */
    spi_config->spi_clk_polarity = QSEE_SPI_CLK_IDLE_LOW;
    /**< Shift mode(CPHA) type to be used for SPI core. */
    spi_config->spi_shift_mode = QSEE_SPI_INPUT_FIRST_MODE;
    /**< CS polarity type to be used for the SPI core. */
    spi_config->spi_cs_polarity = QSEE_SPI_CS_ACTIVE_LOW;
    /**< CS Mode to be used for the SPI core. */
    spi_config->spi_cs_mode = QSEE_SPI_CS_KEEP_ASSERTED;
    /**< Clock mode type to be used for the SPI core. */
    spi_config->spi_clk_always_on = QSEE_SPI_CLK_NORMAL;
    /**< SPI bits per word, any value from 3 to 31 */
    spi_config->spi_bits_per_word = 8;
//#ifdef EXTENEDED_CONFIG
    /**< Put the Device in High Performance */
    spi_config->hs_mode = 0;
    /**< Put the Device in loop back test*/
    spi_config->loopback = 0;
//#ifdef EXTENDED_NEW_CONFIG
    /**< Slave index from 0 to 3, if mulitple SPI devices are connected to the same master */
    spi_config->spi_slave_index = 0;
    /**< The minimum delay between two word(N-bit) transfers */
    spi_config->deassertion_time_ns = 0;
//#endif
//#endif
}

API ESE_HAL_STATUS eseHal_Open(void)
{
#if 0
	eseHal_device_t *dev = eseHal_GetDevice();
	int hal_fd;
	int retryCnt = 0;

	if (dev == NULL) {
		return ESE_HAL_STATUS_NO_DEV;
	}

	ESELOG_I("eseHal_Open");

	do {
		hal_fd = dev->open();
		if (hal_fd == -2) {
			retryCnt++;
			ESELOG_I("Retry eseHal_Open - retry cnt : %d", retryCnt);
			usleep(500000);
		} else if (hal_fd == -3) {
			ESELOG_E("failed to open ese %s", dev->name);
			return ESE_HAL_STATUS_ALREADY_OPENED;
		} else if (hal_fd < 0) {
			ESELOG_E("failed to open ese %s", dev->name);
			return ESE_HAL_STATUS_ERROR;
		} else {
			return ESE_HAL_STATUS_SUCCESS;
		}
	} while (retryCnt < MAX_RETRY_CNT);

	return ESE_HAL_STATUS_BUSY;
#else
	return ESE_HAL_STATUS_SUCCESS;
#endif
}

API int32_t eseHal_Send(uint8_t *txData, uint32_t txDataSize)
{
    qsee_spi_device_id_t deviceId;
    qsee_spi_config_t spi_config;
    qsee_spi_transaction_info_t spi_rx;
    qsee_spi_transaction_info_t spi_tx;
    int ret = 0;
    uint8_t rx_buffer[258] = {0,};
    deviceId = GRDM_SPI_DEVICE_ID;

    grdmSetSpiConfiguration(&spi_config);

    spi_tx.buf_addr = (uint8_t*) txData;
    spi_tx.buf_len = txDataSize;
    spi_rx.buf_addr = rx_buffer;
    spi_rx.buf_len = txDataSize;

    ret = qsee_spi_full_duplex(deviceId, &spi_config, &spi_tx, &spi_rx);
    if (ret != 0) {
        ESELOG_E("gto spi_write error retcode = %d", ret);
        return -1;
    }
    ret = spi_tx.buf_len;
#if 0
#ifdef DEBUG_LOW
    //hex_print_tag("spi_write", (uint8_t*)txData, ret);
	ESELOG_E("spi_write : 0x%x ret : 0x%x", (uint8_t*)txData, ret);
#else
	{
		int i = 0;
		for (i=0; i<txDataSize; i++) {
			ESELOG_E("eseHal_Send : 0x%x ", txData[i]);
		}
	}
    if (ret == 1) {
        // Do not print log
    } else if (ret < 10){
		ESELOG_E("[SEND] : 0x%x\n ret : 0x%x", (uint8_t*)txData, ret);
        //hex_print_tag_iso("[SEND]", (uint8_t*)txData, ret);
    } else {
		ESELOG_E("[SEND] : 0x%x\n ret : 0x%x", (uint8_t*)txData, 10);
        //hex_print_tag_iso("[SEND]", (uint8_t*)txData, 10);
    }
	{
		ESELOG_E("reverse log");
		int i = 0;
		for (i=txDataSize-1; i>=0; i--) {
			ESELOG_E("eseHal_Send : 0x%x ", txData[i]);
		}
	}
#endif
#endif
    return ret;
}

API int32_t eseHal_Receive(uint8_t *rxData, uint32_t rxDataSize)
{
    qsee_spi_device_id_t deviceId;
    qsee_spi_config_t spi_config;
    qsee_spi_transaction_info_t spi_rx;
    qsee_spi_transaction_info_t spi_tx;
    int ret = 0;
    uint8_t tx_buffer[258] = {0,};

    deviceId = GRDM_SPI_DEVICE_ID;

    grdmSetSpiConfiguration(&spi_config);

    spi_tx.buf_addr = tx_buffer;
    spi_tx.buf_len = rxDataSize;
    spi_rx.buf_addr = (uint8_t*) rxData;
    spi_rx.buf_len = rxDataSize;

    ret = qsee_spi_full_duplex(deviceId, &spi_config, &spi_tx, &spi_rx);
    if (ret != 0) {
        ESELOG_E("gto spi_read error retcode = %d", ret);
        return -1;
    }
    ret = spi_rx.buf_len;
#if 0
#ifdef DEBUG_LOW
	ESELOG_D("spi_read	 : 0x%x\n ret : 0x%x", (uint8_t*)rxData, ret);
    //hex_print_tag("spi_read", (uint8_t*)rxData, ret);
#else
    if (ret == 1) {
        // Do not print log
    } else if (ret < 10){
		ESELOG_D("[RECV] : 0x%x\n ret : 0x%x", (uint8_t*)rxData, ret);
        //hex_print_tag_iso("[RECV]", (uint8_t*)rxData, ret);
    } else {
		ESELOG_D("[RECV] : 0x%x\n ret : 0x%x", (uint8_t*)rxData, 10);
        //hex_print_tag_iso("[RECV]", (uint8_t*)rxData, 10);
    }
#endif
#endif
//    ESELOG_E("eseHal_Receive 0x%x retcode = %d", rxData[0], ret);
    return ret;
}

API ESE_HAL_STATUS eseHal_Close(void)
{
/*
	eseHal_device_t *dev = eseHal_GetDevice();

	if (dev == NULL) {
		return ESE_HAL_STATUS_NO_DEV;
	}

	ESELOG_I("eseHal_Close");

	if (dev->close() < 0) {
		return ESE_HAL_STATUS_ERROR;
	}
*/
	return ESE_HAL_STATUS_SUCCESS;
}
