/*
 * Copyright (c) 2020 Nuvoton Technology Corporation.
 *
 * SPDX-License-Identifier: Apache-2.0
 */
#include <zephyr/pm/policy.h>

#define DT_DRV_COMPAT nuvoton_npcx_i2c_ctrl

/**
 * @file
 * @brief Nuvoton NPCX smb/i2c module (controller) driver
 *
 * This file contains the driver of SMB module (controller) which provides full
 * support for a two-wire SMBus/I2C synchronous serial interface. The following
 * is the state diagrams for each Zephyr i2c api functions.
 *
 * case 1: i2c_write()/i2c_burst_write()
 *
 *                              All msg data sent?    Is there next msg?
 *                              +<----------------+<----------------------+
 *                              |       No        |                       | Yes
 *    +------+   +------------+ |  +------- ----+ |    +------- -------+  |
 * +->| IDLE |-->| WAIT_START |--->| WRITE_DATA |-+--->| WRITE_SUSPEND |--+
 * |  +------+   +------------+    +------------+  Yes +---------------+  |
 * |      Issue START    START completed                                  | No
 * |                                            +-----------+             |
 * +--------------------------------------------| WAIT_STOP |<------------+
 *             STOP is completed                +-----------+  Issue STOP
 *
 *
 * case 2: i2c_read()
 *
 *                             All msg data received?  Is there next msg?
 *                              +<-----------------+<---------------------+
 *                              |       No         |                      | Yes
 *    +------+   +------------+ |  +------- ---+   |    +------- ------+  |
 * +->| IDLE |-->| WAIT_START |--->| READ_DATA |---+--->| READ_SUSPEND |--+
 * |  +------+   +------------+    +------------+   Yes +--------------+  |
 * |     Issue START     START completed                                  | No
 * |                                          +-----------+               |
 * +------------------------------------------| WAIT_STOP |<--------------+
 *             STOP is completed              +-----------+  Issue STOP
 *
 *
 * case 3: i2c_write_read()/i2c_burst_read()
 *
 *                              All msg data sent?  Is there next write msg?
 *                              +<----------------+<----------------------+
 *                              |       No        |                       | Yes
 *    +------+   +------------+ |  +------- ----+ |    +------- -------+  |
 * +->| IDLE |-->| WAIT_START |--->| WRITE_DATA |-+--->| WRITE_SUSPEND |--+
 * |  +------+   +------------+    +------------+  Yes +---------------+  |
 * |     Issue START     START completed                                  | No
 * |      +---------------------------------------------------------------+
 * |      |
 * |      |                 All msg data received?  Is there next read msg?
 * |      |                   +<-----------------+<-----------------------+
 * |      |                   |       No         |                        | Yes
 * |      |  +--------------+ |  +------- ---+   |    +------- ------+    |
 * |      +--| WAIT_RESTART |--->| READ_DATA |---+--->| READ_SUSPEND |----+
 * |         +--------------+    +-----------+    Yes +--------------+    |
 * |  Issue RESTART      RESTART completed                                | No
 * |                                           +-----------+              |
 * +-------------------------------------------| WAIT_STOP |<-------------+
 *              STOP is completed              +-----------+  Issue STOP
 *
 */

#include <assert.h>
#include <zephyr/drivers/clock_control.h>
#include <zephyr/drivers/i2c.h>
#include <zephyr/kernel.h>
#include <zephyr/sys/atomic.h>
#include <soc.h>
#include "i2c_npcx_controller.h"
#include "soc_miwu.h"
#include "soc_pins.h"
#include "soc_power.h"

#include <zephyr/logging/log.h>
#include <zephyr/irq.h>
LOG_MODULE_REGISTER(i2c_npcx, CONFIG_I2C_LOG_LEVEL);

/* 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). */
#define I2C_MIN_TIMEOUT 25

/* Default maximum time we allow for an I2C transfer (unit:ms) */
#define I2C_TRANS_TIMEOUT K_MSEC(100)

/* Valid bit fields in SMBST register */
#define NPCX_VALID_SMBST_MASK ~(BIT(NPCX_SMBST_XMIT) | BIT(NPCX_SMBST_MASTER))

#define I2C_RECOVER_SCL_RETRY    10
#define I2C_RECOVER_SDA_RETRY    3

#define NPCX_SMBADDR_SAEN NPCX_SMBADDR1_SAEN /* All the SAEN in SMBADDR is bit_7 */
/*
 * After the last ACK/NACK bit, add a delay that is slightly longer than half of I2C clock cycle
 * before sending STOP condition.
 */
/* 5 us (half I2C clock at 100 KHz) + 1 us (for safety) */
#define NPCX_I2C_ISSUE_STOP_DELAY_100K_NS 6000
/* 1.25 us (half I2C clock at 400 KHz) + 1 us (for safety) */
#define NPCX_I2C_ISSUE_STOP_DELAY_400K_NS 2250
/* 0.5 us (half I2C clock at 1 MHz) + 1 us (for safety) */
#define NPCX_I2C_ISSUE_STOP_DELAY_1M_NS   1500

/* Supported I2C bus frequency */
enum npcx_i2c_freq {
	NPCX_I2C_BUS_SPEED_100KHZ,
	NPCX_I2C_BUS_SPEED_400KHZ,
	NPCX_I2C_BUS_SPEED_1MHZ,
};

/* I2C timing configuration for each i2c speed */
struct npcx_i2c_timing_cfg {
	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) */
};

/* Recommended I2C timing values are based on 15 MHz */
static const struct npcx_i2c_timing_cfg npcx_15m_speed_confs[] = {
	[NPCX_I2C_BUS_SPEED_100KHZ] = {.HLDT = 15, .k1 = 76, .k2 = 0},
	[NPCX_I2C_BUS_SPEED_400KHZ] = {.HLDT = 7, .k1 = 24, .k2 = 18},
	[NPCX_I2C_BUS_SPEED_1MHZ] = {.HLDT = 7, .k1 = 14, .k2 = 10},
};

static const struct npcx_i2c_timing_cfg npcx_20m_speed_confs[] = {
	[NPCX_I2C_BUS_SPEED_100KHZ] = {.HLDT = 15, .k1 = 102, .k2 = 0},
	[NPCX_I2C_BUS_SPEED_400KHZ] = {.HLDT = 7, .k1 = 32, .k2 = 22},
	[NPCX_I2C_BUS_SPEED_1MHZ] = {.HLDT = 7, .k1 = 16, .k2 = 10},
};

