/* Copyright 2014 The Chromium OS Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

/* I2C port module for Chrome EC */

#include "clock.h"
#include "clock_chip.h"
#include "common.h"
#include "console.h"
#include "gpio.h"
#include "hooks.h"
#include "i2c.h"
#include "i2c_chip.h"
#include "registers.h"
#include "task.h"
#include "timer.h"
#include "util.h"

#if !(DEBUG_I2C)
#define CPUTS(...)
#define CPRINTS(...)
#define CPRINTF(...)
#else
#define CPUTS(outstr) cputs(CC_I2C, outstr)
#define CPRINTS(format, args...) cprints(CC_I2C, format, ## args)
#define CPRINTF(format, args...) cprintf(CC_I2C, format, ## args)
#endif

/* Timeout for device should be available after reset (SMBus spec. unit:ms) */
#define I2C_MAX_TIMEOUT 35
/*
 * Timeout for SCL held to low by slave device . (SMBus spec. unit:ms).
 * Some I2C devices may violate this timing and clock stretch for longer.
 * TODO: Consider increasing this timeout.
 */
#define I2C_MIN_TIMEOUT 25

/*
 * I2C module that supports FIFO mode has 32 bytes Tx FIFO and
 * 32 bytes Rx FIFO.
 */
#define NPCX_I2C_FIFO_MAX_SIZE    32

/* Macro functions of I2C */
#define I2C_START(ctrl) SET_BIT(NPCX_SMBCTL1(ctrl), NPCX_SMBCTL1_START)
#define I2C_STOP(ctrl)  SET_BIT(NPCX_SMBCTL1(ctrl), NPCX_SMBCTL1_STOP)
#define I2C_NACK(ctrl)  SET_BIT(NPCX_SMBCTL1(ctrl), NPCX_SMBCTL1_ACK)
/* I2C moudule automatically stall bus after sending slave address */
#define I2C_STALL(ctrl) SET_BIT(NPCX_SMBCTL1(ctrl), NPCX_SMBCTL1_STASTRE)
#define I2C_WRITE_BYTE(ctrl, data) (NPCX_SMBSDA(ctrl) = data)
#define I2C_READ_BYTE(ctrl, data)  (data = NPCX_SMBSDA(ctrl))
#define I2C_TX_FIFO_OCCUPIED(ctrl) (NPCX_SMBTXF_STS(ctrl) & 0x3F)
#define I2C_TX_FIFO_AVAILABLE(ctrl) \
		(NPCX_I2C_FIFO_MAX_SIZE - I2C_TX_FIFO_OCCUPIED(ctrl))

#define I2C_RX_FIFO_OCCUPIED(ctrl) (NPCX_SMBRXF_STS(ctrl) & 0x3F)
#define I2C_RX_FIFO_AVAILABLE(ctrl) \
			(NPCX_I2C_FIFO_MAX_SIZE - I2C_RX_FIFO_OCCUPIED(ctrl))
/* Drive the SCL signal to low */
#define I2C_SCL_STALL(ctrl) \
		(NPCX_SMBCTL3(ctrl) = \
			(NPCX_SMBCTL3(ctrl) & ~BIT(NPCX_SMBCTL3_SCL_LVL)) | \
			 BIT(NPCX_SMBCTL3_SDA_LVL))
/*
 * Release the SCL signal to be pulled up to high level.
 * Note: The SCL might be still driven low either by I2C module or external
 * devices connected to ths bus.
 */
#define I2C_SCL_FREE(ctrl) \
		(NPCX_SMBCTL3(ctrl) |= BIT(NPCX_SMBCTL3_SCL_LVL) | \
			 BIT(NPCX_SMBCTL3_SDA_LVL))

/* Error values that functions can return */
enum smb_error {
	SMB_OK = 0,                 /* No error                            */
	SMB_CH_OCCUPIED,            /* Channel is already occupied         */
	SMB_MEM_POOL_INIT_ERROR,    /* Memory pool initialization error    */
	SMB_BUS_FREQ_ERROR,         /* SMbus freq was not valid            */
	SMB_INVLAID_REGVALUE,       /* Invalid SMbus register value        */
	SMB_UNEXIST_CH_ERROR,       /* Channel does not exist              */
	SMB_NO_SUPPORT_PTL,         /* Not support SMBus Protocol          */
	SMB_BUS_ERROR,              /* Encounter bus error                 */
	SMB_MASTER_NO_ADDRESS_MATCH,/* No slave address match (Master Mode)*/
	SMB_READ_DATA_ERROR,        /* Read data for SDA error             */
	SMB_READ_OVERFLOW_ERROR,    /* Read data over than we predict      */
	SMB_TIMEOUT_ERROR,          /* Timeout expired                     */
	SMB_MODULE_ISBUSY,          /* Module is occupied by other device  */
	SMB_BUS_BUSY,               /* SMBus is occupied by other device   */
};

/*
 * Internal SMBus Interface driver states values, which reflect events
 * which occurred on the bus
 */
enum smb_oper_state_t {
	SMB_IDLE,
	SMB_MASTER_START,
	SMB_WRITE_OPER,
	SMB_READ_OPER,
	SMB_FAKE_READ_OPER,
	SMB_REPEAT_START,
	SMB_WRITE_SUSPEND,
	SMB_READ_SUSPEND,
};

