/******************************************************************************
 *
 * Copyright 2017, Lattice Semiconductor, Inc. All rights reserved.
 * No part of this work may be reproduced, modified, distributed, transmitted,
 * transcribed, or translated into any language or computer format, in any form
 * or by any means without written permission of Lattice Semiconductor Inc.,
 * 111 SW 5th Ave, Suite 700, Portland, OR 97204.
 *
 *****************************************************************************/
/**
 * @file sii_platform_api.h
 *
 * @brief Minimum Platform API function set for Sii9437/Sii9438 Driver
 *
 *****************************************************************************/

#ifndef SII_PLATFORM_API_H
#define SII_PLATFORM_API_H

#ifdef __cplusplus
extern "C"{
#endif

/***** #include statements ***************************************************/

//#include <stdio.h>
#include "x_os.h"
#include "sii_datatypes.h"

/***** public macro definitions ***********************************************/
#define SII943X_USER_DEF__MULTI_THREAD
#ifdef SII943X_USER_DEF__MULTI_THREAD
	extern HANDLE_T sii_platform_sema_create(void);
	extern void sii_platform_sema_delete(void);
	extern void sii_platform_sema_lock(void);
	extern void sii_platform_sema_unlock(void);
	#define SII_OSAL_MUTEX_CREATE(dev_id) sii_platform_sema_create()
	#define SII_OSAL_MUTEX_DELETE(p_mutex) sii_platform_sema_delete()
	#define SII_OSAL_MUTEX_SET(p_mutex) sii_platform_sema_lock()
	#define SII_OSAL_MUTEX_CLR(p_mutex) sii_platform_sema_unlock()
#else
	#define SII_OSAL_MUTEX_CREATE(dev_id)
	#define SII_OSAL_MUTEX_DELETE(p_mutex)
	#define SII_OSAL_MUTEX_SET(p_mutex)
	#define SII_OSAL_MUTEX_CLR(p_mutex)
#endif /* SII943X_USER_DEF__MULTI_THREAD */

#define GPIO_PORT_MASK	(PA_BASE | PB_BASE | PC_BASE | PD_BASE | PF_BASE)
#define GPIO_PIN_MASK	0x0000003C

/***** public type definitions ***********************************************/

struct sii_platform_interface {
	uint32_t dev_id;
};

#define SII_SYS_TIME_MILLI_T	uint32_t

/**
* @brief Platform operation (read/write/platform initialisation) status
*/
enum {
	/* !< Platform operation successful */
	SII_PLATFORM_STATUS__SUCCESS = 0,
	/* !< platform operation failed */
	SII_PLATFORM_STATUS__FAILED = (-1)
};

/**
* @brief GPIO direction
*/
enum sii_platform_gpio_direction {
	SII_PLATFORM_GPIO_DIRECTION__INPUT, /* !< GPIO pin as Input */
	SII_PLATFORM_GPIO_DIRECTION__OUTPUT,/* !< GPIO pin as output */
	SII_PLATFORM_GPIO_DIRECTION__OPEN_DRAIN,/* !< GPIO pin as Open drain */
	SII_PLATFORM_GPIO_DIRECTION__INOUT, /* !< GPIO pin as bi-directional */
};

/* SiI9438 Driver Instance Device IDs and associated Slave IDs*/
#define SII9437_INST_1		1
#ifdef SII_BUILD_FPGA
#define	SII9437_INST_1_I2C_ADDR_PAGE0	0x62 /* main page */
#else
#define	SII9437_INST_1_I2C_ADDR_PAGE0	0x60 /* main page */
#endif
#define	SII9437_INST_1_I2C_ADDR_PAGE1	0x6E /* eArcRxAddr */
#define	SII9437_INST_1_I2C_ADDR_PAGE2	0x64 /* phyAddr */


#define SII9438_OFFSET_SIZE_BYTES		1
#define SII9612_OFFSET_SIZE_BYTES		2

#define SII_I2C_ADDR				0x60

#define IRQ_HANDLED
#define IRQ_NONE

#define SII_DRIVER_NAME "sii9438"
#define COMPATIBLE_NAME "simg,sii9438"

struct list_node {
	uint8_t data[28];
	uint16_t header;
	struct list_node *link;
};

/* Dynamic Memory Management APIs */
void *sii_mem_alloc(uint32_t Size);
void sii_mem_free(void *p);

#undef offsetof
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
/*
#define container_of(ptr, type, member) ({                      \
	const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
	(type *)( (char *)__mptr - offsetof(type,member) );})
*/

#define list_add_tail(a, b) do {} while (0)
#define list_del(a) do {} while (0)
//#define list_for_each_entry(a, b, c) while (0)

#define PRINT_LOGS

#if defined(PRINT_LOGS)
/* #define printf */
#define pr_cmd(format, ...)     do {} while (0)
//#define pr_info(format, ...)    tsprintf(format, ## __VA_ARGS__)

//#define pr_debug(format, ...)   do {} while (0)

//#define pr_warn(format, ...)    tsprintf(format, ## __VA_ARGS__)

#define pr_info_timer(format, ...)   do {} while (0)
#define pr_debug_timer(format, ...)  do {} while (0)
#define pr_debug1(format, ...)       tsprintf(format, ## __VA_ARGS__)
#define pr_debug2(format, ...)       do {} while (0)

#define dev_err(format, ...)         do {} while (0)

#define pr_intr(format, ...)    tsprintf(format, ## __VA_ARGS__)

#else

#define pr_cmd(format, ...)     do {} while (0)
#define pr_info(format, ...)    do {} while (0)

#define pr_debug(format, ...)   do {} while (0)

#define pr_warn(format, ...) do {} while (0)

#define pr_info_timer(format, ...)   do {} while (0)
#define pr_debug_timer(format, ...)  do {} while (0)
#define pr_debug1(format, ...)       do {} while (0)
#define pr_debug2(format, ...)       do {} while (0)

#define dev_err(format, ...)         do {} while (0)

#define pr_intr(format, ...)    do {} while (0)

#endif


struct workqueue_struct {
	uint8_t dummy;
};

struct device {
	void *dev_context;
};

void msleep(uint32_t millisec);

#define MAX_THREAD_STACK_SIZE 256

#define SUCCESS 0
#define FAIL    (-1)

//#define GFP_KERNEL FALSE

#define EPERM            1      /* Operation not permitted */
#define ENOENT           2      /* No such file or directory */
#define ESRCH            3      /* No such process */
#define EINTR            4      /* Interrupted system call */
#define EIO              5      /* I/O error */
#define ENXIO            6      /* No such device or address */
#define E2BIG            7      /* Argument list too long */
#define ENOEXEC          8      /* Exec format error */
#define EBADF            9      /* Bad file number */
#define ECHILD          10      /* No child processes */
#define EAGAIN          11      /* Try again */
#define ENOMEM          12      /* Out of memory */
#define EACCES          13      /* Permission denied */
#define EFAULT          14      /* Bad address */
#define ENOTBLK         15      /* Block device required */
#define EBUSY           16      /* Device or resource busy */
#define EEXIST          17      /* File exists */
#define EXDEV           18      /* Cross-device link */
#define ENODEV          19      /* No such device */
#define ENOTDIR         20      /* Not a directory */
#define EISDIR          21      /* Is a directory */
#define EINVAL          22      /* Invalid argument */
#define ENFILE          23      /* File table overflow */
#define EMFILE          24      /* Too many open files */
#define ENOTTY          25      /* Not a typewriter */
#define ETXTBSY         26      /* Text file busy */
#define EFBIG           27      /* File too large */
#define ENOSPC          28      /* No space left on device */
#define ESPIPE          29      /* Illegal seek */
#define EROFS           30      /* Read-only file system */
#define EMLINK          31      /* Too many links */
#define EPIPE           32      /* Broken pipe */
#define EDOM            33      /* Math argument out of domain of func */
#define ERANGE          34      /* Math result not representable */

extern unsigned long volatile jiffies;

#define ANSI_ESC_RESET_TEXT "\x1b[0m"
#define ANSI_ESC_YELLOW_BG "\x1b[43m"
#define ANSI_ESC_WHITE_BG "\x1b[47m"
#define ANSI_ESC_RED_TEXT "\x1b[31m"
#define ANSI_ESC_YELLOW_TEXT "\x1b[33m"
#define ANSI_ESC_GREEN_TEXT "\x1b[32m"
#define ANSI_ESC_BLACK_TEXT "\1b[30m"
#define ANSI_ESC_WHITE_TEXT "\x1b[37m\x1b[1m"
#define ANSI_ESC_MAGENTA_TEXT "\x1b[35m"
#define ANSI_ESC_CYAN_TEXT "\x1b[36m"

/* Sii9438 Specific */

struct gpio {
	unsigned        gpio;
	unsigned long   flags;
	const char      *label;
};

/***** public functions ******************************************************/

/*****************************************************************************/
/**
* @brief Blocking sleep function
*
* This function should not exit until ・ｽｿｽmSec・ｽｿｽ milliseconds of time.
* The sii9436 host driver uses this function for brief delays
* (less than 100 milliseconds).
*
* @param[in]	time_to_sleep	Number of milliseconds that this function
				should wait before it returns.
*
******************************************************************************/
void sii_platform_sleep_msec(uint32_t time_to_sleep);

/*****************************************************************************/
/**
* @brief Time inquiry in milliseconds
*
* Provides time in milliseconds passed since system was powered up.
*
* @retval	Absolute time in milliseconds started from system power up.
*
******************************************************************************/
uint32_t sii_platform_time_msec_query(void);

/*****************************************************************************/
/**
* @brief I2C/SPI Data write function
*
* Implements either I2C or SPI write access to the sii9436 by writing
* ・ｽｿｽsize・ｽｿｽ bytes to memory starting at ・ｽｿｽaddr・ｽｿｽ. If multiple devices are
* present on the platform ・ｽｿｽdevId・ｽｿｽ is used by this function to determine
*  which device to access. This function should return ・ｽｿｽ0・ｽｿｽ if all bytes
* are successfully written and should return ・ｽｿｽ-1・ｽｿｽ if the write fails.
*
* @param[in]	dev_id	Hardware device ID passed to ・ｽｿｽsii943xCreate()・ｽｿｽ.
*			This ID is associated with a physical hardware device
*			and is allocated by the user when this function is
*			implemented.
* @param[in]	address		16 bit address of register.
* @param[in]	p_data_out	Pointer to array of bytes that is required to be
*				written to register 'addr'.
* @param[in]	length		Number of bytes in array that is required to be
*				written to device.
*
* @retval	0 : Write was successful
*		-1 : Write has failed
*
******************************************************************************/
uint32_t sii_platform_host_block_write(uint32_t dev_id, uint16_t address,
		const uint8_t *p_data_out, uint16_t length);

/*****************************************************************************/
/**
* @brief I2C/SPI Data read function
*
* Implements either I2C or SPI read access to the sii9436 by reading 'size'
* bytes from memory starting at ・ｽｿｽaddr・ｽｿｽ. If multiple devices are present on
* the platform ・ｽｿｽdevId・ｽｿｽ is used by this function to determine which device
* to access. This function should return ・ｽｿｽ0・ｽｿｽ if all bytes are successfully
* written and should return ・ｽｿｽ-1・ｽｿｽ if the write fails.
*
* @param[in]	dev_id	Hardware device ID passed to ・ｽｿｽsii9436Create()・ｽｿｽ.
*			This ID is associated with a physical hardware device
*			and is allocated by the user when this function is
*			implemented.
* @param[in]	address		16 bit address of register.
* @param[in]	p_data_in	Pointer to array of bytes that is required to
*				be read from register 'addr'.
* @param[in]	length		Number of bytes in array that is required to be
*				read from device.
*
* @retval               0 : Read was successful
*                      -1 : Read has failed
*
******************************************************************************/
uint32_t sii_platform_host_block_read(uint32_t dev_id, uint16_t address,
		uint8_t *p_data_in,
		uint16_t length);

/*****************************************************************************/
/**
* @brief Device Hardware Reset
*
* Controls level of reset signal connected to device's RST pin.
*
* @param[in]	dev_id		Hardware device ID passed to ・ｽｿｽsii9436Create()・ｽｿｽ.
*				This ID is associated with a physical hardware
*				device and is allocated by the user when this
*				function is implemented.
*
* @param[in]	on		Requested level of reset signal:
*				FALSE : No reset
*				TRUE  : Active reset
*
******************************************************************************/
void sii_platform_device_reset_set(uint32_t devId, bool_t on);

/*****************************************************************************/
/**
* @brief ASCII string logger
*
* Function for outputting NULL terminated log strings to a platform specific
* logging mechanism such as a UART or log file.
*
* @param[in]	msg_str	Pointer to string to be logged.
*
******************************************************************************/
void sii_platform_log_print(const char *msg_str);


void sii_platform_register_api(
		uint32_t (*in_block_write)(uint32_t dev_id, uint16_t addr, const uint8_t *p_data, uint16_t size),
		uint32_t (*in_block_read)(uint32_t dev_id, uint16_t addr, uint8_t *p_data, uint16_t size),
		void (*in_reset_set)(bool_t b_on),
		uint32_t (*in_time_msec_query)(void),
		void (*in_log_print)(const char *message),
		void (*in_sleep_msec)(uint32_t millisec));

#ifdef __cplusplus
}
#endif

#endif /* SII_PLATFORM_API_H */
