/*
 * Copyright (c) 2021 ITE Corporation. All Rights Reserved.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#define DT_DRV_COMPAT ite_it8xxx2_espi

#include <assert.h>
#include <zephyr/drivers/espi.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/drivers/interrupt_controller/wuc_ite_it51xxx.h>
#include <zephyr/drivers/interrupt_controller/wuc_ite_it8xxx2.h>
#include <zephyr/kernel.h>
#include <zephyr/sys/util.h>
#include <soc.h>
#include <soc_dt.h>
#include "soc_espi.h"
#include "espi_utils.h"

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

#define ESPI_ITE_GET_GCTRL_BASE ((struct gctrl_ite_ec_regs *)DT_REG_ADDR(DT_NODELABEL(gctrl)))

#define IT8XXX2_ESPI_IRQ     DT_INST_IRQ_BY_IDX(0, 0, irq)
#define IT8XXX2_ESPI_VW_IRQ  DT_INST_IRQ_BY_IDX(0, 1, irq)
#define IT8XXX2_KBC_IBF_IRQ  DT_INST_IRQ_BY_IDX(0, 2, irq)
#define IT8XXX2_KBC_OBE_IRQ  DT_INST_IRQ_BY_IDX(0, 3, irq)
#define IT8XXX2_PMC1_IBF_IRQ DT_INST_IRQ_BY_IDX(0, 4, irq)
#define IT8XXX2_PORT_80_IRQ  DT_INST_IRQ_BY_IDX(0, 5, irq)
#define IT8XXX2_PMC2_IBF_IRQ DT_INST_IRQ_BY_IDX(0, 6, irq)
#define IT8XXX2_TRANS_IRQ    DT_INST_IRQ_BY_IDX(0, 7, irq)
#define IT8XXX2_PMC3_IBF_IRQ DT_INST_IRQ_BY_IDX(0, 8, irq)
#define IT8XXX2_PMC4_IBF_IRQ DT_INST_IRQ_BY_IDX(0, 9, irq)
#define IT8XXX2_PMC5_IBF_IRQ DT_INST_IRQ_BY_IDX(0, 10, irq)

/* General Capabilities and Configuration 1 */
#define IT8XXX2_ESPI_MAX_FREQ_MASK GENMASK(2, 0)
#define IT8XXX2_ESPI_CAPCFG1_MAX_FREQ_20 0
#define IT8XXX2_ESPI_CAPCFG1_MAX_FREQ_25 1
#define IT8XXX2_ESPI_CAPCFG1_MAX_FREQ_33 2
#define IT8XXX2_ESPI_CAPCFG1_MAX_FREQ_50 3
#define IT8XXX2_ESPI_CAPCFG1_MAX_FREQ_66 4

#define IT8XXX2_ESPI_PC_READY_MASK  BIT(1)
#define IT8XXX2_ESPI_VW_READY_MASK  BIT(1)
#define IT8XXX2_ESPI_OOB_READY_MASK BIT(1)
#define IT8XXX2_ESPI_FC_READY_MASK  BIT(1)

#define IT8XXX2_ESPI_INTERRUPT_ENABLE          BIT(7)
#define IT8XXX2_ESPI_TO_WUC_ENABLE             BIT(4)
#define IT8XXX2_ESPI_VW_INTERRUPT_ENABLE       BIT(7)
#define IT8XXX2_ESPI_INTERRUPT_PUT_PC          BIT(7)

/*
 * VWCTRL2 register:
 * bit4 = 1b: Refers to ESPI_RESET# for PLTRST#.
 */
#define IT8XXX2_ESPI_VW_RESET_PLTRST           BIT(4)

#define IT8XXX2_ESPI_UPSTREAM_ENABLE           BIT(7)
#define IT8XXX2_ESPI_UPSTREAM_GO               BIT(6)
#define IT8XXX2_ESPI_UPSTREAM_INTERRUPT_ENABLE BIT(5)
#define IT8XXX2_ESPI_UPSTREAM_CHANNEL_DISABLE  BIT(2)
#define IT8XXX2_ESPI_UPSTREAM_DONE             BIT(1)
#define IT8XXX2_ESPI_UPSTREAM_BUSY             BIT(0)

#define IT8XXX2_ESPI_CYCLE_TYPE_OOB            0x07

#define IT8XXX2_ESPI_PUT_OOB_STATUS            BIT(7)
#define IT8XXX2_ESPI_PUT_OOB_INTERRUPT_ENABLE  BIT(7)
#define IT8XXX2_ESPI_PUT_OOB_LEN_MASK          GENMASK(6, 0)

#define IT8XXX2_ESPI_INPUT_PAD_GATING          BIT(6)

#define IT8XXX2_ESPI_FLASH_MAX_PAYLOAD_SIZE    64
#define IT8XXX2_ESPI_PUT_FLASH_TAG_MASK        GENMASK(7, 4)
#define IT8XXX2_ESPI_PUT_FLASH_LEN_MASK        GENMASK(6, 0)

/*
 * EC2I bridge registers
 */
struct ec2i_regs {
	/* 0x00: Indirect Host I/O Address Register */
	volatile uint8_t IHIOA;
	/* 0x01: Indirect Host Data Register */
	volatile uint8_t IHD;
	/* 0x02: Lock Super I/O Host Access Register */
	volatile uint8_t LSIOHA;
	/* 0x03: Super I/O Access Lock Violation Register */
	volatile uint8_t SIOLV;
	/* 0x04: EC to I-Bus Modules Access Enable Register */
	volatile uint8_t IBMAE;
	/* 0x05: I-Bus Control Register */
	volatile uint8_t IBCTL;
};

/* Index list of the host interface registers of PNPCFG */
enum host_pnpcfg_index {
	/* Logical Device Number */
	HOST_INDEX_LDN = 0x07,
	/* Chip ID Byte 1 */
	HOST_INDEX_CHIPID1 = 0x20,
	/* Chip ID Byte 2 */
	HOST_INDEX_CHIPID2 = 0x21,
	/* Chip Version */
	HOST_INDEX_CHIPVER = 0x22,
	/* Super I/O Control */
	HOST_INDEX_SIOCTRL = 0x23,
	/* Super I/O IRQ Configuration */
	HOST_INDEX_SIOIRQ = 0x25,
	/* Super I/O General Purpose */
	HOST_INDEX_SIOGP = 0x26,
	/* Super I/O Power Mode */
	HOST_INDEX_SIOPWR = 0x2D,
	/* Depth 2 I/O Address */
	HOST_INDEX_D2ADR = 0x2E,
	/* Depth 2 I/O Data */
	HOST_INDEX_D2DAT = 0x2F,
	/* Logical Device Activate Register */
	HOST_INDEX_LDA = 0x30,
	/* I/O Port Base Address Bits [15:8] for Descriptor 0 */
	HOST_INDEX_IOBAD0_MSB = 0x60,
	/* I/O Port Base Address Bits [7:0] for Descriptor 0 */
	HOST_INDEX_IOBAD0_LSB = 0x61,
	/* I/O Port Base Address Bits [15:8] for Descriptor 1 */
	HOST_INDEX_IOBAD1_MSB = 0x62,
	/* I/O Port Base Address Bits [7:0] for Descriptor 1 */
	HOST_INDEX_IOBAD1_LSB = 0x63,
	/* Interrupt Request Number and Wake-Up on IRQ Enabled */
	HOST_INDEX_IRQNUMX = 0x70,
	/* Interrupt Request Type Select */
	HOST_INDEX_IRQTP = 0x71,
	/* DMA Channel Select 0 */
	HOST_INDEX_DMAS0 = 0x74,
	/* DMA Channel Select 1 */
	HOST_INDEX_DMAS1 = 0x75,
	/* Device Specific Logical Device Configuration 1 to 10 */
	HOST_INDEX_DSLDC1 = 0xF0,
	HOST_INDEX_DSLDC2 = 0xF1,
	HOST_INDEX_DSLDC3 = 0xF2,
	HOST_INDEX_DSLDC4 = 0xF3,
	HOST_INDEX_DSLDC5 = 0xF4,
	HOST_INDEX_DSLDC6 = 0xF5,
	HOST_INDEX_DSLDC7 = 0xF6,
	HOST_INDEX_DSLDC8 = 0xF7,
	HOST_INDEX_DSLDC9 = 0xF8,
	HOST_INDEX_DSLDC10 = 0xF9,
	HOST_INDEX_DSLDC11 = 0xFA,
	HOST_INDEX_DSLDC12 = 0xFB,
	HOST_INDEX_DSLDC13 = 0xFD,
};

/* List of logical device number (LDN) assignments */
enum logical_device_number {
	/* Serial Port 1 */
	LDN_UART1 = 0x01,
	/* Serial Port 2 */
	LDN_UART2 = 0x02,
	/* System Wake-Up Control */
	LDN_SWUC = 0x04,
	/* KBC/Mouse Interface */
	LDN_KBC_MOUSE = 0x05,
	/* KBC/Keyboard Interface */
	LDN_KBC_KEYBOARD = 0x06,
	/* Consumer IR */
	LDN_CIR = 0x0A,
	/* Shared Memory/Flash Interface */
	LDN_SMFI = 0x0F,
	/* RTC-like Timer */
	LDN_RTCT = 0x10,
	/* Power Management I/F Channel 1 */
	LDN_PMC1 = 0x11,
	/* Power Management I/F Channel 2 */
	LDN_PMC2 = 0x12,
	/* Serial Peripheral Interface */
	LDN_SSPI = 0x13,
	/* Platform Environment Control Interface */
	LDN_PECI = 0x14,
	/* Power Management I/F Channel 3 */
	LDN_PMC3 = 0x17,
	/* Power Management I/F Channel 4 */
	LDN_PMC4 = 0x18,
	/* Power Management I/F Channel 5 */
	LDN_PMC5 = 0x19,
};

/* Structure for initializing PNPCFG via ec2i. */
struct ec2i_t {
	/* index port */
	enum host_pnpcfg_index index_port;
	/* data port */
	uint8_t data_port;
};

/* EC2I access index/data port */
enum ec2i_access {
	/* index port */
	EC2I_ACCESS_INDEX = 0,
	/* data port */
	EC2I_ACCESS_DATA = 1,
};

/* EC to I-Bus Access Enabled */
#define EC2I_IBCTL_CSAE  BIT(0)
/* EC Read from I-Bus */
#define EC2I_IBCTL_CRIB  BIT(1)
/* EC Write to I-Bus */
#define EC2I_IBCTL_CWIB  BIT(2)
#define EC2I_IBCTL_CRWIB (EC2I_IBCTL_CRIB | EC2I_IBCTL_CWIB)

/* PNPCFG Register EC Access Enable */
#define EC2I_IBMAE_CFGAE BIT(0)

/*
 * KBC registers
 */
struct kbc_regs {
	/* 0x00: KBC Host Interface Control Register */
	volatile uint8_t KBHICR;
	/* 0x01: Reserved1 */
	volatile uint8_t reserved1;
	/* 0x02: KBC Interrupt Control Register */
	volatile uint8_t KBIRQR;
	/* 0x03: Reserved2 */
	volatile uint8_t reserved2;
	/* 0x04: KBC Host Interface Keyboard/Mouse Status Register */
	volatile uint8_t KBHISR;
	/* 0x05: Reserved3 */
	volatile uint8_t reserved3;
	/* 0x06: KBC Host Interface Keyboard Data Output Register */
	volatile uint8_t KBHIKDOR;
	/* 0x07: Reserved4 */
	volatile uint8_t reserved4;
	/* 0x08: KBC Host Interface Mouse Data Output Register */
	volatile uint8_t KBHIMDOR;
	/* 0x09: Reserved5 */
	volatile uint8_t reserved5;
	/* 0x0a: KBC Host Interface Keyboard/Mouse Data Input Register */
	volatile uint8_t KBHIDIR;
};

/* Output Buffer Full */
#define KBC_KBHISR_OBF      BIT(0)
/* Input Buffer Full */
#define KBC_KBHISR_IBF      BIT(1)
/* A2 Address (A2) */
#define KBC_KBHISR_A2_ADDR  BIT(3)
#define KBC_KBHISR_STS_MASK (KBC_KBHISR_OBF | KBC_KBHISR_IBF | KBC_KBHISR_A2_ADDR)

/* Clear Output Buffer Full */
#define KBC_KBHICR_COBF      BIT(6)
/* IBF/OBF Clear Mode Enable */
#define KBC_KBHICR_IBFOBFCME BIT(5)
/* Input Buffer Full CPU Interrupt Enable */
#define KBC_KBHICR_IBFCIE    BIT(3)
/* Output Buffer Empty CPU Interrupt Enable */
#define KBC_KBHICR_OBECIE    BIT(2)
/* Output Buffer Full Mouse Interrupt Enable */
#define KBC_KBHICR_OBFMIE    BIT(1)
/* Output Buffer Full Keyboard Interrupt Enable */
#define KBC_KBHICR_OBFKIE    BIT(0)

/*
 * PMC registers
 */
struct pmc_regs {
	/* 0x00: Host Interface PM Channel 1 Status */
	volatile uint8_t PM1STS;
	/* 0x01: Host Interface PM Channel 1 Data Out Port */
	volatile uint8_t PM1DO;
	/* 0x02: Host Interface PM Channel 1 Data Out Port with SCI# */
	volatile uint8_t PM1DOSCI;
	/* 0x03: Host Interface PM Channel 1 Data Out Port with SMI# */
	volatile uint8_t PM1DOSMI;
	/* 0x04: Host Interface PM Channel 1 Data In Port */
	volatile uint8_t PM1DI;
	/* 0x05: Host Interface PM Channel 1 Data In Port with SCI# */
	volatile uint8_t PM1DISCI;
	/* 0x06: Host Interface PM Channel 1 Control */
	volatile uint8_t PM1CTL;
	/* 0x07: Host Interface PM Channel 1 Interrupt Control */
	volatile uint8_t PM1IC;
	/* 0x08: Host Interface PM Channel 1 Interrupt Enable */
	volatile uint8_t PM1IE;
	/* 0x09-0x0f: Reserved1 */
	volatile uint8_t reserved1[7];
	/* 0x10: Host Interface PM Channel 2 Status */
	volatile uint8_t PM2STS;
	/* 0x11: Host Interface PM Channel 2 Data Out Port */
	volatile uint8_t PM2DO;
	/* 0x12: Host Interface PM Channel 2 Data Out Port with SCI# */
	volatile uint8_t PM2DOSCI;
	/* 0x13: Host Interface PM Channel 2 Data Out Port with SMI# */
	volatile uint8_t PM2DOSMI;
	/* 0x14: Host Interface PM Channel 2 Data In Port */
	volatile uint8_t PM2DI;
	/* 0x15: Host Interface PM Channel 2 Data In Port with SCI# */
	volatile uint8_t PM2DISCI;
	/* 0x16: Host Interface PM Channel 2 Control */
	volatile uint8_t PM2CTL;
	/* 0x17: Host Interface PM Channel 2 Interrupt Control */
	volatile uint8_t PM2IC;
	/* 0x18: Host Interface PM Channel 2 Interrupt Enable */
	volatile uint8_t PM2IE;
	/* 0x19: Mailbox Control */
	volatile uint8_t MBXCTRL;
	/* 0x1a-0x1f: Reserved2 */
	volatile uint8_t reserved2[6];
	/* 0x20: Host Interface PM Channel 3 Status */
	volatile uint8_t PM3STS;
	/* 0x21: Host Interface PM Channel 3 Data Out Port */
	volatile uint8_t PM3DO;
	/* 0x22: Host Interface PM Channel 3 Data In Port */
	volatile uint8_t PM3DI;
	/* 0x23: Host Interface PM Channel 3 Control */
	volatile uint8_t PM3CTL;
	/* 0x24: Host Interface PM Channel 3 Interrupt Control */
	volatile uint8_t PM3IC;
	/* 0x25: Host Interface PM Channel 3 Interrupt Enable */
	volatile uint8_t PM3IE;
	/* 0x26-0x2f: reserved_26_2f */
	volatile uint8_t reserved_26_2f[10];
	/* 0x30: PMC4 Status Register */
	volatile uint8_t PM4STS;
	/* 0x31: PMC4 Data Out Port */
	volatile uint8_t PM4DO;
	/* 0x32: PMC4 Data In Port */
	volatile uint8_t PM4DI;
	/* 0x33: PMC4 Control */
	volatile uint8_t PM4CTL;
	/* 0x34: PMC4 Interrupt Control */
	volatile uint8_t PM4IC;
	/* 0x35: PMC4 Interrupt Enable*/
	volatile uint8_t PM4IE;
	/* 0x36-0x3f: reserved_36_3f */
	volatile uint8_t reserved_36_3f[10];
	/* 0x40: PMC5 Status Register */
	volatile uint8_t PM5STS;
	/* 0x41: PMC5 Data Out Port */
	volatile uint8_t PM5DO;
	/* 0x42: PMC5 Data In Port */
	volatile uint8_t PM5DI;
	/* 0x43: PMC5 Control */
	volatile uint8_t PM5CTL;
	/* 0x44: PMC5 Interrupt Control */
	volatile uint8_t PM5IC;
	/* 0x45: PMC5 Interrupt Enable*/
	volatile uint8_t PM5IE;
	/* 0x46-0xff: reserved_46_ff */
	volatile uint8_t reserved_46_ff[0xba];
};