/* I2C controller state data */
struct i2c_status {
	int                   flags;     /* Flags (I2C_XFER_*) */
	const uint8_t        *tx_buf;    /* Entry pointer of transmit buffer */
	uint8_t              *rx_buf;    /* Entry pointer of receive buffer  */
	uint16_t              sz_txbuf;  /* Size of Tx buffer in bytes */
	uint16_t              sz_rxbuf;  /* Size of rx buffer in bytes */
	uint16_t              idx_buf;   /* Current index of Tx/Rx buffer */
	uint16_t              slave_addr_flags;/* Target slave address */
	enum smb_oper_state_t oper_state;/* Smbus operation state */
	enum smb_error        err_code;  /* Error code */
	int                   task_waiting; /* Task waiting on controller */
	uint32_t              timeout_us;/* Transaction timeout */
};
/* I2C controller state data array */
static struct i2c_status i2c_stsobjs[I2C_CONTROLLER_COUNT];

/* I2C timing setting */
struct i2c_timing {
	uint8_t clock; /* I2C source clock. (Unit: MHz)*/
	uint8_t HLDT;  /* I2C hold-time. (Unit: clocks) */
	uint8_t k1;    /* k1 = SCL low-time (Unit: clocks) */
	uint8_t k2;    /* k2 = SCL high-time (Unit: clocks) */
};

/* I2C timing setting array of 400K & 1M Hz */
static const struct i2c_timing i2c_400k_timings[] = {
	{20,  7, 32, 22},
	{15,  7, 24, 18},};
const unsigned int i2c_400k_timing_used = ARRAY_SIZE(i2c_400k_timings);

static const struct i2c_timing i2c_1m_timings[] = {
	{20, 7, 16, 10},
	{15, 7, 14, 10},};
const unsigned int i2c_1m_timing_used = ARRAY_SIZE(i2c_1m_timings);

/* IRQ for each port */
const uint32_t i2c_irqs[I2C_CONTROLLER_COUNT] = {
		NPCX_IRQ_SMB1, NPCX_IRQ_SMB2, NPCX_IRQ_SMB3, NPCX_IRQ_SMB4,
#if NPCX_FAMILY_VERSION >= NPCX_FAMILY_NPCX7
		NPCX_IRQ_SMB5, NPCX_IRQ_SMB6, NPCX_IRQ_SMB7, NPCX_IRQ_SMB8,
#endif
};
BUILD_ASSERT(ARRAY_SIZE(i2c_irqs) == I2C_CONTROLLER_COUNT);

static void i2c_init_bus(int controller)
{
	/* Enable FIFO mode */
	if (IS_ENABLED(NPCX_I2C_FIFO_SUPPORT))
		SET_BIT(NPCX_SMBFIF_CTL(controller), NPCX_SMBFIF_CTL_FIFO_EN);

	/* Enable module - before configuring CTL1 */
	SET_BIT(NPCX_SMBCTL2(controller), NPCX_SMBCTL2_ENABLE);

	/* Enable SMB interrupt and New Address Match interrupt source */
	SET_BIT(NPCX_SMBCTL1(controller), NPCX_SMBCTL1_NMINTE);
	SET_BIT(NPCX_SMBCTL1(controller), NPCX_SMBCTL1_INTEN);
}

int i2c_bus_busy(int controller)
{
	return IS_BIT_SET(NPCX_SMBCST(controller), NPCX_SMBCST_BB) ? 1 : 0;
}

static int i2c_wait_stop_completed(int controller, int timeout)
{
	if (timeout <= 0)
		return EC_ERROR_INVAL;

	/* Wait till STOP condition is generated. ie. I2C bus is idle. */
	while (timeout > 0) {
		if (!IS_BIT_SET(NPCX_SMBCTL1(controller), NPCX_SMBCTL1_STOP))
			break;
		if (--timeout > 0)
			msleep(1);
	}

	if (timeout)
		return EC_SUCCESS;
	else
		return EC_ERROR_TIMEOUT;
}

static void i2c_abort_data(int controller)
{
	/* Clear NEGACK, STASTR and BER bits */
	SET_BIT(NPCX_SMBST(controller), NPCX_SMBST_BER);
	SET_BIT(NPCX_SMBST(controller), NPCX_SMBST_STASTR);
	SET_BIT(NPCX_SMBST(controller), NPCX_SMBST_NEGACK);

	/* Wait till STOP condition is generated */
	if (i2c_wait_stop_completed(controller, I2C_MAX_TIMEOUT)
			!= EC_SUCCESS) {
		cprintf(CC_I2C, "Abort i2c %02x fail!\n", controller);
		/* Clear BB (BUS BUSY) bit */
		SET_BIT(NPCX_SMBCST(controller), NPCX_SMBCST_BB);
		return;
	}

	/* Clear BB (BUS BUSY) bit */
	SET_BIT(NPCX_SMBCST(controller), NPCX_SMBCST_BB);
}

static int i2c_reset(int controller)
{
	uint16_t timeout = I2C_MAX_TIMEOUT;
	/* Disable the SMB module */
	CLEAR_BIT(NPCX_SMBCTL2(controller), NPCX_SMBCTL2_ENABLE);

	while (--timeout) {
		/* WAIT FOR SCL & SDA IS HIGH */
		if (IS_BIT_SET(NPCX_SMBCTL3(controller), NPCX_SMBCTL3_SCL_LVL)
		  && IS_BIT_SET(NPCX_SMBCTL3(controller), NPCX_SMBCTL3_SDA_LVL))
			break;
		msleep(1);
	}

	if (timeout == 0) {
		cprintf(CC_I2C, "Reset i2c %02x fail!\n", controller);
		return 0;
	}

	/* Init the SMB module again */
	i2c_init_bus(controller);
	return 1;
}

static void i2c_select_bank(int controller, int bank)
{
	if (bank)
		SET_BIT(NPCX_SMBCTL3(controller), NPCX_SMBCTL3_BNK_SEL);
	else
		CLEAR_BIT(NPCX_SMBCTL3(controller), NPCX_SMBCTL3_BNK_SEL);
}

