/*
 * Copyright (c) 2017 Actions Semiconductor Co., Ltd
 *
 * SPDX-License-Identifier: Apache-2.0
 */

/**
 * @file
 * @brief I2C master driver for Actions SoC
 */

//#define DT_DRV_COMPAT actions_acts_i2c

#include <errno.h>
#include <sys/__assert.h>
#include <stdbool.h>
#include <kernel.h>
#include <device.h>
#include <init.h>
#include <drivers/i2c.h>
#include <soc.h>
#include <board_cfg.h>
#include <sys/ring_buffer.h>

#define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
#include <logging/log.h>
LOG_MODULE_REGISTER(i2c_acts_i2c);

//#define I2C_TIMEOUT_MS					Z_TIMEOUT_MS(50)
#define I2C_WAIT_COMPLETE_MS            (2)
#define I2C_WAIT_TX_FIFO_EMPTY          (1000)
#define I2C_WAIT_ASYNC_TIMEOUT_US       (6000000)

/* I2Cx_CTL */
#define I2C_CTL_GRAS					(0x1 << 0)
#define	I2C_CTL_GRAS_ACK				(0)
#define	I2C_CTL_GRAS_NACK				I2C_CTL_GRAS
#define I2C_CTL_RB						(0x1 << 1)
#define I2C_CTL_GBCC_MASK				(0x3 << 2)
#define I2C_CTL_GBCC(x)					(((x) & 0x3) << 2)
#define	I2C_CTL_GBCC_NONE				I2C_CTL_GBCC(0)
#define	I2C_CTL_GBCC_START				I2C_CTL_GBCC(1)
#define	I2C_CTL_GBCC_STOP				I2C_CTL_GBCC(2)
#define	I2C_CTL_GBCC_RESTART			I2C_CTL_GBCC(3)
#define I2C_CTL_EN						(0x1 << 5)
#define I2C_CTL_IRQE					(0x1 << 6)
#define I2C_CTL_BUSSEL					(1 << 7)
#define I2C_CTL_DRQRE					(1 << 8)
#define I2C_CTL_DRQTE					(1 << 9)
#define I2C_CTL_RX_IRQ_THREHOLD_4BYTES	(0x1 << 10)
#define I2C_CTL_ADM_IRQ_EN				(0x1 << 16)
#define I2C_CTL_NACK_IRQ_EN				(0x1 << 17)
#define I2C_CTL_STD_IRQ_EN				(0x1 << 19)
#define I2C_CTL_FIFO_IRQ_EN				(0x1 << 20)

/* I2Cx_CLKDIV */
#define I2C_CLKDIV_DIV_MASK				(0xff << 0)
#define I2C_CLKDIV_DIV(x)				(((x) & 0xff) << 0)

/* I2Cx_STAT */
#define I2C_STAT_RACK					(0x1 << 0)
#define I2C_STAT_BEB					(0x1 << 1)
#define I2C_STAT_IRQP					(0x1 << 2)
#define I2C_STAT_STPD					(0x1 << 4)
#define I2C_STAT_STAD					(0x1 << 5)
#define I2C_STAT_BBB					(0x1 << 6)
#define I2C_STAT_TCB					(0x1 << 7)
#define I2C_STAT_LBST					(0x1 << 8)
#define I2C_STAT_SAMB					(0x1 << 9)
#define I2C_STAT_SRGC					(0x1 << 10)

/* I2Cx_CMD */
#define I2C_CMD_SBE						(0x1 << 0)
#define I2C_CMD_AS_MASK					(0x7 << 1)
#define I2C_CMD_AS(x)					(((x) & 0x7) << 1)
#define I2C_CMD_RBE						(0x1 << 4)
#define I2C_CMD_SAS_MASK				(0x7 << 5)
#define I2C_CMD_SAS(x)					(((x) & 0x7) << 5)
#define I2C_CMD_DE						(0x1 << 8)
#define I2C_CMD_NS						(0x1 << 9)
#define I2C_CMD_SE						(0x1 << 10)
#define I2C_CMD_MSS						(0x1 << 11)
#define I2C_CMD_WRS						(0x1 << 12)
#define I2C_CMD_EXEC					(0x1 << 15)

/* I2Cx_FIFOCTL */
#define I2C_FIFOCTL_NIB					(0x1 << 0)
#define I2C_FIFOCTL_RFR					(0x1 << 1)
#define I2C_FIFOCTL_TFR					(0x1 << 2)

/* I2Cx_FIFOSTAT */
#define I2C_FIFOSTAT_CECB				(0x1 << 0)
#define I2C_FIFOSTAT_RNB				(0x1 << 1)
#define I2C_FIFOSTAT_RFE				(0x1 << 2)
#define I2C_FIFOSTAT_RFF				(0x1 << 3)
#define I2C_FIFOSTAT_TFE				(0x1 << 4)
#define I2C_FIFOSTAT_TFF				(0x1 << 5)
#define I2C_FIFOSTAT_WRS				(0x1 << 6)
#define I2C_FIFOSTAT_RFD_MASK			(0xf << 8)
#define I2C_FIFOSTAT_RFD_SHIFT			(8)
#define I2C_FIFOSTAT_TFD_MASK			(0xf << 12)
#define I2C_FIFOSTAT_TFD_SHIFT			(12)