static const struct npcx_i2c_timing_cfg npcx_25m_speed_confs[] = {
	[NPCX_I2C_BUS_SPEED_100KHZ] = {.HLDT = 15, .k1 = 125, .k2 = 0},
	[NPCX_I2C_BUS_SPEED_400KHZ] = {.HLDT = 8, .k1 = 40, .k2 = 26},
	[NPCX_I2C_BUS_SPEED_1MHZ] = {.HLDT = 7, .k1 = 16, .k2 = 12},
};

static const struct npcx_i2c_timing_cfg npcx_50m_speed_confs[] = {
	[NPCX_I2C_BUS_SPEED_100KHZ] = {.HLDT = 17, .k1 = 252, .k2 = 0},
	[NPCX_I2C_BUS_SPEED_400KHZ] = {.HLDT = 17, .k1 = 80, .k2 = 52},
	[NPCX_I2C_BUS_SPEED_1MHZ] = {.HLDT = 8, .k1 = 32, .k2 = 22},
};

#if defined(CONFIG_PM) && defined(CONFIG_I2C_TARGET)
static void i2c_npcx_pm_policy_state_lock_get(const struct device *dev,
					      enum i2c_pm_policy_state_flag flag)
{
	const struct i2c_ctrl_config *const config = dev->config;
	struct i2c_ctrl_data *const data = dev->data;

	if (!config->wakeup_source) {
		return;
	}

	if (atomic_test_and_set_bit(data->pm_policy_state_flag, flag) == 0) {
		pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES);
	}
}

static void i2c_npcx_pm_policy_state_lock_put(const struct device *dev,
					      enum i2c_pm_policy_state_flag flag)
{
	const struct i2c_ctrl_config *const config = dev->config;
	struct i2c_ctrl_data *const data = dev->data;

	if (!config->wakeup_source) {
		return;
	}

	if (atomic_test_and_clear_bit(data->pm_policy_state_flag, flag) == 1) {
		pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES);
	}
}
#endif /* CONFIG_PM && CONFIG_I2C_TARGET */

/* I2C controller inline functions access shared registers */
static inline int i2c_ctrl_bus_busy(const struct device *dev)
{
	struct smb_reg *const inst = HAL_I2C_INSTANCE(dev);

	return IS_BIT_SET(inst->SMBCST, NPCX_SMBCST_BB);
}

#ifdef CONFIG_I2C_TARGET
static volatile uint8_t *npcx_i2c_ctrl_target_get_reg_smbaddr(const struct device *i2c_dev,
							      int index)
{
	struct smb_reg *const inst = HAL_I2C_INSTANCE(i2c_dev);

	switch (index) {
	case 0:
		return &inst->SMBADDR1;
	case 1:
		return &inst->SMBADDR2;
	case 2:
		return &inst->SMBADDR3;
	case 3:
		return &inst->SMBADDR4;
	case 4:
		return &inst->SMBADDR5;
	case 5:
		return &inst->SMBADDR6;
	case 6:
		return &inst->SMBADDR7;
	case 7:
		return &inst->SMBADDR8;
	default:
		LOG_ERR("Invalid SMBADDR index: %d", index);
		return NULL;
	}
}
#endif /* CONFIG_I2C_TARGET */

static void i2c_ctrl_init_module(const struct device *dev)
{
	struct smb_reg *const inst = HAL_I2C_INSTANCE(dev);

	i2c_ctrl_bank_sel(dev, NPCX_I2C_BANK_NORMAL);

	/* Enable FIFO mode first if selected */
	if (IS_ENABLED(CONFIG_I2C_NPCX_FIFO_DRIVEN)) {
		inst->SMBFIF_CTL |= BIT(NPCX_SMBFIF_CTL_FIFO_EN);
	}

	/* Enable module - before configuring CTL1 */
	inst->SMBCTL2  |= BIT(NPCX_SMBCTL2_ENABLE);

#ifdef CONFIG_I2C_TARGET
	volatile uint8_t *reg_smbaddr;

	/* Clear all the SMBnADDR */
	for (int i = 0; i < NPCX_I2C_FLAG_COUNT; i++) {
		reg_smbaddr = npcx_i2c_ctrl_target_get_reg_smbaddr(dev, i);
		*reg_smbaddr = 0;
	}
#endif

	/* Enable SMB interrupt and 'New Address Match' interrupt source */
	inst->SMBCTL1 |= BIT(NPCX_SMBCTL1_NMINTE) | BIT(NPCX_SMBCTL1_INTEN);

	i2c_ctrl_bank_sel(dev, NPCX_I2C_BANK_FIFO);
}

static void i2c_ctrl_config_bus_freq(const struct device *dev,
						enum npcx_i2c_freq bus_freq)
{
	struct smb_reg *const inst = HAL_I2C_INSTANCE(dev);
	struct i2c_ctrl_data *const data = dev->data;
	const struct npcx_i2c_timing_cfg bus_cfg =
						data->ptr_speed_confs[bus_freq];

	/* Switch to bank 0 to configure bus speed */
	i2c_ctrl_bank_sel(dev, NPCX_I2C_BANK_NORMAL);

	/* Configure bus speed */
	if (bus_freq == NPCX_I2C_BUS_SPEED_100KHZ) {
		/* Enable 'Normal' Mode */
		inst->SMBCTL3 &= ~(BIT(NPCX_SMBCTL3_400K));
		/* Set freq of SCL. For 100KHz, only k1 is used.  */
		SET_FIELD(inst->SMBCTL2, NPCX_SMBCTL2_SCLFRQ0_6_FIELD,
				bus_cfg.k1/2 & 0x7f);
		SET_FIELD(inst->SMBCTL3, NPCX_SMBCTL3_SCLFRQ7_8_FIELD,
				bus_cfg.k1/2 >> 7);
		SET_FIELD(inst->SMBCTL4, NPCX_SMBCTL4_HLDT_FIELD,
				bus_cfg.HLDT);
	} else {
		/* Enable 'Fast' Mode for 400K or higher freq. */
		inst->SMBCTL3 |= BIT(NPCX_SMBCTL3_400K);
		/* Set high/low time of SCL and hold-time */
		inst->SMBSCLLT = bus_cfg.k1/2;
		inst->SMBSCLHT = bus_cfg.k2/2;
		SET_FIELD(inst->SMBCTL4, NPCX_SMBCTL4_HLDT_FIELD,
				bus_cfg.HLDT);
	}

