#include "tee_internal_api.h"
#include <stdio.h>
#include <string.h>
#include "gpio-mst.h"
#include "mstdrv.h"
#include "regs-gpio-mst.h"
#include "time.h"
#include <tees_critical.h>

#define TAG "MSTDRV : "

/* MST gpio pin number */
uint8_t gpio_mst_en_pin = 5; // md
uint8_t gpio_mst_data_pin = 4; // pd

/* usec delay */
struct timespec req;
struct timespec rem;
struct timespec ts_start;
struct timespec ts_end;

static unsigned long timespec2us(struct timespec *ts)
{
	return ts->tv_nsec / 1000 + ts->tv_sec * 1000000;
}

static void udelay(unsigned int us)
{
	struct timespec t0, t1;
	unsigned long usec;

	clock_gettime(CLOCK_BOOTTIME, &t0);
	for (;;) {
		clock_gettime(CLOCK_BOOTTIME, &t1);

		usec = timespec2us(&t1) - timespec2us(&t0);
		if (usec >= us)
			break;
	}
//	printf(TAG "%s : busyloop takes %luus\n", __func__, usec);
}

static int trans_loop(int i)
{
    int ret = 0;

    gpio_set_mst_data(i, GPIO_VECIDX_MST_DATA, GPIO_MST_DATA_PIN); //mst_data
    ret = (i == 0) ? 1 : 0;

    return ret;
}

int transmitMST(unsigned char * input)
{
	unsigned int baud_rate = (unsigned int)*(input+2) * 256 + (unsigned int)*(input+3);
	unsigned int total_bit_length = (unsigned int)*(input+4) * 256 + (unsigned int)*(input+5);
	unsigned char * loop_va = (unsigned char*)(input+6);

	int loi = 0;
	int loj = 0;
	int count = 0;
	int trans_cnt = 0;
	int ret = 0;

	if (baud_rate > 1800) {
		printf(TAG "%s : invalid baud_rate : %u\n", __func__, baud_rate);
		return -1;
	}
	if (total_bit_length > 2480) {
		printf(TAG "%s : invalid total_bit_length : %u\n", __func__, total_bit_length);
		return -1;
	}
	if (loop_va == NULL) {
		printf(TAG "%s : loop_va is NULL\n", __func__);
		return -1;
	}

	printf(TAG "%s : baud_rate : %d\n", __func__, baud_rate);
	printf(TAG "%s : total_bit_length : %d\n", __func__, total_bit_length);

	if (gpio_phys_to_vaddr() != TEE_SUCCESS) {
		return -1;
	}
	//printf(TAG "%s : mst gpio init\n", __func__);
	gpio_set_mst_init();

	udelay(3000);

	//printf(TAG "%s : gpio en set to 1\n", __func__);
	gpio_set_mst_data(1, GPIO_VECIDX_MST_EN, GPIO_MST_EN_PIN);

	udelay(7000);

	loi = 0;
	count = 0;
#if 0 
	printf(TAG "%s : Enter Critical section\n", __func__);
	ret = TEES_EnterCritical();
	printf(TAG "%s : ret = %d\n", __func__, ret);

	for (int i =0; i<200; i++) {
		clock_gettime(CLOCK_REALTIME, &ts_start);
	//	printf("ts_start timestamp : sec=%d, nsec=%u\n", (uint32_t)ts_start.tv_sec, (uint32_t)ts_start.tv_nsec);
		udelay(300);
		clock_gettime(CLOCK_REALTIME, &ts_end);
	//	printf("ts_end timestamp : sec=%d, nsec=%u\n", (uint32_t)ts_end.tv_sec, (uint32_t)ts_end.tv_nsec);
		printf("time consumption[%d] : %u\n", i,  (unsigned int)((ts_end.tv_nsec - ts_start.tv_nsec) / 1000 + (ts_end.tv_sec - ts_start.tv_sec) * 1000));
	}
	TEES_ExitCritical();
#endif	
#if 1 
	printf(TAG "%s : Enter Critical section\n", __func__);
	ret = TEES_EnterCritical();
	if (ret != 0) {
		printf(TAG "%s : Enter Critical Section failed, ret = %d\n", __func__, ret);
		gpio_set_mst_exit();
		return -1;
	}

	printf(TAG "%s : mst transmit start\n", __func__);

	do{
		for(loj = 7 ; loj >= 0 ; loj--) {
			if(((loop_va[loi] & (1 << loj)) >> loj) == 1) {
				trans_cnt = trans_loop(trans_cnt);
				udelay(baud_rate/2);
				trans_cnt = trans_loop(trans_cnt);
				udelay(baud_rate/2);
				count++;
			}else{
				trans_cnt = trans_loop(trans_cnt);
				udelay(baud_rate);
				count++;
			}

			if(count == total_bit_length)
				break;
		}
		loi++;
	}
	while ( loi < (total_bit_length/8)+1 );
	printf(TAG "%s : Exit Critical section\n", __func__);
	TEES_ExitCritical();
#endif
	udelay(3000);

	gpio_set_mst_init();
	gpio_set_mst_exit();
	return 0;
}

#define MST_TRACK_DATA_MAX_LEN		512
#define MST_TRACK_DATA_HEADER_LEN	6

bool check_valid_mem_for_trackdata(unsigned char *track_data, unsigned int size)
{
	unsigned int data_size = 0;

	if (size >= MST_TRACK_DATA_MAX_LEN) {
		printf(TAG "%s : mem size is enough!!! (size : %d)\n", __func__, size);
		return true;
	}

	if (size < MST_TRACK_DATA_HEADER_LEN) {
		printf(TAG "%s : mem size is too small!!! (size : %d)\n", __func__, size);
		return false;
	}

	data_size = (((unsigned int)*(track_data+4) * 256 + (unsigned int)*(track_data+5)) / 8 + 1) + MST_TRACK_DATA_HEADER_LEN;
	printf(TAG "%s : real size : %d, acquire size : %d\n", __func__, data_size, size);
	if (data_size < size) {
		return true;
	}

	return false;
}