/* extract fifo level from fifostat */
#define I2C_RX_FIFO_LEVEL(x)			(((x) >> 8) & 0xff)
#define I2C_TX_FIFO_LEVEL(x)			(((x) >> 12) & 0xff)

#if defined(CONFIG_SOC_SERIES_LEOPARD)
#define MAX_CNT_ONCE 1023
#else
#define MAX_CNT_ONCE 255
#endif

enum i2c_state {
	STATE_INVALID,
	STATE_READ_DATA,
	STATE_WRITE_DATA,
	STATE_TRANSFER_OVER,
	STATE_TRANSFER_ERROR,
};

/* I2C controller */
struct i2c_acts_controller {
	volatile uint32_t ctl;
	volatile uint32_t clkdiv;
	volatile uint32_t stat;
	volatile uint32_t addr;
	volatile uint32_t txdat;
	volatile uint32_t rxdat;
	volatile uint32_t cmd;
	volatile uint32_t fifoctl;
	volatile uint32_t fifostat;
	volatile uint32_t datcnt;
	volatile uint32_t rcnt;
};

struct acts_i2c_config {
	struct i2c_acts_controller *base;
	void (*irq_config_func)(void);
	const char *dma_dev_name;
	uint8_t clock_id;
	uint8_t reset_id;
	uint8_t irq_id;
	uint8_t dma_id;
	uint8_t dma_chan;
	uint8_t use_dma; //not 0, use dma tranfser
	uint8_t use_cmd; //not 0, use cmd tranfser
	uint32_t clk_freq;
};

/* Device run time data */
struct acts_i2c_data {
	struct k_mutex mutex;
	struct k_sem complete_sem;
	struct i2c_msg *cur_msg;
	uint32_t msg_buf_ptr;
	uint32_t xfer_len;
	enum i2c_state state;
	uint32_t clk_freq;
#ifdef CONFIG_I2C_SLAVE
	bool master_active;
	uint32_t status;
	struct i2c_slave_config *slave_cfg;
	bool slave_attached;
#endif

#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
	uint32_t device_power_state;
#endif
#ifdef CONFIG_I2C_ASYNC
	struct ring_buf cbuf;
	struct i2c_msg_async cur_msg_async;
#ifdef CONFIG_I2C_ASYNC_MSG_INTERNAL_BUFFER
	uint8_t *rx_sync_buf;
#endif
	uint8_t on_irq_async_msg : 1; /* If 1 to indicate that irq is on handling async messages */
	uint8_t cur_msg_async_valid : 1; /* If 1 to indicate that the current async message is valid */
	uint8_t i2c_isbusy : 1;
#endif
};

#define DEV_NAME(dev) ((dev)->name)
#define DEV_CFG(dev) \
	((const struct acts_i2c_config *const)(dev)->config)
#define DEV_DATA(dev) \
	((struct acts_i2c_data *const)(dev)->data)

#ifdef CONFIG_I2C_ASYNC
#if IS_ENABLED(CONFIG_I2C_0)
#define I2C0_RINGBUF_SIZE (CONFIG_I2C_0_MAX_ASYNC_ITEMS * sizeof(struct i2c_msg_async))
static uint8_t i2c0_ringbuf[I2C0_RINGBUF_SIZE];
#endif

#if IS_ENABLED(CONFIG_I2C_1)
#define I2C1_RINGBUF_SIZE (CONFIG_I2C_1_MAX_ASYNC_ITEMS * sizeof(struct i2c_msg_async))
static uint8_t i2c1_ringbuf[I2C1_RINGBUF_SIZE];
#endif

#if defined(CONFIG_SOC_SERIES_LEOPARD)
#if IS_ENABLED(CONFIG_I2C_2)
#define I2C2_RINGBUF_SIZE (CONFIG_I2C_2_MAX_ASYNC_ITEMS * sizeof(struct i2c_msg_async))
static uint8_t i2c2_ringbuf[I2C2_RINGBUF_SIZE];
#endif

#if IS_ENABLED(CONFIG_I2C_3)
#define I2C3_RINGBUF_SIZE (CONFIG_I2C_3_MAX_ASYNC_ITEMS * sizeof(struct i2c_msg_async))
static uint8_t i2c3_ringbuf[I2C3_RINGBUF_SIZE];
#endif
#endif

#endif

static void i2c_acts_dump_regs(struct i2c_acts_controller *i2c)
{

	LOG_INF("I2C base 0x%x:\n" \
		"  ctl:      %x  clkdiv: %x  stat:    %x\n" \
		"  addr:     %x  cmd:    %x  fifoctl: %x\n" \
		"  fifostat: %x  datcnt: %x  rcnt:    %x\n",
		(unsigned int)i2c,
		i2c->ctl, i2c->clkdiv, i2c->stat,
		i2c->addr, i2c->cmd, i2c->fifoctl,
		i2c->fifostat, i2c->datcnt, i2c->rcnt);

}

static void i2c_acts_set_clk(struct i2c_acts_controller *i2c,
		 uint32_t clk_freq)
{
	uint32_t div;
	uint32_t pclk_freq = CONFIG_HOSC_CLK_MHZ*1000000;

	if ((pclk_freq == 0) || (clk_freq == 0))
		return;

	div = (pclk_freq + clk_freq * 16 - 1) / (clk_freq * 16);
	i2c->clkdiv = I2C_CLKDIV_DIV(div);

	return;
}