	/* Switch to bank 1 to access I2C FIFO registers */
	i2c_ctrl_bank_sel(dev, NPCX_I2C_BANK_FIFO);
}

/* I2C controller local functions */
static int i2c_ctrl_wait_stop_completed(const struct device *dev, int timeout)
{
	struct smb_reg *const inst = HAL_I2C_INSTANCE(dev);

	if (timeout <= 0) {
		return -EINVAL;
	}

	do {
		/*
		 * Wait till i2c bus is idle. This bit is cleared to 0
		 * automatically after the STOP condition is generated.
		 */
		if (!IS_BIT_SET(inst->SMBCTL1, NPCX_SMBCTL1_STOP)) {
			break;
		}
		k_msleep(1);
	} while (--timeout);

	if (timeout > 0) {
		return 0;
	} else {
		return -ETIMEDOUT;
	}
}

static int i2c_ctrl_wait_idle_completed(const struct device *dev, int timeout)
{
	if (timeout <= 0) {
		return -EINVAL;
	}

	do {
		/* Wait for both SCL & SDA lines are high */
		if (i2c_ctrl_is_scl_sda_both_high(dev)) {
			break;
		}
		k_msleep(1);
	} while (--timeout);

	if (timeout > 0) {
		return 0;
	} else {
		return -ETIMEDOUT;
	}
}

static int i2c_ctrl_recovery(const struct device *dev)
{
	struct smb_reg *const inst = HAL_I2C_INSTANCE(dev);
	struct i2c_ctrl_data *const data = dev->data;
	int ret;

	if (data->oper_state != NPCX_I2C_ERROR_RECOVERY) {
		data->oper_state = NPCX_I2C_ERROR_RECOVERY;
	}

	/* Step 1: Make sure the bus is not stalled before exit in FIFO mode. */
#if defined(CONFIG_I2C_NPCX_FIFO_DRIVEN)
	i2c_ctrl_fifo_hold_bus(dev, 0);
#endif

	/*
	 * Step 2: Abort data, wait for STOP condition completed.
	 * - Clearing NEGACK and BER bits first
	 * - Wait for STOP condition completed
	 * - Then clear BB (BUS BUSY) bit
	 */
	inst->SMBST = BIT(NPCX_SMBST_BER) | BIT(NPCX_SMBST_NEGACK);
	ret = i2c_ctrl_wait_stop_completed(dev, I2C_MAX_TIMEOUT);
	inst->SMBCST |= BIT(NPCX_SMBCST_BB);
	if (ret != 0) {
		LOG_ERR("Abort i2c %s::%02x fail! Bus might be stalled.", dev->name, data->port);
	}

	/*
	 * Step 3: Reset i2c module to clear all internal state machine of it
	 * - Disable the SMB module first
	 * - Wait both SCL/SDA line are high
	 * - Enable i2c module again
	 */
	inst->SMBCTL2 &= ~BIT(NPCX_SMBCTL2_ENABLE);
	ret = i2c_ctrl_wait_idle_completed(dev, I2C_MAX_TIMEOUT);
	if (ret != 0) {
		LOG_ERR("Reset i2c %s::%02x fail! Bus might be stalled.", dev->name, data->port);
		return -EIO;
	}

	/* Reset module and internal state machine */
	i2c_ctrl_init_module(dev);

	/* Recovery is completed */
	data->oper_state = NPCX_I2C_IDLE;
	return 0;
}

static int i2c_ctrl_wait_completion(const struct device *dev)
{
	struct i2c_ctrl_data *const data = dev->data;

	if (k_sem_take(&data->sync_sem, I2C_TRANS_TIMEOUT) == 0) {
		return data->trans_err;
	} else {
		return -ETIMEDOUT;
	}
}

size_t i2c_ctrl_calculate_msg_remains(const struct device *dev)
{
	struct i2c_ctrl_data *const data = dev->data;
	uint8_t *buf_end = data->msg->buf + data->msg->len;

	return (buf_end > data->ptr_msg) ? (buf_end - data->ptr_msg) : 0;
}

static int i2c_ctrl_proc_write_msg(const struct device *dev,
							struct i2c_msg *msg)
{
	struct i2c_ctrl_data *const data = dev->data;

	data->is_write = 1;
	data->ptr_msg = msg->buf;
	data->msg = msg;

	if (data->oper_state == NPCX_I2C_IDLE) {
		data->oper_state = NPCX_I2C_WAIT_START;
#if defined(CONFIG_I2C_NPCX_FIFO_DRIVEN)
		/* Clear FIFO status before starting a new transaction */
		i2c_ctrl_fifo_clear_status(dev);
#endif
		/* Issue a START, wait for transaction completed */
		i2c_ctrl_start(dev);

		return i2c_ctrl_wait_completion(dev);
	} else if (data->oper_state == NPCX_I2C_WRITE_SUSPEND) {
		data->oper_state = NPCX_I2C_WRITE_DATA;
#if defined(CONFIG_I2C_NPCX_DMA_DRIVEN)
		/* Start the following DMA transmitted transaction */
		i2c_ctrl_dma_proceed_write(dev);
#endif
		i2c_ctrl_irq_enable(dev, 1);

		return i2c_ctrl_wait_completion(dev);
	}

	LOG_ERR("Unexpected state %d during writing i2c port%02x!",
					data->oper_state, data->port);
	data->trans_err = -EIO;
	return data->trans_err;
}