/* Input Buffer Full Interrupt Enable */
#define PMC_PM1CTL_IBFIE   BIT(0)
/* Output Buffer Full */
#define PMC_PM1STS_OBF     BIT(0)
/* Input Buffer Full */
#define PMC_PM1STS_IBF     BIT(1)
/* General Purpose Flag */
#define PMC_PM1STS_GPF     BIT(2)
/* A2 Address (A2) */
#define PMC_PM1STS_A2_ADDR BIT(3)

/* PMC2 Input Buffer Full Interrupt Enable */
#define PMC_PM2CTL_IBFIE BIT(0)
/* General Purpose Flag */
#define PMC_PM2STS_GPF   BIT(2)

/* PMC3 Input Buffer Full Interrupt Enable */
#define PMC_PM3CTL_IBFIE   BIT(0)
/* A2 Address (A2) */
#define PMC_PM3STS_A2_ADDR BIT(3)
/* Input Buffer Full Interrupt Enable */
#define PMC_PM4CTL_IBFIE   BIT(0)
/* A2 Address (A2) */
#define PMC_PM4STS_A2_ADDR BIT(3)
/* Input Buffer Full Interrupt Enable */
#define PMC_PM5CTL_IBFIE   BIT(0)
/* A2 Address (A2) */
#define PMC_PM5STS_A2_ADDR BIT(3)

/*
 * Dedicated Interrupt
 * 0b:
 * INT3: PMC Output Buffer Empty Int
 * INT25: PMC Input Buffer Full Int
 * 1b:
 * INT3: PMC1 Output Buffer Empty Int
 * INT25: PMC1 Input Buffer Full Int
 * INT26: PMC2 Output Buffer Empty Int
 * INT27: PMC2 Input Buffer Full Int
 */
#define PMC_MBXCTRL_DINT BIT(5)

/*
 * eSPI slave registers
 */
struct espi_slave_regs {
	/* 0x00-0x03: Reserved1 */
	volatile uint8_t reserved1[4];

	/* 0x04: General Capabilities and Configuration 0 */
	volatile uint8_t GCAPCFG0;
	/* 0x05: General Capabilities and Configuration 1 */
	volatile uint8_t GCAPCFG1;
	/* 0x06: General Capabilities and Configuration 2 */
	volatile uint8_t GCAPCFG2;
	/* 0x07: General Capabilities and Configuration 3 */
	volatile uint8_t GCAPCFG3;

	/* Channel 0 (Peripheral Channel) Capabilities and Configurations */
	/* 0x08: Channel 0 Capabilities and Configuration 0 */
	volatile uint8_t CH_PC_CAPCFG0;
	/* 0x09: Channel 0 Capabilities and Configuration 1 */
	volatile uint8_t CH_PC_CAPCFG1;
	/* 0x0A: Channel 0 Capabilities and Configuration 2 */
	volatile uint8_t CH_PC_CAPCFG2;
	/* 0x0B: Channel 0 Capabilities and Configuration 3 */
	volatile uint8_t CH_PC_CAPCFG3;

	/* Channel 1 (Virtual Wire Channel) Capabilities and Configurations */
	/* 0x0C: Channel 1 Capabilities and Configuration 0 */
	volatile uint8_t CH_VW_CAPCFG0;
	/* 0x0D: Channel 1 Capabilities and Configuration 1 */
	volatile uint8_t CH_VW_CAPCFG1;
	/* 0x0E: Channel 1 Capabilities and Configuration 2 */
	volatile uint8_t CH_VW_CAPCFG2;
	/* 0x0F: Channel 1 Capabilities and Configuration 3 */
	volatile uint8_t CH_VW_CAPCFG3;

	/* Channel 2 (OOB Message Channel) Capabilities and Configurations */
	/* 0x10: Channel 2 Capabilities and Configuration 0 */
	volatile uint8_t CH_OOB_CAPCFG0;
	/* 0x11: Channel 2 Capabilities and Configuration 1 */
	volatile uint8_t CH_OOB_CAPCFG1;
	/* 0x12: Channel 2 Capabilities and Configuration 2 */
	volatile uint8_t CH_OOB_CAPCFG2;
	/* 0x13: Channel 2 Capabilities and Configuration 3 */
	volatile uint8_t CH_OOB_CAPCFG3;

	/* Channel 3 (Flash Access Channel) Capabilities and Configurations */
	/* 0x14: Channel 3 Capabilities and Configuration 0 */
	volatile uint8_t CH_FLASH_CAPCFG0;
	/* 0x15: Channel 3 Capabilities and Configuration 1 */
	volatile uint8_t CH_FLASH_CAPCFG1;
	/* 0x16: Channel 3 Capabilities and Configuration 2 */
	volatile uint8_t CH_FLASH_CAPCFG2;
	/* 0x17: Channel 3 Capabilities and Configuration 3 */
	volatile uint8_t CH_FLASH_CAPCFG3;
	/* Channel 3 Capabilities and Configurations 2 */
	/* 0x18: Channel 3 Capabilities and Configuration 2-0 */
	volatile uint8_t CH_FLASH_CAPCFG2_0;
	/* 0x19: Channel 3 Capabilities and Configuration 2-1 */
	volatile uint8_t CH_FLASH_CAPCFG2_1;
	/* 0x1A: Channel 3 Capabilities and Configuration 2-2 */
	volatile uint8_t CH_FLASH_CAPCFG2_2;
	/* 0x1B: Channel 3 Capabilities and Configuration 2-3 */
	volatile uint8_t CH_FLASH_CAPCFG2_3;

	/* 0x1c-0x1f: Reserved2 */
	volatile uint8_t reserved2[4];
	/* 0x20-0x8f: Reserved3 */
	volatile uint8_t reserved3[0x70];

	/* 0x90: eSPI PC Control 0 */
	volatile uint8_t ESPCTRL0;
	/* 0x91: eSPI PC Control 1 */
	volatile uint8_t ESPCTRL1;
	/* 0x92: eSPI PC Control 2 */
	volatile uint8_t ESPCTRL2;
	/* 0x93: eSPI PC Control 3 */
	volatile uint8_t ESPCTRL3;
	/* 0x94: eSPI PC Control 4 */
	volatile uint8_t ESPCTRL4;
	/* 0x95: eSPI PC Control 5 */
	volatile uint8_t ESPCTRL5;
	/* 0x96: eSPI PC Control 6 */
	volatile uint8_t ESPCTRL6;
	/* 0x97: eSPI PC Control 7 */
	volatile uint8_t ESPCTRL7;
	/* 0x98-0x9f: Reserved4 */
	volatile uint8_t reserved4[8];

	/* 0xa0: eSPI General Control 0 */
	volatile uint8_t ESGCTRL0;
	/* 0xa1: eSPI General Control 1 */
	volatile uint8_t ESGCTRL1;
	/* 0xa2: eSPI General Control 2 */
	volatile uint8_t ESGCTRL2;
	/* 0xa3: eSPI General Control 3 */
	volatile uint8_t ESGCTRL3;
	/* 0xa4-0xaf: Reserved5 */
	volatile uint8_t reserved5[12];

	/* 0xb0: eSPI Upstream Control 0 */
	volatile uint8_t ESUCTRL0;
	/* 0xb1: eSPI Upstream Control 1 */
	volatile uint8_t ESUCTRL1;
	/* 0xb2: eSPI Upstream Control 2 */
	volatile uint8_t ESUCTRL2;
	/* 0xb3: eSPI Upstream Control 3 */
	volatile uint8_t ESUCTRL3;
	/* 0xb4-0xb5: Reserved6 */
	volatile uint8_t reserved6[2];
	/* 0xb6: eSPI Upstream Control 6 */
	volatile uint8_t ESUCTRL6;
	/* 0xb7: eSPI Upstream Control 7 */
	volatile uint8_t ESUCTRL7;
	/* 0xb8: eSPI Upstream Control 8 */
	volatile uint8_t ESUCTRL8;
	/* 0xb9-0xbf: Reserved7 */
	volatile uint8_t reserved7[7];

	/* 0xc0: eSPI OOB Control 0 */
	volatile uint8_t ESOCTRL0;
	/* 0xc1: eSPI OOB Control 1 */
	volatile uint8_t ESOCTRL1;
	/* 0xc2-0xc3: Reserved8 */
	volatile uint8_t reserved8[2];
	/* 0xc4: eSPI OOB Control 4 */
	volatile uint8_t ESOCTRL4;
	/* 0xc5-0xcf: Reserved9 */
	volatile uint8_t reserved9[11];

	/* 0xd0: eSPI SAFS Control 0 */
	volatile uint8_t ESPISAFSC0;
	/* 0xd1: eSPI SAFS Control 1 */
	volatile uint8_t ESPISAFSC1;
	/* 0xd2: eSPI SAFS Control 2 */
	volatile uint8_t ESPISAFSC2;
	/* 0xd3: eSPI SAFS Control 3 */
	volatile uint8_t ESPISAFSC3;
	/* 0xd4: eSPI SAFS Control 4 */
	volatile uint8_t ESPISAFSC4;
	/* 0xd5: eSPI SAFS Control 5 */
	volatile uint8_t ESPISAFSC5;
	/* 0xd6: eSPI SAFS Control 6 */
	volatile uint8_t ESPISAFSC6;
	/* 0xd7: eSPI SAFS Control 7 */
	volatile uint8_t ESPISAFSC7;
};

/*
 * eSPI VW registers
 */
struct espi_vw_regs {
	/* 0x00-0x7f: VW index */
	volatile uint8_t VW_INDEX[0x80];
	/* 0x80-0x8f: Reserved1 */
	volatile uint8_t reserved1[0x10];
	/* 0x90: VW Control 0 */
	volatile uint8_t VWCTRL0;
	/* 0x91: VW Control 1 */
	volatile uint8_t VWCTRL1;
	/* 0x92: VW Control 2 */
	volatile uint8_t VWCTRL2;
	/* 0x93: VW Control 3 */
	volatile uint8_t VWCTRL3;
	/* 0x94: Reserved2 */
	volatile uint8_t reserved2;
	/* 0x95: VW Control 5 */
	volatile uint8_t VWCTRL5;
	/* 0x96: VW Control 6 */
	volatile uint8_t VWCTRL6;
	/* 0x97: VW Control 7 */
	volatile uint8_t VWCTRL7;
	/* 0x98-0x99: Reserved3 */
	volatile uint8_t reserved3[2];
};

#define ESPI_IT8XXX2_OOB_MAX_PAYLOAD_SIZE 80
/*
 * eSPI Queue 0 registers
 */
struct espi_queue0_regs {
	/* 0x00-0x3f: PUT_PC Data Byte 0-63 */
	volatile uint8_t PUT_PC_DATA[0x40];
	/* 0x40-0x7f: Reserved1 */
	volatile uint8_t reserved1[0x40];
	/* 0x80-0xcf: PUT_OOB Data Byte 0-79 */
	volatile uint8_t PUT_OOB_DATA[ESPI_IT8XXX2_OOB_MAX_PAYLOAD_SIZE];
};

/*
 * eSPI Queue 1 registers
 */
struct espi_queue1_regs {
	/* 0x00-0x4f: Upstream Data Byte 0-79 */
	volatile uint8_t UPSTREAM_DATA[ESPI_IT8XXX2_OOB_MAX_PAYLOAD_SIZE];
	/* 0x50-0x7f: Reserved1 */
	volatile uint8_t reserved1[0x30];
	/* 0x80-0xbf: PUT_FLASH_NP Data Byte 0-63 */
	volatile uint8_t PUT_FLASH_NP_DATA[0x40];
};

/* H2RAM Path Select. 1b: H2RAM through LPC IO cycle. */
#define SMFI_H2RAMPS       BIT(4)
/* H2RAM Window 1 Enable */
#define SMFI_H2RAMW1E      BIT(1)
/* H2RAM Window 0 Enable */
#define SMFI_H2RAMW0E      BIT(0)
/* Host RAM Window x Write Protect Enable (All protected) */
#define SMFI_HRAMWXWPE_ALL (BIT(5) | BIT(4))

/* Accept Port 80h Cycle */
#define IT8XXX2_GCTRL_ACP80 BIT(6)
/* Accept Port 81h Cycle */
#define IT8XXX2_GCTRL_ACP81 BIT(3)

#define IT8XXX2_GPIO_GCR_ESPI_RST_D2      0x2
#define IT8XXX2_GPIO_GCR_ESPI_RST_POS     1
#define IT8XXX2_GPIO_GCR_ESPI_RST_EN_MASK (0x3 << IT8XXX2_GPIO_GCR_ESPI_RST_POS)

/*
 * VCC Detector Option.
 * bit[7-6] = 1: The VCC power status is treated as power-on.
 * The VCC supply of eSPI and related functions (EC2I, KBC, PMC and
 * PECI). It means VCC should be logic high before using these
 * functions, or firmware treats VCC logic high.
 */
#define IT8XXX2_GCTRL_VCCDO_MASK   (BIT(6) | BIT(7))
#define IT8XXX2_GCTRL_VCCDO_VCC_ON BIT(6)
/*
 * bit[3] = 0: The reset source of PNPCFG is RSTPNP bit in RSTCH
 * register and WRST#.
 */
#define IT8XXX2_GCTRL_HGRST        BIT(3)
/* bit[2] = 1: Enable global reset. */
#define IT8XXX2_GCTRL_GRST         BIT(2)

/*
 * IT8XXX2 register structure size/offset checking macro function to mitigate
 * the risk of unexpected compiling results.
 */
#define IT8XXX2_ESPI_REG_SIZE_CHECK(reg_def, size)                                                 \
	BUILD_ASSERT(sizeof(struct reg_def) == size, "Failed in size check of register "           \
						     "structure!")
#define IT8XXX2_ESPI_REG_OFFSET_CHECK(reg_def, member, offset)                                     \
	BUILD_ASSERT(offsetof(struct reg_def, member) == offset,                                   \
		     "Failed in offset check of register structure member!")

/* EC2I register structure check */
IT8XXX2_ESPI_REG_SIZE_CHECK(ec2i_regs, 0x06);
IT8XXX2_ESPI_REG_OFFSET_CHECK(ec2i_regs, IHIOA, 0x00);
IT8XXX2_ESPI_REG_OFFSET_CHECK(ec2i_regs, IHD, 0x01);
IT8XXX2_ESPI_REG_OFFSET_CHECK(ec2i_regs, LSIOHA, 0x02);
IT8XXX2_ESPI_REG_OFFSET_CHECK(ec2i_regs, IBMAE, 0x04);
IT8XXX2_ESPI_REG_OFFSET_CHECK(ec2i_regs, IBCTL, 0x05);

/* KBC register structure check */
IT8XXX2_ESPI_REG_SIZE_CHECK(kbc_regs, 0x0b);
IT8XXX2_ESPI_REG_OFFSET_CHECK(kbc_regs, KBHICR, 0x00);
IT8XXX2_ESPI_REG_OFFSET_CHECK(kbc_regs, KBIRQR, 0x02);
IT8XXX2_ESPI_REG_OFFSET_CHECK(kbc_regs, KBHISR, 0x04);
IT8XXX2_ESPI_REG_OFFSET_CHECK(kbc_regs, KBHIKDOR, 0x06);
IT8XXX2_ESPI_REG_OFFSET_CHECK(kbc_regs, KBHIMDOR, 0x08);
IT8XXX2_ESPI_REG_OFFSET_CHECK(kbc_regs, KBHIDIR, 0x0a);

/* PMC register structure check */
IT8XXX2_ESPI_REG_SIZE_CHECK(pmc_regs, 0x100);
IT8XXX2_ESPI_REG_OFFSET_CHECK(pmc_regs, PM1STS, 0x00);
IT8XXX2_ESPI_REG_OFFSET_CHECK(pmc_regs, PM1DO, 0x01);
IT8XXX2_ESPI_REG_OFFSET_CHECK(pmc_regs, PM1DI, 0x04);
IT8XXX2_ESPI_REG_OFFSET_CHECK(pmc_regs, PM1CTL, 0x06);
IT8XXX2_ESPI_REG_OFFSET_CHECK(pmc_regs, PM2STS, 0x10);
IT8XXX2_ESPI_REG_OFFSET_CHECK(pmc_regs, PM2DO, 0x11);
IT8XXX2_ESPI_REG_OFFSET_CHECK(pmc_regs, PM2DI, 0x14);
IT8XXX2_ESPI_REG_OFFSET_CHECK(pmc_regs, PM2CTL, 0x16);
IT8XXX2_ESPI_REG_OFFSET_CHECK(pmc_regs, MBXCTRL, 0x19);
IT8XXX2_ESPI_REG_OFFSET_CHECK(pmc_regs, PM3STS, 0x20);
IT8XXX2_ESPI_REG_OFFSET_CHECK(pmc_regs, PM3DO, 0x21);
IT8XXX2_ESPI_REG_OFFSET_CHECK(pmc_regs, PM3DI, 0x22);
IT8XXX2_ESPI_REG_OFFSET_CHECK(pmc_regs, PM3CTL, 0x23);
IT8XXX2_ESPI_REG_OFFSET_CHECK(pmc_regs, PM3IC, 0x24);
IT8XXX2_ESPI_REG_OFFSET_CHECK(pmc_regs, PM3IE, 0x25);