static void i2c_stall_bus(int controller, int stall)
{
	i2c_select_bank(controller, 0);
	/*
	 * Enable the writing to SCL_LVL and SDA_LVL bit in
	 * SMBnCTL3 register. Then, firmware can set SCL_LVL to 0 to
	 * stall the bus when needed. Note: this register should be
	 * accessed when bank = 0.
	 */
	SET_BIT(NPCX_SMBCTL4(controller), NPCX_SMBCTL4_LVL_WE);
	if (stall)
		I2C_SCL_STALL(controller);
	else
		I2C_SCL_FREE(controller);
	/*
	 * Disable the writing to SCL_LVL and SDA_LVL bit in
	 * SMBnCTL3 register. It will prevent form changing the level of
	 * SCL/SDA when touching other bits in SMBnCTL3 register.
	 */
	CLEAR_BIT(NPCX_SMBCTL4(controller), NPCX_SMBCTL4_LVL_WE);
	i2c_select_bank(controller, 1);
}

static void i2c_recovery(int controller, volatile struct i2c_status *p_status)
{
	cprintf(CC_I2C,
		"i2c %d recovery! error code is %d, current state is %d\n",
		controller, p_status->err_code, p_status->oper_state);

	/* Make sure the bus is not stalled before exit. */
	if (IS_ENABLED(NPCX_I2C_FIFO_SUPPORT))
		i2c_stall_bus(controller, 0);

	/* Abort data, wait for STOP condition completed. */
	i2c_abort_data(controller);

	/* Reset i2c controller by re-enable i2c controller*/
	if (!i2c_reset(controller))
		return;

	/* Restore to idle status */
	p_status->oper_state = SMB_IDLE;
}

/*
 * This function can be called in either single-byte mode or FIFO mode.
 * In single-byte mode - it always write 1 byte to SMBSDA register at one time.
 * In FIFO mode - write as many as available bytes in FIFO at one time.
 */
static void i2c_fifo_write_data(int controller)
{
	int len, fifo_avail, i;

	volatile struct i2c_status *p_status = i2c_stsobjs + controller;

	len = 1;
	if (IS_ENABLED(NPCX_I2C_FIFO_SUPPORT)) {
		len = p_status->sz_txbuf - p_status->idx_buf;
		fifo_avail = I2C_TX_FIFO_AVAILABLE(controller);
		len = MIN(len, fifo_avail);
	}
	for (i = 0; i < len; i++) {
		I2C_WRITE_BYTE(controller,
				p_status->tx_buf[p_status->idx_buf++]);
		CPRINTF("%02x ",
				p_status->tx_buf[p_status->idx_buf - 1]);
	}
	CPRINTF("\n");
}

enum smb_error i2c_master_transaction(int controller)
{
	/* Set i2c mode to object */
	int events = 0;
	volatile struct i2c_status *p_status = i2c_stsobjs + controller;

	/* Switch to bank 1 to access I2C FIO registers */
	if (IS_ENABLED(NPCX_I2C_FIFO_SUPPORT))
		i2c_select_bank(controller, 1);

	/* Assign current SMB status of controller */
	if (p_status->oper_state == SMB_IDLE) {
		/* New transaction */
		p_status->oper_state = SMB_MASTER_START;
		/* Clear FIFO and status bit */
		if (IS_ENABLED(NPCX_I2C_FIFO_SUPPORT)) {
			NPCX_SMBFIF_CTS(controller) =
				BIT(NPCX_SMBFIF_CTS_RXF_TXE) |
				BIT(NPCX_SMBFIF_CTS_CLR_FIFO);
		}
	} else if (p_status->oper_state == SMB_WRITE_SUSPEND) {
		if (p_status->sz_txbuf == 0) {
			/* Read bytes from next transaction */
			p_status->oper_state = SMB_REPEAT_START;
			CPUTS("R");
		} else {
			/* Continue to write the other bytes */
			p_status->oper_state = SMB_WRITE_OPER;
			CPRINTS("-W");
			/*
			 * This function can be called in either single-byte
			 * mode or FIFO mode.
			 */
			i2c_fifo_write_data(controller);
		}
	} else if (p_status->oper_state == SMB_READ_SUSPEND) {
		if (!IS_ENABLED(NPCX_I2C_FIFO_SUPPORT)) {
			/*
			 * Do extra read if read length is 1 and I2C_XFER_STOP
			 * is set simultaneously.
			 */
			if (p_status->sz_rxbuf == 1 &&
					(p_status->flags & I2C_XFER_STOP)) {
				/*
				 * Since SCL is released after reading last
				 * byte from previous transaction, adding a
				 * extra byte for next transaction which let
				 * ec sets NACK bit in time is necessary.
				 * Or i2c master cannot generate STOP
				 * when the last byte is ACK during receiving.
				 */
				p_status->sz_rxbuf++;
				p_status->oper_state = SMB_FAKE_READ_OPER;
			} else
				/*
				 * Need to read the other bytes from
				 * next transaction
				 */
				p_status->oper_state = SMB_READ_OPER;
		}
	} else
		cprintf(CC_I2C, "Unexpected i2c state machine! %d\n",
				p_status->oper_state);