static int i2c_ctrl_proc_read_msg(const struct device *dev, struct i2c_msg *msg)
{
	struct i2c_ctrl_data *const data = dev->data;

	data->is_write = 0;
	data->ptr_msg = msg->buf;
	data->msg = msg;

	if (data->oper_state == NPCX_I2C_IDLE) {
		data->oper_state = NPCX_I2C_WAIT_START;
#if defined(CONFIG_I2C_NPCX_FIFO_DRIVEN)
		/* Clear FIFO status before starting a new transaction */
		i2c_ctrl_fifo_clear_status(dev);
#endif
		/* Issue a START, wait for transaction completed */
		i2c_ctrl_start(dev);

		return i2c_ctrl_wait_completion(dev);
	} else if (data->oper_state == NPCX_I2C_WRITE_SUSPEND) {
		data->oper_state = NPCX_I2C_WAIT_RESTART;
		/* Issue a RESTART, wait for transaction completed */
		i2c_ctrl_start(dev);
#if defined(CONFIG_I2C_NPCX_DMA_DRIVEN)
		/* Clear DMA status bit and release bus */
		i2c_ctrl_dma_clear_status(dev);
#endif
		i2c_ctrl_irq_enable(dev, 1);

		return i2c_ctrl_wait_completion(dev);
	} else if (data->oper_state == NPCX_I2C_READ_SUSPEND) {
		data->oper_state = NPCX_I2C_READ_DATA;
#if defined(CONFIG_I2C_NPCX_DMA_DRIVEN)
		/* Start DMA received transaction */
		i2c_ctrl_dma_proceed_read(dev);
#endif
#if defined(CONFIG_I2C_NPCX_FIFO_DRIVEN)
		/* Setup threshold of RX FIFO first */
		i2c_ctrl_fifo_rx_setup_threshold_nack(dev, msg->len,
				(msg->flags & I2C_MSG_STOP) != 0);

		/* Release bus */
		i2c_ctrl_fifo_hold_bus(dev, 0);
#endif
		/* Enable i2c interrupt first */
		i2c_ctrl_irq_enable(dev, 1);
		return i2c_ctrl_wait_completion(dev);
	}

	LOG_ERR("Unexpected state  %d during reading i2c port%02x!",
					data->oper_state, data->port);
	data->trans_err = -EIO;
	return data->trans_err;
}

/* I2C controller isr function */
#ifdef CONFIG_I2C_TARGET
static void i2c_ctrl_target_isr(const struct device *dev, uint8_t status)
{
	struct smb_reg *const inst = HAL_I2C_INSTANCE(dev);
	struct i2c_ctrl_data *const data = dev->data;
	const struct i2c_target_callbacks *target_cb = NULL;
	uint8_t val = 0;

	/* A 'Bus Error' has been identified */
	if (IS_BIT_SET(status, NPCX_SMBST_BER)) {
		/* Clear BER Bit */
		inst->SMBST = BIT(NPCX_SMBST_BER);

		target_cb = data->target_cfg[data->target_idx]->callbacks;

		/* Notify upper layer the end of transaction */
		if ((target_cb != NULL) && target_cb->stop) {
			target_cb->stop(data->target_cfg[data->target_idx]);
		}

		/* Reset i2c module in target mode */
		inst->SMBCTL2 &= ~BIT(NPCX_SMBCTL2_ENABLE);
		inst->SMBCTL2 |= BIT(NPCX_SMBCTL2_ENABLE);

		/*
		 * Re-enable interrupts because they are turned off after the SMBus module
		 * is reset above.
		 */
		inst->SMBCTL1 |= BIT(NPCX_SMBCTL1_NMINTE) | BIT(NPCX_SMBCTL1_INTEN);
		/* End of transaction */
		data->oper_state = NPCX_I2C_IDLE;

#ifdef CONFIG_PM
		i2c_npcx_pm_policy_state_lock_put(dev, I2C_PM_POLICY_STATE_FLAG_TGT);
#endif /* CONFIG_PM */

		LOG_DBG("TGT: Bus error on %s:%02x!", dev->name, data->port);
		return;
	}

	/* A 'Slave Stop' Condition has been identified */
	if (IS_BIT_SET(status, NPCX_SMBST_SLVSTP)) {
		/* Clear SLVSTP Bit */
		inst->SMBST = BIT(NPCX_SMBST_SLVSTP);
		/* End of transaction */
		data->oper_state = NPCX_I2C_IDLE;
		/* Notify upper layer a STOP condition received */
		target_cb = data->target_cfg[data->target_idx]->callbacks;
		if ((target_cb != NULL) && target_cb->stop) {
			target_cb->stop(data->target_cfg[data->target_idx]);
		}

#ifdef CONFIG_PM
		i2c_npcx_pm_policy_state_lock_put(dev, I2C_PM_POLICY_STATE_FLAG_TGT);
#endif /* CONFIG_PM */
		return;
	}

	/* A negative acknowledge has occurred */
	if (IS_BIT_SET(status, NPCX_SMBST_NEGACK)) {
		/* Clear NEGACK Bit */
		inst->SMBST = BIT(NPCX_SMBST_NEGACK);
		/* Do nothing in i2c target mode */
		return;
	}

	/* A 'Target Address Match' has been identified */
	if (IS_BIT_SET(status, NPCX_SMBST_NMATCH)) {
		/* Clear NMATCH Bit */
		inst->SMBST = BIT(NPCX_SMBST_NMATCH);

		/* Check MATCH1F ~ MATCH7F */
		if (inst->SMBCST2 & ~BIT(NPCX_SMBCST2_INTSTS)) {
			for (uint8_t addr_idx = NPCX_I2C_FLAG_TARGET1;
			     addr_idx <= NPCX_I2C_FLAG_TARGET7; addr_idx++) {
				if (inst->SMBCST2 & BIT(addr_idx)) {
					data->target_idx = addr_idx;
					break;
				}
			}
		} else if (inst->SMBCST3 & BIT(NPCX_SMBCST3_MATCHA8F)) {
			data->target_idx = NPCX_I2C_FLAG_TARGET8;
		}

		target_cb = data->target_cfg[data->target_idx]->callbacks;

		/* Distinguish the direction of i2c target mode by reading XMIT bit */
		if (IS_BIT_SET(inst->SMBST, NPCX_SMBST_XMIT)) {
			/* Start transmitting data in i2c target mode */
			data->oper_state = NPCX_I2C_WRITE_DATA;
			/* Write first requested byte after repeated start */
			if ((target_cb != NULL) && target_cb->read_requested) {
				target_cb->read_requested(data->target_cfg[data->target_idx], &val);
			}
			inst->SMBSDA = val;
		} else {
			/* Start receiving data in i2c target mode */
			data->oper_state = NPCX_I2C_READ_DATA;

			if ((target_cb != NULL) && target_cb->write_requested) {
				target_cb->write_requested(data->target_cfg[data->target_idx]);
			}
		}
		return;
	}

	/* Tx byte empty or Rx byte full has occurred */
	if (IS_BIT_SET(status, NPCX_SMBST_SDAST)) {
		target_cb = data->target_cfg[data->target_idx]->callbacks;

		if (data->oper_state == NPCX_I2C_WRITE_DATA) {
			/* Notify upper layer one byte will be transmitted */
			if ((target_cb != NULL) && target_cb->read_processed) {
				target_cb->read_processed(data->target_cfg[data->target_idx], &val);
			}
			inst->SMBSDA = val;
		} else if (data->oper_state == NPCX_I2C_READ_DATA) {
			if ((target_cb != NULL) && target_cb->write_received) {
				val = inst->SMBSDA;
				/* Notify upper layer one byte received */
				target_cb->write_received(data->target_cfg[data->target_idx], val);
			}
		} else {
			LOG_ERR("Unexpected oper state %d on i2c target port%02x!",
				data->oper_state, data->port);
		}
		return;
	}

	/* Clear unexpected status bits */
	if (status != 0) {
		inst->SMBST = status;
		LOG_ERR("Unexpected  SMBST 0x%02x occurred on i2c target port%02x!",
			status, data->port);
	}
}
#endif /* CONFIG_I2C_TARGET */