/* eSPI slave register structure check */
IT8XXX2_ESPI_REG_SIZE_CHECK(espi_slave_regs, 0xd8);
IT8XXX2_ESPI_REG_OFFSET_CHECK(espi_slave_regs, GCAPCFG1, 0x05);
IT8XXX2_ESPI_REG_OFFSET_CHECK(espi_slave_regs, CH_PC_CAPCFG3, 0x0b);
IT8XXX2_ESPI_REG_OFFSET_CHECK(espi_slave_regs, CH_VW_CAPCFG3, 0x0f);
IT8XXX2_ESPI_REG_OFFSET_CHECK(espi_slave_regs, CH_OOB_CAPCFG3, 0x13);
IT8XXX2_ESPI_REG_OFFSET_CHECK(espi_slave_regs, CH_FLASH_CAPCFG3, 0x17);
IT8XXX2_ESPI_REG_OFFSET_CHECK(espi_slave_regs, CH_FLASH_CAPCFG2_3, 0x1b);
IT8XXX2_ESPI_REG_OFFSET_CHECK(espi_slave_regs, ESPCTRL0, 0x90);
IT8XXX2_ESPI_REG_OFFSET_CHECK(espi_slave_regs, ESGCTRL0, 0xa0);
IT8XXX2_ESPI_REG_OFFSET_CHECK(espi_slave_regs, ESGCTRL1, 0xa1);
IT8XXX2_ESPI_REG_OFFSET_CHECK(espi_slave_regs, ESGCTRL2, 0xa2);
IT8XXX2_ESPI_REG_OFFSET_CHECK(espi_slave_regs, ESUCTRL0, 0xb0);
IT8XXX2_ESPI_REG_OFFSET_CHECK(espi_slave_regs, ESOCTRL0, 0xc0);
IT8XXX2_ESPI_REG_OFFSET_CHECK(espi_slave_regs, ESOCTRL1, 0xc1);
IT8XXX2_ESPI_REG_OFFSET_CHECK(espi_slave_regs, ESPISAFSC0, 0xd0);
IT8XXX2_ESPI_REG_OFFSET_CHECK(espi_slave_regs, ESPISAFSC7, 0xd7);

/* eSPI vw register structure check */
IT8XXX2_ESPI_REG_SIZE_CHECK(espi_vw_regs, 0x9a);
IT8XXX2_ESPI_REG_OFFSET_CHECK(espi_vw_regs, VW_INDEX, 0x00);
IT8XXX2_ESPI_REG_OFFSET_CHECK(espi_vw_regs, VWCTRL0, 0x90);
IT8XXX2_ESPI_REG_OFFSET_CHECK(espi_vw_regs, VWCTRL1, 0x91);

/* eSPI Queue 0 registers structure check */
IT8XXX2_ESPI_REG_SIZE_CHECK(espi_queue0_regs, 0xd0);
IT8XXX2_ESPI_REG_OFFSET_CHECK(espi_queue0_regs, PUT_OOB_DATA, 0x80);

/* eSPI Queue 1 registers structure check */
IT8XXX2_ESPI_REG_SIZE_CHECK(espi_queue1_regs, 0xc0);
IT8XXX2_ESPI_REG_OFFSET_CHECK(espi_queue1_regs, UPSTREAM_DATA, 0x00);
IT8XXX2_ESPI_REG_OFFSET_CHECK(espi_queue1_regs, PUT_FLASH_NP_DATA, 0x80);

/* Register used to record VWx data transmitted to the eSPI host. */
#define IT8XXX2_ESPI_VW_REC_VW4 0xe1
#define IT8XXX2_ESPI_VW_REC_VW5 0xe2
#define IT8XXX2_ESPI_VW_REC_VW6 0xe3
#define IT8XXX2_ESPI_VW_REC_VW40 0xe4

struct espi_it8xxx2_wuc {
	/* WUC control device structure */
	const struct device *wucs;
	/* WUC pin mask */
	uint8_t mask;
};

struct espi_it8xxx2_config {
	uintptr_t base_espi_slave;
	uintptr_t base_espi_vw;
	uintptr_t base_espi_queue1;
	uintptr_t base_espi_queue0;
	uintptr_t base_ec2i;
	uintptr_t base_kbc;
	uintptr_t base_pmc;
	uintptr_t base_smfi;
	const struct espi_it8xxx2_wuc wuc;
};

struct espi_it8xxx2_data {
	sys_slist_t callbacks;
#ifdef CONFIG_ESPI_OOB_CHANNEL
	struct k_sem oob_upstream_go;
#endif
#ifdef CONFIG_ESPI_FLASH_CHANNEL
	struct k_sem flash_upstream_go;
	uint8_t put_flash_cycle_type;
	uint8_t put_flash_tag;
	uint8_t put_flash_len;
	uint8_t flash_buf[IT8XXX2_ESPI_FLASH_MAX_PAYLOAD_SIZE];
#endif
};

struct vw_channel_t {
	uint8_t vw_index;    /* VW index of signal */
	uint8_t level_mask;  /* level bit of signal */
	uint8_t valid_mask;  /* valid bit of signal */
	uint8_t vw_sent_reg; /* vw signal sent to host */
};

struct vwidx_isr_t {
	void (*vwidx_isr)(const struct device *dev, uint8_t update_flag);
	uint8_t vw_index;
};

enum espi_ch_enable_isr_type {
	DEASSERTED_FLAG = 0,
	ASSERTED_FLAG = 1,
};

struct espi_isr_t {
	void (*espi_isr)(const struct device *dev, bool enable);
	enum espi_ch_enable_isr_type isr_type;
};

struct espi_vw_signal_t {
	enum espi_vwire_signal signal;
	void (*vw_signal_isr)(const struct device *dev);
};

/* EC2I bridge and PNPCFG devices */
static const struct ec2i_t kbc_settings[] = {
	/* Select logical device 06h(keyboard) */
	{HOST_INDEX_LDN, LDN_KBC_KEYBOARD},
	/* Set IRQ=01h for logical device */
	{HOST_INDEX_IRQNUMX, 0x01},
	/* Configure IRQTP for KBC. */
	/*
	 * Interrupt request type select (IRQTP) for KBC.
	 * bit 1, 0: IRQ request is buffered and applied to SERIRQ
	 *        1: IRQ request is inverted before being applied to SERIRQ
	 * bit 0, 0: Edge triggered mode
	 *        1: Level triggered mode
	 *
	 * This interrupt configuration should the same on both host and EC side
	 */
	{HOST_INDEX_IRQTP, 0x02},
	/* Enable logical device */
	{HOST_INDEX_LDA, 0x01},

#ifdef CONFIG_ESPI_IT8XXX2_PNPCFG_DEVICE_KBC_MOUSE
	/* Select logical device 05h(mouse) */
	{HOST_INDEX_LDN, LDN_KBC_MOUSE},
	/* Set IRQ=0Ch for logical device */
	{HOST_INDEX_IRQNUMX, 0x0C},
	/* Enable logical device */
	{HOST_INDEX_LDA, 0x01},
#endif
};

static const struct ec2i_t pmc1_settings[] = {
	/* Select logical device 11h(PM1 ACPI) */
	{HOST_INDEX_LDN, LDN_PMC1},
	/* Set IRQ=00h for logical device */
	{HOST_INDEX_IRQNUMX, 0x00},
	/* Enable logical device */
	{HOST_INDEX_LDA, 0x01},
};

#ifdef CONFIG_ESPI_PERIPHERAL_HOST_IO_PVT
#define IT8XXX2_ESPI_HOST_IO_PVT_DATA_PORT_MSB                                                     \
	((CONFIG_ESPI_PERIPHERAL_HOST_IO_PVT_PORT_NUM >> 8) & 0xff)
#define IT8XXX2_ESPI_HOST_IO_PVT_DATA_PORT_LSB (CONFIG_ESPI_PERIPHERAL_HOST_IO_PVT_PORT_NUM & 0xff)
#define IT8XXX2_ESPI_HOST_IO_PVT_CMD_PORT_MSB                                                      \
	(((CONFIG_ESPI_PERIPHERAL_HOST_IO_PVT_PORT_NUM + 4) >> 8) & 0xff)
#define IT8XXX2_ESPI_HOST_IO_PVT_CMD_PORT_LSB                                                      \
	((CONFIG_ESPI_PERIPHERAL_HOST_IO_PVT_PORT_NUM + 4) & 0xff)
static const struct ec2i_t pmc3_settings[] = {
	/* Select logical device 17h(PMC3) */
	{HOST_INDEX_LDN, LDN_PMC3},
	/* I/O Port Base Address (data/command ports) */
	{HOST_INDEX_IOBAD0_MSB, IT8XXX2_ESPI_HOST_IO_PVT_DATA_PORT_MSB},
	{HOST_INDEX_IOBAD0_LSB, IT8XXX2_ESPI_HOST_IO_PVT_DATA_PORT_LSB},
	{HOST_INDEX_IOBAD1_MSB, IT8XXX2_ESPI_HOST_IO_PVT_CMD_PORT_MSB},
	{HOST_INDEX_IOBAD1_LSB, IT8XXX2_ESPI_HOST_IO_PVT_CMD_PORT_LSB},
	/* Set IRQ=00h for logical device */
	{HOST_INDEX_IRQNUMX, 0x00},
	/* Enable logical device */
	{HOST_INDEX_LDA, 0x01},
};
#endif

#ifdef CONFIG_ESPI_PERIPHERAL_HOST_IO_PVT2
#define IT8XXX2_ESPI_HOST_IO_PVT2_DATA_PORT_MSB                                                    \
	((CONFIG_ESPI_PERIPHERAL_HOST_IO_PVT2_PORT_NUM >> 8) & 0xff)
#define IT8XXX2_ESPI_HOST_IO_PVT2_DATA_PORT_LSB                                                    \
	(CONFIG_ESPI_PERIPHERAL_HOST_IO_PVT2_PORT_NUM & 0xff)
#define IT8XXX2_ESPI_HOST_IO_PVT2_CMD_PORT_MSB                                                     \
	(((CONFIG_ESPI_PERIPHERAL_HOST_IO_PVT2_PORT_NUM + 4) >> 8) & 0xff)
#define IT8XXX2_ESPI_HOST_IO_PVT2_CMD_PORT_LSB                                                     \
	((CONFIG_ESPI_PERIPHERAL_HOST_IO_PVT2_PORT_NUM + 4) & 0xff)
static const struct ec2i_t pmc4_settings[] = {
	/* Select logical device 18h(PMC4) */
	{HOST_INDEX_LDN, LDN_PMC4},
	/* I/O Port Base Address (data/command ports) */
	{HOST_INDEX_IOBAD0_MSB, IT8XXX2_ESPI_HOST_IO_PVT2_DATA_PORT_MSB},
	{HOST_INDEX_IOBAD0_LSB, IT8XXX2_ESPI_HOST_IO_PVT2_DATA_PORT_LSB},
	{HOST_INDEX_IOBAD1_MSB, IT8XXX2_ESPI_HOST_IO_PVT2_CMD_PORT_MSB},
	{HOST_INDEX_IOBAD1_LSB, IT8XXX2_ESPI_HOST_IO_PVT2_CMD_PORT_LSB},
	/* Set IRQ=00h for logical device */
	{HOST_INDEX_IRQNUMX, 0x00},
	/* Enable logical device */
	{HOST_INDEX_LDA, 0x01},
};
#endif /* CONFIG_ESPI_PERIPHERAL_HOST_IO_PVT2 */

#ifdef CONFIG_ESPI_PERIPHERAL_HOST_IO_PVT3
#define IT8XXX2_ESPI_HOST_IO_PVT3_DATA_PORT_MSB                                                    \
	((CONFIG_ESPI_PERIPHERAL_HOST_IO_PVT3_PORT_NUM >> 8) & 0xff)
#define IT8XXX2_ESPI_HOST_IO_PVT3_DATA_PORT_LSB                                                    \
	(CONFIG_ESPI_PERIPHERAL_HOST_IO_PVT3_PORT_NUM & 0xff)
#define IT8XXX2_ESPI_HOST_IO_PVT3_CMD_PORT_MSB                                                     \
	(((CONFIG_ESPI_PERIPHERAL_HOST_IO_PVT3_PORT_NUM + 4) >> 8) & 0xff)
#define IT8XXX2_ESPI_HOST_IO_PVT3_CMD_PORT_LSB                                                     \
	((CONFIG_ESPI_PERIPHERAL_HOST_IO_PVT3_PORT_NUM + 4) & 0xff)
static const struct ec2i_t pmc5_settings[] = {
	/* Select logical device 19h(PMC5) */
	{HOST_INDEX_LDN, LDN_PMC5},
	/* I/O Port Base Address (data/command ports) */
	{HOST_INDEX_IOBAD0_MSB, IT8XXX2_ESPI_HOST_IO_PVT3_DATA_PORT_MSB},
	{HOST_INDEX_IOBAD0_LSB, IT8XXX2_ESPI_HOST_IO_PVT3_DATA_PORT_LSB},
	{HOST_INDEX_IOBAD1_MSB, IT8XXX2_ESPI_HOST_IO_PVT3_CMD_PORT_MSB},
	{HOST_INDEX_IOBAD1_LSB, IT8XXX2_ESPI_HOST_IO_PVT3_CMD_PORT_LSB},
	/* Set IRQ=00h for logical device */
	{HOST_INDEX_IRQNUMX, 0x00},
	/* Enable logical device */
	{HOST_INDEX_LDA, 0x01},
};
#endif /* CONFIG_ESPI_PERIPHERAL_HOST_IO_PVT3 */

#ifdef CONFIG_ESPI_PERIPHERAL_EC_HOST_CMD
#define IT8XXX2_ESPI_HC_DATA_PORT_MSB \
	((CONFIG_ESPI_PERIPHERAL_HOST_CMD_DATA_PORT_NUM >> 8) & 0xff)
#define IT8XXX2_ESPI_HC_DATA_PORT_LSB \
	(CONFIG_ESPI_PERIPHERAL_HOST_CMD_DATA_PORT_NUM & 0xff)
#define IT8XXX2_ESPI_HC_CMD_PORT_MSB \
	(((CONFIG_ESPI_PERIPHERAL_HOST_CMD_DATA_PORT_NUM + 4) >> 8) & 0xff)
#define IT8XXX2_ESPI_HC_CMD_PORT_LSB \
	((CONFIG_ESPI_PERIPHERAL_HOST_CMD_DATA_PORT_NUM + 4) & 0xff)
static const struct ec2i_t pmc2_settings[] = {
	/* Select logical device 12h(PM2 host command) */
	{HOST_INDEX_LDN, LDN_PMC2},
	/* I/O Port Base Address (data/command ports) */
	{HOST_INDEX_IOBAD0_MSB, IT8XXX2_ESPI_HC_DATA_PORT_MSB},
	{HOST_INDEX_IOBAD0_LSB, IT8XXX2_ESPI_HC_DATA_PORT_LSB},
	{HOST_INDEX_IOBAD1_MSB, IT8XXX2_ESPI_HC_CMD_PORT_MSB},
	{HOST_INDEX_IOBAD1_LSB, IT8XXX2_ESPI_HC_CMD_PORT_LSB},
	/* Set IRQ=00h for logical device */
	{HOST_INDEX_IRQNUMX, 0x00},
	/* Enable logical device */
	{HOST_INDEX_LDA, 0x01},
};
#endif

#if defined(CONFIG_ESPI_PERIPHERAL_EC_HOST_CMD) || \
	defined(CONFIG_ESPI_PERIPHERAL_ACPI_SHM_REGION)
/*
 * Host to RAM (H2RAM) memory mapping.
 * This feature allows host access EC's memory directly by eSPI I/O cycles.
 * Mapping range is 4K bytes and base address is adjustable.
 * Eg. the I/O cycle 800h~8ffh from host can be mapped to x800h~x8ffh.
 * Linker script will make the pool 4K aligned.
 */
#define IT8XXX2_ESPI_H2RAM_POOL_SIZE_MAX 0x1000
#define IT8XXX2_ESPI_H2RAM_OFFSET_MASK   GENMASK(5, 0)
#define IT8XXX2_ESPI_H2RAM_BASEADDR_MASK GENMASK(19, 0)

#if defined(CONFIG_ESPI_PERIPHERAL_ACPI_SHM_REGION)
#define H2RAM_ACPI_SHM_MAX ((CONFIG_ESPI_IT8XXX2_ACPI_SHM_H2RAM_SIZE) + \
			(CONFIG_ESPI_PERIPHERAL_ACPI_SHM_REGION_PORT_NUM))
#if (H2RAM_ACPI_SHM_MAX > IT8XXX2_ESPI_H2RAM_POOL_SIZE_MAX)
#error "ACPI shared memory region out of h2ram"
#endif
#endif /* CONFIG_ESPI_PERIPHERAL_ACPI_SHM_REGION */

#if defined(CONFIG_ESPI_PERIPHERAL_EC_HOST_CMD)
#define H2RAM_EC_HOST_CMD_MAX ((CONFIG_ESPI_IT8XXX2_HC_H2RAM_SIZE) + \
			(CONFIG_ESPI_PERIPHERAL_HOST_CMD_PARAM_PORT_NUM))
#if (H2RAM_EC_HOST_CMD_MAX > IT8XXX2_ESPI_H2RAM_POOL_SIZE_MAX)
#error "EC host command parameters out of h2ram"
#endif
#endif /* CONFIG_ESPI_PERIPHERAL_EC_HOST_CMD */

#if defined(CONFIG_ESPI_PERIPHERAL_EC_HOST_CMD) && \
	defined(CONFIG_ESPI_PERIPHERAL_ACPI_SHM_REGION)
#if (MIN(H2RAM_ACPI_SHM_MAX, H2RAM_EC_HOST_CMD_MAX) > \
	MAX(CONFIG_ESPI_PERIPHERAL_ACPI_SHM_REGION_PORT_NUM, \
		CONFIG_ESPI_PERIPHERAL_HOST_CMD_PARAM_PORT_NUM))
#error "ACPI and HC sections of h2ram overlap"
#endif
#endif