	if (IS_ENABLED(NPCX_I2C_FIFO_SUPPORT)) {
		if (p_status->sz_rxbuf > 0) {
			if (p_status->sz_rxbuf > NPCX_I2C_FIFO_MAX_SIZE) {
				/* Set RX threshold = FIFO_MAX_SIZE */
				SET_FIELD(NPCX_SMBRXF_CTL(controller),
						NPCX_SMBRXF_CTL_RX_THR,
						NPCX_I2C_FIFO_MAX_SIZE);
			} else {
				/*
				 * set RX threshold = remaining data bytes
				 * (it should be <= FIFO_MAX_SIZE)
				 */
				SET_FIELD(NPCX_SMBRXF_CTL(controller),
						NPCX_SMBRXF_CTL_RX_THR,
						p_status->sz_rxbuf);
				/*
				 * Set LAST bit generate the NACK at the
				 * last byte of the data group in FIFO
				 */
				if (p_status->flags & I2C_XFER_STOP) {
					SET_BIT(NPCX_SMBRXF_CTL(controller),
							NPCX_SMBRXF_CTL_LAST);
				}
			}

			/* Free the stalled SCL signal */
			if (p_status->oper_state == SMB_READ_SUSPEND) {
				p_status->oper_state = SMB_READ_OPER;
				i2c_stall_bus(controller, 0);
			}
		}
	}

	/* Generate a START condition */
	if (p_status->oper_state == SMB_MASTER_START ||
			p_status->oper_state == SMB_REPEAT_START) {
		I2C_START(controller);
		CPUTS("ST");
	}

	/* Enable event and error interrupts */
	task_enable_irq(i2c_irqs[controller]);

	/* Wait for transfer complete or timeout */
	events = task_wait_event_mask(TASK_EVENT_I2C_IDLE,
			p_status->timeout_us);

	/* Disable event and error interrupts */
	task_disable_irq(i2c_irqs[controller]);

	/*
	 * Accessing FIFO register is only needed during transaction.
	 * Switch back to bank 0 at the end of transaction
	 */
	if (IS_ENABLED(NPCX_I2C_FIFO_SUPPORT))
		i2c_select_bank(controller, 0);

	/*
	 * If Stall-After-Start mode is still enabled since NACK or BUS error
	 * occurs, disable it.
	 */
	if (IS_BIT_SET(NPCX_SMBCTL1(controller), NPCX_SMBCTL1_STASTRE))
		CLEAR_BIT(NPCX_SMBCTL1(controller), NPCX_SMBCTL1_STASTRE);

	/* Handle bus timeout */
	if ((events & TASK_EVENT_I2C_IDLE) == 0) {
		p_status->err_code = SMB_TIMEOUT_ERROR;
		/* Recovery I2C controller */
		i2c_recovery(controller, p_status);
	}
	/* Recovery bus if we encounter bus error */
	else if (p_status->err_code == SMB_BUS_ERROR)
		i2c_recovery(controller, p_status);

	/* Wait till STOP condition is generated for normal transaction */
	if (p_status->err_code == SMB_OK && i2c_wait_stop_completed(controller,
			I2C_MIN_TIMEOUT) != EC_SUCCESS) {
		cprintf(CC_I2C,
			"STOP fail! scl %02x is held by slave device!\n",
			controller);
		p_status->err_code = SMB_TIMEOUT_ERROR;
	}

	return p_status->err_code;
}

/* Issue stop condition if necessary and end transaction */
void i2c_done(int controller)
{
	volatile struct i2c_status *p_status = i2c_stsobjs + controller;

	/* need to STOP or not */
	if (p_status->flags & I2C_XFER_STOP) {
		/* Issue a STOP condition on the bus */
		I2C_STOP(controller);
		CPUTS("-SP");
		/* Clear RXF_TXE bit (RX FIFO full/TX FIFO empty) */
		if (IS_ENABLED(NPCX_I2C_FIFO_SUPPORT))
			NPCX_SMBFIF_CTS(controller) =
						BIT(NPCX_SMBFIF_CTS_RXF_TXE);

		/* Clear SDAST by writing mock byte */
		I2C_WRITE_BYTE(controller, 0xFF);
	}

	/* Set error code */
	p_status->err_code = SMB_OK;
	/* Set SMB status if we need stall bus */
	p_status->oper_state = (p_status->flags & I2C_XFER_STOP)
				? SMB_IDLE : SMB_WRITE_SUSPEND;
	/*
	 * Disable interrupt for i2c master stall SCL
	 * and forbid SDAST generate interrupt
	 * until common layer start other transactions
	 */
	if (p_status->oper_state == SMB_WRITE_SUSPEND)
		task_disable_irq(i2c_irqs[controller]);

	/* Notify upper layer */
	task_set_event(p_status->task_waiting, TASK_EVENT_I2C_IDLE);
	CPUTS("-END");
}

static void i2c_handle_receive(int controller)
{
	uint8_t data;
	volatile struct i2c_status *p_status = i2c_stsobjs + controller;

	/* last byte is about to be read - end of transaction */
	if (p_status->idx_buf == (p_status->sz_rxbuf - 1)) {
		/* need to STOP or not */
		if (p_status->flags & I2C_XFER_STOP) {
			/* Stop should set before reading last byte */
			I2C_STOP(controller);
			CPUTS("-SP");
		} else {
			/*
			 * Disable interrupt before i2c master read SDA
			 * reg (stall SCL) and forbid SDAST generate
			 * interrupt until starting other transactions
			 */
			task_disable_irq(i2c_irqs[controller]);
		}
	}
	/* Check if byte-before-last is about to be read */
	else if (p_status->idx_buf == (p_status->sz_rxbuf - 2)) {
		/*
		 * Set nack before reading byte-before-last,
		 * so that nack will be generated after receive
		 * of last byte
		 */
		if (p_status->flags & I2C_XFER_STOP) {
			I2C_NACK(controller);
			CPUTS("-GNA");
		}
	}

	/* Read data for SMBSDA */
	I2C_READ_BYTE(controller, data);
	CPRINTS("-R(%02x)", data);

	/* Read to buf. Skip last byte if meet SMB_FAKE_READ_OPER */
	if (p_status->oper_state == SMB_FAKE_READ_OPER &&
			p_status->idx_buf == (p_status->sz_rxbuf - 1))
		p_status->idx_buf++;
	else
		p_status->rx_buf[p_status->idx_buf++] = data;

	/* last byte is read - end of transaction */
	if (p_status->idx_buf == p_status->sz_rxbuf) {
		/* Set current status */
		p_status->oper_state = (p_status->flags & I2C_XFER_STOP)
				? SMB_IDLE : SMB_READ_SUSPEND;
		/* Set error code */
		p_status->err_code = SMB_OK;
		/* Notify upper layer of missing data */
		task_set_event(p_status->task_waiting, TASK_EVENT_I2C_IDLE);
		CPUTS("-END");
	}
}

