/*
 * Copyright (c) 2022 Andes Technology Corporation
 *
 * SPDX-License-Identifier: Apache-2.0
 */

/**
 * @file I2C driver for AndesTech atciic100 IP
 */
#include <errno.h>
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/i2c.h>
#include <zephyr/sys/util.h>
#include <zephyr/sys/sys_io.h>

#define I2C_MAX_COUNT		256
#define BURST_CMD_COUNT		1

#define RED_IDR			0x00
#define REG_CFG			0x10
#define REG_INTE		0x14
#define REG_STAT		0x18
#define REG_ADDR		0x1C
#define REG_DATA		0x20
#define REG_CTRL		0x24
#define REG_CMD			0x28
#define REG_SET			0x2C

#define I2C_BASE(dev) \
	((const struct i2c_atciic100_config * const)(dev)->config)->base

#define I2C_CFG(dev)	(I2C_BASE(dev) + REG_CFG)
#define I2C_INTE(dev)	(I2C_BASE(dev) + REG_INTE)
#define I2C_STAT(dev)	(I2C_BASE(dev) + REG_STAT)
#define I2C_ADDR(dev)	(I2C_BASE(dev) + REG_ADDR)
#define I2C_CMD(dev)	(I2C_BASE(dev) + REG_CMD)
#define I2C_SET(dev)	(I2C_BASE(dev) + REG_SET)
#define I2C_DATA(dev)	(I2C_BASE(dev) + REG_DATA)
#define I2C_CTRL(dev)	(I2C_BASE(dev) + REG_CTRL)

#define TARGET_ADDR_MSK			BIT_MASK(10)
#define DATA_MSK			BIT_MASK(8)

/* Interrupt Enable Register(RW) */
#define IEN_ALL				BIT_MASK(10)
#define IEN_CMPL			BIT(9)
#define IEN_BYTE_RECV			BIT(8)
#define IEN_BYTE_TRANS			BIT(7)
#define IEN_START			BIT(6)
#define IEN_STOP			BIT(5)
#define IEN_ARB_LOSE			BIT(4)
#define IEN_ADDR_HIT			BIT(3)
#define IEN_FIFO_HALF			BIT(2)
#define IEN_FIFO_FULL			BIT(1)
#define IEN_FIFO_EMPTY			BIT(0)

/* Status Register(RW) */
#define STATUS_W1C_ALL			(BIT_MASK(7) << 3)
#define STATUS_LINE_SDA			BIT(14)
#define STATUS_LINE_SCL			BIT(13)
#define STATUS_GEN_CALL			BIT(12)
#define STATUS_BUS_BUSY			BIT(11)
#define STATUS_ACK			BIT(10)
#define STATUS_CMPL			BIT(9)
#define STATUS_BYTE_RECV		BIT(8)
#define STATUS_BYTE_TRANS		BIT(7)
#define STATUS_START			BIT(6)
#define STATUS_STOP			BIT(5)
#define STATUS_ARB_LOSE			BIT(4)
#define STATUS_ADDR_HIT			BIT(3)
#define STATUS_FIFO_HALF		BIT(2)
#define STATUS_FIFO_FULL		BIT(1)
#define STATUS_FIFO_EMPTY		BIT(0)

/* Control Register(RW) */
#define CTRL_PHASE_START		BIT(12)
#define CTRL_PHASE_ADDR			BIT(11)
#define CTRL_PHASE_DATA			BIT(10)
#define CTRL_PHASE_STOP			BIT(9)
#define CTRL_DIR			BIT(8)
#define CTRL_DATA_COUNT			BIT_MASK(8)

/* Command Register(RW) */
#define CMD_MSK				BIT_MASK(3)
#define CMD_NO_ACT			(0x0)
#define CMD_ISSUE_TRANSACTION		(0x1)
#define CMD_ACK				(0x2)
#define CMD_NACK			(0x3)
#define CMD_CLEAR_FIFO			(0x4)
#define CMD_RESET_I2C			(0x5)

/* Setup Register(RW) */
#define SETUP_T_SUDAT			(BIT_MASK(5) << 24)
#define SETUP_T_SP			(BIT_MASK(3) << 21)
#define SETUP_T_HDDAT			(BIT_MASK(5) << 16)
#define SETUP_T_SCL_RATIO		BIT(13)
#define SETUP_T_SCLHI			(BIT_MASK(9) << 4)
#define SETUP_DMA_EN			BIT(3)
#define SETUP_CONTROLLER		BIT(2)
#define SETUP_ADDRESSING		BIT(1)
#define SETUP_I2C_EN			BIT(0)

#if CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC == 30000000

#define SETUP_T_SUDAT_STD		(0x3)
#define SETUP_T_SP_STD			(0x1)
#define SETUP_T_HDDAT_STD		(5)
#define SETUP_T_SCL_RATIO_STD		(0x0)
#define SETUP_T_SCLHI_STD		(138)

#define SETUP_T_SUDAT_FAST		(0x0)
#define SETUP_T_SP_FAST			(0x1)
#define SETUP_T_HDDAT_FAST		(5)
#define SETUP_T_SCL_RATIO_FAST		(0x1)
#define SETUP_T_SCLHI_FAST		(18)

#define SETUP_T_SUDAT_FAST_P		(0x0)
#define SETUP_T_SP_FAST_P		(0x1)
#define SETUP_T_HDDAT_FAST_P		(0x0)
#define SETUP_T_SCL_RATIO_FAST_P	(0x1)
#define SETUP_T_SCLHI_FAST_P		(6)