#ifdef CONFIG_ESPI_IT8XXX2_H2RAM_SHARED
#define H2RAM_STORAGE
#else
#define H2RAM_STORAGE static
#endif

H2RAM_STORAGE uint8_t h2ram_pool[MAX(H2RAM_ACPI_SHM_MAX, H2RAM_EC_HOST_CMD_MAX)]
	__attribute__((section(".h2ram_pool")));

#define H2RAM_WINDOW_SIZE(ram_size) ((find_msb_set((ram_size) / 16) - 1) & 0x7)

static const struct ec2i_t smfi_settings[] = {
	/* Select logical device 0Fh(SMFI) */
	{HOST_INDEX_LDN, LDN_SMFI},
	/* Internal RAM base address on eSPI I/O space */
	{HOST_INDEX_DSLDC6, 0x00},
	/* Enable H2RAM eSPI I/O cycle */
	{HOST_INDEX_DSLDC7, 0x01},
	/* Enable logical device */
	{HOST_INDEX_LDA, 0x01},
};

static void smfi_it8xxx2_init(const struct device *dev)
{
	const struct espi_it8xxx2_config *const config = dev->config;
	struct smfi_ite_ec_regs *const smfi_reg = (struct smfi_ite_ec_regs *)config->base_smfi;

#ifdef CONFIG_SOC_SERIES_IT8XXX2
	struct gctrl_ite_ec_regs *const gctrl = ESPI_ITE_GET_GCTRL_BASE;
	uint8_t h2ram_offset;

	/* Set the host to RAM cycle address offset */
	h2ram_offset = ((uint32_t)h2ram_pool & IT8XXX2_ESPI_H2RAM_BASEADDR_MASK) /
		       IT8XXX2_ESPI_H2RAM_POOL_SIZE_MAX;
	gctrl->GCTRL_H2ROFSR =
		(gctrl->GCTRL_H2ROFSR & ~IT8XXX2_ESPI_H2RAM_OFFSET_MASK) |
		h2ram_offset;
#endif

#ifdef CONFIG_ESPI_PERIPHERAL_EC_HOST_CMD
	memset(&h2ram_pool[CONFIG_ESPI_PERIPHERAL_HOST_CMD_PARAM_PORT_NUM], 0,
			CONFIG_ESPI_IT8XXX2_HC_H2RAM_SIZE);
	/* Set host RAM window 0 base address */
	smfi_reg->SMFI_HRAMW0BA =
		(CONFIG_ESPI_PERIPHERAL_HOST_CMD_PARAM_PORT_NUM >> 4) & 0xff;
	/* Set host RAM window 0 size. (allow R/W) */
	smfi_reg->SMFI_HRAMW0AAS =
		H2RAM_WINDOW_SIZE(CONFIG_ESPI_IT8XXX2_HC_H2RAM_SIZE);
	/* Enable window 0, H2RAM through IO cycle */
	smfi_reg->SMFI_HRAMWC |= (SMFI_H2RAMPS | SMFI_H2RAMW0E);
#endif

#ifdef CONFIG_ESPI_PERIPHERAL_ACPI_SHM_REGION
	memset(&h2ram_pool[CONFIG_ESPI_PERIPHERAL_ACPI_SHM_REGION_PORT_NUM], 0,
			CONFIG_ESPI_IT8XXX2_ACPI_SHM_H2RAM_SIZE);
	/* Set host RAM window 1 base address */
	smfi_reg->SMFI_HRAMW1BA =
		(CONFIG_ESPI_PERIPHERAL_ACPI_SHM_REGION_PORT_NUM >> 4) & 0xff;
	/* Set host RAM window 1 size. (read-only) */
	smfi_reg->SMFI_HRAMW1AAS =
		H2RAM_WINDOW_SIZE(CONFIG_ESPI_IT8XXX2_ACPI_SHM_H2RAM_SIZE) |
		SMFI_HRAMWXWPE_ALL;
	/* Enable window 1, H2RAM through IO cycle */
	smfi_reg->SMFI_HRAMWC |= (SMFI_H2RAMPS | SMFI_H2RAMW1E);
#endif
}
#endif /* CONFIG_ESPI_PERIPHERAL_EC_HOST_CMD ||
	* CONFIG_ESPI_PERIPHERAL_ACPI_SHM_REGION
	*/

static void ec2i_it8xxx2_wait_status_cleared(const struct device *dev,
						uint8_t mask)
{
	const struct espi_it8xxx2_config *const config = dev->config;
	struct ec2i_regs *const ec2i = (struct ec2i_regs *)config->base_ec2i;

	while (ec2i->IBCTL & mask) {
		;
	}
}

static void ec2i_it8xxx2_write_pnpcfg(const struct device *dev,
					enum ec2i_access sel, uint8_t data)
{
	const struct espi_it8xxx2_config *const config = dev->config;
	struct ec2i_regs *const ec2i = (struct ec2i_regs *)config->base_ec2i;

	/* bit0: EC to I-Bus access enabled. */
	ec2i->IBCTL |= EC2I_IBCTL_CSAE;
	/*
	 * Wait that both CRIB and CWIB bits in IBCTL register
	 * are cleared.
	 */
	ec2i_it8xxx2_wait_status_cleared(dev, EC2I_IBCTL_CRWIB);
	/* Enable EC access to the PNPCFG registers */
	ec2i->IBMAE |= EC2I_IBMAE_CFGAE;
	/* Set indirect host I/O offset. */
	ec2i->IHIOA = sel;
	/* Write the data to IHD register */
	ec2i->IHD = data;
	/* Wait the CWIB bit in IBCTL cleared. */
	ec2i_it8xxx2_wait_status_cleared(dev, EC2I_IBCTL_CWIB);
	/* Disable EC access to the PNPCFG registers. */
	ec2i->IBMAE &= ~EC2I_IBMAE_CFGAE;
	/* Disable EC to I-Bus access. */
	ec2i->IBCTL &= ~EC2I_IBCTL_CSAE;
}

static void ec2i_it8xxx2_write(const struct device *dev,
				enum host_pnpcfg_index index, uint8_t data)
{
	/* Set index */
	ec2i_it8xxx2_write_pnpcfg(dev, EC2I_ACCESS_INDEX, index);
	/* Set data */
	ec2i_it8xxx2_write_pnpcfg(dev, EC2I_ACCESS_DATA, data);
}

static void pnpcfg_it8xxx2_configure(const struct device *dev,
					const struct ec2i_t *settings,
					size_t entries)
{
	for (size_t i = 0; i < entries; i++) {
		ec2i_it8xxx2_write(dev, settings[i].index_port,
					settings[i].data_port);
	}
}