static void i2c_fifo_read_data(int controller, uint8_t bytes_in_fifo)
{
	volatile struct i2c_status *p_status = i2c_stsobjs + controller;

	while (bytes_in_fifo--) {
		uint8_t data;

		data = NPCX_SMBSDA(controller);
		p_status->rx_buf[p_status->idx_buf++] = data;
		CPRINTF("%02x ", data);
	}
	CPRINTF("\n");
}

static void i2c_fifo_handle_receive(int controller)
{
	uint8_t bytes_in_fifo, remaining_bytes;

	volatile struct i2c_status *p_status = i2c_stsobjs + controller;

	/*
	 * Clear RX_THST bit (RX-FIFO Threshold Status).
	 * It is set when RX_BYTES = RX_THR after being RX_BYTES < RX_THR
	 */
	SET_BIT(NPCX_SMBRXF_STS(controller), NPCX_SMBRXF_STS_RX_THST);
	SET_BIT(NPCX_SMBFIF_CTS(controller), NPCX_SMBFIF_CTS_RXF_TXE);

	bytes_in_fifo = I2C_RX_FIFO_OCCUPIED(controller);
	remaining_bytes = p_status->sz_rxbuf - p_status->idx_buf;
	if (remaining_bytes - bytes_in_fifo <= 0) {
		/*
		 * Last byte is about to be read - end of transaction.
		 * Stop should be set before reading last byte.
		 */
		if (p_status->flags & I2C_XFER_STOP) {
			I2C_STOP(controller);
			CPUTS("-FSP");
		} else {
			task_disable_irq(i2c_irqs[controller]);
			/*
			 * The I2C bus will be freed from stalled and continue
			 * to recevie data when reading data from FIFO.
			 * Pull SCL signal down to stall the bus manually.
			 * SCL signal will be freed when it gets a new I2C
			 * transaction call from common layer.
			 */
			i2c_stall_bus(controller, 1);
		}

		CPRINTS("-LFR");
		i2c_fifo_read_data(controller, remaining_bytes);
	} else {
		CPRINTS("-FR");
		/*
		 * The I2C bus will be freed from stalled and continue to
		 * recevie data when reading data from FIFO.
		 * This may caue driver cannot set the new Rx threshold in time.
		 * Manually stall SCL signal until the new Rx threshold is set.
		 */
		i2c_stall_bus(controller, 1);
		i2c_fifo_read_data(controller, bytes_in_fifo);
		remaining_bytes = p_status->sz_rxbuf - p_status->idx_buf;
		if (remaining_bytes > 0) {
			if (remaining_bytes > NPCX_I2C_FIFO_MAX_SIZE) {
				SET_FIELD(NPCX_SMBRXF_CTL(controller),
						NPCX_SMBRXF_CTL_RX_THR,
						NPCX_I2C_FIFO_MAX_SIZE);
			} else {
				SET_FIELD(NPCX_SMBRXF_CTL(controller),
						NPCX_SMBRXF_CTL_RX_THR,
						remaining_bytes);
				if (p_status->flags & I2C_XFER_STOP) {
					SET_BIT(NPCX_SMBRXF_CTL(controller),
							NPCX_SMBRXF_CTL_LAST);
					CPRINTS("-FGNA");
				}
			}

		}
		i2c_stall_bus(controller, 0);

	}
	/* last byte is read - end of transaction */
	if (p_status->idx_buf == p_status->sz_rxbuf) {
		/* Set current status */
		p_status->oper_state = (p_status->flags & I2C_XFER_STOP)
				? SMB_IDLE : SMB_READ_SUSPEND;
		/* Set error code */
		p_status->err_code = SMB_OK;
		/* Notify upper layer of missing data */
		task_set_event(p_status->task_waiting, TASK_EVENT_I2C_IDLE);
		CPUTS("-END");
	}

}