static int i2c_acts_configure(const struct device *dev, uint32_t config)
{
	const struct acts_i2c_config *cfg = DEV_CFG(dev);
	struct acts_i2c_data *data = DEV_DATA(dev);
	struct i2c_acts_controller *i2c = cfg->base;
	uint32_t bitrate;

	if (!(config & I2C_MODE_MASTER)) {
		LOG_ERR("Master Mode is not enabled");
		return -EIO;
	}

	if (config & I2C_ADDR_10_BITS) {
		LOG_ERR("I2C 10-bit addressing is currently not supported");
		LOG_ERR("Please submit a patch");
		return -EIO;
	}

	/* Configure clock */
	switch (I2C_SPEED_GET(config)) {
	case I2C_SPEED_STANDARD:
		bitrate = 100000U;
		break;
	case I2C_SPEED_FAST:
		bitrate = 400000U;
		break;
	case I2C_SPEED_FAST_PLUS:
		bitrate = 1000000U;
		break;
	case I2C_SPEED_HIGH:
	case I2C_SPEED_ULTRA:
		bitrate = 1500000U;
		break;

	default:
		LOG_ERR("Unsupported I2C speed value");
		return -EIO;
	}

	/* Setup clock waveform */
	i2c_acts_set_clk(i2c, bitrate);

	data->clk_freq = bitrate;

	return 0;
}

static void i2c_acts_reset(struct i2c_acts_controller *i2c)
{
	/* reenable i2c controller */
	i2c->ctl = 0;

	/* clear i2c status */
	i2c->stat = 0xff;

	/* clear i2c fifo status */
	i2c->fifoctl = I2C_FIFOCTL_RFR | I2C_FIFOCTL_TFR;

	/* wait until fifo reset complete */
	while(i2c->fifoctl & (I2C_FIFOCTL_RFR | I2C_FIFOCTL_TFR))
		;
}

static int i2c_acts_wait_complete(struct i2c_acts_controller *i2c,
					uint32_t timeout_ms, bool is_read)
{
	uint32_t start_time, curr_time;
	int i = 0;

	start_time = k_cycle_get_32();
	while (!(i2c->fifostat & I2C_FIFOSTAT_CECB)) {
		curr_time = k_cycle_get_32();
		if (k_cyc_to_us_floor32(curr_time - start_time) >= (timeout_ms * 1000)) {
			LOG_ERR("wait i2c cmd done timeout");
			return -ETIMEDOUT;
		}
	}

	/* wait data really output to device */
	if(!is_read){
		for (i = 0; i < I2C_WAIT_TX_FIFO_EMPTY; i++) {
			if (i2c->fifostat & I2C_FIFOSTAT_TFE)
				break;
			k_busy_wait(1);
		}
	}

	if (i == I2C_WAIT_TX_FIFO_EMPTY) {
		LOG_ERR("wait i2c tx fifo:0x%x empty timeout",
				i2c->fifostat);
		return -ETIMEDOUT;
	}

	return 0;
}

#if defined(CONFIG_I2C_SLAVE)
static void i2c_slave_acts_isr(struct device *dev);
#endif

static int __i2c_acts_transfer(const struct device *dev, struct i2c_msg *msgs,
			     uint8_t num_msgs, uint16_t addr)
{
	const struct acts_i2c_config *config = DEV_CFG(dev);
	struct acts_i2c_data *data =  DEV_DATA(dev);
	struct i2c_acts_controller *i2c = config->base;
	struct i2c_msg *msg ;
	int i, is_read, ret = 0;
	uint32_t fifo_cmd;  /* fifostat */

	if (!num_msgs)
		return 0;

#if defined(CONFIG_I2C_SLAVE)
	data->master_active = true;
#endif

	i2c_acts_reset(i2c);

	/* enable I2C controller IRQ */
	i2c->ctl = I2C_CTL_IRQE | I2C_CTL_EN | I2C_CTL_STD_IRQ_EN | I2C_CTL_FIFO_IRQ_EN | I2C_CTL_RX_IRQ_THREHOLD_4BYTES;
	fifo_cmd = I2C_CMD_EXEC | I2C_CMD_MSS | I2C_CMD_SE | I2C_CMD_DE
		| I2C_CMD_NS | I2C_CMD_SBE;

	if (num_msgs == 2) {
		/* set internal address and restart cmd for read operation */
		fifo_cmd |= I2C_CMD_AS(msgs[0].len + 1) | I2C_CMD_SAS(1);

		/* write i2c device address */
		i2c->txdat = (addr << 1);

		/* write internal register address */
		for (i = 0; i < msgs[0].len; i++)
			i2c->txdat = msgs[0].buf[i];

		msg = &msgs[1];
		/* restart flag */
		if (msg->flags & I2C_MSG_RESTART) {
			fifo_cmd |= I2C_CMD_RBE;
		}
	} else {
		/* only send device addess for 1 message */
		fifo_cmd |= I2C_CMD_AS(1);
		msg = &msgs[0];
	}

	data->cur_msg = msg;
	data->msg_buf_ptr = 0;

	LOG_DBG("msg flags:0x%x addr:0x%x buf:%p len:0x%x num_msgs:%d cur_msg:%p",
			msg->flags, addr, msg->buf, msg->len, num_msgs, data->cur_msg);

	is_read = ((msg->flags & I2C_MSG_RW_MASK) == I2C_MSG_READ) ? 1 : 0;
	 /* set data count for the message */
	if(msg->len > MAX_CNT_ONCE){
		data->xfer_len = MAX_CNT_ONCE;
		fifo_cmd &= ~(I2C_CMD_SE | I2C_CMD_NS);
		printk("--i2c is_read=%d  len=%d\n", is_read, msg->len);
	}else{
		data->xfer_len = msg->len;
	}
	i2c->datcnt = data->xfer_len;

	if (is_read) {
		/* read from device, with WR bit */
		i2c->txdat = (addr << 1) | 1;
		data->state = STATE_READ_DATA;
	} else {
		/* write to device */
		if ((num_msgs == 1) || (msg->flags & I2C_MSG_RESTART)) {
			i2c->txdat = (addr << 1);
		}

		/* Write data to FIFO */
		for (i = 0; i < msg->len; i++) {
			if (i2c->fifostat & I2C_FIFOSTAT_TFF)
				break;

			i2c->txdat = msg->buf[i];
		}
		data->msg_buf_ptr = i;
		data->state = STATE_WRITE_DATA;
	}

	i2c->fifoctl = 0;

	/* write fifo command to start transfer */
	i2c->cmd = fifo_cmd;

	return ret;
}