#define PNPCFG(_s)						\
	pnpcfg_it8xxx2_configure(dev, _s##_settings, ARRAY_SIZE(_s##_settings))
extern uint8_t _h2ram_pool_start[];

static void pnpcfg_it8xxx2_init(const struct device *dev)
{
	const struct espi_it8xxx2_config *const config = dev->config;
	struct ec2i_regs *const ec2i = (struct ec2i_regs *)config->base_ec2i;
	struct gctrl_ite_ec_regs *const gctrl = ESPI_ITE_GET_GCTRL_BASE;

	/* The register pair to access PNPCFG is 004Eh and 004Fh */
	gctrl->GCTRL_BADRSEL = 0x1;
	/* Host access is disabled */
	ec2i->LSIOHA |= 0x3;
	/* configure pnpcfg devices */
	if (IS_ENABLED(CONFIG_ESPI_PERIPHERAL_8042_KBC)) {
		PNPCFG(kbc);
	}
	if (IS_ENABLED(CONFIG_ESPI_PERIPHERAL_HOST_IO)) {
		PNPCFG(pmc1);
	}
#ifdef CONFIG_ESPI_PERIPHERAL_EC_HOST_CMD
	PNPCFG(pmc2);
#endif
#ifdef CONFIG_ESPI_PERIPHERAL_HOST_IO_PVT
	PNPCFG(pmc3);
#endif
#ifdef CONFIG_ESPI_PERIPHERAL_HOST_IO_PVT2
	PNPCFG(pmc4);
#endif
#ifdef CONFIG_ESPI_PERIPHERAL_HOST_IO_PVT3
	PNPCFG(pmc5);
#endif
#if defined(CONFIG_ESPI_PERIPHERAL_EC_HOST_CMD) || \
	defined(CONFIG_ESPI_PERIPHERAL_ACPI_SHM_REGION)
	PNPCFG(smfi);

#ifdef CONFIG_SOC_SERIES_IT51XXX
	uint8_t h2ram_pool_idx;

	h2ram_pool_idx = ((uint32_t)_h2ram_pool_start & IT8XXX2_ESPI_H2RAM_BASEADDR_MASK) /
			 IT8XXX2_ESPI_H2RAM_POOL_SIZE_MAX;
	/* H2RAM 4K page select */
	ec2i_it8xxx2_write(dev, HOST_INDEX_DSLDC13, h2ram_pool_idx);
#endif
#endif
}

/* KBC (port 60h/64h) */
#ifdef CONFIG_ESPI_PERIPHERAL_8042_KBC
static void kbc_it8xxx2_ibf_isr(const struct device *dev)
{
	const struct espi_it8xxx2_config *const config = dev->config;
	struct espi_it8xxx2_data *const data = dev->data;
	struct kbc_regs *const kbc_reg = (struct kbc_regs *)config->base_kbc;
	struct espi_event evt = {
		ESPI_BUS_PERIPHERAL_NOTIFICATION,
		ESPI_PERIPHERAL_8042_KBC,
		ESPI_PERIPHERAL_NODATA
	};
	struct espi_evt_data_kbc *kbc_evt =
			(struct espi_evt_data_kbc *)&evt.evt_data;

	/* KBC Input Buffer Full event */
	kbc_evt->evt = HOST_KBC_EVT_IBF;
	/*
	 * Indicates if the host sent a command or data.
	 * 0 = data
	 * 1 = Command.
	 */
	kbc_evt->type = !!(kbc_reg->KBHISR & KBC_KBHISR_A2_ADDR);
	/* The data in KBC Input Buffer */
	kbc_evt->data = kbc_reg->KBHIDIR;

	espi_send_callbacks(&data->callbacks, dev, evt);
}

static void kbc_it8xxx2_obe_isr(const struct device *dev)
{
	const struct espi_it8xxx2_config *const config = dev->config;
	struct espi_it8xxx2_data *const data = dev->data;
	struct kbc_regs *const kbc_reg = (struct kbc_regs *)config->base_kbc;
	struct espi_event evt = {
		ESPI_BUS_PERIPHERAL_NOTIFICATION,
		ESPI_PERIPHERAL_8042_KBC,
		ESPI_PERIPHERAL_NODATA
	};
	struct espi_evt_data_kbc *kbc_evt =
				(struct espi_evt_data_kbc *)&evt.evt_data;

	/* Disable KBC OBE interrupt first */
	kbc_reg->KBHICR &= ~KBC_KBHICR_OBECIE;

	/* Notify application that host already read out data. */
	kbc_evt->evt = HOST_KBC_EVT_OBE;
	kbc_evt->data = 0;
	kbc_evt->type = 0;
	espi_send_callbacks(&data->callbacks, dev, evt);
}

static void kbc_it8xxx2_init(const struct device *dev)
{
	const struct espi_it8xxx2_config *const config = dev->config;
	struct kbc_regs *const kbc_reg = (struct kbc_regs *)config->base_kbc;

	/* Disable KBC serirq IRQ */
	kbc_reg->KBIRQR = 0;

	/*
	 * bit3: Input Buffer Full CPU Interrupt Enable.
	 * bit1: Enable the interrupt to mouse driver in the host processor via
	 *       SERIRQ when the output buffer is full.
	 * bit0: Enable the interrupt to keyboard driver in the host processor
	 *       via SERIRQ when the output buffer is full
	 */
	kbc_reg->KBHICR |=
		(KBC_KBHICR_IBFCIE | KBC_KBHICR_OBFKIE | KBC_KBHICR_OBFMIE);

	/* Input Buffer Full CPU Interrupt Enable. */
	IRQ_CONNECT(IT8XXX2_KBC_IBF_IRQ, 0, kbc_it8xxx2_ibf_isr,
			DEVICE_DT_INST_GET(0), 0);
	irq_enable(IT8XXX2_KBC_IBF_IRQ);

	/* Output Buffer Empty CPU Interrupt Enable */
	IRQ_CONNECT(IT8XXX2_KBC_OBE_IRQ, 0, kbc_it8xxx2_obe_isr,
			DEVICE_DT_INST_GET(0), 0);
	irq_enable(IT8XXX2_KBC_OBE_IRQ);
}
#endif

/* PMC 1 (APCI port 62h/66h) */
#ifdef CONFIG_ESPI_PERIPHERAL_HOST_IO
static void pmc1_it8xxx2_ibf_isr(const struct device *dev)
{
	const struct espi_it8xxx2_config *const config = dev->config;
	struct espi_it8xxx2_data *const data = dev->data;
	struct pmc_regs *const pmc_reg = (struct pmc_regs *)config->base_pmc;
	struct espi_event evt = {
		ESPI_BUS_PERIPHERAL_NOTIFICATION,
		ESPI_PERIPHERAL_HOST_IO,
		ESPI_PERIPHERAL_NODATA
	};
	struct espi_evt_data_acpi *acpi_evt =
				(struct espi_evt_data_acpi *)&evt.evt_data;

	/*
	 * Indicates if the host sent a command or data.
	 * 0 = data
	 * 1 = Command.
	 */
	acpi_evt->type = !!(pmc_reg->PM1STS & PMC_PM1STS_A2_ADDR);
	/* Set processing flag before reading command byte */
	pmc_reg->PM1STS |= PMC_PM1STS_GPF;
	acpi_evt->data = pmc_reg->PM1DI;

	espi_send_callbacks(&data->callbacks, dev, evt);
}

static void pmc1_it8xxx2_init(const struct device *dev)
{
	const struct espi_it8xxx2_config *const config = dev->config;
	struct pmc_regs *const pmc_reg = (struct pmc_regs *)config->base_pmc;

	/* Enable pmc1 input buffer full interrupt */
	pmc_reg->PM1CTL |= PMC_PM1CTL_IBFIE;
	IRQ_CONNECT(IT8XXX2_PMC1_IBF_IRQ, 0, pmc1_it8xxx2_ibf_isr,
			DEVICE_DT_INST_GET(0), 0);
	if (!IS_ENABLED(CONFIG_ESPI_PERIPHERAL_CUSTOM_OPCODE)) {
		irq_enable(IT8XXX2_PMC1_IBF_IRQ);
	}
}
#endif

/* Port 80 */
#ifdef CONFIG_ESPI_PERIPHERAL_DEBUG_PORT_80
static void port80_it8xxx2_isr(const struct device *dev)
{
	struct espi_it8xxx2_data *const data = dev->data;
	struct gctrl_ite_ec_regs *const gctrl = ESPI_ITE_GET_GCTRL_BASE;
	struct espi_event evt = {
		ESPI_BUS_PERIPHERAL_NOTIFICATION,
		(ESPI_PERIPHERAL_INDEX_0 << 16) | ESPI_PERIPHERAL_DEBUG_PORT80,
		ESPI_PERIPHERAL_NODATA
	};

	if (IS_ENABLED(CONFIG_ESPI_IT8XXX2_PORT_81_CYCLE)) {
		evt.evt_data = gctrl->GCTRL_P80HDR | (gctrl->GCTRL_P81HDR << 8);
	} else {
		evt.evt_data = gctrl->GCTRL_P80HDR;
	}
	/* Write 1 to clear this bit */
	gctrl->GCTRL_P80H81HSR |= BIT(0);

	espi_send_callbacks(&data->callbacks, dev, evt);
}

static void port80_it8xxx2_init(const struct device *dev)
{
	ARG_UNUSED(dev);
	struct gctrl_ite_ec_regs *const gctrl = ESPI_ITE_GET_GCTRL_BASE;

	/* Accept Port 80h (and 81h) Cycle */
	if (IS_ENABLED(CONFIG_ESPI_IT8XXX2_PORT_81_CYCLE)) {
		gctrl->GCTRL_SPCTRL1 |=
			(IT8XXX2_GCTRL_ACP80 | IT8XXX2_GCTRL_ACP81);
	} else {
		gctrl->GCTRL_SPCTRL1 |= IT8XXX2_GCTRL_ACP80;
	}
	IRQ_CONNECT(IT8XXX2_PORT_80_IRQ, 0, port80_it8xxx2_isr,
			DEVICE_DT_INST_GET(0), 0);
	irq_enable(IT8XXX2_PORT_80_IRQ);
}
#endif

#ifdef CONFIG_ESPI_PERIPHERAL_EC_HOST_CMD
/* PMC 2 (Host command port CONFIG_ESPI_PERIPHERAL_HOST_CMD_DATA_PORT_NUM) */
static void pmc2_it8xxx2_ibf_isr(const struct device *dev)
{
	const struct espi_it8xxx2_config *const config = dev->config;
	struct espi_it8xxx2_data *const data = dev->data;
	struct pmc_regs *const pmc_reg = (struct pmc_regs *)config->base_pmc;
	struct espi_event evt = {
		ESPI_BUS_PERIPHERAL_NOTIFICATION,
		ESPI_PERIPHERAL_EC_HOST_CMD,
		ESPI_PERIPHERAL_NODATA
	};

	/* Set processing flag before reading command byte */
	pmc_reg->PM2STS |= PMC_PM2STS_GPF;
	evt.evt_data = pmc_reg->PM2DI;

	espi_send_callbacks(&data->callbacks, dev, evt);
}

static void pmc2_it8xxx2_init(const struct device *dev)
{
	const struct espi_it8xxx2_config *const config = dev->config;
	struct pmc_regs *const pmc_reg = (struct pmc_regs *)config->base_pmc;

	/* Dedicated interrupt for PMC2 */
	pmc_reg->MBXCTRL |= PMC_MBXCTRL_DINT;
	/* Enable pmc2 input buffer full interrupt */
	pmc_reg->PM2CTL |= PMC_PM2CTL_IBFIE;
	IRQ_CONNECT(IT8XXX2_PMC2_IBF_IRQ, 0, pmc2_it8xxx2_ibf_isr,
			DEVICE_DT_INST_GET(0), 0);
	if (!IS_ENABLED(CONFIG_ESPI_PERIPHERAL_CUSTOM_OPCODE)) {
		irq_enable(IT8XXX2_PMC2_IBF_IRQ);
	}
}
#endif

#ifdef CONFIG_ESPI_PERIPHERAL_HOST_IO_PVT
/* PMC3 (Host private port) */
static void pmc3_it8xxx2_ibf_isr(const struct device *dev)
{
	const struct espi_it8xxx2_config *const config = dev->config;
	struct espi_it8xxx2_data *const data = dev->data;
	struct pmc_regs *const pmc_reg = (struct pmc_regs *)config->base_pmc;
	struct espi_event evt = {.evt_type = ESPI_BUS_PERIPHERAL_NOTIFICATION,
				 .evt_details = ESPI_PERIPHERAL_HOST_IO_PVT,
				 .evt_data = ESPI_PERIPHERAL_NODATA};
	struct espi_evt_data_pvt *pvt_evt = (struct espi_evt_data_pvt *)&evt.evt_data;

	/*
	 * Indicates if the host sent a command or data.
	 * 0 = data
	 * 1 = Command.
	 */
	pvt_evt->type = !!(pmc_reg->PM3STS & PMC_PM3STS_A2_ADDR);
	pvt_evt->data = pmc_reg->PM3DI;

	espi_send_callbacks(&data->callbacks, dev, evt);
}

static void pmc3_it8xxx2_init(const struct device *dev)
{
	const struct espi_it8xxx2_config *const config = dev->config;
	struct pmc_regs *const pmc_reg = (struct pmc_regs *)config->base_pmc;

	/* Enable pmc3 input buffer full interrupt */
	pmc_reg->PM3CTL |= PMC_PM3CTL_IBFIE;
	IRQ_CONNECT(IT8XXX2_PMC3_IBF_IRQ, 0, pmc3_it8xxx2_ibf_isr, DEVICE_DT_INST_GET(0), 0);
	irq_enable(IT8XXX2_PMC3_IBF_IRQ);
}
#endif

/* PMC4 (Host private port 2) */
#ifdef CONFIG_ESPI_PERIPHERAL_HOST_IO_PVT2
static void pmc4_it8xxx2_ibf_isr(const struct device *dev)
{
	const struct espi_it8xxx2_config *const config = dev->config;
	struct espi_it8xxx2_data *const data = dev->data;
	struct pmc_regs *const pmc_reg = (struct pmc_regs *)config->base_pmc;
	struct espi_event evt = {.evt_type = ESPI_BUS_PERIPHERAL_NOTIFICATION,
				 .evt_details = ESPI_PERIPHERAL_HOST_IO_PVT2,
				 .evt_data = ESPI_PERIPHERAL_NODATA};
	struct espi_evt_data_pvt *pvt_evt = (struct espi_evt_data_pvt *)&evt.evt_data;

	/*
	 * Indicates if the host sent a command or data.
	 * 0 = data
	 * 1 = Command.
	 */
	pvt_evt->type = !!(pmc_reg->PM4STS & PMC_PM4STS_A2_ADDR);
	pvt_evt->data = pmc_reg->PM4DI;

	espi_send_callbacks(&data->callbacks, dev, evt);
}

static void pmc4_it8xxx2_init(const struct device *dev)
{
	const struct espi_it8xxx2_config *const config = dev->config;
	struct pmc_regs *const pmc_reg = (struct pmc_regs *)config->base_pmc;

	/* Enable pmc4 input buffer full interrupt */
	pmc_reg->PM4CTL |= PMC_PM4CTL_IBFIE;
	IRQ_CONNECT(IT8XXX2_PMC4_IBF_IRQ, 0, pmc4_it8xxx2_ibf_isr, DEVICE_DT_INST_GET(0), 0);
	irq_enable(IT8XXX2_PMC4_IBF_IRQ);
}
#endif /* CONFIG_ESPI_PERIPHERAL_HOST_IO_PVT2 */

/* PMC5 (Host private port 3) */
#ifdef CONFIG_ESPI_PERIPHERAL_HOST_IO_PVT3
static void pmc5_it8xxx2_ibf_isr(const struct device *dev)
{
	const struct espi_it8xxx2_config *const config = dev->config;
	struct espi_it8xxx2_data *const data = dev->data;
	struct pmc_regs *const pmc_reg = (struct pmc_regs *)config->base_pmc;
	struct espi_event evt = {.evt_type = ESPI_BUS_PERIPHERAL_NOTIFICATION,
				 .evt_details = ESPI_PERIPHERAL_HOST_IO_PVT3,
				 .evt_data = ESPI_PERIPHERAL_NODATA};
	struct espi_evt_data_pvt *pvt_evt = (struct espi_evt_data_pvt *)&evt.evt_data;

	/*
	 * Indicates if the host sent a command or data.
	 * 0 = data
	 * 1 = Command.
	 */
	pvt_evt->type = !!(pmc_reg->PM5STS & PMC_PM5STS_A2_ADDR);
	pvt_evt->data = pmc_reg->PM5DI;

	espi_send_callbacks(&data->callbacks, dev, evt);
}

static void pmc5_it8xxx2_init(const struct device *dev)
{
	const struct espi_it8xxx2_config *const config = dev->config;
	struct pmc_regs *const pmc_reg = (struct pmc_regs *)config->base_pmc;

	/* Enable pmc5 input buffer full interrupt */
	pmc_reg->PM5CTL |= PMC_PM5CTL_IBFIE;
	IRQ_CONNECT(IT8XXX2_PMC5_IBF_IRQ, 0, pmc5_it8xxx2_ibf_isr, DEVICE_DT_INST_GET(0), 0);
	irq_enable(IT8XXX2_PMC5_IBF_IRQ);
}
#endif /* CONFIG_ESPI_PERIPHERAL_HOST_IO_PVT3 */

#define IT8XXX2_ESPI_VW_SEND_TIMEOUT_US (USEC_PER_MSEC * 10)

/* eSPI api functions */
#define VW_CHAN(signal, index, level, valid, reg) \
	[signal] = {.vw_index = index, .level_mask = level, \
			.valid_mask = valid, .vw_sent_reg = reg}

/* VW signals used in eSPI */
static const struct vw_channel_t vw_channel_list[] = {
	VW_CHAN(ESPI_VWIRE_SIGNAL_SLP_S3,        0x02, BIT(0), BIT(4), 0),
	VW_CHAN(ESPI_VWIRE_SIGNAL_SLP_S4,        0x02, BIT(1), BIT(5), 0),
	VW_CHAN(ESPI_VWIRE_SIGNAL_SLP_S5,        0x02, BIT(2), BIT(6), 0),
	VW_CHAN(ESPI_VWIRE_SIGNAL_OOB_RST_WARN,  0x03, BIT(2), BIT(6), 0),
	VW_CHAN(ESPI_VWIRE_SIGNAL_PLTRST,        0x03, BIT(1), BIT(5), 0),
	VW_CHAN(ESPI_VWIRE_SIGNAL_SUS_STAT,      0x03, BIT(0), BIT(4), 0),
	VW_CHAN(ESPI_VWIRE_SIGNAL_NMIOUT,        0x07, BIT(2), BIT(6), 0),
	VW_CHAN(ESPI_VWIRE_SIGNAL_SMIOUT,        0x07, BIT(1), BIT(5), 0),
	VW_CHAN(ESPI_VWIRE_SIGNAL_HOST_RST_WARN, 0x07, BIT(0), BIT(4), 0),
	VW_CHAN(ESPI_VWIRE_SIGNAL_SLP_A,         0x41, BIT(3), BIT(7), 0),
	VW_CHAN(ESPI_VWIRE_SIGNAL_SUS_PWRDN_ACK, 0x41, BIT(1), BIT(5), 0),
	VW_CHAN(ESPI_VWIRE_SIGNAL_SUS_WARN,      0x41, BIT(0), BIT(4), 0),
	VW_CHAN(ESPI_VWIRE_SIGNAL_SLP_WLAN,      0x42, BIT(1), BIT(5), 0),
	VW_CHAN(ESPI_VWIRE_SIGNAL_SLP_LAN,       0x42, BIT(0), BIT(4), 0),
	VW_CHAN(ESPI_VWIRE_SIGNAL_HOST_C10,      0x47, BIT(0), BIT(4), 0),
	VW_CHAN(ESPI_VWIRE_SIGNAL_DNX_WARN,      0x4a, BIT(1), BIT(5), 0),
	VW_CHAN(ESPI_VWIRE_SIGNAL_PME,           0x04, BIT(3), BIT(7), IT8XXX2_ESPI_VW_REC_VW4),
	VW_CHAN(ESPI_VWIRE_SIGNAL_WAKE,          0x04, BIT(2), BIT(6), IT8XXX2_ESPI_VW_REC_VW4),
	VW_CHAN(ESPI_VWIRE_SIGNAL_OOB_RST_ACK,   0x04, BIT(0), BIT(4), IT8XXX2_ESPI_VW_REC_VW4),
	VW_CHAN(ESPI_VWIRE_SIGNAL_TARGET_BOOT_STS,  0x05, BIT(3), BIT(7), IT8XXX2_ESPI_VW_REC_VW5),
	VW_CHAN(ESPI_VWIRE_SIGNAL_ERR_NON_FATAL, 0x05, BIT(2), BIT(6), IT8XXX2_ESPI_VW_REC_VW5),
	VW_CHAN(ESPI_VWIRE_SIGNAL_ERR_FATAL,     0x05, BIT(1), BIT(5), IT8XXX2_ESPI_VW_REC_VW5),
	VW_CHAN(ESPI_VWIRE_SIGNAL_TARGET_BOOT_DONE, 0x05, BIT(0), BIT(4), IT8XXX2_ESPI_VW_REC_VW5),
	VW_CHAN(ESPI_VWIRE_SIGNAL_HOST_RST_ACK,  0x06, BIT(3), BIT(7), IT8XXX2_ESPI_VW_REC_VW6),
	VW_CHAN(ESPI_VWIRE_SIGNAL_RST_CPU_INIT,  0x06, BIT(2), BIT(6), IT8XXX2_ESPI_VW_REC_VW6),
	VW_CHAN(ESPI_VWIRE_SIGNAL_SMI,           0x06, BIT(1), BIT(5), IT8XXX2_ESPI_VW_REC_VW6),
	VW_CHAN(ESPI_VWIRE_SIGNAL_SCI,           0x06, BIT(0), BIT(4), IT8XXX2_ESPI_VW_REC_VW6),
	VW_CHAN(ESPI_VWIRE_SIGNAL_DNX_ACK,       0x40, BIT(1), BIT(5), IT8XXX2_ESPI_VW_REC_VW40),
	VW_CHAN(ESPI_VWIRE_SIGNAL_SUS_ACK,       0x40, BIT(0), BIT(4), IT8XXX2_ESPI_VW_REC_VW40),
};

static int espi_it8xxx2_configure(const struct device *dev,
					struct espi_cfg *cfg)
{
	const struct espi_it8xxx2_config *const config = dev->config;
	struct espi_slave_regs *const slave_reg =
		(struct espi_slave_regs *)config->base_espi_slave;
	uint8_t capcfg1 = 0;

	/* Set frequency */
	switch (cfg->max_freq) {
	case 20:
		capcfg1 = IT8XXX2_ESPI_CAPCFG1_MAX_FREQ_20;
		break;
	case 25:
		capcfg1 = IT8XXX2_ESPI_CAPCFG1_MAX_FREQ_25;
		break;
	case 33:
		capcfg1 = IT8XXX2_ESPI_CAPCFG1_MAX_FREQ_33;
		break;
	case 50:
		capcfg1 = IT8XXX2_ESPI_CAPCFG1_MAX_FREQ_50;
		break;
	case 66:
		capcfg1 = IT8XXX2_ESPI_CAPCFG1_MAX_FREQ_66;
		break;
	default:
		return -EINVAL;
	}
	slave_reg->GCAPCFG1 =
		(slave_reg->GCAPCFG1 & ~IT8XXX2_ESPI_MAX_FREQ_MASK) | capcfg1;

	/*
	 * Configure eSPI I/O mode. (Register read only)
	 * Supported I/O mode : single, dual and quad.
	 */

	/* Configure eSPI supported channels. (Register read only)
	 * Supported channels: peripheral, virtual wire, OOB, and flash access.
	 */

	return 0;
}

static bool espi_it8xxx2_channel_ready(const struct device *dev,
					enum espi_channel ch)
{
	const struct espi_it8xxx2_config *const config = dev->config;
	struct espi_slave_regs *const slave_reg =
		(struct espi_slave_regs *)config->base_espi_slave;
	bool sts = false;

	switch (ch) {
	case ESPI_CHANNEL_PERIPHERAL:
		sts = slave_reg->CH_PC_CAPCFG3 & IT8XXX2_ESPI_PC_READY_MASK;
		break;
	case ESPI_CHANNEL_VWIRE:
		sts = slave_reg->CH_VW_CAPCFG3 & IT8XXX2_ESPI_VW_READY_MASK;
		break;
	case ESPI_CHANNEL_OOB:
		sts = slave_reg->CH_OOB_CAPCFG3 & IT8XXX2_ESPI_OOB_READY_MASK;
		break;
	case ESPI_CHANNEL_FLASH:
		sts = slave_reg->CH_FLASH_CAPCFG3 & IT8XXX2_ESPI_FC_READY_MASK;
		break;
	default:
		break;
	}

	return sts;
}

static int espi_it8xxx2_send_vwire(const struct device *dev,
			enum espi_vwire_signal signal, uint8_t level)
{
	const struct espi_it8xxx2_config *const config = dev->config;
	struct espi_vw_regs *const vw_reg =
		(struct espi_vw_regs *)config->base_espi_vw;
	uint8_t vw_index = vw_channel_list[signal].vw_index;
	uint8_t level_mask = vw_channel_list[signal].level_mask;
	uint8_t valid_mask = vw_channel_list[signal].valid_mask;
	uint8_t vw_sent = vw_channel_list[signal].vw_sent_reg;

	if (signal > ARRAY_SIZE(vw_channel_list)) {
		return -EIO;
	}

	if (level) {
		vw_reg->VW_INDEX[vw_index] |= level_mask;
	} else {
		vw_reg->VW_INDEX[vw_index] &= ~level_mask;
	}

	vw_reg->VW_INDEX[vw_index] |= valid_mask;

	if (espi_it8xxx2_channel_ready(dev, ESPI_CHANNEL_VWIRE) && vw_sent) {
		if (!WAIT_FOR(vw_reg->VW_INDEX[vw_index] ==
			sys_read8(config->base_espi_vw + vw_sent),
			IT8XXX2_ESPI_VW_SEND_TIMEOUT_US, k_busy_wait(10))) {
			LOG_WRN("VW send to host has timed out vw[0x%x] = 0x%x",
			vw_index, vw_reg->VW_INDEX[vw_index]);
			return -ETIMEDOUT;
		}
	}

	return 0;
}

static int espi_it8xxx2_receive_vwire(const struct device *dev,
				  enum espi_vwire_signal signal, uint8_t *level)
{
	const struct espi_it8xxx2_config *const config = dev->config;
	struct espi_vw_regs *const vw_reg =
		(struct espi_vw_regs *)config->base_espi_vw;
	uint8_t vw_index = vw_channel_list[signal].vw_index;
	uint8_t level_mask = vw_channel_list[signal].level_mask;
	uint8_t valid_mask = vw_channel_list[signal].valid_mask;

	if (signal > ARRAY_SIZE(vw_channel_list)) {
		return -EIO;
	}

	if (IS_ENABLED(CONFIG_ESPI_VWIRE_VALID_BIT_CHECK)) {
		if (vw_reg->VW_INDEX[vw_index] & valid_mask) {
			*level = !!(vw_reg->VW_INDEX[vw_index] & level_mask);
		} else {
			/* Not valid */
			*level = 0;
		}
	} else {
		*level = !!(vw_reg->VW_INDEX[vw_index] & level_mask);
	}

	return 0;
}

#ifdef CONFIG_ESPI_PERIPHERAL_CUSTOM_OPCODE
static void host_custom_opcode_enable_interrupts(void)
{
	if (IS_ENABLED(CONFIG_ESPI_PERIPHERAL_HOST_IO)) {
		irq_enable(IT8XXX2_PMC1_IBF_IRQ);
	}
	if (IS_ENABLED(CONFIG_ESPI_PERIPHERAL_EC_HOST_CMD)) {
		irq_enable(IT8XXX2_PMC2_IBF_IRQ);
	}
}

static void host_custom_opcode_disable_interrupts(void)
{
	if (IS_ENABLED(CONFIG_ESPI_PERIPHERAL_HOST_IO)) {
		irq_disable(IT8XXX2_PMC1_IBF_IRQ);
	}
	if (IS_ENABLED(CONFIG_ESPI_PERIPHERAL_EC_HOST_CMD)) {
		irq_disable(IT8XXX2_PMC2_IBF_IRQ);
	}
}
#endif /* CONFIG_ESPI_PERIPHERAL_CUSTOM_OPCODE */

static int espi_it8xxx2_manage_callback(const struct device *dev,
				    struct espi_callback *callback, bool set)
{
	struct espi_it8xxx2_data *const data = dev->data;

	return espi_manage_callback(&data->callbacks, callback, set);
}

static int espi_it8xxx2_read_lpc_request(const struct device *dev,
				     enum lpc_peripheral_opcode op,
				     uint32_t *data)
{
	const struct espi_it8xxx2_config *const config = dev->config;

	if (op >= E8042_START_OPCODE && op <= E8042_MAX_OPCODE) {
		struct kbc_regs *const kbc_reg =
			(struct kbc_regs *)config->base_kbc;

		switch (op) {
		case E8042_OBF_HAS_CHAR:
			/* EC has written data back to host. OBF is
			 * automatically cleared after host reads
			 * the data
			 */
			*data = !!(kbc_reg->KBHISR & KBC_KBHISR_OBF);
			break;
		case E8042_IBF_HAS_CHAR:
			*data = !!(kbc_reg->KBHISR & KBC_KBHISR_IBF);
			break;
		case E8042_READ_KB_STS:
			*data = kbc_reg->KBHISR;
			break;
		default:
			return -EINVAL;
		}
	} else if (op >= EACPI_START_OPCODE && op <= EACPI_MAX_OPCODE) {
		struct pmc_regs *const pmc_reg =
			(struct pmc_regs *)config->base_pmc;

		switch (op) {
		case EACPI_OBF_HAS_CHAR:
			/* EC has written data back to host. OBF is
			 * automatically cleared after host reads
			 * the data
			 */
			*data = !!(pmc_reg->PM1STS & PMC_PM1STS_OBF);
			break;
		case EACPI_IBF_HAS_CHAR:
			*data = !!(pmc_reg->PM1STS & PMC_PM1STS_IBF);
			break;
		case EACPI_READ_STS:
			*data = pmc_reg->PM1STS;
			break;
#ifdef CONFIG_ESPI_PERIPHERAL_ACPI_SHM_REGION
		case EACPI_GET_SHARED_MEMORY:
			*data = (uint32_t)&h2ram_pool[
			CONFIG_ESPI_PERIPHERAL_ACPI_SHM_REGION_PORT_NUM];
			break;
#endif /* CONFIG_ESPI_PERIPHERAL_ACPI_SHM_REGION */
		default:
			return -EINVAL;
		}
	}
#ifdef CONFIG_ESPI_PERIPHERAL_CUSTOM_OPCODE
	else if (op >= ECUSTOM_START_OPCODE && op <= ECUSTOM_MAX_OPCODE) {

		switch (op) {
		case ECUSTOM_HOST_CMD_GET_PARAM_MEMORY:
			*data = (uint32_t)&h2ram_pool[
				CONFIG_ESPI_PERIPHERAL_HOST_CMD_PARAM_PORT_NUM];
			break;
		case ECUSTOM_HOST_CMD_GET_PARAM_MEMORY_SIZE:
			*data = CONFIG_ESPI_IT8XXX2_HC_H2RAM_SIZE;
			break;
		default:
			return -EINVAL;
		}
	}
#endif /* CONFIG_ESPI_PERIPHERAL_CUSTOM_OPCODE */
	else {
		return -ENOTSUP;
	}

	return 0;
}

static int espi_it8xxx2_write_lpc_request(const struct device *dev,
				      enum lpc_peripheral_opcode op,
				      uint32_t *data)
{
	const struct espi_it8xxx2_config *const config = dev->config;

	if (op >= E8042_START_OPCODE && op <= E8042_MAX_OPCODE) {
		struct kbc_regs *const kbc_reg =
			(struct kbc_regs *)config->base_kbc;

		switch (op) {
		case E8042_WRITE_KB_CHAR:
			kbc_reg->KBHIKDOR = (*data & 0xff);
			/*
			 * Enable OBE interrupt after putting data in
			 * data register.
			 */
			kbc_reg->KBHICR |= KBC_KBHICR_OBECIE;
			break;
		case E8042_WRITE_MB_CHAR:
			kbc_reg->KBHIMDOR = (*data & 0xff);
			/*
			 * Enable OBE interrupt after putting data in
			 * data register.
			 */
			kbc_reg->KBHICR |= KBC_KBHICR_OBECIE;
			break;
		case E8042_RESUME_IRQ:
			/* Enable KBC IBF interrupt */
			irq_enable(IT8XXX2_KBC_IBF_IRQ);
			break;
		case E8042_PAUSE_IRQ:
			/* Disable KBC IBF interrupt */
			irq_disable(IT8XXX2_KBC_IBF_IRQ);
			break;
		case E8042_CLEAR_OBF:
			volatile uint8_t _kbhicr __unused;
			/*
			 * After enabling IBF/OBF clear mode, we have to make
			 * sure that IBF interrupt is not triggered before
			 * disabling the clear mode. Or the interrupt will keep
			 * triggering until the watchdog is reset.
			 */
			unsigned int key = irq_lock();
			/*
			 * When IBFOBFCME is enabled, write 1 to COBF bit to
			 * clear KBC OBF.
			 */
			kbc_reg->KBHICR |= KBC_KBHICR_IBFOBFCME;
			kbc_reg->KBHICR |= KBC_KBHICR_COBF;
			kbc_reg->KBHICR &= ~KBC_KBHICR_COBF;
			/* Disable clear mode */
			kbc_reg->KBHICR &= ~KBC_KBHICR_IBFOBFCME;
			/*
			 * I/O access synchronization, this load operation will
			 * guarantee the above modification of SOC's register
			 * can be seen by any following instructions.
			 */
			_kbhicr = kbc_reg->KBHICR;
			irq_unlock(key);
			break;
		case E8042_SET_FLAG:
			kbc_reg->KBHISR |= (*data & 0xff);
			break;
		case E8042_CLEAR_FLAG:
			kbc_reg->KBHISR &= ~(*data & 0xff);
			break;
		default:
			return -EINVAL;
		}
	} else if (op >= EACPI_START_OPCODE && op <= EACPI_MAX_OPCODE) {
		struct pmc_regs *const pmc_reg =
			(struct pmc_regs *)config->base_pmc;

		switch (op) {
		case EACPI_WRITE_CHAR:
			pmc_reg->PM1DO = (*data & 0xff);
			break;
		case EACPI_WRITE_STS:
			pmc_reg->PM1STS = (*data & 0xff);
			break;
		default:
			return -EINVAL;
		}
	}
#ifdef CONFIG_ESPI_PERIPHERAL_CUSTOM_OPCODE
	else if (op >= ECUSTOM_START_OPCODE && op <= ECUSTOM_MAX_OPCODE) {
		struct pmc_regs *const pmc_reg =
			(struct pmc_regs *)config->base_pmc;

		switch (op) {
		/* Enable/Disable PMCx interrupt */
		case ECUSTOM_HOST_SUBS_INTERRUPT_EN:
			if (*data) {
				host_custom_opcode_enable_interrupts();
			} else {
				host_custom_opcode_disable_interrupts();
			}
			break;
		case ECUSTOM_HOST_CMD_SEND_RESULT:
			/* Write result to data output port (set OBF status) */
			pmc_reg->PM2DO = (*data & 0xff);
			/* Clear processing flag */
			pmc_reg->PM2STS &= ~PMC_PM2STS_GPF;
			break;
		default:
			return -EINVAL;
		}
	}
#endif /* CONFIG_ESPI_PERIPHERAL_CUSTOM_OPCODE */
	else {
		return -ENOTSUP;
	}

	return 0;
}

#ifdef CONFIG_ESPI_OOB_CHANNEL
/* eSPI cycle type field */
#define ESPI_OOB_CYCLE_TYPE          0x21
#define ESPI_OOB_TAG                 0x00
#define ESPI_OOB_TIMEOUT_MS          200

/* eSPI tag + len[11:8] field */
#define ESPI_TAG_LEN_FIELD(tag, len) \
		   ((((tag) & 0xF) << 4) | (((len) >> 8) & 0xF))

struct espi_oob_msg_packet {
	FLEXIBLE_ARRAY_DECLARE(uint8_t, data_byte);
};

static int espi_it8xxx2_send_oob(const struct device *dev,
				struct espi_oob_packet *pckt)
{
	const struct espi_it8xxx2_config *const config = dev->config;
	struct espi_slave_regs *const slave_reg =
		(struct espi_slave_regs *)config->base_espi_slave;
	struct espi_queue1_regs *const queue1_reg =
		(struct espi_queue1_regs *)config->base_espi_queue1;
	struct espi_oob_msg_packet *oob_pckt =
		(struct espi_oob_msg_packet *)pckt->buf;

	if (!(slave_reg->CH_OOB_CAPCFG3 & IT8XXX2_ESPI_OOB_READY_MASK)) {
		LOG_ERR("%s: OOB channel isn't ready", __func__);
		return -EIO;
	}

	if (slave_reg->ESUCTRL0 & IT8XXX2_ESPI_UPSTREAM_BUSY) {
		LOG_ERR("%s: OOB upstream busy", __func__);
		return -EIO;
	}

	if (pckt->len > ESPI_IT8XXX2_OOB_MAX_PAYLOAD_SIZE) {
		LOG_ERR("%s: Out of OOB queue space", __func__);
		return -EINVAL;
	}

	/* Set cycle type */
	slave_reg->ESUCTRL1 = IT8XXX2_ESPI_CYCLE_TYPE_OOB;
	/* Set tag and length[11:8] */
	slave_reg->ESUCTRL2 = ESPI_TAG_LEN_FIELD(0, pckt->len);
	/* Set length [7:0] */
	slave_reg->ESUCTRL3 = pckt->len & 0xff;

	/* Set data byte */
	for (int i = 0; i < pckt->len; i++) {
		queue1_reg->UPSTREAM_DATA[i] = oob_pckt->data_byte[i];
	}

	/* Set upstream enable */
	slave_reg->ESUCTRL0 |= IT8XXX2_ESPI_UPSTREAM_ENABLE;
	/* Set upstream go */
	slave_reg->ESUCTRL0 |= IT8XXX2_ESPI_UPSTREAM_GO;

	return 0;
}

static int espi_it8xxx2_receive_oob(const struct device *dev,
				struct espi_oob_packet *pckt)
{
	const struct espi_it8xxx2_config *const config = dev->config;
	struct espi_slave_regs *const slave_reg =
		(struct espi_slave_regs *)config->base_espi_slave;
	struct espi_queue0_regs *const queue0_reg =
		(struct espi_queue0_regs *)config->base_espi_queue0;
	struct espi_oob_msg_packet *oob_pckt =
		(struct espi_oob_msg_packet *)pckt->buf;
	uint8_t oob_len;

	if (!(slave_reg->CH_OOB_CAPCFG3 & IT8XXX2_ESPI_OOB_READY_MASK)) {
		LOG_ERR("%s: OOB channel isn't ready", __func__);
		return -EIO;
	}

#ifndef CONFIG_ESPI_OOB_CHANNEL_RX_ASYNC
	struct espi_it8xxx2_data *const data = dev->data;
	int ret;

	/* Wait until receive OOB message or timeout */
	ret = k_sem_take(&data->oob_upstream_go, K_MSEC(ESPI_OOB_TIMEOUT_MS));
	if (ret == -EAGAIN) {
		LOG_ERR("%s: Timeout", __func__);
		return -ETIMEDOUT;
	}
#endif

	/* Get length */
	oob_len = (slave_reg->ESOCTRL4 & IT8XXX2_ESPI_PUT_OOB_LEN_MASK);
	/*
	 * Buffer passed to driver isn't enough.
	 * The first three bytes of buffer are cycle type, tag, and length.
	 */
	if (oob_len > pckt->len) {
		LOG_ERR("%s: Out of rx buf %d vs %d", __func__,
			oob_len, pckt->len);
		return -EINVAL;
	}

	pckt->len = oob_len;
	/* Get data byte */
	for (int i = 0; i < oob_len; i++) {
		oob_pckt->data_byte[i] = queue0_reg->PUT_OOB_DATA[i];
	}

	return 0;
}

static void espi_it8xxx2_oob_init(const struct device *dev)
{
	const struct espi_it8xxx2_config *const config = dev->config;
	struct espi_slave_regs *const slave_reg =
		(struct espi_slave_regs *)config->base_espi_slave;

#ifndef CONFIG_ESPI_OOB_CHANNEL_RX_ASYNC
	struct espi_it8xxx2_data *const data = dev->data;

	k_sem_init(&data->oob_upstream_go, 0, 1);
#endif

	/* Upstream interrupt enable */
	slave_reg->ESUCTRL0 |= IT8XXX2_ESPI_UPSTREAM_INTERRUPT_ENABLE;

	/* PUT_OOB interrupt enable */
	slave_reg->ESOCTRL1 |= IT8XXX2_ESPI_PUT_OOB_INTERRUPT_ENABLE;
}
#endif

#ifdef CONFIG_ESPI_FLASH_CHANNEL
#define ESPI_FLASH_TAG                      0x01
#define ESPI_FLASH_READ_TIMEOUT_MS          200
#define ESPI_FLASH_WRITE_TIMEOUT_MS         500
#define ESPI_FLASH_ERASE_TIMEOUT_MS         1000

/* Successful completion without data */
#define ESPI_IT8XXX2_PUT_FLASH_C_SCWOD      0
/* Successful completion with data */
#define ESPI_IT8XXX2_PUT_FLASH_C_SCWD       4

enum espi_flash_cycle_type {
	IT8XXX2_ESPI_CYCLE_TYPE_FLASH_READ = 0x08,
	IT8XXX2_ESPI_CYCLE_TYPE_FLASH_WRITE = 0x09,
	IT8XXX2_ESPI_CYCLE_TYPE_FLASH_ERASE = 0x0A,
};

static int espi_it8xxx2_flash_trans(const struct device *dev,
				struct espi_flash_packet *pckt,
				enum espi_flash_cycle_type tran)
{
	const struct espi_it8xxx2_config *const config = dev->config;
	struct espi_slave_regs *const slave_reg =
		(struct espi_slave_regs *)config->base_espi_slave;
	struct espi_queue1_regs *const queue1_reg =
		(struct espi_queue1_regs *)config->base_espi_queue1;

	if (!(slave_reg->CH_FLASH_CAPCFG3 & IT8XXX2_ESPI_FC_READY_MASK)) {
		LOG_ERR("%s: Flash channel isn't ready (tran:%d)",
			__func__, tran);
		return -EIO;
	}

	if (slave_reg->ESUCTRL0 & IT8XXX2_ESPI_UPSTREAM_BUSY) {
		LOG_ERR("%s: Upstream busy (tran:%d)", __func__, tran);
		return -EIO;
	}

	if (pckt->len > IT8XXX2_ESPI_FLASH_MAX_PAYLOAD_SIZE) {
		LOG_ERR("%s: Invalid size request (tran:%d)", __func__, tran);
		return -EINVAL;
	}

	/* Set cycle type */
	slave_reg->ESUCTRL1 = tran;
	/* Set tag and length[11:8] */
	slave_reg->ESUCTRL2 = (ESPI_FLASH_TAG << 4);
	/*
	 * Set length [7:0]
	 * Note: for erasing, the least significant 3 bit of the length field
	 * specifies the size of the block to be erased:
	 * 001b: 4 Kbytes
	 * 010b: 64Kbytes
	 * 100b: 128 Kbytes
	 * 101b: 256 Kbytes
	 */
	slave_reg->ESUCTRL3 = pckt->len;
	/* Set flash address */
	queue1_reg->UPSTREAM_DATA[0] = (pckt->flash_addr >> 24) & 0xff;
	queue1_reg->UPSTREAM_DATA[1] = (pckt->flash_addr >> 16) & 0xff;
	queue1_reg->UPSTREAM_DATA[2] = (pckt->flash_addr >> 8) & 0xff;
	queue1_reg->UPSTREAM_DATA[3] = pckt->flash_addr & 0xff;

	return 0;
}

static int espi_it8xxx2_flash_read(const struct device *dev,
					struct espi_flash_packet *pckt)
{
	const struct espi_it8xxx2_config *const config = dev->config;
	struct espi_it8xxx2_data *const data = dev->data;
	struct espi_slave_regs *const slave_reg =
		(struct espi_slave_regs *)config->base_espi_slave;
	int ret;

	ret = espi_it8xxx2_flash_trans(dev, pckt,
					IT8XXX2_ESPI_CYCLE_TYPE_FLASH_READ);
	if (ret) {
		return ret;
	}

	/* Set upstream enable */
	slave_reg->ESUCTRL0 |= IT8XXX2_ESPI_UPSTREAM_ENABLE;
	/* Set upstream go */
	slave_reg->ESUCTRL0 |= IT8XXX2_ESPI_UPSTREAM_GO;

	/* Wait until upstream done or timeout */
	ret = k_sem_take(&data->flash_upstream_go,
			K_MSEC(ESPI_FLASH_READ_TIMEOUT_MS));
	if (ret == -EAGAIN) {
		LOG_ERR("%s: Timeout", __func__);
		return -ETIMEDOUT;
	}

	if (data->put_flash_cycle_type != ESPI_IT8XXX2_PUT_FLASH_C_SCWD) {
		LOG_ERR("%s: Unsuccessful completion", __func__);
		return -EIO;
	}

	memcpy(pckt->buf, data->flash_buf, pckt->len);

	LOG_INF("%s: read (%d) bytes from flash over espi", __func__,
		data->put_flash_len);

	return 0;
}

static int espi_it8xxx2_flash_write(const struct device *dev,
					struct espi_flash_packet *pckt)
{
	const struct espi_it8xxx2_config *const config = dev->config;
	struct espi_it8xxx2_data *const data = dev->data;
	struct espi_slave_regs *const slave_reg =
		(struct espi_slave_regs *)config->base_espi_slave;
	struct espi_queue1_regs *const queue1_reg =
		(struct espi_queue1_regs *)config->base_espi_queue1;
	int ret;

	ret = espi_it8xxx2_flash_trans(dev, pckt,
					IT8XXX2_ESPI_CYCLE_TYPE_FLASH_WRITE);
	if (ret) {
		return ret;
	}

	/* Set data byte */
	for (int i = 0; i < pckt->len; i++) {
		queue1_reg->UPSTREAM_DATA[4 + i] = pckt->buf[i];
	}

	/* Set upstream enable */
	slave_reg->ESUCTRL0 |= IT8XXX2_ESPI_UPSTREAM_ENABLE;
	/* Set upstream go */
	slave_reg->ESUCTRL0 |= IT8XXX2_ESPI_UPSTREAM_GO;

	/* Wait until upstream done or timeout */
	ret = k_sem_take(&data->flash_upstream_go,
			K_MSEC(ESPI_FLASH_WRITE_TIMEOUT_MS));
	if (ret == -EAGAIN) {
		LOG_ERR("%s: Timeout", __func__);
		return -ETIMEDOUT;
	}

	if (data->put_flash_cycle_type != ESPI_IT8XXX2_PUT_FLASH_C_SCWOD) {
		LOG_ERR("%s: Unsuccessful completion", __func__);
		return -EIO;
	}

	return 0;
}

static int espi_it8xxx2_flash_erase(const struct device *dev,
					struct espi_flash_packet *pckt)
{
	const struct espi_it8xxx2_config *const config = dev->config;
	struct espi_it8xxx2_data *const data = dev->data;
	struct espi_slave_regs *const slave_reg =
		(struct espi_slave_regs *)config->base_espi_slave;
	int ret;

	ret = espi_it8xxx2_flash_trans(dev, pckt,
					IT8XXX2_ESPI_CYCLE_TYPE_FLASH_ERASE);
	if (ret) {
		return ret;
	}

	/* Set upstream enable */
	slave_reg->ESUCTRL0 |= IT8XXX2_ESPI_UPSTREAM_ENABLE;
	/* Set upstream go */
	slave_reg->ESUCTRL0 |= IT8XXX2_ESPI_UPSTREAM_GO;

	/* Wait until upstream done or timeout */
	ret = k_sem_take(&data->flash_upstream_go,
			K_MSEC(ESPI_FLASH_ERASE_TIMEOUT_MS));
	if (ret == -EAGAIN) {
		LOG_ERR("%s: Timeout", __func__);
		return -ETIMEDOUT;
	}

	if (data->put_flash_cycle_type != ESPI_IT8XXX2_PUT_FLASH_C_SCWOD) {
		LOG_ERR("%s: Unsuccessful completion", __func__);
		return -EIO;
	}

	return 0;
}

static void espi_it8xxx2_flash_upstream_done_isr(const struct device *dev)
{
	const struct espi_it8xxx2_config *const config = dev->config;
	struct espi_it8xxx2_data *const data = dev->data;
	struct espi_slave_regs *const slave_reg =
		(struct espi_slave_regs *)config->base_espi_slave;
	struct espi_queue1_regs *const queue1_reg =
		(struct espi_queue1_regs *)config->base_espi_queue1;

	data->put_flash_cycle_type = slave_reg->ESUCTRL6;
	data->put_flash_tag = slave_reg->ESUCTRL7 &
				IT8XXX2_ESPI_PUT_FLASH_TAG_MASK;
	data->put_flash_len = slave_reg->ESUCTRL8 &
				IT8XXX2_ESPI_PUT_FLASH_LEN_MASK;

	if (slave_reg->ESUCTRL1 == IT8XXX2_ESPI_CYCLE_TYPE_FLASH_READ) {
		if (data->put_flash_len > IT8XXX2_ESPI_FLASH_MAX_PAYLOAD_SIZE) {
			LOG_ERR("%s: Invalid size (%d)", __func__,
							data->put_flash_len);
		} else {
			for (int i = 0; i < data->put_flash_len; i++) {
				data->flash_buf[i] =
					queue1_reg->UPSTREAM_DATA[i];
			}
		}
	}

	k_sem_give(&data->flash_upstream_go);
}

static void espi_it8xxx2_flash_init(const struct device *dev)
{
	const struct espi_it8xxx2_config *const config = dev->config;
	struct espi_it8xxx2_data *const data = dev->data;
	struct espi_slave_regs *const slave_reg =
		(struct espi_slave_regs *)config->base_espi_slave;

	k_sem_init(&data->flash_upstream_go, 0, 1);

	/* Upstream interrupt enable */
	slave_reg->ESUCTRL0 |= IT8XXX2_ESPI_UPSTREAM_INTERRUPT_ENABLE;
}
#endif /* CONFIG_ESPI_FLASH_CHANNEL */

/* eSPI driver registration */
static int espi_it8xxx2_init(const struct device *dev);

static DEVICE_API(espi, espi_it8xxx2_driver_api) = {
	.config = espi_it8xxx2_configure,
	.get_channel_status = espi_it8xxx2_channel_ready,
	.send_vwire = espi_it8xxx2_send_vwire,
	.receive_vwire = espi_it8xxx2_receive_vwire,
	.manage_callback = espi_it8xxx2_manage_callback,
	.read_lpc_request = espi_it8xxx2_read_lpc_request,
	.write_lpc_request = espi_it8xxx2_write_lpc_request,
#ifdef CONFIG_ESPI_OOB_CHANNEL
	.send_oob = espi_it8xxx2_send_oob,
	.receive_oob = espi_it8xxx2_receive_oob,
#endif
#ifdef CONFIG_ESPI_FLASH_CHANNEL
	.flash_read = espi_it8xxx2_flash_read,
	.flash_write = espi_it8xxx2_flash_write,
	.flash_erase = espi_it8xxx2_flash_erase,
#endif
};

static void espi_it8xxx2_vw_notify_system_state(const struct device *dev,
				enum espi_vwire_signal signal)
{
	struct espi_it8xxx2_data *const data = dev->data;
	struct espi_event evt = {ESPI_BUS_EVENT_VWIRE_RECEIVED, 0, 0};
	uint8_t level = 0;

	espi_it8xxx2_receive_vwire(dev, signal, &level);

	evt.evt_details = signal;
	evt.evt_data = level;
	espi_send_callbacks(&data->callbacks, dev, evt);
}

static void espi_vw_signal_no_isr(const struct device *dev)
{
	ARG_UNUSED(dev);
}

static const struct espi_vw_signal_t vwidx2_signals[] = {
	{ESPI_VWIRE_SIGNAL_SLP_S3, NULL},
	{ESPI_VWIRE_SIGNAL_SLP_S4, NULL},
	{ESPI_VWIRE_SIGNAL_SLP_S5, NULL},
};

static void espi_it8xxx2_vwidx2_isr(const struct device *dev,
					uint8_t updated_flag)
{
	for (int i = 0; i < ARRAY_SIZE(vwidx2_signals); i++) {
		enum espi_vwire_signal vw_signal = vwidx2_signals[i].signal;

		if (updated_flag & vw_channel_list[vw_signal].level_mask) {
			espi_it8xxx2_vw_notify_system_state(dev, vw_signal);
		}
	}
}

static void espi_vw_oob_rst_warn_isr(const struct device *dev)
{
	uint8_t level = 0;

	espi_it8xxx2_receive_vwire(dev, ESPI_VWIRE_SIGNAL_OOB_RST_WARN, &level);
	espi_it8xxx2_send_vwire(dev, ESPI_VWIRE_SIGNAL_OOB_RST_ACK, level);
}

static void espi_vw_pltrst_isr(const struct device *dev)
{
	uint8_t pltrst = 0;

	espi_it8xxx2_receive_vwire(dev, ESPI_VWIRE_SIGNAL_PLTRST, &pltrst);

	if (pltrst) {
		espi_it8xxx2_send_vwire(dev, ESPI_VWIRE_SIGNAL_SMI, 1);
		espi_it8xxx2_send_vwire(dev, ESPI_VWIRE_SIGNAL_SCI, 1);
		espi_it8xxx2_send_vwire(dev, ESPI_VWIRE_SIGNAL_HOST_RST_ACK, 1);
		espi_it8xxx2_send_vwire(dev, ESPI_VWIRE_SIGNAL_RST_CPU_INIT, 1);
	}

	LOG_INF("VW PLTRST_L %sasserted", pltrst ? "de" : "");
}

static const struct espi_vw_signal_t vwidx3_signals[] = {
	{ESPI_VWIRE_SIGNAL_OOB_RST_WARN, espi_vw_oob_rst_warn_isr},
	{ESPI_VWIRE_SIGNAL_PLTRST,       espi_vw_pltrst_isr},
};

static void espi_it8xxx2_vwidx3_isr(const struct device *dev,
					uint8_t updated_flag)
{
	for (int i = 0; i < ARRAY_SIZE(vwidx3_signals); i++) {
		enum espi_vwire_signal vw_signal = vwidx3_signals[i].signal;

		if (updated_flag & vw_channel_list[vw_signal].level_mask) {
			vwidx3_signals[i].vw_signal_isr(dev);
			espi_it8xxx2_vw_notify_system_state(dev, vw_signal);
		}
	}
}

static void espi_vw_host_rst_warn_isr(const struct device *dev)
{
	uint8_t level = 0;

	espi_it8xxx2_receive_vwire(dev,
		ESPI_VWIRE_SIGNAL_HOST_RST_WARN, &level);
	espi_it8xxx2_send_vwire(dev, ESPI_VWIRE_SIGNAL_HOST_RST_ACK, level);
}

static const struct espi_vw_signal_t vwidx7_signals[] = {
	{ESPI_VWIRE_SIGNAL_HOST_RST_WARN, espi_vw_host_rst_warn_isr},
};

static void espi_it8xxx2_vwidx7_isr(const struct device *dev,
					uint8_t updated_flag)
{
	for (int i = 0; i < ARRAY_SIZE(vwidx7_signals); i++) {
		enum espi_vwire_signal vw_signal = vwidx7_signals[i].signal;

		if (updated_flag & vw_channel_list[vw_signal].level_mask) {
			vwidx7_signals[i].vw_signal_isr(dev);
			espi_it8xxx2_vw_notify_system_state(dev, vw_signal);
		}
	}
}

static void espi_vw_sus_warn_isr(const struct device *dev)
{
	uint8_t level = 0;

	espi_it8xxx2_receive_vwire(dev, ESPI_VWIRE_SIGNAL_SUS_WARN, &level);
	espi_it8xxx2_send_vwire(dev, ESPI_VWIRE_SIGNAL_SUS_ACK, level);
}

static const struct espi_vw_signal_t vwidx41_signals[] = {
	{ESPI_VWIRE_SIGNAL_SUS_WARN,      espi_vw_sus_warn_isr},
	{ESPI_VWIRE_SIGNAL_SUS_PWRDN_ACK, espi_vw_signal_no_isr},
	{ESPI_VWIRE_SIGNAL_SLP_A,         espi_vw_signal_no_isr},
};

static void espi_it8xxx2_vwidx41_isr(const struct device *dev,
					uint8_t updated_flag)
{
	for (int i = 0; i < ARRAY_SIZE(vwidx41_signals); i++) {
		enum espi_vwire_signal vw_signal = vwidx41_signals[i].signal;

		if (updated_flag & vw_channel_list[vw_signal].level_mask) {
			vwidx41_signals[i].vw_signal_isr(dev);
			espi_it8xxx2_vw_notify_system_state(dev, vw_signal);
		}
	}
}

static const struct espi_vw_signal_t vwidx42_signals[] = {
	{ESPI_VWIRE_SIGNAL_SLP_LAN, NULL},
	{ESPI_VWIRE_SIGNAL_SLP_WLAN, NULL},
};

static void espi_it8xxx2_vwidx42_isr(const struct device *dev,
					uint8_t updated_flag)
{
	for (int i = 0; i < ARRAY_SIZE(vwidx42_signals); i++) {
		enum espi_vwire_signal vw_signal = vwidx42_signals[i].signal;

		if (updated_flag & vw_channel_list[vw_signal].level_mask) {
			espi_it8xxx2_vw_notify_system_state(dev, vw_signal);
		}
	}
}

static void espi_it8xxx2_vwidx43_isr(const struct device *dev,
					uint8_t updated_flag)
{
	ARG_UNUSED(dev);
	/*
	 * We haven't send callback to system because there is no index 43
	 * virtual wire signal is listed in enum espi_vwire_signal.
	 */
	LOG_INF("vw isr %s is ignored!", __func__);
}

static void espi_it8xxx2_vwidx44_isr(const struct device *dev,
					uint8_t updated_flag)
{
	ARG_UNUSED(dev);
	/*
	 * We haven't send callback to system because there is no index 44
	 * virtual wire signal is listed in enum espi_vwire_signal.
	 */
	LOG_INF("vw isr %s is ignored!", __func__);
}

static const struct espi_vw_signal_t vwidx47_signals[] = {
	{ESPI_VWIRE_SIGNAL_HOST_C10, NULL},
};
static void espi_it8xxx2_vwidx47_isr(const struct device *dev,
					uint8_t updated_flag)
{
	for (int i = 0; i < ARRAY_SIZE(vwidx47_signals); i++) {
		enum espi_vwire_signal vw_signal = vwidx47_signals[i].signal;

		if (updated_flag & vw_channel_list[vw_signal].level_mask) {
			espi_it8xxx2_vw_notify_system_state(dev, vw_signal);
		}
	}
}

/*
 * The ISR of espi VW interrupt in array needs to match bit order in
 * ESPI VW VWCTRL1 register.
 */
static const struct vwidx_isr_t vwidx_isr_list[] = {
	[0] = {espi_it8xxx2_vwidx2_isr,  0x02},
	[1] = {espi_it8xxx2_vwidx3_isr,  0x03},
	[2] = {espi_it8xxx2_vwidx7_isr,  0x07},
	[3] = {espi_it8xxx2_vwidx41_isr, 0x41},
	[4] = {espi_it8xxx2_vwidx42_isr, 0x42},
	[5] = {espi_it8xxx2_vwidx43_isr, 0x43},
	[6] = {espi_it8xxx2_vwidx44_isr, 0x44},
	[7] = {espi_it8xxx2_vwidx47_isr, 0x47},
};

/*
 * This is used to record the previous VW valid/level field state to discover
 * changes. Then do following sequence only when state is changed.
 */
static uint8_t vwidx_cached_flag[ARRAY_SIZE(vwidx_isr_list)];

static void espi_it8xxx2_reset_vwidx_cache(const struct device *dev)
{
	const struct espi_it8xxx2_config *const config = dev->config;
	struct espi_vw_regs *const vw_reg =
		(struct espi_vw_regs *)config->base_espi_vw;

	/* reset vwidx_cached_flag */
	for (int i = 0; i < ARRAY_SIZE(vwidx_isr_list); i++) {
		vwidx_cached_flag[i] =
			vw_reg->VW_INDEX[vwidx_isr_list[i].vw_index];
	}
}

static void espi_it8xxx2_vw_isr(const struct device *dev)
{
	const struct espi_it8xxx2_config *const config = dev->config;
	struct espi_vw_regs *const vw_reg =
		(struct espi_vw_regs *)config->base_espi_vw;
	uint8_t vwidx_updated = vw_reg->VWCTRL1;

	/* write-1 to clear */
	vw_reg->VWCTRL1 = vwidx_updated;

	for (int i = 0; i < ARRAY_SIZE(vwidx_isr_list); i++) {
		if (vwidx_updated & BIT(i)) {
			uint8_t vw_flag;

			vw_flag = vw_reg->VW_INDEX[vwidx_isr_list[i].vw_index];
			vwidx_isr_list[i].vwidx_isr(dev,
					vwidx_cached_flag[i] ^ vw_flag);
			vwidx_cached_flag[i] = vw_flag;
		}
	}
}

static void espi_it8xxx2_ch_notify_system_state(const struct device *dev,
						enum espi_channel ch, bool en)
{
	struct espi_it8xxx2_data *const data = dev->data;
	struct espi_event evt = {
		.evt_type = ESPI_BUS_EVENT_CHANNEL_READY,
		.evt_details = ch,
		.evt_data = en,
	};

	espi_send_callbacks(&data->callbacks, dev, evt);
}

/*
 * Peripheral channel enable asserted flag.
 * A 0-to-1 or 1-to-0 transition on "Peripheral Channel Enable" bit.
 */
static void espi_it8xxx2_peripheral_ch_en_isr(const struct device *dev,
						bool enable)
{
	espi_it8xxx2_ch_notify_system_state(dev,
					ESPI_CHANNEL_PERIPHERAL, enable);
}

/*
 * VW channel enable asserted flag.
 * A 0-to-1 or 1-to-0 transition on "Virtual Wire Channel Enable" bit.
 */
static void espi_it8xxx2_vw_ch_en_isr(const struct device *dev, bool enable)
{
	espi_it8xxx2_ch_notify_system_state(dev, ESPI_CHANNEL_VWIRE, enable);
}

/*
 * OOB message channel enable asserted flag.
 * A 0-to-1 or 1-to-0 transition on "OOB Message Channel Enable" bit.
 */
static void espi_it8xxx2_oob_ch_en_isr(const struct device *dev, bool enable)
{
	espi_it8xxx2_ch_notify_system_state(dev, ESPI_CHANNEL_OOB, enable);
}

/*
 * Flash channel enable asserted flag.
 * A 0-to-1 or 1-to-0 transition on "Flash Access Channel Enable" bit.
 */
static void espi_it8xxx2_flash_ch_en_isr(const struct device *dev, bool enable)
{
	if (enable) {
		espi_it8xxx2_send_vwire(dev, ESPI_VWIRE_SIGNAL_TARGET_BOOT_STS, 1);
		espi_it8xxx2_send_vwire(dev,
					ESPI_VWIRE_SIGNAL_TARGET_BOOT_DONE, 1);
	}

	espi_it8xxx2_ch_notify_system_state(dev, ESPI_CHANNEL_FLASH, enable);
}

static void espi_it8xxx2_put_pc_status_isr(const struct device *dev)
{
	const struct espi_it8xxx2_config *const config = dev->config;
	struct espi_slave_regs *const slave_reg =
		(struct espi_slave_regs *)config->base_espi_slave;

	/*
	 * TODO: To check cycle type (bit[3-0] at ESPCTRL0) and make
	 * corresponding modification if needed.
	 */
	LOG_INF("isr %s is ignored!", __func__);

	/* write-1-clear to release PC_FREE */
	slave_reg->ESPCTRL0 = IT8XXX2_ESPI_INTERRUPT_PUT_PC;
}

#ifdef CONFIG_ESPI_OOB_CHANNEL
static void espi_it8xxx2_upstream_channel_disable_isr(const struct device *dev)
{
	const struct espi_it8xxx2_config *const config = dev->config;
	struct espi_slave_regs *const slave_reg =
		(struct espi_slave_regs *)config->base_espi_slave;

	LOG_INF("isr %s is ignored!", __func__);

	/* write-1 to clear this bit */
	slave_reg->ESUCTRL0 |= IT8XXX2_ESPI_UPSTREAM_CHANNEL_DISABLE;
}

static void espi_it8xxx2_put_oob_status_isr(const struct device *dev)
{
	const struct espi_it8xxx2_config *const config = dev->config;
	struct espi_it8xxx2_data *const data = dev->data;
	struct espi_slave_regs *const slave_reg =
		(struct espi_slave_regs *)config->base_espi_slave;
#ifdef CONFIG_ESPI_OOB_CHANNEL_RX_ASYNC
	struct espi_event evt = { .evt_type = ESPI_BUS_EVENT_OOB_RECEIVED,
				  .evt_details = 0,
				  .evt_data = 0 };
#endif

	/* Write-1 to clear this bit for the next coming posted transaction. */
	slave_reg->ESOCTRL0 |= IT8XXX2_ESPI_PUT_OOB_STATUS;

#ifndef CONFIG_ESPI_OOB_CHANNEL_RX_ASYNC
	k_sem_give(&data->oob_upstream_go);
#else
	/* Additional detail is length field of PUT_OOB message packet. */
	evt.evt_details = (slave_reg->ESOCTRL4 & IT8XXX2_ESPI_PUT_OOB_LEN_MASK);
	espi_send_callbacks(&data->callbacks, dev, evt);
#endif
}
#endif

#if defined(CONFIG_ESPI_OOB_CHANNEL) || defined(CONFIG_ESPI_FLASH_CHANNEL)
static void espi_it8xxx2_upstream_done_isr(const struct device *dev)
{
	const struct espi_it8xxx2_config *const config = dev->config;
	struct espi_slave_regs *const slave_reg =
		(struct espi_slave_regs *)config->base_espi_slave;

#ifdef CONFIG_ESPI_FLASH_CHANNEL
	/* cycle type is flash read, write, or erase */
	if (slave_reg->ESUCTRL1 != IT8XXX2_ESPI_CYCLE_TYPE_OOB) {
		espi_it8xxx2_flash_upstream_done_isr(dev);
	}
#endif

	/* write-1 to clear this bit */
	slave_reg->ESUCTRL0 |= IT8XXX2_ESPI_UPSTREAM_DONE;
	/* upstream disable */
	slave_reg->ESUCTRL0 &= ~IT8XXX2_ESPI_UPSTREAM_ENABLE;
}
#endif

/*
 * The ISR of espi interrupt event in array need to be matched bit order in
 * IT8XXX2 ESPI ESGCTRL0 register.
 */
static const struct espi_isr_t espi_isr_list[] = {
	[0] = {espi_it8xxx2_peripheral_ch_en_isr, ASSERTED_FLAG},
	[1] = {espi_it8xxx2_vw_ch_en_isr,         ASSERTED_FLAG},
	[2] = {espi_it8xxx2_oob_ch_en_isr,        ASSERTED_FLAG},
	[3] = {espi_it8xxx2_flash_ch_en_isr,      ASSERTED_FLAG},
	[4] = {espi_it8xxx2_peripheral_ch_en_isr, DEASSERTED_FLAG},
	[5] = {espi_it8xxx2_vw_ch_en_isr,         DEASSERTED_FLAG},
	[6] = {espi_it8xxx2_oob_ch_en_isr,        DEASSERTED_FLAG},
	[7] = {espi_it8xxx2_flash_ch_en_isr,      DEASSERTED_FLAG},
};

static void espi_it8xxx2_isr(const struct device *dev)
{
	const struct espi_it8xxx2_config *const config = dev->config;
	struct espi_slave_regs *const slave_reg =
		(struct espi_slave_regs *)config->base_espi_slave;
	/* get espi interrupt events */
	uint8_t espi_event = slave_reg->ESGCTRL0;
#if defined(CONFIG_ESPI_OOB_CHANNEL) || defined(CONFIG_ESPI_FLASH_CHANNEL)
	uint8_t espi_upstream = slave_reg->ESUCTRL0;
#endif

	/* write-1 to clear */
	slave_reg->ESGCTRL0 = espi_event;

	/* process espi interrupt events */
	for (int i = 0; i < ARRAY_SIZE(espi_isr_list); i++) {
		if (espi_event & BIT(i)) {
			espi_isr_list[i].espi_isr(dev,
				espi_isr_list[i].isr_type);
		}
	}

	/*
	 * bit7: the peripheral has received a peripheral posted/completion.
	 * This bit indicates the peripheral has received a packet from eSPI
	 * peripheral channel.
	 */
	if (slave_reg->ESPCTRL0 & IT8XXX2_ESPI_INTERRUPT_PUT_PC) {
		espi_it8xxx2_put_pc_status_isr(dev);
	}

#ifdef CONFIG_ESPI_OOB_CHANNEL
	/*
	 * The corresponding channel of the eSPI upstream transaction is
	 * disabled.
	 */
	if (espi_upstream & IT8XXX2_ESPI_UPSTREAM_CHANNEL_DISABLE) {
		espi_it8xxx2_upstream_channel_disable_isr(dev);
	}

	/* The eSPI slave has received a PUT_OOB message. */
	if (slave_reg->ESOCTRL0 & IT8XXX2_ESPI_PUT_OOB_STATUS) {
		espi_it8xxx2_put_oob_status_isr(dev);
	}
#endif

	/* eSPI oob and flash channels use the same interrupt of upstream. */
#if defined(CONFIG_ESPI_OOB_CHANNEL) || defined(CONFIG_ESPI_FLASH_CHANNEL)
	/* The eSPI upstream transaction is done. */
	if (espi_upstream & IT8XXX2_ESPI_UPSTREAM_DONE) {
		espi_it8xxx2_upstream_done_isr(dev);
	}
#endif
}

void espi_it8xxx2_enable_pad_ctrl(const struct device *dev, bool enable)
{
	const struct espi_it8xxx2_config *const config = dev->config;
	struct espi_slave_regs *const slave_reg =
		(struct espi_slave_regs *)config->base_espi_slave;

	if (enable) {
		/* Enable eSPI pad. */
		slave_reg->ESGCTRL2 &= ~IT8XXX2_ESPI_INPUT_PAD_GATING;
	} else {
		/* Disable eSPI pad. */
		slave_reg->ESGCTRL2 |= IT8XXX2_ESPI_INPUT_PAD_GATING;
	}
}

void espi_it8xxx2_enable_trans_irq(const struct device *dev, bool enable)
{
	const struct espi_it8xxx2_config *const config = dev->config;

	if (enable) {
		irq_enable(IT8XXX2_TRANS_IRQ);
	} else {
		irq_disable(IT8XXX2_TRANS_IRQ);
		/* Clear pending interrupt */
#ifdef CONFIG_SOC_SERIES_IT51XXX
		it51xxx_wuc_clear_status(config->wuc.wucs, config->wuc.mask);
#else
		it8xxx2_wuc_clear_status(config->wuc.wucs, config->wuc.mask);
#endif
	}
}

static void espi_it8xxx2_trans_isr(const struct device *dev)
{
	/*
	 * This interrupt is only used to wake up CPU, there is no need to do
	 * anything in the isr in addition to disable interrupt.
	 */
	espi_it8xxx2_enable_trans_irq(dev, false);
}

void espi_it8xxx2_espi_reset_isr(const struct device *port,
				struct gpio_callback *cb, uint32_t pins)
{
	struct espi_it8xxx2_data *const data = ESPI_IT8XXX2_SOC_DEV->data;
	struct espi_event evt = {ESPI_BUS_RESET, 0, 0};
	bool espi_reset = gpio_pin_get(port, (find_msb_set(pins) - 1));

	if (!(espi_reset)) {
		/* Reset vwidx_cached_flag[] when espi_reset# asserted. */
		espi_it8xxx2_reset_vwidx_cache(ESPI_IT8XXX2_SOC_DEV);
	}

	evt.evt_data = espi_reset;
	espi_send_callbacks(&data->callbacks, ESPI_IT8XXX2_SOC_DEV, evt);

	LOG_INF("eSPI reset %sasserted", espi_reset ? "de" : "");
}

/* eSPI reset# is enabled on GPD2 */
#define ESPI_IT8XXX2_ESPI_RESET_PORT DEVICE_DT_GET(DT_NODELABEL(gpiod))
#define ESPI_IT8XXX2_ESPI_RESET_PIN  2
static void espi_it8xxx2_enable_reset(void)
{
	struct gpio_ite_ec_regs *const gpio_regs = GPIO_ITE_EC_REGS_BASE;
	static struct gpio_callback espi_reset_cb;

	/* eSPI reset is enabled on GPD2 */
	gpio_regs->GPIO_GCR =
		(gpio_regs->GPIO_GCR & ~IT8XXX2_GPIO_GCR_ESPI_RST_EN_MASK) |
		(IT8XXX2_GPIO_GCR_ESPI_RST_D2 << IT8XXX2_GPIO_GCR_ESPI_RST_POS);
	/* enable eSPI reset isr */
	gpio_init_callback(&espi_reset_cb, espi_it8xxx2_espi_reset_isr,
				BIT(ESPI_IT8XXX2_ESPI_RESET_PIN));
	gpio_add_callback(ESPI_IT8XXX2_ESPI_RESET_PORT, &espi_reset_cb);
	gpio_pin_interrupt_configure(ESPI_IT8XXX2_ESPI_RESET_PORT,
					ESPI_IT8XXX2_ESPI_RESET_PIN,
					GPIO_INT_MODE_EDGE | GPIO_INT_TRIG_BOTH);
}

static struct espi_it8xxx2_data espi_it8xxx2_data_0;
static const struct espi_it8xxx2_config espi_it8xxx2_config_0 = {
	.base_espi_slave = DT_INST_REG_ADDR_BY_IDX(0, 0),
	.base_espi_vw = DT_INST_REG_ADDR_BY_IDX(0, 1),
	.base_espi_queue0 = DT_INST_REG_ADDR_BY_IDX(0, 2),
	.base_espi_queue1 = DT_INST_REG_ADDR_BY_IDX(0, 3),
	.base_ec2i = DT_INST_REG_ADDR_BY_IDX(0, 4),
	.base_kbc = DT_INST_REG_ADDR_BY_IDX(0, 5),
	.base_pmc = DT_INST_REG_ADDR_BY_IDX(0, 6),
	.base_smfi = DT_INST_REG_ADDR_BY_IDX(0, 7),
	.wuc = IT8XXX2_DT_WUC_ITEMS_FUNC(0, 0),
};

DEVICE_DT_INST_DEFINE(0, &espi_it8xxx2_init, NULL,
		    &espi_it8xxx2_data_0, &espi_it8xxx2_config_0,
		    PRE_KERNEL_2, CONFIG_ESPI_INIT_PRIORITY,
		    &espi_it8xxx2_driver_api);

static int espi_it8xxx2_init(const struct device *dev)
{
	const struct espi_it8xxx2_config *const config = dev->config;
	struct espi_vw_regs *const vw_reg =
		(struct espi_vw_regs *)config->base_espi_vw;
	struct espi_slave_regs *const slave_reg =
		(struct espi_slave_regs *)config->base_espi_slave;
	struct gctrl_ite_ec_regs *const gctrl = ESPI_ITE_GET_GCTRL_BASE;

	/* configure VCC detector */
	gctrl->GCTRL_RSTS = (gctrl->GCTRL_RSTS &
			~(IT8XXX2_GCTRL_VCCDO_MASK | IT8XXX2_GCTRL_HGRST)) |
			(IT8XXX2_GCTRL_VCCDO_VCC_ON | IT8XXX2_GCTRL_GRST);

	/* enable PNPCFG devices */
	pnpcfg_it8xxx2_init(dev);

#ifdef CONFIG_ESPI_PERIPHERAL_8042_KBC
	/* enable kbc port (60h/64h) */
	kbc_it8xxx2_init(dev);
#endif
#ifdef CONFIG_ESPI_PERIPHERAL_HOST_IO
	/* enable pmc1 for ACPI port (62h/66h) */
	pmc1_it8xxx2_init(dev);
#endif
#ifdef CONFIG_ESPI_PERIPHERAL_DEBUG_PORT_80
	/* Accept Port 80h Cycle */
	port80_it8xxx2_init(dev);
#endif
#if defined(CONFIG_ESPI_PERIPHERAL_EC_HOST_CMD) || \
	defined(CONFIG_ESPI_PERIPHERAL_ACPI_SHM_REGION)
	smfi_it8xxx2_init(dev);
#endif
#ifdef CONFIG_ESPI_PERIPHERAL_EC_HOST_CMD
	/* enable pmc2 for host command port */
	pmc2_it8xxx2_init(dev);
#endif
#ifdef CONFIG_ESPI_PERIPHERAL_HOST_IO_PVT
	/* enable pmc3 for host private port */
	pmc3_it8xxx2_init(dev);
#endif
#ifdef CONFIG_ESPI_PERIPHERAL_HOST_IO_PVT2
	/* enable pmc4 for host private port */
	pmc4_it8xxx2_init(dev);
#endif
#ifdef CONFIG_ESPI_PERIPHERAL_HOST_IO_PVT3
	/* enable pmc5 for host private port */
	pmc5_it8xxx2_init(dev);
#endif

	/* Reset vwidx_cached_flag[] at initialization */
	espi_it8xxx2_reset_vwidx_cache(dev);

	/* Enable espi vw interrupt */
	vw_reg->VWCTRL0 |= IT8XXX2_ESPI_VW_INTERRUPT_ENABLE;
	IRQ_CONNECT(IT8XXX2_ESPI_VW_IRQ, 0, espi_it8xxx2_vw_isr,
			DEVICE_DT_INST_GET(0), 0);
	irq_enable(IT8XXX2_ESPI_VW_IRQ);

	/* Reset PLTRST# virtual wire signal during eSPI reset */
	vw_reg->VWCTRL2 |= IT8XXX2_ESPI_VW_RESET_PLTRST;

#ifdef CONFIG_ESPI_OOB_CHANNEL
	espi_it8xxx2_oob_init(dev);
#endif

#ifdef CONFIG_ESPI_FLASH_CHANNEL
	espi_it8xxx2_flash_init(dev);
#endif

	/* Enable espi interrupt */
	slave_reg->ESGCTRL1 |= IT8XXX2_ESPI_INTERRUPT_ENABLE;
	IRQ_CONNECT(IT8XXX2_ESPI_IRQ, 0, espi_it8xxx2_isr,
			DEVICE_DT_INST_GET(0), 0);
	irq_enable(IT8XXX2_ESPI_IRQ);

	/* enable interrupt and reset from eSPI_reset# */
	espi_it8xxx2_enable_reset();

	/*
	 * Enable eSPI to WUC.
	 * If an eSPI transaction is accepted, WU42 interrupt will be asserted.
	 */
	slave_reg->ESGCTRL2 |= IT8XXX2_ESPI_TO_WUC_ENABLE;

	/* Enable WU42 of WUI */
#ifdef CONFIG_SOC_SERIES_IT51XXX
	it51xxx_wuc_clear_status(config->wuc.wucs, config->wuc.mask);
	it51xxx_wuc_enable(config->wuc.wucs, config->wuc.mask);
#else
	it8xxx2_wuc_clear_status(config->wuc.wucs, config->wuc.mask);
	it8xxx2_wuc_enable(config->wuc.wucs, config->wuc.mask);
#endif
	/*
	 * Only register isr here, the interrupt only need to be enabled
	 * before CPU and RAM clocks gated in the idle function.
	 */
	IRQ_CONNECT(IT8XXX2_TRANS_IRQ, 0, espi_it8xxx2_trans_isr,
			DEVICE_DT_INST_GET(0), 0);

	return 0;
}