/* I2C controller isr function */
static void i2c_ctrl_isr(const struct device *dev)
{
	struct smb_reg *const inst = HAL_I2C_INSTANCE(dev);
	struct i2c_ctrl_data *const data = dev->data;
	uint8_t status = inst->SMBST & NPCX_VALID_SMBST_MASK;
#if defined(CONFIG_I2C_NPCX_DMA_DRIVEN)
	uint8_t dma_status = inst->DMA_CTRL;
#endif

#ifdef CONFIG_I2C_TARGET
	if (atomic_get(&data->registered_target_mask) != (atomic_val_t) 0) {
		i2c_ctrl_target_isr(dev, status);
		return;
	}
#endif /* CONFIG_I2C_TARGET */

	/* A 'Bus Error' has been identified */
	if (IS_BIT_SET(status, NPCX_SMBST_BER)) {
		uint8_t tmp;

		/* Generate a STOP condition immediately */
		i2c_ctrl_stop(dev);

		/* Clear BER Bit */
		inst->SMBST = BIT(NPCX_SMBST_BER);

		/* Make sure slave doesn't hold bus by reading FIFO again */
		tmp = i2c_ctrl_data_read(dev);

		LOG_ERR("Bus error occurred on i2c %s::%02x!", dev->name, data->port);
		data->oper_state = NPCX_I2C_ERROR_RECOVERY;

		/* I/O error occurred */
		i2c_ctrl_notify(dev, -EIO);
		return;
	}

	/* A negative acknowledge has occurred */
	if (IS_BIT_SET(status, NPCX_SMBST_NEGACK)) {
		/* Generate a STOP condition immediately */
		i2c_ctrl_stop(dev);

		/* Clear NEGACK Bit */
		inst->SMBST = BIT(NPCX_SMBST_NEGACK);

#if defined(CONFIG_I2C_NPCX_DMA_DRIVEN)
		/* Clear DMA status bit to release bus */
		i2c_ctrl_dma_clear_status(dev);
#endif

		/* End transaction */
		data->oper_state = NPCX_I2C_WAIT_STOP;

		/* No such device or address */
		i2c_ctrl_notify(dev, -ENXIO);
		return;
	}

	/* START, tx FIFO empty or rx FIFO full has occurred */
	if (IS_BIT_SET(status, NPCX_SMBST_SDAST)) {
		if (data->is_write) {
			i2c_ctrl_handle_write_int_event(dev);
		} else {
			i2c_ctrl_handle_read_int_event(dev);
		}
		return;
	}

	/* DMA transaction has been finished */
#if defined(CONFIG_I2C_NPCX_DMA_DRIVEN)
	if (IS_BIT_SET(dma_status, NPCX_DMA_CTL_IRQSTS)) {
		if (data->is_write) {
			return i2c_ctrl_handle_write_dma_int_event(dev);
		} else {
			return i2c_ctrl_handle_read_dma_int_event(dev);
		}
	}
#endif

	/* Clear unexpected status bits */
	if (status != 0) {
		inst->SMBST = status;
		LOG_ERR("Unexpected  SMBST 0x%02x occurred on i2c port%02x!",
			status, data->port);
	}
}

/* NPCX specific I2C controller functions */
void npcx_i2c_ctrl_mutex_lock(const struct device *i2c_dev)
{
	struct i2c_ctrl_data *const data = i2c_dev->data;

	k_sem_take(&data->lock_sem, K_FOREVER);
}

void npcx_i2c_ctrl_mutex_unlock(const struct device *i2c_dev)
{
	struct i2c_ctrl_data *const data = i2c_dev->data;

	k_sem_give(&data->lock_sem);
}

int npcx_i2c_ctrl_configure(const struct device *i2c_dev, uint32_t dev_config)
{
	struct i2c_ctrl_data *const data = i2c_dev->data;

	switch (I2C_SPEED_GET(dev_config)) {
	case I2C_SPEED_STANDARD:
		data->bus_freq = NPCX_I2C_BUS_SPEED_100KHZ;
#if defined(CONFIG_I2C_NPCX_INVALID_STOP_WORKAROUND)
		data->stop_dealy_cycle_time = k_ns_to_cyc_near32(NPCX_I2C_ISSUE_STOP_DELAY_100K_NS);
#endif
		break;
	case I2C_SPEED_FAST:
		data->bus_freq = NPCX_I2C_BUS_SPEED_400KHZ;
#if defined(CONFIG_I2C_NPCX_INVALID_STOP_WORKAROUND)
		data->stop_dealy_cycle_time = k_ns_to_cyc_near32(NPCX_I2C_ISSUE_STOP_DELAY_400K_NS);
#endif
		break;
	case I2C_SPEED_FAST_PLUS:
		data->bus_freq = NPCX_I2C_BUS_SPEED_1MHZ;
#if defined(CONFIG_I2C_NPCX_INVALID_STOP_WORKAROUND)
		data->stop_dealy_cycle_time = k_ns_to_cyc_near32(NPCX_I2C_ISSUE_STOP_DELAY_1M_NS);
#endif
		break;
	default:
		return -ERANGE;
	}

	i2c_ctrl_config_bus_freq(i2c_dev, data->bus_freq);
	data->is_configured = true;

	return 0;
}

int npcx_i2c_ctrl_get_speed(const struct device *i2c_dev, uint32_t *speed)
{
	struct i2c_ctrl_data *const data = i2c_dev->data;

	if (!data->is_configured) {
		return -EIO;
	}

	switch (data->bus_freq) {
	case NPCX_I2C_BUS_SPEED_100KHZ:
		*speed = I2C_SPEED_SET(I2C_SPEED_STANDARD);
		break;
	case NPCX_I2C_BUS_SPEED_400KHZ:
		*speed = I2C_SPEED_SET(I2C_SPEED_FAST);
		break;
	case NPCX_I2C_BUS_SPEED_1MHZ:
		*speed = I2C_SPEED_SET(I2C_SPEED_FAST_PLUS);
		break;
	default:
		return -ERANGE;
	}

	return 0;
}