static void i2c_acts_update_cur_async_msg(const struct device *dev,
				struct i2c_msg_async *src_msg)
{
	struct acts_i2c_data *data = DEV_DATA(dev);

	memcpy(&data->cur_msg_async, src_msg, sizeof(struct i2c_msg_async));

#ifdef CONFIG_I2C_ASYNC_MSG_INTERNAL_BUFFER
	uint8_t i;
	for (i = 0; i < data->cur_msg_async.num_msgs; i++) {
		if (data->cur_msg_async.msg[i].flags & I2C_MSG_READ) {
			memset(data->cur_msg_async.rx_buf, 0,
					sizeof(data->cur_msg_async.rx_buf));
			data->cur_msg_async.msg[i].buf = data->cur_msg_async.rx_buf;
		} else {
			memcpy(data->cur_msg_async.tx_buf,
					data->cur_msg_async.msg[i].buf,
					data->cur_msg_async.msg[i].len);
			data->cur_msg_async.msg[i].buf = data->cur_msg_async.tx_buf;
		}
	}
#endif

	data->cur_msg_async_valid = 1;
}

void i2c_acts_isr(void *arg)
{
	struct device *dev = (struct device *)arg;
	const struct acts_i2c_config *config =  DEV_CFG(dev);
	struct acts_i2c_data *data =  DEV_DATA(dev);
	struct i2c_acts_controller *i2c = config->base;
	struct i2c_msg *cur_msg = data->cur_msg;
	uint32_t stat, fifostat, len, fifo_cmd;
	int ret;

	LOG_DBG("stat:0x%x fifostat:0x%x state:%d",
			i2c->stat, i2c->fifostat, data->state);

#if defined(CONFIG_I2C_SLAVE)
	if (data->slave_attached && !data->master_active) {
		i2c_slave_acts_isr(dev);
		return;
	}
#endif

	stat = i2c->stat;
	fifostat = i2c->fifostat;

	/* check error */
	if (fifostat & I2C_FIFOSTAT_RNB) {
		LOG_ERR("no ACK from device");
		data->state = STATE_TRANSFER_ERROR;
		goto stop;
	} else if (stat & I2C_STAT_BEB) {
		LOG_ERR("bus error");
		data->state = STATE_TRANSFER_ERROR;
		goto stop;
	}
	i2c->stat |= I2C_STAT_IRQP;
	LOG_DBG("msg_buf_ptr:%d cur_msg:%p len:%d", data->msg_buf_ptr, cur_msg, data->xfer_len);

	if (data->state == STATE_READ_DATA) {
		/* read data from FIFO */
		while ((!(i2c->fifostat & I2C_FIFOSTAT_RFE)) &&
			data->msg_buf_ptr < data->xfer_len) {
			cur_msg->buf[data->msg_buf_ptr++] = i2c->rxdat;
		}

		/* all data is transfered? */
		if (data->msg_buf_ptr >= cur_msg->len) {
			data->state = STATE_TRANSFER_OVER;
		}
	} else {
		/* all data is transfered? */
		if (data->msg_buf_ptr >= cur_msg->len) {
			data->state = STATE_TRANSFER_OVER;
		}
		/* write data to FIFO */
		while (!(i2c->fifostat & I2C_FIFOSTAT_TFF) &&
		       data->msg_buf_ptr < data->xfer_len) {
			i2c->txdat = cur_msg->buf[data->msg_buf_ptr++];

			/* wait fifo stat is updated */
			fifostat = i2c->fifostat;
		}
	}
	if(I2C_FIFOSTAT_CECB & fifostat){
		if (data->msg_buf_ptr < cur_msg->len){
			len = cur_msg->len - data->msg_buf_ptr;
			printk("--i2c irq remain =%d\n", len);
			if(len > MAX_CNT_ONCE){
				data->xfer_len += MAX_CNT_ONCE;
				i2c->datcnt = MAX_CNT_ONCE;
				fifo_cmd = I2C_CMD_EXEC | I2C_CMD_MSS | I2C_CMD_DE; // 0x8900
			}else{
				data->xfer_len += len;
				i2c->datcnt = len;
				fifo_cmd = I2C_CMD_NS | I2C_CMD_SE|I2C_CMD_EXEC | I2C_CMD_MSS | I2C_CMD_DE; // 0x8f00;
			}
			if (data->state != STATE_READ_DATA) {
				/* write data to FIFO */
				while (!(i2c->fifostat & I2C_FIFOSTAT_TFF) &&
					   data->msg_buf_ptr < data->xfer_len) {
					i2c->txdat = cur_msg->buf[data->msg_buf_ptr++];

					/* wait fifo stat is updated */
					fifostat = i2c->fifostat;
				}
			}
			i2c->cmd = fifo_cmd;
		}
	}

stop:
	//i2c->stat |= I2C_STAT_IRQP;

	if (data->state == STATE_TRANSFER_ERROR ||
	    data->state == STATE_TRANSFER_OVER) {

		/* FIXME: add extra 2 bytes for TX to generate IRQ */
		if (i2c->datcnt != cur_msg->len) {
			i2c->datcnt = cur_msg->len;
		}

		ret = i2c_acts_wait_complete(i2c, I2C_WAIT_COMPLETE_MS,
			((cur_msg->flags & I2C_MSG_RW_MASK) == I2C_MSG_READ) ? true : false);
		if (ret)
			data->state = STATE_TRANSFER_ERROR;

		if(data->state == STATE_TRANSFER_ERROR){
			i2c_acts_dump_regs(i2c);
		}
		/* disable i2c controller */
		i2c->ctl = 0;

		if (data->cur_msg_async.async_func) {
			data->cur_msg_async.async_func(data->cur_msg_async.cb_data,
				data->cur_msg_async.msg, data->cur_msg_async.num_msgs,
			(data->state == STATE_TRANSFER_ERROR)? true : false);
		}
		data->cur_msg_async_valid = 0;

		/* read next async message */
		struct i2c_msg_async msg_async = {0};
		ret = ring_buf_get(&data->cbuf, (uint8_t *)&msg_async, sizeof(struct i2c_msg_async));
		if (ret > 0) {
			LOG_DBG("read cbuf msg addr:0x%x", msg_async.addr);
			data->on_irq_async_msg = 1;

			i2c_acts_update_cur_async_msg(dev, &msg_async);

			__i2c_acts_transfer(dev, data->cur_msg_async.msg,
				data->cur_msg_async.num_msgs, data->cur_msg_async.addr);
		} else {
			ring_buf_reset(&data->cbuf);
			data->on_irq_async_msg = 0;
			data->i2c_isbusy = 0; /*i2c is stop*/

#if defined(CONFIG_I2C_SLAVE)
			data->master_active = false;
#endif
		}
	}
}