static void i2c_handle_sda_irq(int controller)
{
	volatile struct i2c_status *p_status = i2c_stsobjs + controller;
	uint8_t addr_8bit = I2C_STRIP_FLAGS(p_status->slave_addr_flags) << 1;

	/* 1 Issue Start is successful ie. write address byte */
	if (p_status->oper_state == SMB_MASTER_START
			|| p_status->oper_state == SMB_REPEAT_START) {
		/* Prepare address byte */
		if (p_status->sz_txbuf == 0) {/* Receive mode */
			p_status->oper_state = SMB_READ_OPER;
			/*
			 * Receiving one or zero bytes - stall bus after START
			 * condition. If there's no slave devices on bus, FW
			 * needn't to set ACK bit.
			 */
			if (p_status->sz_rxbuf < 2)
				I2C_STALL(controller);

			/* Write the address to the bus R bit*/
			I2C_WRITE_BYTE(controller, (addr_8bit | 0x1));
			CPRINTS("-ARR-0x%02x", addr_8bit);
		} else {/* Transmit mode */
			p_status->oper_state = SMB_WRITE_OPER;
			/* Write the address to the bus W bit*/
			I2C_WRITE_BYTE(controller, addr_8bit);
			CPRINTS("-ARW-0x%02x", addr_8bit);
		}
		/* Completed handling START condition */
		return;
	}
	/* 2 Handle master write operation  */
	else if (p_status->oper_state == SMB_WRITE_OPER) {
		/* all bytes have been written, in a pure write operation */
		if (p_status->idx_buf == p_status->sz_txbuf) {
			/*  no more message */
			if (p_status->sz_rxbuf == 0)
				i2c_done(controller);
			/* need to restart & send slave address immediately */
			else {
				/*
				 * Prepare address byte
				 * and start to receive bytes
				 */
				p_status->oper_state = SMB_READ_OPER;
				/* Reset index of buffer */
				p_status->idx_buf = 0;

				/*
				 * Generate (Repeated) Start
				 * upon next write to SDA
				 */
				I2C_START(controller);
				CPUTS("-RST");
				/*
				 * Receiving one byte only - set NACK just
				 * before writing address byte.
				 * Set NACK (ACK bit in the SMBnCTL1 register)
				 * only in the single-byte mode.
				 * In FIFO mode, NACK is set via LAST bit
				 * in the SMBnTXF_CTL register.
				 */
				if (p_status->sz_rxbuf == 1 &&
					(p_status->flags & I2C_XFER_STOP) &&
					!IS_ENABLED(NPCX_I2C_FIFO_SUPPORT)) {
					I2C_NACK(controller);
					CPUTS("-GNA");
				}
				/* Write the address to the bus R bit*/
				I2C_WRITE_BYTE(controller,
					       (addr_8bit | 0x1));
				CPUTS("-ARR");
			}
		}
		/* write next byte (not last byte and not slave address */
		else {
			/*
			 * This function can be called in either single-byte
			 * mode or FIFO mode.
			 */
			CPRINTS("-W");
			i2c_fifo_write_data(controller);
		}
	}
	/* 3 Handle master read operation (read or after a write operation) */
	else if (p_status->oper_state == SMB_READ_OPER ||
			p_status->oper_state == SMB_FAKE_READ_OPER) {
		if (IS_ENABLED(NPCX_I2C_FIFO_SUPPORT))
			i2c_fifo_handle_receive(controller);
		else
			i2c_handle_receive(controller);
	}
}

void i2c_master_int_handler (int controller)
{
	volatile struct i2c_status *p_status = i2c_stsobjs + controller;

	/* Condition 1 : A Bus Error has been identified */
	if (IS_BIT_SET(NPCX_SMBST(controller), NPCX_SMBST_BER)) {
		uint8_t __attribute__((unused)) data;
		/* Generate a STOP condition */
		I2C_STOP(controller);
		CPUTS("-SP");
		/* Clear BER Bit */
		SET_BIT(NPCX_SMBST(controller), NPCX_SMBST_BER);
		/* Make sure slave doesn't hold bus by reading */
		I2C_READ_BYTE(controller, data);

		/* Set error code */
		p_status->err_code = SMB_BUS_ERROR;
		/* Notify upper layer */
		p_status->oper_state = SMB_IDLE;
		task_set_event(p_status->task_waiting, TASK_EVENT_I2C_IDLE);
		CPUTS("-BER");

		/*
		 * Disable smb's interrupts to forbid ec to enter ISR again
		 * before executing error recovery.
		 */
		task_disable_irq(i2c_irqs[controller]);

		/* return for executing error recovery immediately */
		return;
	}

	/* Condition 2: A negative acknowledge has occurred */
	if (IS_BIT_SET(NPCX_SMBST(controller), NPCX_SMBST_NEGACK)) {
		/* Generate a STOP condition */
		I2C_STOP(controller);
		CPUTS("-SP");
		/* Clear NEGACK Bit */
		SET_BIT(NPCX_SMBST(controller), NPCX_SMBST_NEGACK);
		/* Set error code */
		p_status->err_code = SMB_MASTER_NO_ADDRESS_MATCH;
		/* Notify upper layer */
		p_status->oper_state = SMB_IDLE;
		task_set_event(p_status->task_waiting, TASK_EVENT_I2C_IDLE);
		CPUTS("-NA");
	}

	/* Condition 3: A Stall after START has occurred for READ-BYTE */
	if (IS_BIT_SET(NPCX_SMBST(controller), NPCX_SMBST_STASTR)) {
		CPUTS("-STL");

		/* Disable Stall-After-Start mode first */
		CLEAR_BIT(NPCX_SMBCTL1(controller), NPCX_SMBCTL1_STASTRE);

		/*
		 * Generate stop condition and return success status since
		 * ACK received on zero-byte transaction.
		 */
		if (p_status->sz_rxbuf == 0)
			i2c_done(controller);
		/*
		 * Otherwise we have a one-byte transaction, so NACK after
		 * receiving next byte, if requested.
		 * Set NACK (ACK bit in the SMBnCTL1 register) only in the
		 * single-byte mode.
		 * In FIFO mode, NACK is set via LAST bit in the SMBnTXF_CTL
		 * register.
		 */
		else if ((p_status->flags & I2C_XFER_STOP) &&
				 !IS_ENABLED(NPCX_I2C_FIFO_SUPPORT)) {
			I2C_NACK(controller);
		}

		/* Clear STASTR to release SCL after setting NACK/STOP bits */
		SET_BIT(NPCX_SMBST(controller), NPCX_SMBST_STASTR);
	}

	/* Condition 4: SDA status is set - transmit or receive */
	if (IS_BIT_SET(NPCX_SMBST(controller), NPCX_SMBST_SDAST)) {
		i2c_handle_sda_irq(controller);
#if DEBUG_I2C
		/* SDAST still issued with unexpected state machine */
		if (IS_BIT_SET(NPCX_SMBST(controller), NPCX_SMBST_SDAST) &&
				p_status->oper_state != SMB_WRITE_SUSPEND) {
			cprints(CC_I2C, "i2c %d unknown state %d, error %d\n",
			  controller, p_status->oper_state, p_status->err_code);
		}
#endif
	}
}