#elif CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC == 40000000

#define SETUP_T_SUDAT_STD		(0x4)
#define SETUP_T_SP_STD			(0x2)
#define SETUP_T_HDDAT_STD		(0x6)
#define SETUP_T_SCL_RATIO_STD		(0x0)
#define SETUP_T_SCLHI_STD		(182)

#define SETUP_T_SUDAT_FAST		(0x0)
#define SETUP_T_SP_FAST			(0x2)
#define SETUP_T_HDDAT_FAST		(0x6)
#define SETUP_T_SCL_RATIO_FAST		(0x1)
#define SETUP_T_SCLHI_FAST		(23)

#define SETUP_T_SUDAT_FAST_P		(0x0)
#define SETUP_T_SP_FAST_P		(0x2)
#define SETUP_T_HDDAT_FAST_P		(0x0)
#define SETUP_T_SCL_RATIO_FAST_P	(0x1)
#define SETUP_T_SCLHI_FAST_P		(7)

#else

#define SETUP_T_SUDAT_STD		(0x9)
#define SETUP_T_SP_STD			(0x3)
#define SETUP_T_HDDAT_STD		(12)
#define SETUP_T_SCL_RATIO_STD		(0x0)
#define SETUP_T_SCLHI_STD		(287)

#define SETUP_T_SUDAT_FAST		(0x0)
#define SETUP_T_SP_FAST			(0x3)
#define SETUP_T_HDDAT_FAST		(12)
#define SETUP_T_SCL_RATIO_FAST		(0x1)
#define SETUP_T_SCLHI_FAST		(38)

#define SETUP_T_SUDAT_FAST_P		(0x0)
#define SETUP_T_SP_FAST_P		(0x3)
#define SETUP_T_HDDAT_FAST_P		(0x0)
#define SETUP_T_SCL_RATIO_FAST_P	(0x1)
#define SETUP_T_SCLHI_FAST_P		(13)

#endif

#define SETUP_SPEED_MSK			(SETUP_T_SUDAT		| \
					SETUP_T_SP		| \
					SETUP_T_HDDAT		| \
					SETUP_T_SCL_RATIO	| \
					SETUP_T_SCLHI)

#define SETUP_SPEED_STD			((SETUP_T_SUDAT_STD << 24)	| \
					(SETUP_T_SP_STD  << 21)		| \
					(SETUP_T_HDDAT_STD << 16)	| \
					(SETUP_T_SCL_RATIO_STD << 13)	| \
					(SETUP_T_SCLHI_STD << 4))

#define SETUP_SPEED_FAST		((SETUP_T_SUDAT_FAST << 24)	| \
					(SETUP_T_SP_FAST  << 21)	| \
					(SETUP_T_HDDAT_FAST << 16)	| \
					(SETUP_T_SCL_RATIO_FAST << 13)	| \
					(SETUP_T_SCLHI_FAST << 4))

#define SETUP_SPEED_FAST_PLUS		((SETUP_T_SUDAT_FAST_P << 24)	| \
					(SETUP_T_SP_FAST_P  << 21)	| \
					(SETUP_T_HDDAT_FAST_P << 16)	| \
					(SETUP_T_SCL_RATIO_FAST_P << 13)| \
					(SETUP_T_SCLHI_FAST_P << 4))

#define MAX_XFER_SZ			(256)

enum _i2c_ctrl_reg_item_dir {
	I2C_CONTROLLER_TX = 0x0,
	I2C_CONTROLLER_RX = 0x1,
	I2C_TARGET_TX = 0x1,
	I2C_TARGET_RX = 0x0,
};

/* I2C driver running state */
enum _i2c_driver_state {
	I2C_DRV_NONE = 0x0,
	I2C_DRV_INIT = BIT(0),
	I2C_DRV_POWER = BIT(1),
	I2C_DRV_CFG_PARAM = BIT(2),
	I2C_DRV_CONTROLLER_TX = BIT(3),
	I2C_DRV_CONTROLLER_RX = BIT(4),
	I2C_DRV_TARGET_TX = BIT(5),
	I2C_DRV_TARGET_RX = BIT(6),
	I2C_DRV_CONTROLLER_TX_CMPL = BIT(7),
	I2C_DRV_CONTROLLER_RX_CMPL = BIT(8),
	I2C_DRV_TARGET_TX_CMPL = BIT(9),
	I2C_DRV_TARGET_RX_CMPL = BIT(10),
};

/* brief I2C Status */
struct _i2c_status {
/* /< Mode: 0=Slave, 1=Master */
	uint32_t mode:1;
	uint32_t general_call: 1;
	uint32_t arbitration_lost : 1;
	uint32_t target_ack       : 1;
};

struct i2c_atciic100_dev_data_t {
	struct k_sem			bus_lock;
	struct k_sem			device_sync_sem;
	volatile uint32_t		driver_state;
	uint8_t				*middleware_rx_buf;
	uint8_t				*middleware_tx_buf;
	uint32_t			fifo_depth;
	uint32_t			target_addr;
	uint32_t			xfer_wt_num;
	uint32_t			xfer_rd_num;
	uint32_t			xfered_data_wt_ptr; /* write pointer  */
	uint32_t			xfered_data_rd_ptr; /* read pointer  */
	volatile struct _i2c_status	status;
	const struct i2c_target_callbacks	*target_callbacks;
	struct i2c_target_config	*target_config;
};