static int i2c_acts_transfer_async(const struct device *dev, struct i2c_msg_async *msg_async)
{
	struct acts_i2c_data *data = DEV_DATA(dev);
	//const struct acts_i2c_config *config = DEV_CFG(dev);
	//struct i2c_acts_controller *i2c = config->base;
	int ret, flags;
	bool need_start_flag = false;

	if ((!msg_async->num_msgs)|| (msg_async->num_msgs > 2)) {
		LOG_ERR("invalid msg number:%d", msg_async->num_msgs);
		return -EINVAL;
	}

	flags = irq_lock();
	if ((!data->on_irq_async_msg) && (!data->cur_msg_async_valid))
		need_start_flag = 1;


	if (need_start_flag) {

		i2c_acts_update_cur_async_msg(dev, msg_async);

		ret = __i2c_acts_transfer(dev, data->cur_msg_async.msg,
				data->cur_msg_async.num_msgs, data->cur_msg_async.addr);
		data->i2c_isbusy = 1; /*i2c is busy*/
	} else {
		LOG_DBG("write msg addr:0x%x to cbuf", msg_async->addr);
		ret = ring_buf_put(&data->cbuf, (const uint8_t *)msg_async, sizeof(struct i2c_msg_async));
		if (!ret) {
			LOG_ERR("write cbuf error(%d, %d)", data->on_irq_async_msg, data->cur_msg_async_valid);
			//i2c_acts_dump_regs(i2c);
			//i2c_acts_reset(i2c);
			//ring_buf_reset(&data->cbuf);
			//data->cur_msg_async_valid = 0;
			//data->on_irq_async_msg = 0;
			ret = -EAGAIN;
		} else {
			ret = 0;
		}
	}

	irq_unlock(flags);

	return ret;
}