int npcx_i2c_ctrl_recover_bus(const struct device *dev)
{
	struct smb_reg *const inst = HAL_I2C_INSTANCE(dev);
	int ret = 0;

	i2c_ctrl_bank_sel(dev, NPCX_I2C_BANK_NORMAL);

	/*
	 * When the SCL is low, wait for a while in case of the clock is stalled
	 * by a I2C target.
	 */
	if (!IS_BIT_SET(inst->SMBCTL3, NPCX_SMBCTL3_SCL_LVL)) {
		for (int i = 0;; i++) {
			if (i >= I2C_RECOVER_SCL_RETRY) {
				ret = -EBUSY;
				goto recover_exit;
			}
			k_busy_wait(I2C_RECOVER_BUS_DELAY_US);
			if (IS_BIT_SET(inst->SMBCTL3, NPCX_SMBCTL3_SCL_LVL)) {
				break;
			}
		}
	}

	if (IS_BIT_SET(inst->SMBCTL3, NPCX_SMBCTL3_SDA_LVL)) {
		goto recover_exit;
	}

	for (int i = 0; i < I2C_RECOVER_SDA_RETRY; i++) {
		if (i2c_ctrl_toggle_scls(dev)) {
			ret = 0;
			goto recover_exit;
		}
	}

	if (!IS_BIT_SET(inst->SMBCTL3, NPCX_SMBCTL3_SDA_LVL)) {
		LOG_ERR("Recover SDA fail");
		ret = -EBUSY;
	}
	if (!IS_BIT_SET(inst->SMBCTL3, NPCX_SMBCTL3_SCL_LVL)) {
		LOG_ERR("Recover SCL fail");
		ret = -EBUSY;
	}

recover_exit:
	i2c_ctrl_bank_sel(dev, NPCX_I2C_BANK_FIFO);

	return ret;
}

#ifdef CONFIG_I2C_TARGET
int npcx_i2c_ctrl_target_register(const struct device *i2c_dev,
				 struct i2c_target_config *target_cfg, uint8_t port)
{
	struct smb_reg *const inst = HAL_I2C_INSTANCE(i2c_dev);
	const struct i2c_ctrl_config *const config = i2c_dev->config;
	struct i2c_ctrl_data *const data = i2c_dev->data;
	int idx_ctrl = (port & 0xF0) >> 4;
	int idx_port = (port & 0x0F);
	int avail_addr_slot;
	volatile uint8_t *reg_smbaddr;
	uint8_t smbaddr_val = BIT(NPCX_SMBADDR_SAEN) | target_cfg->address;
	uint32_t i2c_tgt_mask = (uint32_t)atomic_get(&data->registered_target_mask);
	int addr_idx;

	/* A transiaction is ongoing */
	if (data->oper_state != NPCX_I2C_IDLE && data->oper_state != NPCX_I2C_ERROR_RECOVERY) {
		LOG_ERR("Reg TGT in err state: %d", data->oper_state);
		return -EBUSY;
	}
	if (data->oper_state == NPCX_I2C_ERROR_RECOVERY) {
		LOG_WRN("Reg TGT in Recovery");
	}

	/* Find valid smbaddr location */
	avail_addr_slot = find_lsb_set(~i2c_tgt_mask) - 1;
	if (avail_addr_slot == -1 || avail_addr_slot >= NPCX_I2C_FLAG_COUNT) {
		LOG_ERR("No available smbaddr register, smbaddr_idx: %d", avail_addr_slot);
		return -ENOSPC;
	}

	/* Check if the address is duplicated */
	while (i2c_tgt_mask) {
		addr_idx = find_lsb_set(i2c_tgt_mask) - 1;
		reg_smbaddr = npcx_i2c_ctrl_target_get_reg_smbaddr(i2c_dev, addr_idx);

		/* Check if the address is duplicated */
		if (*reg_smbaddr == smbaddr_val) {
			LOG_ERR("Address %#x is already set", target_cfg->address);
			return -EINVAL;
		}

		i2c_tgt_mask &= ~BIT(addr_idx);
	}

	/* Mark the selected address slot */
	atomic_set_bit(&data->registered_target_mask, avail_addr_slot);

	i2c_ctrl_irq_enable(i2c_dev, 0);

	data->port = port; /* Update the I2C port index */

	/* Config new address */
	reg_smbaddr = npcx_i2c_ctrl_target_get_reg_smbaddr(i2c_dev, avail_addr_slot);
	*reg_smbaddr = smbaddr_val; /* Set address register */
	data->target_cfg[avail_addr_slot] = target_cfg; /* Set target config */

	/* Switch correct port for i2c controller first */
	npcx_pinctrl_i2c_port_sel(idx_ctrl, idx_port);

	/* Reset I2C module */
	inst->SMBCTL2 &= ~BIT(NPCX_SMBCTL2_ENABLE);
	inst->SMBCTL2 |= BIT(NPCX_SMBCTL2_ENABLE);

	/* Select normal bank and single byte mode for i2c target mode */
	i2c_ctrl_bank_sel(i2c_dev, NPCX_I2C_BANK_NORMAL);
	inst->SMBFIF_CTL &= ~BIT(NPCX_SMBFIF_CTL_FIFO_EN);

	/* Reconfigure SMBCTL1 */
	inst->SMBCTL1 |= BIT(NPCX_SMBCTL1_NMINTE) | BIT(NPCX_SMBCTL1_INTEN);

	/* Enable irq of smb wake-up event */
	if (IS_ENABLED(CONFIG_PM) && config->wakeup_source) {

		/* Enable SMB wake up detection */
		npcx_i2c_target_start_wk_enable(idx_ctrl, true);
		/* Enable start detect in IDLE */
		inst->SMBCTL3 |= BIT(NPCX_SMBCTL3_IDL_START);
		/* Enable SMB's MIWU interrupts */
		npcx_miwu_irq_enable(&config->smb_wui);
	}

	i2c_ctrl_irq_enable(i2c_dev, 1);

	return 0;
}