/**
 * Handle an interrupt on the specified controller.
 *
 * @param controller   I2C controller generating interrupt
 */
void handle_interrupt(int controller)
{
	i2c_master_int_handler(controller);
}

void i2c0_interrupt(void) { handle_interrupt(0); }
void i2c1_interrupt(void) { handle_interrupt(1); }
void i2c2_interrupt(void) { handle_interrupt(2); }
void i2c3_interrupt(void) { handle_interrupt(3); }
#if NPCX_FAMILY_VERSION >= NPCX_FAMILY_NPCX7
void i2c4_interrupt(void) { handle_interrupt(4); }
void i2c5_interrupt(void) { handle_interrupt(5); }
void i2c6_interrupt(void) { handle_interrupt(6); }
void i2c7_interrupt(void) { handle_interrupt(7); }
#endif

DECLARE_IRQ(NPCX_IRQ_SMB1, i2c0_interrupt, 4);
DECLARE_IRQ(NPCX_IRQ_SMB2, i2c1_interrupt, 4);
DECLARE_IRQ(NPCX_IRQ_SMB3, i2c2_interrupt, 4);
DECLARE_IRQ(NPCX_IRQ_SMB4, i2c3_interrupt, 4);
#if NPCX_FAMILY_VERSION >= NPCX_FAMILY_NPCX7
DECLARE_IRQ(NPCX_IRQ_SMB5, i2c4_interrupt, 4);
DECLARE_IRQ(NPCX_IRQ_SMB6, i2c5_interrupt, 4);
DECLARE_IRQ(NPCX_IRQ_SMB7, i2c6_interrupt, 4);
DECLARE_IRQ(NPCX_IRQ_SMB8, i2c7_interrupt, 4);
#endif

/*****************************************************************************/
/* IC specific low-level driver */

void i2c_set_timeout(int port, uint32_t timeout)
{
	int ctrl = i2c_port_to_controller(port);

	/* Return if i2c_port_to_controller() returned an error */
	if (ctrl < 0)
		return;

	/* Param is port, but timeout is stored by-controller. */
	i2c_stsobjs[ctrl].timeout_us =
		timeout ? timeout : I2C_TIMEOUT_DEFAULT_US;
}

int chip_i2c_xfer(const int port,
		  const uint16_t slave_addr_flags,
		  const uint8_t *out, int out_size,
		  uint8_t *in, int in_size, int flags)
{
	volatile struct i2c_status *p_status;
	int ctrl = i2c_port_to_controller(port);

	/* Return error if i2c_port_to_controller() returned an error */
	if (ctrl < 0)
		return EC_ERROR_INVAL;

	/* Skip unnecessary transaction */
	if (out_size == 0 && in_size == 0)
		return EC_SUCCESS;

	p_status = i2c_stsobjs + ctrl;

	/* Assign current task ID */
	p_status->task_waiting = task_get_current();

	/* Select port for multi-ports i2c controller */
	i2c_select_port(port);

	/* Copy data to controller struct */
	p_status->flags       = flags;
	p_status->tx_buf      = out;
	p_status->sz_txbuf    = out_size;
	p_status->rx_buf      = in;
	p_status->sz_rxbuf    = in_size;
	p_status->slave_addr_flags = slave_addr_flags;

	/* Reset index & error */
	p_status->idx_buf     = 0;
	p_status->err_code    = SMB_OK;

	/* Make sure we're in a good state to start */
	if ((flags & I2C_XFER_START) &&
	     /* Ignore busy bus for repeated start */
	     p_status->oper_state != SMB_WRITE_SUSPEND &&
	     (i2c_bus_busy(ctrl)
	     || (i2c_get_line_levels(port) != I2C_LINE_IDLE))) {
		int ret;

		/* Attempt to unwedge the i2c port */
		ret = i2c_unwedge(port);
		if (ret)
			return ret;
		p_status->err_code = SMB_BUS_BUSY;
		/* recover i2c controller */
		i2c_recovery(ctrl, p_status);
		/* Select port again for recovery */
		i2c_select_port(port);
	}

	CPUTS("\n");

	/* Start master transaction */
	i2c_master_transaction(ctrl);

	/* Reset task ID */
	p_status->task_waiting = TASK_ID_INVALID;

	CPRINTS("-Err:0x%02x", p_status->err_code);

	return (p_status->err_code == SMB_OK) ? EC_SUCCESS : EC_ERROR_UNKNOWN;
}

/**
 * Return raw I/O line levels (I2C_LINE_*) for a port when port is in alternate
 * function mode.
 *
 * @param port  Port to check
 * @return      State of SCL/SDA bit 0/1
 */
int i2c_get_line_levels(int port)
{
	return (i2c_raw_get_sda(port) ? I2C_LINE_SDA_HIGH : 0) |
		   (i2c_raw_get_scl(port) ? I2C_LINE_SCL_HIGH : 0);
}

int i2c_raw_get_scl(int port)
{
	enum gpio_signal g;

	/*
	 * Check do we support this port of i2c and return gpio number of scl.
	 * Please notice we cannot read voltage level from GPIO in M4 EC
	 */
	if (get_scl_from_i2c_port(port, &g) == EC_SUCCESS) {
		if (i2c_is_raw_mode(port))
			return gpio_get_level(g);
		else
			return IS_BIT_SET(NPCX_SMBCTL3(
			i2c_port_to_controller(port)), NPCX_SMBCTL3_SCL_LVL);
	}

	/* If no SCL pin defined for this port, then return 1 to appear idle */
	return 1;
}