static int i2c_acts_async_dummy_cb(void *cb_data, struct i2c_msg *msgs,
					uint8_t num_msgs, bool is_err)
{
	const struct device *dev = (const struct device *)cb_data;
	struct acts_i2c_data *data = DEV_DATA(dev);

#ifdef CONFIG_I2C_ASYNC_MSG_INTERNAL_BUFFER
	if (data->rx_sync_buf && data->cur_msg_async_valid) {
		uint8_t i;
		for (i = 0; i < data->cur_msg_async.num_msgs; i++) {
			if (data->cur_msg_async.msg[i].flags & I2C_MSG_READ) {
				memcpy(data->rx_sync_buf,
						data->cur_msg_async.msg[i].buf,
						data->cur_msg_async.msg[i].len);
				break;
			}
		}
	}
#endif

	k_sem_give(&data->complete_sem);

	return 0;
}
static uint32_t i2c_get_msg_overtimer(const struct device *dev, struct i2c_msg_async *msg)
{
	const struct acts_i2c_config *config = DEV_CFG(dev);
	struct acts_i2c_data *data =  DEV_DATA(dev);
	uint32_t tlen ,clk_freq, ot;

	tlen = msg->msg[0].len;
	if(msg->num_msgs == 2){
		tlen +=  msg->msg[1].len;
	}
	clk_freq = config->clk_freq;
	if(data->clk_freq)
		clk_freq = data->clk_freq;
	/* > 50*/
	ot = ((tlen<<15)/clk_freq + 50);
	//printk("ot=%d, len=%d, clk_freq=%d\n", ot, tlen, clk_freq);
	return  ot;   // ms = tlen*1000 /clk_freq/10 = 10000*tlen/clk_freq, mul= 3, # (tlen<<15)/clk_freq
}

static int i2c_acts_transfer(const struct device *dev, struct i2c_msg *msgs,
			     uint8_t num_msgs, uint16_t addr)
{
	const struct acts_i2c_config *config = DEV_CFG(dev);
	struct acts_i2c_data *data =  DEV_DATA(dev);
	struct i2c_acts_controller *i2c = config->base;
	int i = 0, ret = 0;
	uint32_t start_time, ot;
	struct i2c_msg_async msg_async = {0};

	if ((!num_msgs) || (num_msgs > 2)) {
		LOG_ERR("invalid num_msgs:%d", num_msgs);
		return -EINVAL;
	}

	msg_async.num_msgs = num_msgs;
	msg_async.async_func = i2c_acts_async_dummy_cb;
	msg_async.cb_data = (void *)dev;
	msg_async.addr = addr;

	for (i = 0; i < num_msgs; i++)
		memcpy(&msg_async.msg[i], &msgs[i], sizeof(struct i2c_msg));

	k_mutex_lock(&data->mutex, K_FOREVER);

#ifdef CONFIG_I2C_ASYNC_MSG_INTERNAL_BUFFER
	for (i = 0; i < num_msgs; i++) {
		if (msgs[i].flags & I2C_MSG_READ) {
			data->rx_sync_buf = msgs[i].buf;
			break;
		}
	}
#endif

	/* wait async messages finished */
	start_time = k_cycle_get_32();
	while (ring_buf_size_get(&data->cbuf) > 0) {
		if (k_cyc_to_us_floor32(k_cycle_get_32() - start_time)
			>= I2C_WAIT_ASYNC_TIMEOUT_US) {
			LOG_ERR("wait async timeout");
			k_mutex_unlock(&data->mutex);
			return -ETIMEDOUT;
		}
	}

	/* reset sem to fix i2c-isr problem */
	k_sem_reset(&data->complete_sem);

	ret = i2c_acts_transfer_async(dev, &msg_async);
	if (ret) {
		LOG_ERR("i2c async error:%d", ret);
		i2c_acts_dump_regs(i2c);
		goto out;
	}

	//ret = k_sem_take(&data->complete_sem, I2C_TIMEOUT_MS);
	ot = i2c_get_msg_overtimer(dev, &msg_async);
	ret = k_sem_take(&data->complete_sem, Z_TIMEOUT_MS(ot));
	if (ret) {
		/* wait timeout */
		LOG_ERR("addr 0x%x: wait =%d ms timeout ", addr, ot);
		ret = -ETIMEDOUT;
	}

	if (data->state == STATE_TRANSFER_ERROR) {
		LOG_ERR("addr 0x%x: transfer error", addr);
		//i2c_acts_dump_regs(i2c);
		ret = -EIO;
	}

#ifdef CONFIG_I2C_ASYNC_MSG_INTERNAL_BUFFER
	data->rx_sync_buf = NULL;
#endif

out:
	if (ret) {
		i2c_acts_dump_regs(i2c);
		#ifdef CONFIG_I2C_ASYNC
		data->cur_msg_async_valid = 0;
		ring_buf_reset(&data->cbuf);
		data->on_irq_async_msg = 0;
		#endif
	}

	k_mutex_unlock(&data->mutex);
	return ret;
}