int npcx_i2c_ctrl_target_unregister(const struct device *i2c_dev,
				   struct i2c_target_config *target_cfg, uint8_t port)
{
	struct smb_reg *const inst = HAL_I2C_INSTANCE(i2c_dev);
	const struct i2c_ctrl_config *const config = i2c_dev->config;
	struct i2c_ctrl_data *const data = i2c_dev->data;
	int idx_ctrl = (port & 0xF0) >> 4;
	int cur_addr_slot;
	volatile uint8_t *reg_smbaddr;
	uint8_t smbaddr_val = BIT(NPCX_SMBADDR_SAEN) | target_cfg->address;
	uint32_t i2c_tgt_mask = (uint32_t)atomic_get(&data->registered_target_mask);

	/* No I2c module has been configured to target mode */
	if (atomic_get(&data->registered_target_mask) == (atomic_val_t) 0) {
		LOG_ERR("No available target to ungister");
		return -EINVAL;
	}

	/* A transiaction is ongoing */
	if (data->oper_state != NPCX_I2C_IDLE) {
		return -EBUSY;
	}

	/* Find target address in smbaddr */
	while (i2c_tgt_mask) {
		cur_addr_slot = find_lsb_set(i2c_tgt_mask) - 1;
		reg_smbaddr = npcx_i2c_ctrl_target_get_reg_smbaddr(i2c_dev, cur_addr_slot);
		if (reg_smbaddr == NULL) {
			LOG_ERR("Invalid smbaddr register");
			return -EINVAL;
		}

		/* Target address found */
		if (*reg_smbaddr == smbaddr_val) {
			break;
		}

		i2c_tgt_mask &= ~BIT(cur_addr_slot);
	}

	/* Input addrss is not in the smbaddr */
	if (i2c_tgt_mask == 0 || reg_smbaddr == NULL) {
		LOG_ERR("Address %#x is not found", target_cfg->address);
		return -EINVAL;
	}

	i2c_ctrl_irq_enable(i2c_dev, 0);

	*reg_smbaddr = 0; /* Disable target mode and clear address setting */
	data->target_cfg[cur_addr_slot] = NULL; /* Clear target config */

	/* Mark it as controller mode */
	atomic_clear_bit(&data->registered_target_mask, cur_addr_slot);

	/* Switch I2C to controller mode if no any other valid address in smbaddr */
	if (atomic_get(&data->registered_target_mask) == (atomic_val_t) 0) {

		/* Reset I2C module */
		inst->SMBCTL2 &= ~BIT(NPCX_SMBCTL2_ENABLE);
		inst->SMBCTL2 |= BIT(NPCX_SMBCTL2_ENABLE);

		/* Enable FIFO mode and select to FIFO bank for i2c controller mode */
		inst->SMBFIF_CTL |= BIT(NPCX_SMBFIF_CTL_FIFO_EN);
		i2c_ctrl_bank_sel(i2c_dev, NPCX_I2C_BANK_FIFO);

		/* Reconfigure SMBCTL1 */
		inst->SMBCTL1 |= BIT(NPCX_SMBCTL1_INTEN);

		/* Disable irq of smb wake-up event */
		if (IS_ENABLED(CONFIG_PM)) {
			/* Disable SMB wake up detection */
			npcx_i2c_target_start_wk_enable(idx_ctrl, false);
			/* Disable start detect in IDLE */
			inst->SMBCTL3 &= ~BIT(NPCX_SMBCTL3_IDL_START);
			/* Disable SMB's MIWU interrupts */
			npcx_miwu_irq_disable(&config->smb_wui);
		}
	}

	i2c_ctrl_irq_enable(i2c_dev, 1);

	return 0;
}

static void i2c_target_wk_isr(const struct device *dev, struct npcx_wui *wui)
{
	/* Clear wake up detection event status */
	npcx_i2c_target_clear_detection_event();

	/*
	 * Suspend-to-idle stops SMB module clocks (derived from APB2/APB3), which must remain
	 * active during a transaction.
	 *
	 * This also prevent Sr set pm_policy_state_lock_get() twice.
	 * Otherwise, it will cause I2C cannot switch to deep sleep state for the next time.
	 */
#ifdef CONFIG_PM
	i2c_npcx_pm_policy_state_lock_get(dev, I2C_PM_POLICY_STATE_FLAG_TGT);
#endif /* CONFIG_PM */
}
#endif /* CONFIG_I2C_TARGET */

int npcx_i2c_ctrl_transfer(const struct device *i2c_dev, struct i2c_msg *msgs, uint8_t num_msgs,
			   uint16_t addr, uint8_t port)
{
	struct i2c_ctrl_data *const data = i2c_dev->data;
	int ret = 0;
	struct i2c_msg *msg = msgs;

#ifdef CONFIG_I2C_TARGET
	/* I2c module has been configured to target mode */
	if (atomic_get(&data->registered_target_mask) != (atomic_val_t) 0) {
		return -EBUSY;
	}
#endif /* CONFIG_I2C_TARGET */

	/*
	 * suspend-to-idle stops SMB module clocks (derived from APB2/APB3), which must remain
	 * active during a transaction
	 */
	pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES);

	/* Does bus need recovery? */
	if (data->oper_state != NPCX_I2C_WRITE_SUSPEND &&
			data->oper_state != NPCX_I2C_READ_SUSPEND) {
		if (i2c_ctrl_bus_busy(i2c_dev) || !i2c_ctrl_is_scl_sda_both_high(i2c_dev) ||
		    data->oper_state == NPCX_I2C_ERROR_RECOVERY) {
			ret = npcx_i2c_ctrl_recover_bus(i2c_dev);
			if (ret != 0) {
				LOG_ERR("Recover Bus failed: %s::%d", i2c_dev->name, port);
				goto out;
			}

			ret = i2c_ctrl_recovery(i2c_dev);
			/* Recovery failed, return it immediately */
			if (ret) {
				goto out;
			}
		}
	}

	/* Start i2c transaction */
	data->port = port;
	data->trans_err = 0;
	data->addr = addr;

	data->msg_head = msgs;
	data->msg_max_num = num_msgs;
	data->msg_curr_idx = 0;

	/*
	 * Reset i2c event-completed semaphore before starting transactions.
	 * Some interrupt events such as BUS_ERROR might change its counter
	 * when bus is idle.
	 */
	k_sem_reset(&data->sync_sem);

	if ((msg->flags & I2C_MSG_RW_MASK) == I2C_MSG_WRITE) {
		ret = i2c_ctrl_proc_write_msg(i2c_dev, msg);
	} else { /* Handle read transaction */
		ret = i2c_ctrl_proc_read_msg(i2c_dev, msg);
	}

	/* Check STOP completed? */
	if (data->oper_state == NPCX_I2C_WAIT_STOP) {
		data->trans_err = i2c_ctrl_wait_stop_completed(i2c_dev,
							I2C_MIN_TIMEOUT);
		if (data->trans_err == 0) {
			data->oper_state = NPCX_I2C_IDLE;
		} else {
			LOG_ERR("STOP fail! bus is held on i2c %s::%02x!\n", i2c_dev->name,
				data->port);
			data->oper_state = NPCX_I2C_ERROR_RECOVERY;
		}
	}

	if (data->oper_state == NPCX_I2C_ERROR_RECOVERY || ret == -ETIMEDOUT) {
		int recovery_error = i2c_ctrl_recovery(i2c_dev);
		/*
		 * Recovery failed, return it immediately. Otherwise, the upper
		 * layer still needs to know why the transaction failed.
		 */
		if (recovery_error != 0) {
			ret = recovery_error;
		}
	}