int i2c_raw_get_sda(int port)
{
	enum gpio_signal g;

	/*
	 * Check do we support this port of i2c and return gpio number of scl.
	 * Please notice we cannot read voltage level from GPIO in M4 EC
	 */
	if (get_sda_from_i2c_port(port, &g) == EC_SUCCESS) {
		if (i2c_is_raw_mode(port))
			return gpio_get_level(g);
		else
			return IS_BIT_SET(NPCX_SMBCTL3(
			i2c_port_to_controller(port)), NPCX_SMBCTL3_SDA_LVL);
	}


	/* If no SDA pin defined for this port, then return 1 to appear idle */
	return 1;
}

/*****************************************************************************/
/* Hooks */
static void i2c_freq_changed(void)
{
	int freq, i, j;

	for (i = 0; i < i2c_ports_used; i++) {
		int bus_freq = i2c_ports[i].kbps;
		int ctrl = i2c_port_to_controller(i2c_ports[i].port);
		int scl_freq;

#if NPCX_FAMILY_VERSION >= NPCX_FAMILY_NPCX7
		/*
		 * SMB0/1/4/5/6/7 use APB3 clock
		 * SMB2/3 use APB2 clock
		 */
		freq = (ctrl < 2 || ctrl > 3) ?
		       clock_get_apb3_freq() : clock_get_apb2_freq();
#else /* CHIP_FAMILY_NPCX5 */
		/*
		 * SMB0/1 use core clock
		 * SMB2/3 use APB2 clock
		 */
		freq = (ctrl < 2) ? clock_get_freq() : clock_get_apb2_freq();
#endif

		/*
		 * Set SCL frequency by formula:
		 * tSCL = 4 * SCLFRQ * tCLK
		 * fSCL = fCLK / (4*SCLFRQ)
		 * SCLFRQ = ceil(fCLK/(4*fSCL))
		 */
		scl_freq = DIV_ROUND_UP(freq, bus_freq*4000); /* Unit in bps */

		/* Normal mode if i2c freq is under 100kHz */
		if (bus_freq <= 100) {
			/* Set divider value of SCL */
			SET_FIELD(NPCX_SMBCTL2(ctrl), NPCX_SMBCTL2_SCLFRQ7_FIELD
					, (scl_freq & 0x7F));
			SET_FIELD(NPCX_SMBCTL3(ctrl), NPCX_SMBCTL3_SCLFRQ2_FIELD
					, (scl_freq >> 7));
		} else {
			const struct i2c_timing *pTiming;
			int i2c_timing_used;

			/* use Fast Mode */
			SET_BIT(NPCX_SMBCTL3(ctrl), NPCX_SMBCTL3_400K);
			/*
			 * Set SCLH(L)T and hold-time directly for best i2c
			 * timing condition for all source clocks. Please refer
			 * Section 7.5.9 "SMBus Timing - Fast Mode" for detail.
			 */
			if (bus_freq == 400) {
				pTiming = i2c_400k_timings;
				i2c_timing_used = i2c_400k_timing_used;
			} else if (bus_freq == 1000) {
				pTiming = i2c_1m_timings;
				i2c_timing_used = i2c_1m_timing_used;
			} else {
				/* Set value from formula */
				NPCX_SMBSCLLT(ctrl) = scl_freq;
				NPCX_SMBSCLHT(ctrl) = scl_freq;
				cprints(CC_I2C,
					"Warning: Use 400K or 1MHz for better timing of I2c %d",
					ctrl);
				continue;
			}

			for (j = 0; j < i2c_timing_used; j++, pTiming++) {
				if (pTiming->clock == (freq/SECOND)) {
					/* Set SCLH(L)T and hold-time */
					NPCX_SMBSCLLT(ctrl) = pTiming->k1/2;
					NPCX_SMBSCLHT(ctrl) = pTiming->k2/2;
					SET_FIELD(NPCX_SMBCTL4(ctrl),
					NPCX_SMBCTL4_HLDT_FIELD, pTiming->HLDT);
					break;
				}
			}
			if (j == i2c_timing_used)
				cprints(CC_I2C,
					"Error: Please make sure src clock of i2c %d is supported",
					ctrl);
		}
	}
}
DECLARE_HOOK(HOOK_FREQ_CHANGE, i2c_freq_changed, HOOK_PRIO_DEFAULT);

void i2c_init(void)
{
	int i;

	/* Configure pins from GPIOs to I2Cs */
	gpio_config_module(MODULE_I2C, 1);

	/* Enable clock for I2C peripheral */
	clock_enable_peripheral(CGC_OFFSET_I2C, CGC_I2C_MASK,
			CGC_MODE_RUN | CGC_MODE_SLEEP);
#if NPCX_FAMILY_VERSION >= NPCX_FAMILY_NPCX7
	clock_enable_peripheral(CGC_OFFSET_I2C2, CGC_I2C_MASK2,
			CGC_MODE_RUN | CGC_MODE_SLEEP);
#endif

	/* Set I2C freq */
	i2c_freq_changed();
	/*
	 * initialize smb status and register
	 */
	for (i = 0; i < i2c_ports_used; i++) {
		volatile struct i2c_status *p_status;
		int port = i2c_ports[i].port;
		int ctrl = i2c_port_to_controller(port);

		/* ignore the port if i2c_port_to_controller() failed */
		if (ctrl < 0)
			continue;

		p_status = i2c_stsobjs + ctrl;

		/* status init */
		p_status->oper_state = SMB_IDLE;

		/* Reset task ID */
		p_status->task_waiting = TASK_ID_INVALID;

		/* Use default timeout. */
		i2c_set_timeout(port, 0);

		/* Init the SMB module */
		i2c_init_bus(ctrl);
	}
}