int i2c_acts_init(const struct device *dev)
{
	const struct acts_i2c_config *config = DEV_CFG(dev);;
	struct acts_i2c_data *data = DEV_DATA(dev);

	/* enable i2c controller clock */
	acts_clock_peripheral_enable(config->clock_id);

	/* reset i2c controller */
	acts_reset_peripheral(config->reset_id);


	/* setup default clock to 100K */
	i2c_acts_set_clk(config->base, config->clk_freq);

	printk("i2c%d:clk=%d,cmd=%d,dma=%d\n",config->clock_id-CLOCK_ID_I2C0, config->clk_freq,
		config->use_cmd, config->use_dma);

	k_mutex_init(&data->mutex);
	k_sem_init(&data->complete_sem, 0, UINT_MAX);

#if IS_ENABLED(CONFIG_I2C_0)
	if ((uint32_t)config->base == I2C0_REG_BASE)
		ring_buf_init(&data->cbuf, sizeof(i2c0_ringbuf), i2c0_ringbuf);
#endif
#if IS_ENABLED(CONFIG_I2C_1)
	if ((uint32_t)config->base == I2C1_REG_BASE)
		ring_buf_init(&data->cbuf, sizeof(i2c1_ringbuf), i2c1_ringbuf);
#endif
#if defined(CONFIG_SOC_SERIES_LEOPARD)
#if IS_ENABLED(CONFIG_I2C_2)
	if ((uint32_t)config->base == I2C2_REG_BASE)
		ring_buf_init(&data->cbuf, sizeof(i2c2_ringbuf), i2c2_ringbuf);
#endif
#if IS_ENABLED(CONFIG_I2C_3)
	if ((uint32_t)config->base == I2C3_REG_BASE)
		ring_buf_init(&data->cbuf, sizeof(i2c3_ringbuf), i2c3_ringbuf);
#endif
#endif


	data->on_irq_async_msg = 0;
	data->i2c_isbusy = 0;
	config->irq_config_func();

	return 0;
}

#if defined(CONFIG_I2C_SLAVE)

#define I2C_SLAVE_STATUS_IDLE		0
#define I2C_SLAVE_STATUS_READY		1
#define I2C_SLAVE_STATUS_START		2
#define I2C_SLAVE_STATUS_ADDRESS	3
#define I2C_SLAVE_STATUS_MASTER_WRITE	4
#define I2C_SLAVE_STATUS_MASTER_READ	5
#define I2C_SLAVE_STATUS_STOPED		6
#define I2C_SLAVE_STATUS_ERR		15

static void i2c_slave_acts_isr(struct device *dev)
{
	const struct acts_i2c_config *cfg = DEV_CFG(dev);
	struct acts_i2c_data *data = DEV_DATA(dev);
	struct i2c_acts_controller *i2c = cfg->base;
	const struct i2c_slave_callbacks *cf= data->slave_cfg->callbacks;

	uint32_t stat;
	uint16_t addr;
	uint8_t val;

	stat = i2c->stat;
	/* clear pending */
	i2c->stat = I2C_STAT_IRQP;

	/* check error */
	if (stat & I2C_STAT_BEB) {
		LOG_ERR("bus error\n");
		i2c_acts_dump_regs(i2c);
		i2c_acts_reset(i2c);
		data->status = I2C_SLAVE_STATUS_ERR;
		goto out;
	}

	/* detected start signal */
	if (stat & I2C_STAT_STAD) {
		i2c->stat = I2C_STAT_STAD;
		data->status = I2C_SLAVE_STATUS_START;
	}

	/* recieved address or data  */
	if (stat & I2C_STAT_TCB) {
		i2c->stat = I2C_STAT_TCB;
		if (!(i2c->stat & I2C_STAT_LBST)) {
			/* receive address */
			data->status = I2C_SLAVE_STATUS_ADDRESS;
			addr = i2c->rxdat;
			if ((addr >> 1) != data->slave_cfg->address) {
				LOG_ERR("bus address (0x%x) not matched with (0x%x)\n",
					addr >> 1, data->slave_cfg->address);
				i2c->stat |= 0x1ff;
				goto out;
			}

			if (addr & 1) {
				/* master read */
				cf->read_requested(data->slave_cfg, &val);
				i2c->txdat = val;
				data->status = I2C_SLAVE_STATUS_MASTER_READ;
			} else {
				/* master write */
				i2c->ctl &= ~I2C_CTL_GRAS_ACK;
				cf->write_requested(data->slave_cfg);
				data->status = I2C_SLAVE_STATUS_MASTER_WRITE;
			}
		} else {
			/* receive data */
			if (data->status == I2C_SLAVE_STATUS_MASTER_READ) {
				/* master <--- slave */
				if (!(stat & I2C_STAT_RACK)) {
					/* received NACK */
					goto out;
				}
				cf->read_processed(data->slave_cfg, &val);
				i2c->txdat = val;

		    } else {
				/* master ---> slave */
				val = i2c->rxdat;
				if(!cf->write_received(data->slave_cfg, val))
					i2c->ctl |= I2C_CTL_GRAS_ACK;

			}
		}
	}

	/* detected stop signal */
	if (stat & I2C_STAT_STPD) {
		i2c->stat = I2C_STAT_STPD;
		cf->stop(data->slave_cfg);
		i2c->ctl &= ~I2C_CTL_GRAS_ACK;
 	}
out:
	i2c->ctl |= I2C_CTL_RB;
}


/* Attach and start I2C as slave */
int i2c_acts_slave_register(const struct device *dev,
			     struct i2c_slave_config *config)
{
	const struct acts_i2c_config *cfg = DEV_CFG(dev);
	struct acts_i2c_data *data = DEV_DATA(dev);
	struct i2c_acts_controller *i2c = cfg->base;