out:
	pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES);
	return ret;
}

/* I2C controller driver registration */
static int i2c_ctrl_init(const struct device *dev)
{
	const struct i2c_ctrl_config *const config = dev->config;
	struct i2c_ctrl_data *const data = dev->data;
	const struct device *const clk_dev = DEVICE_DT_GET(NPCX_CLK_CTRL_NODE);
	uint32_t i2c_rate;

	if (!device_is_ready(clk_dev)) {
		LOG_ERR("clock control device not ready");
		return -ENODEV;
	}

	/* Turn on device clock first and get source clock freq. */
	if (clock_control_on(clk_dev,
		(clock_control_subsys_t) &config->clk_cfg) != 0) {
		LOG_ERR("Turn on %s clock fail.", dev->name);
		return -EIO;
	}

	/*
	 * If apb2/3's clock is not 15MHz, we need to add the other timing
	 * configuration of the device to meet SMBus timing spec. Please refer
	 * Table 21/22/23 and section 7.5.9 SMBus Timing for more detail.
	 */
	if (clock_control_get_rate(clk_dev, (clock_control_subsys_t)
			&config->clk_cfg, &i2c_rate) != 0) {
		LOG_ERR("Get %s clock rate error.", dev->name);
		return -EIO;
	}

	if (i2c_rate == 15000000 || i2c_rate == 16000000) {
		data->ptr_speed_confs = npcx_15m_speed_confs;
	} else if (i2c_rate == 20000000) {
		data->ptr_speed_confs = npcx_20m_speed_confs;
	} else if (i2c_rate == 25000000) {
		data->ptr_speed_confs = npcx_25m_speed_confs;
	} else if (i2c_rate == 50000000) {
		data->ptr_speed_confs = npcx_50m_speed_confs;
	} else {
		LOG_ERR("Unsupported apb2/3 freq for %s.", dev->name);
		return -EIO;
	}

	/* Initialize i2c module */
	i2c_ctrl_init_module(dev);

#ifdef CONFIG_I2C_TARGET
	if (IS_ENABLED(CONFIG_PM) && config->wakeup_source) {
		/* Initialize a miwu device input and its callback function */
		npcx_miwu_init_dev_callback(&data->smb_wk_cb, &config->smb_wui,
					    i2c_target_wk_isr, dev);
		npcx_miwu_manage_callback(&data->smb_wk_cb, true);
		/*
		 * Configure Start condition wake-up configuration of SMB
		 * controller.
		 */
		npcx_miwu_interrupt_configure(&config->smb_wui, NPCX_MIWU_MODE_EDGE,
					      NPCX_MIWU_TRIG_HIGH);
	}
#endif /* CONFIG_I2C_TARGET */

	/* initialize mutex and semaphore for i2c/smb controller */
	k_sem_init(&data->lock_sem, 1, 1);
	k_sem_init(&data->sync_sem, 0, K_SEM_MAX_LIMIT);

	/* Initialize driver status machine */
	data->oper_state = NPCX_I2C_IDLE;

	return 0;
}

/* I2C controller init macro functions */
#define NPCX_I2C_CTRL_INIT_FUNC(inst) _CONCAT(i2c_ctrl_init_, inst)
#define NPCX_I2C_CTRL_INIT_FUNC_DECL(inst) \
	static int i2c_ctrl_init_##inst(const struct device *dev)
#define NPCX_I2C_CTRL_INIT_FUNC_IMPL(inst)                                     \
	static int i2c_ctrl_init_##inst(const struct device *dev)              \
	{	                                                               \
		int ret;                                                       \
									       \
		ret = i2c_ctrl_init(dev);                                      \
		IRQ_CONNECT(DT_INST_IRQN(inst),		                       \
			DT_INST_IRQ(inst, priority),                           \
			i2c_ctrl_isr,                                          \
			DEVICE_DT_INST_GET(inst),                              \
			0);                                                    \
		irq_enable(DT_INST_IRQN(inst));                                \
									       \
		return ret;                                                    \
	}

#define NPCX_I2C_CTRL_INIT(inst)                                                                   \
	NPCX_I2C_CTRL_INIT_FUNC_DECL(inst);                                                        \
									                           \
	static const struct i2c_ctrl_config i2c_ctrl_cfg_##inst = {                                \
		.base = DT_INST_REG_ADDR(inst),                                                    \
		.irq = DT_INST_IRQN(inst),                                                         \
		.clk_cfg = NPCX_DT_CLK_CFG_ITEM(inst),                                             \
		IF_ENABLED(CONFIG_I2C_TARGET, (                                                    \
			.smb_wui = NPCX_DT_WUI_ITEM_BY_NAME(inst, smb_wui),                        \
			.wakeup_source = DT_INST_PROP_OR(inst, wakeup_source, 0)                   \
		))                                                                                 \
	};                                                                                         \
									                           \
	static struct i2c_ctrl_data i2c_ctrl_data_##inst;                                          \
									                           \
	DEVICE_DT_INST_DEFINE(inst,                                                                \
			    NPCX_I2C_CTRL_INIT_FUNC(inst),                                         \
			    NULL,                                                                  \
			    &i2c_ctrl_data_##inst, &i2c_ctrl_cfg_##inst,                           \
			    PRE_KERNEL_1, CONFIG_I2C_INIT_PRIORITY,                                \
			    NULL);                                                                 \
									                           \
	NPCX_I2C_CTRL_INIT_FUNC_IMPL(inst)

DT_INST_FOREACH_STATUS_OKAY(NPCX_I2C_CTRL_INIT)