	if (!config) {
		return -EINVAL;
	}

	if (data->slave_attached) {
		LOG_ERR("i2c: err slave is registered\n");
		return -EBUSY;
	}

	if (data->master_active) {
		LOG_ERR("i2c: master is transfer\n");
		return -EBUSY;
	}
	i2c->addr = config->address << 1;
	data->slave_cfg = config;
	data->slave_attached = true;
	LOG_DBG("i2c: slave registered");
	i2c->ctl = I2C_CTL_IRQE | I2C_CTL_EN | I2C_CTL_RB | I2C_CTL_GRAS_ACK | I2C_CTL_STD_IRQ_EN;

	return 0;
}

int i2c_acts_slave_unregister(const struct device *dev,
			       struct i2c_slave_config *config)
{
	const struct acts_i2c_config *cfg = DEV_CFG(dev);
	struct acts_i2c_data *data = DEV_DATA(dev);
	struct i2c_acts_controller *i2c = cfg->base;

	if (!data->slave_attached) {
		return -EINVAL;
	}

	if (data->master_active) {
		return -EBUSY;
	}
	data->slave_cfg = NULL;
	/* disable i2c controller */
	i2c->ctl = 0;

	data->slave_attached = false;

	LOG_DBG("i2c: slave unregistered");

	return 0;
}

#endif /* defined(CONFIG_I2C_SLAVE) */

const struct i2c_driver_api i2c_acts_driver_api = {
	.configure = i2c_acts_configure,
	.transfer = i2c_acts_transfer,
#if defined(CONFIG_I2C_SLAVE)
	.slave_register = i2c_acts_slave_register,
	.slave_unregister = i2c_acts_slave_unregister,
#endif

#if defined(CONFIG_I2C_ASYNC)
	.transfer_async = i2c_acts_transfer_async,
#endif
};

#ifdef CONFIG_PM_DEVICE
int i2c_acts_pm_control(const struct device *device, enum pm_device_action action)
{
	struct acts_i2c_data *data = DEV_DATA(device);
	if(action == PM_DEVICE_ACTION_SUSPEND){
		if (data->i2c_isbusy) {
			printk("i2c busy, not suspend\n");
			return -EINVAL;
		}
	}
	if(action == PM_DEVICE_ACTION_RESUME){
		const struct acts_i2c_config *config = device->config;
		i2c_acts_set_clk(config->base, config->clk_freq);
	}
	return 0;
}
#else
#define i2c_acts_pm_control 	NULL
#endif


#define  dma_use(n)  	(\
		.dma_dev_name =  CONFIG_DMA_0_NAME, \
		.dma_id = CONFIG_I2C_##n##_DMA_ID,\
		.dma_chan = CONFIG_I2C_##n##_DMA_CHAN,\
		.use_dma = 1,					\
		)

#define dma_not(n)	(\
		.use_dma = 0, \
		 )
//		 COND_CODE_1(CONFIG_I2C_##n##_USE_DMA,dma_use(n), dma_not(n))

#define I2C_ACTS_INIT(n)						\
	static const struct device DEVICE_NAME_GET(i2c##n##_acts);		\
									\
	static void i2c##n##_acts_irq_config(void)			\
	{								\
		IRQ_CONNECT(IRQ_ID_I2C##n, CONFIG_I2C_##n##_IRQ_PRI,	\
			    i2c_acts_isr,				\
			    DEVICE_GET(i2c##n##_acts), 0);		\
		irq_enable(IRQ_ID_I2C##n);				\
	}								\
									\
	static const struct acts_i2c_config i2c##n##_acts_config = {	\
		.base = (struct i2c_acts_controller *)I2C##n##_REG_BASE,			\
		.irq_config_func = i2c##n##_acts_irq_config,			\
		.clock_id = CLOCK_ID_I2C##n,\
		.reset_id = RESET_ID_I2C##n,\
		 COND_DMA_CODE(CONFIG_I2C_##n##_USE_DMA, CONFIG_I2C_##n##_DMA_ID, CONFIG_I2C_##n##_DMA_CHAN) \
		.use_cmd = 0,\
		.irq_id = IRQ_ID_I2C##n,			\
		.clk_freq = CONFIG_I2C_##n##_CLK_FREQ,		\
	};								\
									\
	static  struct acts_i2c_data i2c##n##_acts_data;		\
									\
	DEVICE_DEFINE(i2c##n##_acts, CONFIG_I2C_##n##_NAME,		\
			    &i2c_acts_init, i2c_acts_pm_control,		\
			    &i2c##n##_acts_data, &i2c##n##_acts_config,	\
			    POST_KERNEL, CONFIG_I2C_INIT_PRIORITY,	\
			    &i2c_acts_driver_api);

#if IS_ENABLED(CONFIG_I2C_0)
I2C_ACTS_INIT(0)
#endif
#if IS_ENABLED(CONFIG_I2C_1)
I2C_ACTS_INIT(1)
#endif
#if defined(CONFIG_SOC_SERIES_LEOPARD)
#if IS_ENABLED(CONFIG_I2C_2)
I2C_ACTS_INIT(2)
#endif
#if IS_ENABLED(CONFIG_I2C_3)
I2C_ACTS_INIT(3)
#endif
#endif
