diff --git a/boards/ite/it515xx_evb/it515xx_evb.dts b/boards/ite/it515xx_evb/it515xx_evb.dts index 4d0ccfb7485f..76801b4b5a2b 100644 --- a/boards/ite/it515xx_evb/it515xx_evb.dts +++ b/boards/ite/it515xx_evb/it515xx_evb.dts @@ -15,6 +15,7 @@ compatible = "ite,it515xx-evb"; aliases { + i2c-0 = &i2c0; led0 = &led0; watchdog0 = &twd0; }; @@ -38,6 +39,14 @@ }; }; +&i2c0 { + status = "okay"; + clock-frequency = ; + pinctrl-0 = <&i2c0_clk_gpf2_default + &i2c0_data_gpf3_default>; + pinctrl-names = "default"; +}; + &uart1 { status = "okay"; current-speed = <115200>; diff --git a/boards/ite/it515xx_evb/it515xx_evb.yaml b/boards/ite/it515xx_evb/it515xx_evb.yaml index cddae71d22d7..5ac8ab272d7e 100644 --- a/boards/ite/it515xx_evb/it515xx_evb.yaml +++ b/boards/ite/it515xx_evb/it515xx_evb.yaml @@ -8,6 +8,7 @@ ram: 128 supported: - flash - gpio + - i2c - pinctrl - pm - uart diff --git a/drivers/i2c/CMakeLists.txt b/drivers/i2c/CMakeLists.txt index 7a4dbfc53898..67ca17fd252e 100644 --- a/drivers/i2c/CMakeLists.txt +++ b/drivers/i2c/CMakeLists.txt @@ -38,6 +38,7 @@ zephyr_library_sources_ifdef(CONFIG_I2C_INFINEON_CAT1 i2c_ifx_cat1.c) zephyr_library_sources_ifdef(CONFIG_I2C_INFINEON_XMC4 i2c_ifx_xmc4.c) zephyr_library_sources_ifdef(CONFIG_I2C_IPROC i2c_bcm_iproc.c) zephyr_library_sources_ifdef(CONFIG_I2C_ITE_ENHANCE i2c_ite_enhance.c) +zephyr_library_sources_ifdef(CONFIG_I2C_ITE_IT51XXX i2c_ite_it51xxx.c) zephyr_library_sources_ifdef(CONFIG_I2C_ITE_IT8XXX2 i2c_ite_it8xxx2.c) zephyr_library_sources_ifdef(CONFIG_I2C_LITEX i2c_litex.c) zephyr_library_sources_ifdef(CONFIG_I2C_LITEX_LITEI2C i2c_litex_litei2c.c) diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 25bd2dfea781..0ae73d788084 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -132,6 +132,7 @@ source "drivers/i2c/Kconfig.gpio" source "drivers/i2c/Kconfig.i2c_emul" source "drivers/i2c/Kconfig.ifx_cat1" source "drivers/i2c/Kconfig.ifx_xmc4" +source "drivers/i2c/Kconfig.it51xxx" source "drivers/i2c/Kconfig.it8xxx2" source "drivers/i2c/Kconfig.litex" source "drivers/i2c/Kconfig.lpc11u6x" diff --git a/drivers/i2c/Kconfig.it51xxx b/drivers/i2c/Kconfig.it51xxx new file mode 100644 index 000000000000..4afa5fe5c55d --- /dev/null +++ b/drivers/i2c/Kconfig.it51xxx @@ -0,0 +1,51 @@ +# Copyright (c) 2025 ITE Corporation. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 + +config I2C_ITE_IT51XXX + bool "ITE IT51XXX I2C driver" + default y + depends on DT_HAS_ITE_IT51XXX_I2C_ENABLED + select PINCTRL + select I2C_BITBANG + help + Enable I2C support on IT51XXX series. + Supports nine hosts and three targets and each one able to located + at I2C interface0~8. + Three I2C targets on design A, B and C. Support 16 bytes dedicated + FIFO mode for read/write. + Supported Speeds: 50kHz, 100kHz, 400kHz and 1MHz. + This driver supports repeated start. + +if I2C_ITE_IT51XXX + +config I2C_IT51XXX_FIFO_MODE + bool "IT51XXX I2C FIFO mode" + default y + help + This is an option to enable FIFO mode which can reduce the time + between each byte to improve the I2C bus clock stretching during + I2C transaction. + The I2C controller supports two 32-bytes FIFOs, + FIFO1 supports I2C 0, and FIFO2 supports other ports. + I2C FIFO mode of IT51XXX can support I2C APIs including: + i2c_write(), i2c_read(), i2c_burst_read. + +endif # I2C_ITE_IT51XXX + +if I2C_TARGET + +config I2C_TARGET_IT51XXX_MAX_BUF_SIZE + int "It is allowed to configure the dedicated FIFO size up to 256 bytes." + default 256 + +config I2C_IT51XXX_MAX_SHARE_FIFO_SIZE + int "It is allowed to configure the shared FIFO size up to 256 bytes." + range 16 256 + default 256 + +config SOC_IT51XXX_CPU_IDLE_GATING + default y + help + This option is used when the I2C target shared FIFO property is enabled. + +endif # I2C_TARGET diff --git a/drivers/i2c/i2c_ite_it51xxx.c b/drivers/i2c/i2c_ite_it51xxx.c new file mode 100644 index 000000000000..bbd2806bbca7 --- /dev/null +++ b/drivers/i2c/i2c_ite_it51xxx.c @@ -0,0 +1,1888 @@ +/* + * Copyright (c) 2025 ITE Corporation. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ite_it51xxx_i2c + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(i2c_ite_it51xxx, CONFIG_I2C_LOG_LEVEL); +#include "i2c_bitbang.h" +#include "i2c-priv.h" + +/* + * it51xxx SMBus host registers definition + * base1(0xf04100): A, B, C, D, E, F; base2(0xf04200): G, H, I + */ +/* Host Status Register: base1: 0x00. 0x28, 0x50, 0x78, 0xa0, 0xc8 + * base2: 0x60, 0x88, 0xb0 + */ +#define SMB_HOSTA 0x00 +#define SMB_BDS BIT(7) +#define SMB_TMOE BIT(6) +#define SMB_NACK BIT(5) +#define SMB_FAIL BIT(4) +#define SMB_BSER BIT(3) +#define SMB_DVER BIT(2) +#define SMB_FINTR BIT(1) +#define SMB_HOBY BIT(0) +/* Host Control Register: base1: 0x01. 0x29, 0x51, 0x79, 0xa1, 0xc9 + * base2: 0x61, 0x89, 0xb1 + */ +#define SMB_HOCTL 0x01 +#define SMB_PEC_EN BIT(7) +#define SMB_SRT BIT(6) +#define SMB_LABY BIT(5) +#define SMB_SMCD(n) FIELD_PREP(GENMASK(4, 2), n) +#define SMB_KILL BIT(1) +#define SMB_INTREN BIT(0) +/* Transmit Slave Address Register: base1: 0x03, 0x2b, 0x53, 0x7b, 0xa3, 0xcb + * base2: 0x63, 0x8b, 0xb3 + */ +#define SMB_TRASLA 0x03 +#define SMB_DIR BIT(0) +/* Data 0 Register: base1: 0x04, 0x2c, 0x54, 0x7c, 0xa4, 0xcc + * base2: 0x64, 0x8c, 0xb4 + */ +#define SMB_D0REG 0x04 +/* I2C Shared FIFO Byte Count H: base1: 0x05, 0x2d, 0x55, 0x7d, 0xa5, 0xcd + * base2: 0x65, 0x8d, 0xb5 + */ +#define SMB_ISFBCH 0x05 +/* Host Block Data Byte Register: base1: 0x07, 0x2f, 0x57, 0x7f, 0xa7, 0xcf + * base2: 0x67, 0x8f, 0xb7 + */ +#define SMB_HOBDB 0x07 +/* SMBus Pin Control Register: base1: 0x09, 0x31, 0x59, 0x81, 0xa9, 0xd1 + * base2: 0x69, 0x91, 0xb9 + */ +#define SMB_SMBPCTL 0x09 +#define SMB_DASTI(n) FIELD_PREP(GENMASK(7, 4), n) +#define SMB_HSMBDCS BIT(1) +#define SMB_HSMBCS BIT(0) +/* Host Nack Source: base1: 0x0a, 0x32, 0x5a, 0x82, 0xaa, 0xd2 + * base2: 0x6a, 0x92, 0xba + */ +#define SMB_HONACKSRC 0x0a +#define SMB_HSMCDTD BIT(4) +/* Host Control 2: base1: 0x0b, 0x33, 0x5b, 0x83, 0xab, 0xd3 + * base2: 0x6b, 0x93, 0xbb + */ +#define SMB_HOCTL2 0x0b +#define SMB_HTIFYEN BIT(6) +#define SMB_SMD_TO_EN BIT(4) +#define I2C_SW_EN BIT(3) +#define I2C_SW_WAIT BIT(2) +#define I2C_EN BIT(1) +#define SMB_SMH_EN BIT(0) +/* SMCLK Timing Setting Register: base1: 0x0c, 0x34, 0x5c, 0x84, 0xac, 0xd4 + * base2: 0x6c, 0x94, 0xbc + */ +#define SMB_MSCLKTS 0x0c +/* BIT[1:0]: SMCLK Setting */ +#define SMB_CLKS_1M 4 +#define SMB_CLKS_400K 3 +#define SMB_CLKS_100K 2 +#define SMB_CLKS_50K 1 +/* 4.7us Low Register: base1: 0x0d, 0x35, 0x5d, 0x85, 0xad, 0xd5 + * base2: 0x6d, 0x95, 0xbd + */ +#define SMB_4P7USL 0x0d +/* 4.0us Low Register: base1: 0x0e, 0x36, 0x5e, 0x86, 0xae, 0xd6 + * base2: 0x6e, 0x96, 0xbe + */ +#define SMB_4P0USL 0x0e +/* 250ns Register: base1: 0x10, 0x38, 0x60, 0x88, 0xb0, 0xd8 + * base2: 0x70, 0x98, 0xc0 + */ +#define SMB_250NSREG 0x10 +/* 25ms Register: base1: 0x11, 0x39, 0x61, 0x89, 0xb1, 0xd9 + * base2: 0x71, 0x99, 0xc1 + */ +#define SMB_25MSREG 0x11 +/* 45.3us Low Register: base1: 0x12, 0x3a, 0x62, 0x8a, 0xb2, 0xda + * base2: 0x72, 0x9a, 0xc2 + */ +#define SMB_45P3USLREG 0x12 +/* 45.3us High Register: base1: 0x13, 0x3b, 0x63, 0x8b, 0xb3, 0xdb + * base2: 0x73, 0x9b, 0xc3 + */ +#define SMB_45P3USHREG 0x13 +/* 4.7us And 4.0us High Register: base1: 0x14, 0x3c, 0x64, 0x8c, 0xb4, 0xdc + * base2: 0x74, 0x9c, 0xc4 + */ +#define SMB_4P7A4P0H 0x14 +/* I2C Wr to Rd FIFO Register: base1: 0x1b, 0x43, 0x6b, 0x93, 0xbb, 0xe3 + * base2: 0x7b, 0xa3, 0xcb + */ +#define SMB_I2CW2RF 0x1b +#define SMB_MAIFID BIT(2) +#define SMB_MAIF BIT(1) +#define SMB_MAIFI BIT(0) +/* 0x16: Shared FIFO Base Address MSB for Master A */ +#define SMB_SFBAMMA 0x16 +/* 0x17: Shared FIFO Base Address for Master A */ +#define SMB_SFBAMA 0x17 +/* 0x18: Shared FIFO Ctrl for Master A */ +#define SMB_SFCMA 0x18 +#define SMB_SFSAE BIT(3) +#define SMB_SFSFSA(n) FIELD_PREP(GENMASK(2, 0), n) +/* Shared FIFO Base Address MSB for Master n: base1: 0x3e, 0x66, 0x8e, 0xb6, 0xde + * base2: 0x76, 0x9e, 0xc6 + */ +#define SMB_SFBAMMn 0x3e +/* Shared FIFO Base Address LSB for Master n: base1: 0x3f, 0x67, 0x8f, 0xb7, 0xdf + * base2: 0x77, 0x9f, 0xc7 + */ +#define SMB_SFBAMn 0x3f +/* Master n Shared FIFO Size Select: base1: 0x40, 0x68, 0x90, 0xb8, 0xe0 + * base2: 0x78, 0xa0, 0xc8 + */ +#define SMB_MnSFSS 0x40 +/* 0xf0: Master FIFO Control Status Register */ +#define SMB_MSTFCSTS 0xf0 +#define SMB_BLKDS2 BIT(6) +#define SMB_SFDFSF BIT(6) +#define SMB_FF2EN BIT(5) +#define SMB_BLKDS1 BIT(4) +#define SMB_SFDFSFA BIT(4) +#define SMB_FF1EN BIT(3) +#define SMB_FFCHSEL2(n) FIELD_PREP(GENMASK(2, 0), n) +/* 0xf1: Master FIFO Status 1 Register */ +#define SMB_MSTFSTS1 0xf1 +#define SMB_FIFO1_EMPTY BIT(7) +#define SMB_FIFO1_FULL BIT(6) +/* 0xf2: Master FIFO Status 2 Register */ +#define SMB_MSTFSTS2 0xf2 +#define SMB_FIFO2_EMPTY BIT(7) +#define SMB_FIFO2_FULL BIT(6) +/* 0xf4: SMBus Interface Switch Pin Control 0 */ +#define SMB_SISPC0 0xf4 +/* 0xf5: SMBus Interface Switch Pin Control 1 */ +#define SMB_SISPC1 0xf5 + +/* + * it51xxx SMBus target registers definition + * base(0xf04200): A, B, C + */ +/* 0x00, 0x20, 0x40: Receive Slave Address Register */ +#define SMB_RESLADR 0x00 +/* 0x01, 0x21, 0x41: Slave Data Register n */ +#define SMB_SLDn 0x01 +/* 0x02, 0x22, 0x42: Slave Status Register n */ +#define SMB_SLSTn 0x02 +#define SMB_SPDS BIT(5) +#define SMB_RCS BIT(3) +#define SMB_STS BIT(2) +#define SMB_SDS BIT(1) +/* 0x03, 0x23, 0x43: Slave Interrupt Control Register n */ +#define SMB_SICRn 0x03 +#define SMB_SDSEN BIT(3) +#define SMB_SDLTOEN BIT(2) +#define SMB_SITEN BIT(1) +/* 0x05, 0x25, 0x45: Slave Control Register n */ +#define SMB_SLVCTLn 0x05 +#define SMB_RSCS BIT(2) +#define SMB_SSCL BIT(1) +#define SMB_SLVEN BIT(0) +/* 0x06, 0x26, 0x45: SMCLK Timing Setting Register n */ +#define SMB_SSCLKTSn 0x06 +#define SMB_DSASTI(n) FIELD_PREP(GENMASK(5, 2), n) +#define SMB_SCLKSA1M BIT(1) +#define SMB_SSMCDTD BIT(0) +/* 0x07, 0x27, 0x47: 25 ms Slave Register */ +#define SMB_25SLVREGn 0x07 +/* 0x0a, 0x2a, 0x4a: Slave n Dedicated FIFO Pre-defined Control */ +#define SMB_SnDFPCTL 0x0a +#define SMB_SADFE BIT(0) +/* 0x0b, 0x2b, 0x4b: Slave n Dedicated FIFO status */ +#define SMB_SFFSTn 0x0b +#define SMB_FIFO_FULL BIT(6) +/* 0x0e, 0x2e, 0x4e: Shared FIFO Base Address MSB for Slave n */ +#define SMB_SFBAMSn 0x0e +/* 0x0f, 0x2f, 0x4f: Shared FIFO Base Address LSB for Slave n */ +#define SMB_SFBASn 0x0f +/* 0x11, 0x31, 0x51: Slave Shared FIFO Ctrl n */ +#define SMB_SSFIFOCn 0x11 + +/* + * TODO: Some registers are not correctly mapped to the new baseaddress: 0xf04100, so the old + * baseaddress must be used to avoid invalid functionality. + */ +#ifdef CONFIG_SOC_IT51526AW +/* 0x09, 0x1a, 0x5b: Slave Data */ +#define SMB_SLDA(ch) ((ch) == 0 ? 0x09 : (ch) == 1 ? 0x1a : (ch) == 2 ? 0x5b : 0) +/* 0x0b, 0x1c, 0x52: Slave Status */ +#define SMB_SLSTA(ch) ((ch) == 0 ? 0x0b : (ch) == 1 ? 0x1c : (ch) == 2 ? 0x52 : 0) +/* 0x45: Master FIFO Control 1 */ +#define SMB_MSTFCTRL1 0x45 +/* 0x47: Master FIFO Control 2 */ +#define SMB_MSTFCTRL2 0x47 +#define SMB_BLKDS BIT(4) +#define SMB_FFEN BIT(3) + +#ifdef CONFIG_I2C_IT51XXX_FIFO_MODE +BUILD_ASSERT((DT_PROP(DT_NODELABEL(i2c6), fifo_enable) == false) && + (DT_PROP(DT_NODELABEL(i2c7), fifo_enable) == false) && + (DT_PROP(DT_NODELABEL(i2c8), fifo_enable) == false), + "I2C6, I2C7, I2C8 cannot use FIFO mode in it51526aw soc."); +#endif /* CONFIG_I2C_IT51XXX_FIFO_MODE */ +#endif /* CONFIG_SOC_IT51526AW */ + +#ifdef CONFIG_I2C_IT51XXX_FIFO_MODE +#define SMB_FIFO_MODE_MAX_SIZE 32 +#define SMB_FIFO_MODE_TOTAL_LEN 255 +#define SMB_MSG_BURST_READ_MASK (I2C_MSG_RESTART | I2C_MSG_STOP | I2C_MSG_READ) +#define FIFO_ENABLE_NODE(idx) DT_PROP(DT_NODELABEL(i2c##idx), fifo_enable) +#define FIFO_ENABLE_COUNT \ + (FIFO_ENABLE_NODE(1) + FIFO_ENABLE_NODE(2) + FIFO_ENABLE_NODE(3) + FIFO_ENABLE_NODE(4) + \ + FIFO_ENABLE_NODE(5) + FIFO_ENABLE_NODE(6) + FIFO_ENABLE_NODE(7) + FIFO_ENABLE_NODE(8)) +BUILD_ASSERT(FIFO_ENABLE_COUNT <= 1, "More than one node has fifo2-enable property enabled!"); +#endif /* CONFIG_I2C_IT51XXX_FIFO_MODE */ + +#ifdef CONFIG_I2C_TARGET +#define SMB_TARGET_IT51XXX_MAX_FIFO_SIZE 16 + +struct target_shared_fifo_size_sel { + uint16_t fifo_size; + uint8_t value; +}; + +static const struct target_shared_fifo_size_sel fifo_size_table[] = { + [0] = {16, 0x1}, [1] = {32, 0x2}, [2] = {64, 0x3}, [3] = {128, 0x4}, [4] = {256, 0x5}, +}; +#endif /* CONFIG_I2C_TARGET */ + +/* Start smbus session from idle state */ +#define SMB_MSG_START BIT(5) +#define SMB_LINE_SCL_HIGH BIT(0) +#define SMB_LINE_SDA_HIGH BIT(1) +#define SMB_LINE_IDLE (SMB_LINE_SCL_HIGH | SMB_LINE_SDA_HIGH) + +struct i2c_it51xxx_config { + /* I2C alternate configuration */ + const struct pinctrl_dev_config *pcfg; + /* SCL GPIO cells */ + struct gpio_dt_spec scl_gpios; + /* SDA GPIO cells */ + struct gpio_dt_spec sda_gpios; + int transfer_timeout_ms; + mm_reg_t host_base; + mm_reg_t target_base; + mm_reg_t i2cbase; + mm_reg_t i2cbase_mapping; + uint32_t bitrate; + uint8_t i2c_irq_base; + uint8_t i2cs_irq_base; + uint8_t port; + uint8_t channel_switch_sel; + bool fifo_enable; + bool target_enable; + bool target_fifo_mode; + bool target_shared_fifo_mode; + bool push_pull_recovery; +}; + +enum i2c_ch_status { + I2C_CH_NORMAL = 0, + I2C_CH_REPEAT_START, + I2C_CH_WAIT_READ, + I2C_CH_WAIT_NEXT_XFER, +}; + +enum i2c_ite_pm_policy_state_flag { + I2CM_ITE_PM_POLICY_FLAG, + I2CS_ITE_PM_POLICY_FLAG, + I2C_ITE_PM_POLICY_FLAG_COUNT, +}; + +struct i2c_it51xxx_data { + struct i2c_msg *msg; + struct k_mutex mutex; + struct k_sem device_sync_sem; + struct i2c_bitbang bitbang; + enum i2c_ch_status i2ccs; + /* Index into output data */ + size_t widx; + /* Index into input data */ + size_t ridx; + /* operation freq of i2c */ + uint32_t bus_freq; + /* Error code, if any */ + uint32_t err; + /* Address of device */ + uint16_t addr_16bit; + /* Wait for stop bit interrupt */ + uint8_t stop; +#ifdef CONFIG_I2C_IT51XXX_FIFO_MODE + struct i2c_msg *msgs_list; + /* Read or write byte counts. */ + uint32_t bytecnt; + /* Number of messages. */ + uint8_t num_msgs; + uint8_t msg_index; +#endif +#ifdef CONFIG_I2C_TARGET + struct i2c_target_config *target_cfg; + const struct target_shared_fifo_size_sel *fifo_size_list; + uint32_t w_index; + uint32_t r_index; + /* Target mode FIFO buffer. */ + uint8_t __aligned(4) target_in_buffer[CONFIG_I2C_TARGET_IT51XXX_MAX_BUF_SIZE]; + uint8_t __aligned(4) target_out_buffer[CONFIG_I2C_TARGET_IT51XXX_MAX_BUF_SIZE]; + /* Target shared FIFO mode. */ + uint8_t __aligned(16) target_shared_fifo[CONFIG_I2C_IT51XXX_MAX_SHARE_FIFO_SIZE]; + bool target_attached; +#endif +#ifdef CONFIG_PM + ATOMIC_DEFINE(pm_policy_state_flag, I2C_ITE_PM_POLICY_FLAG_COUNT); +#endif +}; + +enum i2c_host_status { + /* Host busy */ + HOSTA_HOBY = 0x01, + /* Finish Interrupt */ + HOSTA_FINTR = 0x02, + /* Device error */ + HOSTA_DVER = 0x04, + /* Bus error */ + HOSTA_BSER = 0x08, + /* Fail */ + HOSTA_FAIL = 0x10, + /* Not response ACK */ + HOSTA_NACK = 0x20, + /* Time-out error */ + HOSTA_TMOE = 0x40, + /* Byte done status */ + HOSTA_BDS = 0x80, + /* Error bit is set */ + HOSTA_ANY_ERROR = (HOSTA_DVER | HOSTA_BSER | HOSTA_FAIL | HOSTA_NACK | HOSTA_TMOE), + /* W/C for next byte */ + HOSTA_NEXT_BYTE = HOSTA_BDS, + /* W/C host status register */ + HOSTA_ALL_WC_BIT = (HOSTA_FINTR | HOSTA_ANY_ERROR | HOSTA_BDS), +}; + +enum i2c_reset_cause { + I2C_RC_NO_IDLE_FOR_START = 1, + I2C_RC_TIMEOUT, +}; + +#ifdef CONFIG_PM +static void i2c_ite_pm_policy_state_lock_get(struct i2c_it51xxx_data *data, + enum i2c_ite_pm_policy_state_flag flag) +{ + if (atomic_test_and_set_bit(data->pm_policy_state_flag, flag) == 0) { + pm_policy_state_lock_get(PM_STATE_STANDBY, PM_ALL_SUBSTATES); + } +} + +static void i2c_ite_pm_policy_state_lock_put(struct i2c_it51xxx_data *data, + enum i2c_ite_pm_policy_state_flag flag) +{ + if (atomic_test_and_clear_bit(data->pm_policy_state_flag, flag) == 1) { + pm_policy_state_lock_put(PM_STATE_STANDBY, PM_ALL_SUBSTATES); + } +} +#endif /* CONFIG_PM */ + +#ifdef CONFIG_I2C_TARGET +static void target_i2c_isr_fifo(const struct device *dev) +{ + const struct i2c_it51xxx_config *config = dev->config; + struct i2c_it51xxx_data *data = dev->data; + const struct i2c_target_callbacks *target_cb = data->target_cfg->callbacks; + uint32_t count, len; + uint8_t sdfpctl; + uint8_t target_status, fifo_status; + +#ifdef CONFIG_SOC_IT51526AW + target_status = sys_read8(config->i2cbase_mapping + SMB_SLSTA(config->port)); +#else + target_status = sys_read8(config->target_base + SMB_SLSTn); +#endif + fifo_status = sys_read8(config->target_base + SMB_SFFSTn); + /* bit0-4 : FIFO byte count */ + count = fifo_status & GENMASK(4, 0); + + /* Any error */ + if (target_status & SMB_STS) { + data->w_index = 0; + data->r_index = 0; + goto done; + } + /* Target data status, the register is waiting for read or write. */ + if (target_status & SMB_SDS) { + if (target_status & SMB_RCS) { + uint8_t *rdata = NULL; + +#ifdef CONFIG_I2C_TARGET_BUFFER_MODE + /* Read data callback function */ + if (target_cb->buf_read_requested) { + target_cb->buf_read_requested(data->target_cfg, &rdata, &len); + } +#endif + if (len > sizeof(data->target_out_buffer)) { + LOG_ERR("I2CS ch%d: The length exceeds out_buffer size=%d", + config->port, sizeof(data->target_out_buffer)); + } else { + memcpy(data->target_out_buffer, rdata, len); + } + + for (int i = 0; i < SMB_TARGET_IT51XXX_MAX_FIFO_SIZE; i++) { + /* Host receiving, target transmitting */ +#ifdef CONFIG_SOC_IT51526AW + sys_write8(data->target_out_buffer[i + data->r_index], + config->i2cbase_mapping + SMB_SLDA(config->port)); +#else + sys_write8(data->target_out_buffer[i + data->r_index], + config->target_base + SMB_SLDn); +#endif + } + /* Index to next 16 bytes of read buffer */ + data->r_index += SMB_TARGET_IT51XXX_MAX_FIFO_SIZE; + } else { + for (int i = 0; i < count; i++) { + /* Host transmitting, target receiving */ +#ifdef CONFIG_SOC_IT51526AW + data->target_in_buffer[i + data->w_index] = + sys_read8(config->i2cbase_mapping + SMB_SLDA(config->port)); +#else + data->target_in_buffer[i + data->w_index] = + sys_read8(config->target_base + SMB_SLDn); +#endif + } +#ifdef CONFIG_I2C_TARGET_BUFFER_MODE + /* Write data done callback function */ + if (target_cb->buf_write_received) { + target_cb->buf_write_received(data->target_cfg, + data->target_in_buffer, count); + } +#endif + /* Index to next 16 bytes of write buffer */ + data->w_index += count; + if (data->w_index > sizeof(data->target_in_buffer)) { + LOG_ERR("I2CS ch%d: The write size exceeds in buffer size=%d", + config->port, sizeof(data->target_in_buffer)); + } + } + } + /* Stop condition, indicate stop condition detected. */ + if (target_status & SMB_SPDS) { + /* Read data less 16 bytes status */ + if (target_status & SMB_RCS) { + /* Disable FIFO mode to clear left count */ + sdfpctl = sys_read8(config->target_base + SMB_SnDFPCTL); + sys_write8(sdfpctl & ~SMB_SADFE, config->target_base + SMB_SnDFPCTL); + /* Target n FIFO Enable */ + sdfpctl = sys_read8(config->target_base + SMB_SnDFPCTL); + sys_write8(sdfpctl | SMB_SADFE, config->target_base + SMB_SnDFPCTL); + } else { + for (int i = 0; i < count; i++) { + /* Host transmitting, target receiving */ +#ifdef CONFIG_SOC_IT51526AW + data->target_in_buffer[i + data->w_index] = + sys_read8(config->i2cbase_mapping + SMB_SLDA(config->port)); +#else + data->target_in_buffer[i + data->w_index] = + sys_read8(config->target_base + SMB_SLDn); +#endif + } +#ifdef CONFIG_I2C_TARGET_BUFFER_MODE + /* Write data done callback function */ + if (target_cb->buf_write_received) { + target_cb->buf_write_received(data->target_cfg, + data->target_in_buffer, count); + } +#endif + } + + /* Transfer done callback function */ + if (target_cb->stop) { + target_cb->stop(data->target_cfg); + } + data->w_index = 0; + data->r_index = 0; + } + +done: + /* W/C */ +#ifdef CONFIG_SOC_IT51526AW + sys_write8(target_status, config->i2cbase_mapping + SMB_SLSTA(config->port)); +#else + sys_write8(target_status, config->target_base + SMB_SLSTn); +#endif +} + +static void target_i2c_isr_pio(const struct device *dev) +{ + const struct i2c_it51xxx_config *config = dev->config; + struct i2c_it51xxx_data *data = dev->data; + const struct i2c_target_callbacks *target_cb = data->target_cfg->callbacks; + int ret; + uint8_t target_status; + uint8_t val; + + target_status = sys_read8(config->target_base + SMB_SLSTn); + + /* Any error */ + if (target_status & SMB_STS) { + data->w_index = 0; + data->r_index = 0; + goto done; + } + if (target_status & SMB_SDS) { + if (target_status & SMB_RCS) { + /* Target shared FIFO mode */ + if (config->target_shared_fifo_mode) { + uint32_t len; + uint8_t *rdata = NULL; + uint8_t sndfpctl; + +#ifdef CONFIG_I2C_TARGET_BUFFER_MODE + /* Read data callback function */ + if (target_cb->buf_read_requested) { + target_cb->buf_read_requested(data->target_cfg, &rdata, + &len); + } +#endif + if (len > sizeof(data->target_shared_fifo)) { + LOG_ERR("I2CS ch%d: The length exceeds shared fifo size=%d", + config->port, sizeof(data->target_shared_fifo)); + } else { + memcpy(data->target_shared_fifo, rdata, len); + } + /* Target n FIFO enable */ + sndfpctl = sys_read8(config->target_base + SMB_SnDFPCTL); + sys_write8(sndfpctl | SMB_SADFE, + config->target_base + SMB_SnDFPCTL); + } else { + /* Host receiving, target transmitting */ + if (!data->r_index) { + if (target_cb->read_requested) { + target_cb->read_requested(data->target_cfg, &val); + } + } else { + if (target_cb->read_processed) { + target_cb->read_processed(data->target_cfg, &val); + } + } + /* Write data */ + sys_write8(val, config->target_base + SMB_SLDn); + /* Release clock pin */ + sys_write8(val, config->target_base + SMB_SLDn); + data->r_index++; + } + } else { + /* Host transmitting, target receiving */ + if (!data->w_index) { + if (target_cb->write_requested) { + target_cb->write_requested(data->target_cfg); + } + } + /* Read data */ + val = sys_read8(config->target_base + SMB_SLDn); + if (target_cb->write_received) { + ret = target_cb->write_received(data->target_cfg, val); + if (!ret) { + /* Release clock pin */ + val = sys_read8(config->target_base + SMB_SLDn); + } + } + + data->w_index++; + } + } + /* Stop condition, indicate stop condition detected. */ + if (target_status & SMB_SPDS) { + /* Transfer done callback function */ + if (target_cb->stop) { + target_cb->stop(data->target_cfg); + } + data->w_index = 0; + data->r_index = 0; + + if (config->target_shared_fifo_mode) { + uint8_t sdfpctl; + + /* Disable FIFO mode to clear left count */ + sdfpctl = sys_read8(config->target_base + SMB_SnDFPCTL); + sys_write8(sdfpctl & ~SMB_SADFE, config->target_base + SMB_SnDFPCTL); + } + } + +done: + sys_write8(sys_read8(config->target_base + SMB_SLVCTLn) | SMB_RSCS, + config->target_base + SMB_SLVCTLn); + + /* W/C */ +#ifdef CONFIG_SOC_IT51526AW + sys_write8(target_status, config->i2cbase_mapping + SMB_SLSTA(config->port)); +#else + sys_write8(target_status, config->target_base + SMB_SLSTn); +#endif +} + +static void target_i2c_isr(const struct device *dev) +{ + const struct i2c_it51xxx_config *config = dev->config; + + if (config->target_fifo_mode) { + target_i2c_isr_fifo(dev); + } else { + target_i2c_isr_pio(dev); + } +} +#endif /* CONFIG_I2C_TARGET */ + +static int i2c_parsing_return_value(const struct device *dev) +{ + const struct i2c_it51xxx_config *config = dev->config; + struct i2c_it51xxx_data *data = dev->data; + + if (!data->err) { + return 0; + } + + if (data->err == ETIMEDOUT) { + /* Connection timed out */ + LOG_ERR("I2C ch%d Address:0x%X Transaction time out.", config->port, + data->addr_16bit); + } else { + LOG_DBG("I2C ch%d Address:0x%X Host error bits message:", config->port, + data->addr_16bit); + /* Host error bits message*/ + if (data->err & HOSTA_TMOE) { + LOG_ERR("Time-out error: hardware time-out error."); + } + if (data->err & HOSTA_NACK) { + LOG_DBG("NACK error: device does not response ACK."); + } + if (data->err & HOSTA_FAIL) { + LOG_ERR("Fail: a processing transmission is killed."); + } + if (data->err & HOSTA_BSER) { + LOG_ERR("BUS error: SMBus has lost arbitration."); + } + } + + return -EIO; +} + +static int i2c_get_line_levels(const struct device *dev) +{ + const struct i2c_it51xxx_config *config = dev->config; + + return (sys_read8(config->host_base + SMB_SMBPCTL) & (SMB_HSMBDCS | SMB_HSMBCS)); +} + +static int i2c_is_busy(const struct device *dev) +{ + const struct i2c_it51xxx_config *config = dev->config; + + return (sys_read8(config->host_base + SMB_HOSTA) & (HOSTA_HOBY | HOSTA_ALL_WC_BIT)); +} + +static int i2c_bus_not_available(const struct device *dev) +{ + if (i2c_is_busy(dev) || (i2c_get_line_levels(dev) != SMB_LINE_IDLE)) { + return -EIO; + } + + return 0; +} + +static void i2c_reset(const struct device *dev) +{ + const struct i2c_it51xxx_config *config = dev->config; + + /* bit1, kill current transaction. */ + sys_write8(SMB_KILL, config->host_base + SMB_HOCTL); + sys_write8(0, config->host_base + SMB_HOCTL); + /* W/C host status register */ + sys_write8(HOSTA_ALL_WC_BIT, config->host_base + SMB_HOSTA); +} + +void i2c_r_last_byte(const struct device *dev) +{ + const struct i2c_it51xxx_config *config = dev->config; + struct i2c_it51xxx_data *data = dev->data; + uint8_t hoctl; + + /* + * bit5, The firmware shall write 1 to this bit + * when the next byte will be the last byte for i2c read. + */ + if ((data->msg->flags & I2C_MSG_STOP) && (data->ridx == data->msg->len - 1)) { + hoctl = sys_read8(config->host_base + SMB_HOCTL); + sys_write8(hoctl | SMB_LABY, config->host_base + SMB_HOCTL); + } +} + +void i2c_w2r_change_direction(const struct device *dev) +{ + const struct i2c_it51xxx_config *config = dev->config; + uint8_t hoctl2; + + /* I2C switch direction */ + if (sys_read8(config->host_base + SMB_HOCTL2) & I2C_SW_EN) { + i2c_r_last_byte(dev); + sys_write8(SMB_BDS, config->host_base + SMB_HOSTA); + } else { + hoctl2 = sys_read8(config->host_base + SMB_HOCTL2); + sys_write8(hoctl2 | I2C_SW_EN | I2C_SW_WAIT, config->host_base + SMB_HOCTL2); + + sys_write8(SMB_BDS, config->host_base + SMB_HOSTA); + i2c_r_last_byte(dev); + + hoctl2 = sys_read8(config->host_base + SMB_HOCTL2); + sys_write8(hoctl2 & ~I2C_SW_WAIT, config->host_base + SMB_HOCTL2); + } +} + +int i2c_tran_read(const struct device *dev) +{ + const struct i2c_it51xxx_config *config = dev->config; + struct i2c_it51xxx_data *data = dev->data; + + if (data->msg->flags & SMB_MSG_START) { + /* I2C enable */ + sys_write8(SMB_SMD_TO_EN | I2C_EN | SMB_SMH_EN, config->host_base + SMB_HOCTL2); + + sys_write8((uint8_t)(data->addr_16bit << 1) | SMB_DIR, + config->host_base + SMB_TRASLA); + /* Clear start flag */ + data->msg->flags &= ~SMB_MSG_START; + + if ((data->msg->len == 1) && (data->msg->flags & I2C_MSG_STOP)) { + sys_write8(SMB_SRT | SMB_LABY | SMB_SMCD(7) | SMB_INTREN, + config->host_base + SMB_HOCTL); + } else { + sys_write8(SMB_SRT | SMB_SMCD(7) | SMB_INTREN, + config->host_base + SMB_HOCTL); + } + } else { + if ((data->i2ccs == I2C_CH_REPEAT_START) || (data->i2ccs == I2C_CH_WAIT_READ)) { + if (data->i2ccs == I2C_CH_REPEAT_START) { + /* Write to read */ + i2c_w2r_change_direction(dev); + } else { + /* For last byte */ + i2c_r_last_byte(dev); + /* W/C for next byte */ + sys_write8(SMB_BDS, config->host_base + SMB_HOSTA); + } + data->i2ccs = I2C_CH_NORMAL; + } else if (sys_read8(config->host_base + SMB_HOSTA) & SMB_BDS) { + if (data->ridx < data->msg->len) { + /* To get received data. */ + *(data->msg->buf++) = sys_read8(config->host_base + SMB_HOBDB); + data->ridx++; + /* For last byte */ + i2c_r_last_byte(dev); + /* Done */ + if (data->ridx == data->msg->len) { + data->msg->len = 0; + if (data->msg->flags & I2C_MSG_STOP) { + /* W/C for finish */ + sys_write8(SMB_BDS, config->host_base + SMB_HOSTA); + + data->stop = 1; + } else { + data->i2ccs = I2C_CH_WAIT_READ; + return 0; + } + } else { + /* W/C for next byte */ + sys_write8(SMB_BDS, config->host_base + SMB_HOSTA); + } + } + } + } + + return 1; +} + +int i2c_tran_write(const struct device *dev) +{ + const struct i2c_it51xxx_config *config = dev->config; + struct i2c_it51xxx_data *data = dev->data; + + if (data->msg->flags & SMB_MSG_START) { + /* I2C enable */ + sys_write8(SMB_SMD_TO_EN | I2C_EN | SMB_SMH_EN, config->host_base + SMB_HOCTL2); + + sys_write8((uint8_t)(data->addr_16bit << 1), config->host_base + SMB_TRASLA); + /* Send first byte */ + sys_write8(*(data->msg->buf++), config->host_base + SMB_HOBDB); + + data->widx++; + /* Clear start flag */ + data->msg->flags &= ~SMB_MSG_START; + + sys_write8(SMB_SRT | SMB_SMCD(7) | SMB_INTREN, config->host_base + SMB_HOCTL); + } else { + /* Host has completed the transmission of a byte */ + if (sys_read8(config->host_base + SMB_HOSTA) & SMB_BDS) { + if (data->widx < data->msg->len) { + /* Send next byte */ + sys_write8(*(data->msg->buf++), config->host_base + SMB_HOBDB); + + data->widx++; + /* W/C byte done for next byte */ + sys_write8(SMB_BDS, config->host_base + SMB_HOSTA); + + if (data->i2ccs == I2C_CH_REPEAT_START) { + data->i2ccs = I2C_CH_NORMAL; + } + } else { + /* Done */ + data->msg->len = 0; + if (data->msg->flags & I2C_MSG_STOP) { + /* Set I2C_EN = 0 */ + sys_write8(SMB_SMD_TO_EN | SMB_SMH_EN, + config->host_base + SMB_HOCTL2); + /* W/C byte done for finish */ + sys_write8(SMB_BDS, config->host_base + SMB_HOSTA); + + data->stop = 1; + } else { + data->i2ccs = I2C_CH_REPEAT_START; + return 0; + } + } + } + } + + return 1; +} + +int i2c_pio_transaction(const struct device *dev) +{ + const struct i2c_it51xxx_config *config = dev->config; + struct i2c_it51xxx_data *data = dev->data; + + /* Any error */ + if (sys_read8(config->host_base + SMB_HOSTA) & HOSTA_ANY_ERROR) { + data->err = sys_read8(config->host_base + SMB_HOSTA) & HOSTA_ANY_ERROR; + } else { + if (!data->stop) { + /* + * The return value indicates if there is more data to be read or written. + * If the return value = 1, it means that the interrupt cannot be disable + * and continue to transmit data. + */ + if (data->msg->flags & I2C_MSG_READ) { + return i2c_tran_read(dev); + } else { + return i2c_tran_write(dev); + } + } + /* Wait finish */ + if (!(sys_read8(config->host_base + SMB_HOSTA) & SMB_FINTR)) { + return 1; + } + } + /* W/C */ + sys_write8(HOSTA_ALL_WC_BIT, config->host_base + SMB_HOSTA); + + /* Disable the SMBus host interface */ + sys_write8(0, config->host_base + SMB_HOCTL2); + + data->stop = 0; + /* Done doing work */ + return 0; +} + +#ifdef CONFIG_I2C_IT51XXX_FIFO_MODE +void i2c_fifo_en_w2r(const struct device *dev, bool enable) +{ + const struct i2c_it51xxx_config *config = dev->config; + unsigned int key = irq_lock(); + uint8_t i2cw2rf; + + i2cw2rf = sys_read8(config->host_base + SMB_I2CW2RF); + + if (enable) { + sys_write8(i2cw2rf | SMB_MAIF | SMB_MAIFI, config->host_base + SMB_I2CW2RF); + + } else { + sys_write8(i2cw2rf & ~(SMB_MAIF | SMB_MAIFI), config->host_base + SMB_I2CW2RF); + } + + irq_unlock(key); +} + +void i2c_tran_fifo_write_start(const struct device *dev) +{ + const struct i2c_it51xxx_config *config = dev->config; + struct i2c_it51xxx_data *data = dev->data; + uint32_t i; + uint8_t fifo_en; + + /* Clear start flag. */ + data->msg->flags &= ~SMB_MSG_START; + + fifo_en = (config->port == SMB_CHANNEL_A) ? SMB_FF1EN : SMB_FF2EN; + /* Enable SMB channel in FIFO mode. */ + sys_write8(sys_read8(config->i2cbase + SMB_MSTFCSTS) | fifo_en, + config->i2cbase + SMB_MSTFCSTS); + + /* I2C enable. */ + sys_write8(SMB_SMD_TO_EN | I2C_EN | SMB_SMH_EN, config->host_base + SMB_HOCTL2); + /* Set write byte counts. */ + sys_write8(data->msg->len, config->host_base + SMB_D0REG); + /* Set transmit target address */ + sys_write8((uint8_t)(data->addr_16bit << 1), config->host_base + SMB_TRASLA); + + /* The maximum fifo size is 32 bytes. */ + data->bytecnt = MIN(data->msg->len, SMB_FIFO_MODE_MAX_SIZE); + for (i = 0; i < data->bytecnt; i++) { + /* Set host block data byte. */ + sys_write8(*(data->msg->buf++), config->host_base + SMB_HOBDB); + } + /* Calculate the remaining byte counts. */ + data->bytecnt = data->msg->len - data->bytecnt; + + /* Set host control */ + sys_write8(SMB_SRT | SMB_SMCD(7) | SMB_INTREN, config->host_base + SMB_HOCTL); +} + +void i2c_tran_fifo_write_next_block(const struct device *dev) +{ + const struct i2c_it51xxx_config *config = dev->config; + struct i2c_it51xxx_data *data = dev->data; + uint32_t i, _bytecnt; + uint8_t blkds; + + blkds = (config->port == SMB_CHANNEL_A) ? SMB_BLKDS1 : SMB_BLKDS2; + + /* The maximum fifo size is 32 bytes. */ + _bytecnt = MIN(data->bytecnt, SMB_FIFO_MODE_MAX_SIZE); + for (i = 0; i < _bytecnt; i++) { + /* Set host block data byte. */ + sys_write8(*(data->msg->buf++), config->host_base + SMB_HOBDB); + } + + /* Clear FIFO block done status. */ +#ifdef CONFIG_SOC_IT51526AW + uint8_t mstfctrl; + + mstfctrl = (config->port == SMB_CHANNEL_A) ? SMB_MSTFCTRL1 : SMB_MSTFCTRL2; + sys_write8(sys_read8(config->i2cbase_mapping + mstfctrl) | SMB_BLKDS, + config->i2cbase_mapping + mstfctrl); +#else + sys_write8(sys_read8(config->i2cbase + SMB_MSTFCSTS) | blkds, + config->i2cbase + SMB_MSTFCSTS); +#endif + /* Calculate the remaining byte counts. */ + data->bytecnt -= _bytecnt; +} + +void i2c_tran_fifo_write_finish(const struct device *dev) +{ + const struct i2c_it51xxx_config *config = dev->config; + + /* Clear byte count register. */ + sys_write8(0, config->host_base + SMB_D0REG); + /* W/C */ + sys_write8(HOSTA_ALL_WC_BIT, config->host_base + SMB_HOSTA); + /* Disable the SMBus host interface. */ + sys_write8(0, config->host_base + SMB_HOCTL2); +} + +int i2c_tran_fifo_w2r_change_direction(const struct device *dev) +{ + const struct i2c_it51xxx_config *config = dev->config; + struct i2c_it51xxx_data *data = dev->data; + uint8_t hoctl2; + + if (++data->msg_index >= data->num_msgs) { + LOG_ERR("%s: Current message index is error.", dev->name); + data->err = EINVAL; + /* W/C */ + sys_write8(HOSTA_ALL_WC_BIT, config->host_base + SMB_HOSTA); + /* Disable the SMBus host interface. */ + sys_write8(0, config->host_base + SMB_HOCTL2); + + return 0; + } + + /* Set I2C_SW_EN = 1 */ + hoctl2 = sys_read8(config->host_base + SMB_HOCTL2); + sys_write8(hoctl2 | I2C_SW_EN | I2C_SW_WAIT, config->host_base + SMB_HOCTL2); + + hoctl2 = sys_read8(config->host_base + SMB_HOCTL2); + sys_write8(hoctl2 & ~I2C_SW_WAIT, config->host_base + SMB_HOCTL2); + + /* Point to the next msg for the read location. */ + data->msg = &data->msgs_list[data->msg_index]; + /* Set read byte counts. */ + sys_write8(data->msg->len, config->host_base + SMB_D0REG); + data->bytecnt = data->msg->len; + + /* W/C I2C W2R FIFO interrupt status. */ + sys_write8(sys_read8(config->host_base + SMB_I2CW2RF) | SMB_MAIFID, + config->host_base + SMB_I2CW2RF); + + return 1; +} + +void i2c_tran_fifo_read_start(const struct device *dev) +{ + const struct i2c_it51xxx_config *config = dev->config; + struct i2c_it51xxx_data *data = dev->data; + uint8_t fifo_en; + + /* Clear start flag. */ + data->msg->flags &= ~SMB_MSG_START; + + fifo_en = (config->port == SMB_CHANNEL_A) ? SMB_FF1EN : SMB_FF2EN; + /* Enable SMB channel in FIFO mode. */ + sys_write8(sys_read8(config->i2cbase + SMB_MSTFCSTS) | fifo_en, + config->i2cbase + SMB_MSTFCSTS); + + data->bytecnt = data->msg->len; + + /* I2C enable. */ + sys_write8(SMB_SMD_TO_EN | I2C_EN | SMB_SMH_EN, config->host_base + SMB_HOCTL2); + /* Set read byte counts. */ + sys_write8(data->msg->len, config->host_base + SMB_D0REG); + /* Set transmit target address */ + sys_write8((uint8_t)(data->addr_16bit << 1) | SMB_DIR, config->host_base + SMB_TRASLA); + /* Set host control */ + sys_write8(SMB_SRT | SMB_SMCD(7) | SMB_INTREN, config->host_base + SMB_HOCTL); +} + +void i2c_tran_fifo_read_next_block(const struct device *dev) +{ + const struct i2c_it51xxx_config *config = dev->config; + struct i2c_it51xxx_data *data = dev->data; + uint32_t i; + uint8_t blkds; + + blkds = (config->port == SMB_CHANNEL_A) ? SMB_BLKDS1 : SMB_BLKDS2; + + for (i = 0; i < SMB_FIFO_MODE_MAX_SIZE; i++) { + /* To get received data. */ + *(data->msg->buf++) = sys_read8(config->host_base + SMB_HOBDB); + } + /* Clear FIFO block done status. */ + sys_write8(sys_read8(config->i2cbase + SMB_MSTFCSTS) | blkds, + config->i2cbase + SMB_MSTFCSTS); + + /* Calculate the remaining byte counts. */ + data->bytecnt -= SMB_FIFO_MODE_MAX_SIZE; +} + +void i2c_tran_fifo_read_finish(const struct device *dev) +{ + const struct i2c_it51xxx_config *config = dev->config; + struct i2c_it51xxx_data *data = dev->data; + uint32_t i; + + for (i = 0; i < data->bytecnt; i++) { + /* To get received data. */ + *(data->msg->buf++) = sys_read8(config->host_base + SMB_HOBDB); + } + /* Clear byte count register. */ + sys_write8(0, config->host_base + SMB_D0REG); + /* W/C */ + sys_write8(HOSTA_ALL_WC_BIT, config->host_base + SMB_HOSTA); + /* Disable the SMBus host interface. */ + sys_write8(0, config->host_base + SMB_HOCTL2); +} + +int i2c_tran_fifo_write_to_read(const struct device *dev) +{ + const struct i2c_it51xxx_config *config = dev->config; + struct i2c_it51xxx_data *data = dev->data; + int ret = 1; + uint8_t blkds; + + blkds = (config->port == SMB_CHANNEL_A) ? SMB_BLKDS1 : SMB_BLKDS2; + + if (data->msg->flags & SMB_MSG_START) { + /* Enable I2C write to read FIFO mode. */ + i2c_fifo_en_w2r(dev, true); + i2c_tran_fifo_write_start(dev); + } else { + /* Check block done status. */ + if (sys_read8(config->i2cbase + SMB_MSTFCSTS) & blkds) { + if (sys_read8(config->host_base + SMB_HOCTL2) & I2C_SW_EN) { + i2c_tran_fifo_read_next_block(dev); + } else { + i2c_tran_fifo_write_next_block(dev); + } + } else if (sys_read8(config->host_base + SMB_I2CW2RF) & SMB_MAIFID) { + /* + * This function returns 0 on a failure to indicate that the current + * transaction is completed and returned the data->err. + */ + ret = i2c_tran_fifo_w2r_change_direction(dev); + } else { + /* Wait finish. */ + if (sys_read8(config->host_base + SMB_HOSTA) & HOSTA_FINTR) { + i2c_tran_fifo_read_finish(dev); + /* Done doing work. */ + ret = 0; + } + } + } + + return ret; +} + +int i2c_tran_fifo_read(const struct device *dev) +{ + const struct i2c_it51xxx_config *config = dev->config; + struct i2c_it51xxx_data *data = dev->data; + uint8_t blkds; + + blkds = (config->port == SMB_CHANNEL_A) ? SMB_BLKDS1 : SMB_BLKDS2; + + if (data->msg->flags & SMB_MSG_START) { + i2c_tran_fifo_read_start(dev); + } else { + /* Check block done status. */ + if (sys_read8(config->i2cbase + SMB_MSTFCSTS) & blkds) { + i2c_tran_fifo_read_next_block(dev); + } else { + /* Wait finish. */ + if (sys_read8(config->host_base + SMB_HOSTA) & HOSTA_FINTR) { + i2c_tran_fifo_read_finish(dev); + /* Done doing work. */ + return 0; + } + } + } + + return 1; +} + +int i2c_tran_fifo_write(const struct device *dev) +{ + const struct i2c_it51xxx_config *config = dev->config; + struct i2c_it51xxx_data *data = dev->data; + uint8_t blkds; + + blkds = (config->port == SMB_CHANNEL_A) ? SMB_BLKDS1 : SMB_BLKDS2; + + if (data->msg->flags & SMB_MSG_START) { + i2c_tran_fifo_write_start(dev); + } else { + /* Check block done status. */ + if (sys_read8(config->i2cbase + SMB_MSTFCSTS) & blkds) { + i2c_tran_fifo_write_next_block(dev); + } else { + /* Wait finish. */ + if (sys_read8(config->host_base + SMB_HOSTA) & HOSTA_FINTR) { + i2c_tran_fifo_write_finish(dev); + /* Done doing work. */ + return 0; + } + } + } + + return 1; +} + +int i2c_fifo_transaction(const struct device *dev) +{ + const struct i2c_it51xxx_config *config = dev->config; + struct i2c_it51xxx_data *data = dev->data; + + /* Any error. */ + if (sys_read8(config->host_base + SMB_HOSTA) & HOSTA_ANY_ERROR) { + data->err = (sys_read8(config->host_base + SMB_HOSTA) & HOSTA_ANY_ERROR); + } else { + if (data->num_msgs == 2) { + return i2c_tran_fifo_write_to_read(dev); + } else if (data->msg->flags & I2C_MSG_READ) { + return i2c_tran_fifo_read(dev); + } else { + return i2c_tran_fifo_write(dev); + } + } + /* W/C */ + sys_write8(HOSTA_ALL_WC_BIT, config->host_base + SMB_HOSTA); + /* Disable the SMBus host interface. */ + sys_write8(0, config->host_base + SMB_HOCTL2); + + return 0; +} + +static void i2c_it51xxx_isr(const void *arg) +{ + const struct device *dev = arg; + const struct i2c_it51xxx_config *config = dev->config; + struct i2c_it51xxx_data *data = dev->data; + +#ifdef CONFIG_I2C_TARGET + if (data->target_attached) { + target_i2c_isr(dev); + } else { +#endif +#ifdef CONFIG_I2C_IT51XXX_FIFO_MODE + uint8_t fifo_en; + + fifo_en = (config->port == SMB_CHANNEL_A) ? SMB_FF1EN : SMB_FF2EN; + /* If done doing work, wake up the task waiting for the transfer. */ + if (config->fifo_enable && (sys_read8(config->i2cbase + SMB_MSTFCSTS) & fifo_en)) { + if (i2c_fifo_transaction(dev)) { + return; + } + } else { +#endif + if (i2c_pio_transaction(dev)) { + return; + } +#ifdef CONFIG_I2C_IT51XXX_FIFO_MODE + } +#endif + irq_disable(config->i2c_irq_base); + k_sem_give(&data->device_sync_sem); +#ifdef CONFIG_I2C_TARGET + } +#endif +} + +bool fifo_mode_allowed(const struct device *dev, struct i2c_msg *msgs) +{ + const struct i2c_it51xxx_config *config = dev->config; + struct i2c_it51xxx_data *data = dev->data; + + /* + * If the transaction of write or read is divided into two transfers(not two messages), + * the FIFO mode does not support. + */ + if (data->i2ccs != I2C_CH_NORMAL) { + return false; + } + /* + * FIFO2 only supports one channel of B or C. If the FIFO of channel is not enabled, + * it will select PIO mode. + */ + if (!config->fifo_enable) { + return false; + } + /* + * When there is only one message, use the FIFO mode transfer directly. + * Transfer payload too long (>255 bytes), use PIO mode. + * Write or read of I2C target address without data, used by cmd_i2c_scan. Use PIO mode. + */ + if (data->num_msgs == 1 && (msgs[0].flags & I2C_MSG_STOP) && + (msgs[0].len <= SMB_FIFO_MODE_TOTAL_LEN) && (msgs[0].len != 0)) { + return true; + } + /* + * When there are two messages, we need to judge whether or not there is I2C_MSG_RESTART + * flag from the second message, and then decide todo the FIFO mode or PIO mode transfer. + */ + if (data->num_msgs == 2) { + /* + * The first of two messages must be write. + * Transfer payload too long (>255 bytes), use PIO mode. + */ + if (((msgs[0].flags & I2C_MSG_RW_MASK) == I2C_MSG_WRITE) && + (msgs[0].len <= SMB_FIFO_MODE_TOTAL_LEN)) { + /* + * The transfer is i2c_burst_read(). + * + * e.g. msg[0].flags = I2C_MSG_WRITE; + * msg[1].flags = I2C_MSG_RESTART | I2C_MSG_READ | + * I2C_MSG_STOP; + */ + if ((msgs[1].flags == SMB_MSG_BURST_READ_MASK) && + (msgs[1].len <= SMB_FIFO_MODE_TOTAL_LEN)) { + return true; + } + } + } + + return false; +} +#endif /* CONFIG_I2C_IT51XXX_FIFO_MODE */ + +static void i2c_standard_port_timing_regs_400khz(const struct device *dev) +{ + const struct i2c_it51xxx_config *config = dev->config; + + /* Port clock frequency depends on setting of timing registers. */ + sys_write8(0, config->host_base + SMB_MSCLKTS); + /* Suggested setting of timing registers of 400kHz. */ + sys_write8(0x05, config->host_base + SMB_4P7USL); + sys_write8(0x01, config->host_base + SMB_4P0USL); + sys_write8(0x03, config->host_base + SMB_250NSREG); + sys_write8(0xc9, config->host_base + SMB_45P3USLREG); + sys_write8(0x01, config->host_base + SMB_45P3USHREG); + sys_write8(0x00, config->host_base + SMB_4P7A4P0H); +} + +static void i2c_standard_port_set_frequency(const struct device *dev, int freq_hz, int freq_set) +{ + const struct i2c_it51xxx_config *config = dev->config; + uint8_t honacksrc; + + /* + * If port's clock frequency is 400kHz, we use timing registers for setting. So we can + * adjust tlow to meet timing. The others use basic 50/100/1000 KHz setting. + */ + if (freq_hz == I2C_BITRATE_FAST) { + i2c_standard_port_timing_regs_400khz(dev); + } else { + sys_write8(freq_set, config->host_base + SMB_MSCLKTS); + } + + /* Host SMCLK & SMDAT timeout disable */ + honacksrc = sys_read8(config->host_base + SMB_HONACKSRC); + sys_write8(honacksrc | SMB_HSMCDTD, config->host_base + SMB_HONACKSRC); +} + +static int i2c_it51xxx_configure(const struct device *dev, uint32_t dev_config_raw) +{ + const struct i2c_it51xxx_config *config = dev->config; + struct i2c_it51xxx_data *const data = dev->data; + uint32_t freq_set; + + if (!(I2C_MODE_CONTROLLER & dev_config_raw)) { + return -EINVAL; + } + + if (I2C_ADDR_10_BITS & dev_config_raw) { + return -ENOTSUP; + } + + data->bus_freq = I2C_SPEED_GET(dev_config_raw); + + switch (data->bus_freq) { + case I2C_SPEED_DT: + freq_set = SMB_CLKS_50K; + break; + case I2C_SPEED_STANDARD: + freq_set = SMB_CLKS_100K; + break; + case I2C_SPEED_FAST: + freq_set = SMB_CLKS_400K; + break; + case I2C_SPEED_FAST_PLUS: + freq_set = SMB_CLKS_1M; + break; + default: + return -EINVAL; + } + + i2c_standard_port_set_frequency(dev, config->bitrate, freq_set); + + return 0; +} + +static int i2c_it51xxx_get_config(const struct device *dev, uint32_t *dev_config) +{ + struct i2c_it51xxx_data *const data = dev->data; + uint32_t speed; + + if (!data->bus_freq) { + LOG_ERR("The bus frequency is not initially configured."); + return -EIO; + } + + switch (data->bus_freq) { + case I2C_SPEED_DT: + case I2C_SPEED_STANDARD: + case I2C_SPEED_FAST: + case I2C_SPEED_FAST_PLUS: + speed = I2C_SPEED_SET(data->bus_freq); + break; + default: + return -ERANGE; + } + + *dev_config = (I2C_MODE_CONTROLLER | speed); + + return 0; +} + +static int i2c_it51xxx_transfer(const struct device *dev, struct i2c_msg *msgs, uint8_t num_msgs, + uint16_t addr) +{ + const struct i2c_it51xxx_config *config = dev->config; + struct i2c_it51xxx_data *data = dev->data; + int ret; + +#ifdef CONFIG_I2C_TARGET + if (data->target_attached) { + LOG_ERR("I2CS ch%d: Device is registered as target", config->port); + return -EBUSY; + } +#endif + /* Lock mutex of i2c controller */ + k_mutex_lock(&data->mutex, K_FOREVER); + /* + * If the transaction of write to read is divided into two transfers, the repeat start + * transfer uses this flag to exclude checking bus busy. + */ + if (data->i2ccs == I2C_CH_NORMAL) { + /* Make sure we're in a good state to start */ + if (i2c_bus_not_available(dev)) { + /* Recovery I2C bus */ + i2c_recover_bus(dev); + /* + * After resetting I2C bus, if I2C bus is not available + * (No external pull-up), drop the transaction. + */ + if (i2c_bus_not_available(dev)) { + /* Unlock mutex of i2c controller */ + k_mutex_unlock(&data->mutex); + return -EIO; + } + } + + msgs[0].flags |= SMB_MSG_START; + } + +#ifdef CONFIG_I2C_IT51XXX_FIFO_MODE + /* Store num_msgs to data struct. */ + data->num_msgs = num_msgs; + /* Store msgs to data struct. */ + data->msgs_list = msgs; + data->msg_index = 0; + + bool fifo_mode_enable = fifo_mode_allowed(dev, msgs); + + if (fifo_mode_enable) { +#ifdef CONFIG_PM + /* Block to enter power policy. */ + i2c_ite_pm_policy_state_lock_get(data, I2CM_ITE_PM_POLICY_FLAG); +#endif + } +#endif + for (int i = 0; i < num_msgs; i++) { + data->widx = 0; + data->ridx = 0; + data->err = 0; + data->msg = &msgs[i]; + data->addr_16bit = addr; + +#ifdef CONFIG_I2C_IT51XXX_FIFO_MODE + /* + * Start transaction. + * The return value indicates if the initial configuration + * of I2C transaction for read or write has been completed. + */ + if (fifo_mode_enable) { + if (i2c_fifo_transaction(dev)) { + /* Enable i2c interrupt */ + irq_enable(config->i2c_irq_base); + } + } else { +#endif + if (i2c_pio_transaction(dev)) { + /* Enable i2c interrupt */ + irq_enable(config->i2c_irq_base); + } +#ifdef CONFIG_I2C_IT51XXX_FIFO_MODE + } +#endif + /* Wait for the transfer to complete */ + ret = k_sem_take(&data->device_sync_sem, K_MSEC(config->transfer_timeout_ms)); + /* + * The irq will be enabled at the condition of start or repeat start of I2C. + * If timeout occurs without being wake up during suspend(ex: interrupt is not + * fired), the irq should be disabled immediately. + */ + irq_disable(config->i2c_irq_base); + /* + * The transaction is dropped on any error(timeout, NACK, fail,bus error, + * device error). + */ + if (data->err) { + break; + } + + if (ret != 0) { + data->err = ETIMEDOUT; + /* Reset i2c port */ + i2c_reset(dev); + LOG_ERR("I2C ch%d:0x%X reset cause %d", config->port, data->addr_16bit, + I2C_RC_TIMEOUT); + /* If this message is sent fail, drop the transaction. */ + break; + } + +#ifdef CONFIG_I2C_IT51XXX_FIFO_MODE + /* In FIFO mode, messages are compressed into a single transaction. */ + if (fifo_mode_enable) { + break; + } +#endif + } +#ifdef CONFIG_I2C_IT51XXX_FIFO_MODE + if (fifo_mode_enable) { + uint8_t fifo_en; + + fifo_en = (config->port == SMB_CHANNEL_A) ? SMB_FF1EN : SMB_FF2EN; + + /* Disable SMB channels in FIFO mode. */ + sys_write8(sys_read8(config->i2cbase + SMB_MSTFCSTS) & ~fifo_en, + config->i2cbase + SMB_MSTFCSTS); + + /* Disable I2C write to read FIFO mode. */ + if (data->num_msgs == 2) { + i2c_fifo_en_w2r(dev, false); + } +#ifdef CONFIG_PM + /* Permit to enter power policy. */ + i2c_ite_pm_policy_state_lock_put(data, I2CM_ITE_PM_POLICY_FLAG); +#endif + } +#endif + /* Reset i2c channel status */ + if (data->err || (data->msg->flags & I2C_MSG_STOP)) { + data->i2ccs = I2C_CH_NORMAL; + } + + /* Save return value. */ + ret = i2c_parsing_return_value(dev); + + /* Unlock mutex of i2c controller */ + k_mutex_unlock(&data->mutex); + + return ret; +} + +static void i2c_it51xxx_set_scl(void *io_context, int state) +{ + const struct i2c_it51xxx_config *config = io_context; + + gpio_pin_set_dt(&config->scl_gpios, state); +} + +static void i2c_it51xxx_set_sda(void *io_context, int state) +{ + const struct i2c_it51xxx_config *config = io_context; + + gpio_pin_set_dt(&config->sda_gpios, state); +} + +static int i2c_it51xxx_get_sda(void *io_context) +{ + const struct i2c_it51xxx_config *config = io_context; + int ret = gpio_pin_get_dt(&config->sda_gpios); + + /* Default high as that would be a NACK */ + return ret != 0; +} + +static const struct i2c_bitbang_io i2c_it51xxx_bitbang_io = { + .set_scl = i2c_it51xxx_set_scl, + .set_sda = i2c_it51xxx_set_sda, + .get_sda = i2c_it51xxx_get_sda, +}; + +static int i2c_it51xxx_recover_bus(const struct device *dev) +{ + const struct i2c_it51xxx_config *config = dev->config; + struct i2c_it51xxx_data *data = dev->data; + int ret; + + /* Output type selection */ + gpio_flags_t flags = GPIO_OUTPUT | (config->push_pull_recovery ? 0 : GPIO_OPEN_DRAIN); + /* Set SCL of I2C as GPIO pin */ + gpio_pin_configure_dt(&config->scl_gpios, flags); + /* Set SDA of I2C as GPIO pin */ + gpio_pin_configure_dt(&config->sda_gpios, flags); + + i2c_bitbang_init(&data->bitbang, &i2c_it51xxx_bitbang_io, (void *)config); + + ret = i2c_bitbang_recover_bus(&data->bitbang); + if (ret != 0) { + LOG_ERR("%s: Failed to recover bus (err %d)", dev->name, ret); + } + + /* Set GPIO back to I2C alternate function of SCL */ + ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); + if (ret < 0) { + LOG_ERR("%s: Failed to configure I2C pins", dev->name); + return ret; + } + + /* Reset i2c port */ + i2c_reset(dev); + LOG_ERR("I2C ch%d reset cause %d", config->port, I2C_RC_NO_IDLE_FOR_START); + + return 0; +} + +#ifdef CONFIG_I2C_TARGET +static int i2c_it51xxx_target_register(const struct device *dev, + struct i2c_target_config *target_cfg) +{ + const struct i2c_it51xxx_config *config = dev->config; + struct i2c_it51xxx_data *data = dev->data; + uint8_t slsta; + + if (!target_cfg) { + return -EINVAL; + } + + if (target_cfg->flags & I2C_TARGET_FLAGS_ADDR_10_BITS) { + return -ENOTSUP; + } + + if (data->target_attached) { + return -EBUSY; + } + + data->target_cfg = target_cfg; + data->target_attached = true; + + /* Target address[6:0] */ + sys_write8(target_cfg->address, config->target_base + SMB_RESLADR); + + /* Reset i2c port */ + i2c_reset(dev); + + /* W/C all target status */ + slsta = sys_read8(config->target_base + SMB_SLSTn); + sys_write8(slsta | SMB_SPDS | SMB_STS | SMB_SDS, config->target_base + SMB_SLSTn); + + if (config->target_shared_fifo_mode) { + uint32_t fifo_addr; + + memset(data->target_shared_fifo, 0, sizeof(data->target_shared_fifo)); + fifo_addr = (uint32_t)data->target_shared_fifo & GENMASK(23, 0); + /* Define shared FIFO base address bit[11:4] */ + sys_write8((fifo_addr >> 4) & GENMASK(7, 0), config->target_base + SMB_SFBASn); + /* Define shared FIFO base address bit[17:12] */ + sys_write8((fifo_addr >> 12) & GENMASK(5, 0), config->target_base + SMB_SFBAMSn); + /* Block to enter idle mode. */ + chip_block_idle(); + } +#ifdef CONFIG_PM + /* Block to enter power policy. */ + i2c_ite_pm_policy_state_lock_get(data, I2CS_ITE_PM_POLICY_FLAG); +#endif + /* Enable the SMBus target device. */ + sys_write8(sys_read8(config->target_base + SMB_SLVCTLn) | SMB_SLVEN, + config->target_base + SMB_SLVCTLn); + + ite_intc_isr_clear(config->i2cs_irq_base); + irq_enable(config->i2cs_irq_base); + + return 0; +} + +static int i2c_it51xxx_target_unregister(const struct device *dev, struct i2c_target_config *cfg) +{ + const struct i2c_it51xxx_config *config = dev->config; + struct i2c_it51xxx_data *data = dev->data; + + if (!data->target_attached) { + return -EINVAL; + } + + irq_disable(config->i2cs_irq_base); + +#ifdef CONFIG_PM + /* Permit to enter power policy. */ + i2c_ite_pm_policy_state_lock_put(data, I2CS_ITE_PM_POLICY_FLAG); +#endif + if (config->target_shared_fifo_mode) { + /* Permit to enter idle mode. */ + chip_permit_idle(); + } + + data->target_cfg = NULL; + data->target_attached = false; + + return 0; +} +#endif /* CONFIG_I2C_TARGET */ + +static DEVICE_API(i2c, i2c_it51xxx_driver_api) = { + .configure = i2c_it51xxx_configure, + .get_config = i2c_it51xxx_get_config, + .transfer = i2c_it51xxx_transfer, + .recover_bus = i2c_it51xxx_recover_bus, +#ifdef CONFIG_I2C_TARGET + .target_register = i2c_it51xxx_target_register, + .target_unregister = i2c_it51xxx_target_unregister, +#endif +#ifdef CONFIG_I2C_RTIO + .iodev_submit = i2c_iodev_submit_fallback, +#endif +}; + +static int i2c_it51xxx_init(const struct device *dev) +{ + struct i2c_it51xxx_data *data = dev->data; + const struct i2c_it51xxx_config *config = dev->config; + int error, status; + uint32_t bitrate_cfg; + uint8_t smbpctlr; + +#ifdef CONFIG_I2C_TARGET + uint8_t ssclkts; + + if (config->target_enable) { + if (config->target_fifo_mode) { + LOG_INF("I2CS ch%d: target_in_buffer=%p, target_out_buffer=%p\n", + config->port, data->target_in_buffer, data->target_out_buffer); + /* Target A or B or C FIFO Enable */ + sys_write8(sys_read8(config->target_base + SMB_SnDFPCTL) | SMB_SADFE, + config->target_base + SMB_SnDFPCTL); + } else if (config->target_shared_fifo_mode) { + uint8_t ssfifoc, target_fifo_size_val = 0; + + LOG_INF("I2CS ch%d: target_shared_fifo=%p\n", config->port, + data->target_shared_fifo); + + data->fifo_size_list = fifo_size_table; + for (int i = 0; i <= ARRAY_SIZE(fifo_size_table); i++) { + if (i == ARRAY_SIZE(fifo_size_table)) { + LOG_ERR("I2CS ch%d: Unsupported target FIFO size %d", + config->port, sizeof(data->target_shared_fifo)); + return -ENOTSUP; + } + + if (sizeof(data->target_shared_fifo) == + data->fifo_size_list[i].fifo_size) { + target_fifo_size_val = data->fifo_size_list[i].value; + break; + } + } + /* Shared FIFO size for target A, B, C */ + ssfifoc = sys_read8(config->target_base + SMB_SSFIFOCn); + sys_write8(ssfifoc | SMB_SFSFSA(target_fifo_size_val), + config->target_base + SMB_SSFIFOCn); + /* Shared FIFO for target enable */ + sys_write8(sys_read8(config->target_base + SMB_SSFIFOCn) | SMB_SFSAE, + config->target_base + SMB_SSFIFOCn); + } + + /* Target SMCLK & SMDAT timeout disable */ + sys_write8(sys_read8(config->target_base + SMB_SSCLKTSn) | SMB_SSMCDTD, + config->target_base + SMB_SSCLKTSn); + /* Target SMCLK 1MHz setting disable */ + sys_write8(sys_read8(config->target_base + SMB_SSCLKTSn) & ~SMB_SCLKSA1M, + config->target_base + SMB_SSCLKTSn); + /* Target channelA-C switch selection of interface */ + ssclkts = sys_read8(config->target_base + SMB_SSCLKTSn); + sys_write8((ssclkts & ~GENMASK(5, 2)) | SMB_DSASTI(config->channel_switch_sel), + config->target_base + SMB_SSCLKTSn); + + /* target interrupt control */ + sys_write8(SMB_SDSEN | SMB_SDLTOEN | SMB_SITEN, config->target_base + SMB_SICRn); + + irq_connect_dynamic(config->i2cs_irq_base, 0, i2c_it51xxx_isr, dev, 0); + + goto pin_config; + } +#endif + /* Initialize mutex and semaphore */ + k_mutex_init(&data->mutex); + k_sem_init(&data->device_sync_sem, 0, K_SEM_MAX_LIMIT); + + /* Enable SMBus function */ + sys_write8(SMB_SMD_TO_EN | SMB_SMH_EN, config->host_base + SMB_HOCTL2); + /* Kill SMBus host transaction. And enable the interrupt for the master interface */ + sys_write8(SMB_KILL | SMB_INTREN, config->host_base + SMB_HOCTL); + sys_write8(SMB_INTREN, config->host_base + SMB_HOCTL); + /* W/C host status register */ + sys_write8(HOSTA_ALL_WC_BIT, config->host_base + SMB_HOSTA); + sys_write8(0, config->host_base + SMB_HOCTL2); + + /* Set clock frequency for I2C ports */ + if (config->bitrate == I2C_BITRATE_STANDARD || config->bitrate == I2C_BITRATE_FAST || + config->bitrate == I2C_BITRATE_FAST_PLUS) { + bitrate_cfg = i2c_map_dt_bitrate(config->bitrate); + } else { + /* Device tree specified speed */ + bitrate_cfg = I2C_SPEED_DT << I2C_SPEED_SHIFT; + } + + /* Host channelA-I switch selection of interface */ + smbpctlr = sys_read8(config->host_base + SMB_SMBPCTL); + sys_write8((smbpctlr & ~GENMASK(7, 4)) | SMB_DASTI(config->channel_switch_sel), + config->host_base + SMB_SMBPCTL); + +#ifdef CONFIG_I2C_IT51XXX_FIFO_MODE + /* Select which port to use FIFO2 except port A */ + if ((config->port != SMB_CHANNEL_A) && config->fifo_enable) { + sys_write8(SMB_FFCHSEL2(config->port - 1), config->i2cbase + SMB_MSTFCSTS); + } +#endif + error = i2c_it51xxx_configure(dev, I2C_MODE_CONTROLLER | bitrate_cfg); + data->i2ccs = I2C_CH_NORMAL; + + if (error) { + LOG_ERR("%s: Host failure initializing", dev->name); + return error; + } + + irq_connect_dynamic(config->i2c_irq_base, 0, i2c_it51xxx_isr, dev, 0); + +#ifdef CONFIG_I2C_TARGET +pin_config: +#endif + /* Set the pin to I2C alternate function. */ + status = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); + if (status < 0) { + LOG_ERR("%s: Failed to configure I2C pins", dev->name); + return status; + } + + return 0; +} + +#define I2C_ITE_IT51XXX_INIT(inst) \ + PINCTRL_DT_INST_DEFINE(inst); \ + BUILD_ASSERT((DT_INST_PROP(inst, clock_frequency) == 50000) || \ + (DT_INST_PROP(inst, clock_frequency) == I2C_BITRATE_STANDARD) || \ + (DT_INST_PROP(inst, clock_frequency) == I2C_BITRATE_FAST) || \ + (DT_INST_PROP(inst, clock_frequency) == I2C_BITRATE_FAST_PLUS), \ + "Not support I2C bit rate value"); \ + \ + static const struct i2c_it51xxx_config i2c_it51xxx_cfg_##inst = { \ + .i2cbase = DT_REG_ADDR_BY_IDX(DT_NODELABEL(i2cbase), 0), \ + .i2cbase_mapping = DT_REG_ADDR_BY_IDX(DT_NODELABEL(i2cbase), 1), \ + .host_base = DT_INST_REG_ADDR_BY_IDX(inst, 0), \ + .target_base = DT_INST_REG_ADDR_BY_IDX(inst, 1), \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \ + .scl_gpios = GPIO_DT_SPEC_INST_GET(inst, scl_gpios), \ + .sda_gpios = GPIO_DT_SPEC_INST_GET(inst, sda_gpios), \ + .transfer_timeout_ms = DT_INST_PROP(inst, transfer_timeout_ms), \ + .bitrate = DT_INST_PROP(inst, clock_frequency), \ + .i2c_irq_base = DT_INST_IRQ_BY_IDX(inst, 0, irq), \ + .i2cs_irq_base = DT_INST_IRQ_BY_IDX(inst, 1, irq), \ + .port = DT_INST_PROP(inst, port_num), \ + .channel_switch_sel = DT_INST_PROP(inst, channel_switch_sel), \ + .fifo_enable = DT_INST_PROP(inst, fifo_enable), \ + .target_enable = DT_INST_PROP(inst, target_enable), \ + .target_fifo_mode = DT_INST_PROP(inst, target_fifo_mode), \ + .target_shared_fifo_mode = DT_INST_PROP(inst, target_shared_fifo_mode), \ + .push_pull_recovery = DT_INST_PROP(inst, push_pull_recovery), \ + }; \ + \ + static struct i2c_it51xxx_data i2c_it51xxx_data_##inst; \ + \ + I2C_DEVICE_DT_INST_DEFINE(inst, i2c_it51xxx_init, NULL, &i2c_it51xxx_data_##inst, \ + &i2c_it51xxx_cfg_##inst, POST_KERNEL, CONFIG_I2C_INIT_PRIORITY, \ + &i2c_it51xxx_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(I2C_ITE_IT51XXX_INIT) diff --git a/dts/bindings/i2c/ite,it51xxx-i2c.yaml b/dts/bindings/i2c/ite,it51xxx-i2c.yaml new file mode 100644 index 000000000000..ff88bd71b111 --- /dev/null +++ b/dts/bindings/i2c/ite,it51xxx-i2c.yaml @@ -0,0 +1,201 @@ +# Copyright (c) 2025 ITE Corporation. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 + +description: ITE it51xxx I2C + +compatible: "ite,it51xxx-i2c" + +include: [i2c-controller.yaml, pinctrl-device.yaml] + +properties: + reg: + required: true + + interrupts: + required: true + + pinctrl-0: + required: true + + pinctrl-names: + required: true + + scl-gpios: + type: phandle-array + required: true + description: | + The SCL pin for the selected port. + + sda-gpios: + type: phandle-array + required: true + description: | + The SDA pin for the selected port. + + transfer-timeout-ms: + type: int + default: 500 + description: | + Maximum time allowed for an I2C transfer. + + port-num: + type: int + required: true + enum: + - 0 + - 1 + - 2 + - 3 + - 4 + - 5 + - 6 + - 7 + - 8 + description: Ordinal identifying the port + 0 = SMB_CHANNEL_A, + 1 = SMB_CHANNEL_B, + 2 = SMB_CHANNEL_C, + 3 = SMB_CHANNEL_D, + 4 = SMB_CHANNEL_E, + 5 = SMB_CHANNEL_F, + 6 = SMB_CHANNEL_G, + 7 = SMB_CHANNEL_H, + 8 = SMB_CHANNEL_I, + + channel-switch-sel: + type: int + required: true + enum: + - 1 + - 2 + - 3 + - 4 + - 5 + - 6 + - 7 + - 8 + - 9 + - 10 + - 11 + - 12 + - 13 + description: | + The default setting is as described below + 1 = SMB_SWITCH_INTERFACE0: Switch to interface0 SMCLK0/SMDAT0 + 2 = SMB_SWITCH_INTERFACE1: Switch to interface1 SMCLK1/SMDAT1 + 3 = SMB_SWITCH_INTERFACE2: Switch to interface2 SMCLK2/SMDAT2 + 4 = SMB_SWITCH_INTERFACE3: Switch to interface3 SMCLK3/SMDAT3 + 5 = SMB_SWITCH_INTERFACE4: Switch to interface4 SMCLK4/SMDAT4 + 6 = SMB_SWITCH_INTERFACE5: Switch to interface5 SMCLK5/SMDAT5 + 7 = SMB_SWITCH_INTERFACE6: Switch to interface6 SMCLK6/SMDAT6 + 8 = SMB_SWITCH_INTERFACE7: Switch to interface7 SMCLK7/SMDAT7 + 9 = SMB_SWITCH_INTERFACE8: Switch to interface8 SMCLK8/SMDAT8 + 10 = SMB_SWITCH_INTERFACE9: Switch to interface9 SMCLK9/SMDAT9 + 11 = SMB_SWITCH_INTERFACE10: Switch to interface10 SMCLK10/SMDAT10 + 12 = SMB_SWITCH_INTERFACE11: Switch to interface11 SMCLK11/SMDAT11 + 13 = SMB_SWITCH_INTERFACE12: Switch to interface12 SMCLK12/SMDAT12 + + The following is an example of the 'channel-switch-sel' property + being swapped between node &i2c0 and &i2c2 in the application: + Note: The property of 'port-num' cannot be changed in the + application. + + If the property of 'channel-switch-sel' is changed, the pinctrl + setting and recovery pin in &i2c0 and &i2c2 nodes must also be + modified accordingly. + + Valid example(Host): + + Channel A switches to interface2: + &i2c0 { + status = "okay"; + pinctrl-0 = <&i2c2_clk_gpf6_default + &i2c2_data_gpf7_default>; + pinctrl-names = "default"; + scl-gpios = <&gpiof 6 0>; + sda-gpios = <&gpiof 7 0>; + channel-switch-sel = ; + }; + + Channel C switches to interface0: + &i2c2 { + status = "okay"; + pinctrl-0 = <&i2c0_clk_gpf2_default + &i2c0_data_gpf3_default>; + pinctrl-names = "default"; + scl-gpios = <&gpiof 2 0>; + sda-gpios = <&gpiof 3 0>; + channel-switch-sel = ; + }; + + Invalid example(Host): + + Channel A switches to interface2: + &i2c0 { + status = "okay"; + pinctrl-0 = <&i2c2_clk_gpf6_default + &i2c2_data_gpf7_default>; + pinctrl-names = "default"; + scl-gpios = <&gpiof 6 0>; + sda-gpios = <&gpiof 7 0>; + channel-switch-sel = ; + }; + + Channel C maintains the original configuration: + &i2c2 { + status = "okay"; + pinctrl-0 = <&i2c2_clk_gpf6_default + &i2c2_data_gpf7_default>; + pinctrl-names = "default"; + }; + + Valid example(Target): + + Channel A switches to interface5: + &i2c0 { + status = "okay"; + pinctrl-0 = <&i2c5_clk_gpa4_default + &i2c5_data_gpa5_default>; + pinctrl-names = "default"; + scl-gpios = <&gpioa 4 0>; + sda-gpios = <&gpioa 5 0>; + channel-switch-sel = ; + + target-enable; + i2c0_target: target@52 { + compatible = "ite,target-i2c"; + reg = <0x52>; + }; + }; + + target-enable: + type: boolean + description: | + This option is used when the I2C target is enabled. It is + necessary to prevent the target port from being configured + with I2C host related initialization. + + target-fifo-mode: + type: boolean + description: | + Only supports write or read mode and the maximum buffer size + is 256 bytes. Support dedicated FIFO mode 16 bytes. + + target-shared-fifo-mode: + type: boolean + description: | + This option is used to support non-FIFO write to shared FIFO + read mode. The maximum supported shared FIFO is 256 bytes. + + fifo-enable: + type: boolean + description: | + The I2C controller supports two 32-bytes FIFOs, + FIFO1 supports I2C port 0. FIFO2 only supports one port among + 1~8. The default is I2C port 1. + + push-pull-recovery: + type: boolean + description: | + This property is enabled when selecting the push-pull GPIO output + type to drive the I2C recovery. The default is open-drain. diff --git a/dts/riscv/ite/it51xxx-pinctrl-map.dtsi b/dts/riscv/ite/it51xxx-pinctrl-map.dtsi index f5bcaf53a238..d7f352c9950c 100644 --- a/dts/riscv/ite/it51xxx-pinctrl-map.dtsi +++ b/dts/riscv/ite/it51xxx-pinctrl-map.dtsi @@ -113,6 +113,39 @@ pinmuxs = <&pinctrlj 6 IT8XXX2_ALT_FUNC_4>; }; + /* I2C switch to interface */ + i2c9_clk_gpj3_default: i2c9_clk_gpj3_default { + pinmuxs = <&pinctrlj 3 IT8XXX2_ALT_FUNC_3>; + }; + + i2c9_data_gpj4_default: i2c9_data_gpj4_default { + pinmuxs = <&pinctrlj 4 IT8XXX2_ALT_FUNC_3>; + }; + + i2c10_clk_gpj5_default: i2c10_clk_gpj5_default { + pinmuxs = <&pinctrlj 5 IT8XXX2_ALT_FUNC_3>; + }; + + i2c10_data_gpe1_default: i2c10_data_gpe1_default { + pinmuxs = <&pinctrle 1 IT8XXX2_ALT_FUNC_3>; + }; + + i2c11_clk_gpe2_default: i2c11_clk_gpe2_default { + pinmuxs = <&pinctrle 2 IT8XXX2_ALT_FUNC_3>; + }; + + i2c11_data_gpe3_default: i2c11_data_gpe3_default { + pinmuxs = <&pinctrle 3 IT8XXX2_ALT_FUNC_3>; + }; + + i2c12_clk_gpf0_default: i2c12_clk_gpf0_default { + pinmuxs = <&pinctrlf 0 IT8XXX2_ALT_FUNC_3>; + }; + + i2c12_data_gpf1_default: i2c12_data_gpf1_default { + pinmuxs = <&pinctrlf 1 IT8XXX2_ALT_FUNC_3>; + }; + /* I3C alternate function */ i3c0_clk_gpj3_default: i3c0_clk_gpj3_default { pinmuxs = <&pinctrlj 3 IT8XXX2_ALT_FUNC_1>; diff --git a/dts/riscv/ite/it51xxx.dtsi b/dts/riscv/ite/it51xxx.dtsi index 3538a62be567..77db31daad53 100644 --- a/dts/riscv/ite/it51xxx.dtsi +++ b/dts/riscv/ite/it51xxx.dtsi @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include #include #include @@ -602,9 +604,9 @@ compatible = "ite,it8xxx2-pinctrl-func"; reg = <0x00f01630 8 /* GPCR */ NO_FUNC 1>; - func3-gcr = <0xf016f3 NO_FUNC NO_FUNC NO_FUNC + func3-gcr = <0xf016f3 0xf016ed 0xf016ed 0xf016ed NO_FUNC 0xf016f0 0xf016fe 0xf016fe>; - func3-en-mask = ; func4-gcr = <0xf016fe NO_FUNC NO_FUNC NO_FUNC NO_FUNC NO_FUNC 0xf016f5 NO_FUNC >; @@ -622,9 +624,9 @@ compatible = "ite,it8xxx2-pinctrl-func"; reg = <0x00f01638 8 /* GPCR */ NO_FUNC 1>; - func3-gcr = ; - func3-en-mask = <0 0 0 0 + func3-en-mask = ; func4-gcr = ; @@ -702,10 +704,10 @@ compatible = "ite,it8xxx2-pinctrl-func"; reg = <0x00f01658 8 /* GPCR */ NO_FUNC 1>; - func3-gcr = <0xf016f1 0xf016fe NO_FUNC NO_FUNC - NO_FUNC NO_FUNC 0xf016f4 0xf016d1>; - func3-en-mask = ; + func3-gcr = <0xf016f1 0xf016fe NO_FUNC 0xf016ed + 0xf016ed 0xf016ed 0xf016f4 0xf016d1>; + func3-en-mask = ; func4-gcr = ; func4-en-mask = <0 0 0 0 @@ -927,6 +929,165 @@ #wuc-cells = <1>; }; + i2cbase: i2cbase@f04100 { + compatible = "ite,it51xxx-i2cbase"; + reg = <0x00f04100 1 + 0x00f01c00 1>; + }; + + i2c0: i2c@f04100 { + compatible = "ite,it51xxx-i2c"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + reg = <0x00f04100 0x0028 + 0x00f04200 0x0020>; + interrupts = ; + interrupt-parent = <&intc>; + scl-gpios = <&gpiof 2 0>; + sda-gpios = <&gpiof 3 0>; + port-num = ; + channel-switch-sel = ; + fifo-enable; /* FIFO1 */ + }; + + i2c1: i2c@f04128 { + compatible = "ite,it51xxx-i2c"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + reg = <0x00f04128 0x0028 + 0x00f04220 0x0020>; + interrupts = ; + interrupt-parent = <&intc>; + scl-gpios = <&gpioc 1 0>; + sda-gpios = <&gpioc 2 0>; + port-num = ; + channel-switch-sel = ; + fifo-enable; /* FIFO2 */ + }; + + i2c2: i2c@f04150 { + compatible = "ite,it51xxx-i2c"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + reg = <0x00f04150 0x0028 + 0x00f04240 0x0020>; + interrupts = ; + interrupt-parent = <&intc>; + scl-gpios = <&gpiof 6 0>; + sda-gpios = <&gpiof 7 0>; + port-num = ; + channel-switch-sel = ; + /delete-property/ fifo-enable; /* FIFO2 */ + }; + + i2c3: i2c@f04178 { + compatible = "ite,it51xxx-i2c"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + reg = <0x00f04178 0x0028 + 0 1>; + interrupts = ; + interrupt-parent = <&intc>; + scl-gpios = <&gpioh 1 0>; + sda-gpios = <&gpioh 2 0>; + port-num = ; + channel-switch-sel = ; + /delete-property/ fifo-enable; /* FIFO2 */ + }; + + i2c4: i2c@f041a0 { + compatible = "ite,it51xxx-i2c"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + reg = <0x00f041a0 0x0028 + 0 1>; + interrupts = ; + interrupt-parent = <&intc>; + scl-gpios = <&gpioe 0 0>; + sda-gpios = <&gpioe 7 0>; + port-num = ; + channel-switch-sel = ; + /delete-property/ fifo-enable; /* FIFO2 */ + }; + + i2c5: i2c@f041c8 { + compatible = "ite,it51xxx-i2c"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + reg = <0x00f041c8 0x0028 + 0 1>; + interrupts = ; + interrupt-parent = <&intc>; + scl-gpios = <&gpioa 4 0>; + sda-gpios = <&gpioa 5 0>; + port-num = ; + channel-switch-sel = ; + /delete-property/ fifo-enable; /* FIFO2 */ + }; + + i2c6: i2c@f04260 { + compatible = "ite,it51xxx-i2c"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + reg = <0x00f04260 0x0028 + 0 1>; + interrupts = ; + interrupt-parent = <&intc>; + scl-gpios = <&gpiod 0 0>; + sda-gpios = <&gpiod 1 0>; + port-num = ; + channel-switch-sel = ; + /delete-property/ fifo-enable; /* FIFO2 */ + }; + + i2c7: i2c@f04288 { + compatible = "ite,it51xxx-i2c"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + reg = <0x00f04288 0x0028 + 0 1>; + interrupts = ; + interrupt-parent = <&intc>; + scl-gpios = <&gpiob 2 0>; + sda-gpios = <&gpioh 0 0>; + port-num = ; + channel-switch-sel = ; + /delete-property/ fifo-enable; /* FIFO2 */ + }; + + i2c8: i2c@f042b0 { + compatible = "ite,it51xxx-i2c"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + reg = <0x00f042b0 0x0028 + 0 1>; + interrupts = ; + interrupt-parent = <&intc>; + scl-gpios = <&gpiob 5 0>; + sda-gpios = <&gpioj 6 0>; + port-num = ; + channel-switch-sel = ; + /delete-property/ fifo-enable; /* FIFO2 */ + }; + ecpm: clock-controller@f01e00 { compatible = "ite,it51xxx-ecpm"; reg = <0x00f01e00 0x0a>; diff --git a/include/zephyr/dt-bindings/i2c/i2c.h b/include/zephyr/dt-bindings/i2c/i2c.h index 751eef2e54b9..419570c3aa5c 100644 --- a/include/zephyr/dt-bindings/i2c/i2c.h +++ b/include/zephyr/dt-bindings/i2c/i2c.h @@ -15,6 +15,12 @@ #define SMB_CHANNEL_A 0 #define SMB_CHANNEL_B 1 #define SMB_CHANNEL_C 2 +#define SMB_CHANNEL_D 3 +#define SMB_CHANNEL_E 4 +#define SMB_CHANNEL_F 5 +#define SMB_CHANNEL_G 6 +#define SMB_CHANNEL_H 7 +#define SMB_CHANNEL_I 8 #define I2C_CHANNEL_D 3 #define I2C_CHANNEL_E 4 #define I2C_CHANNEL_F 5 diff --git a/include/zephyr/dt-bindings/i2c/it51xxx-i2c.h b/include/zephyr/dt-bindings/i2c/it51xxx-i2c.h new file mode 100644 index 000000000000..10fe27d51652 --- /dev/null +++ b/include/zephyr/dt-bindings/i2c/it51xxx-i2c.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2025 ITE Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_I2C_IT51XXX_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_I2C_IT51XXX_H_ + +/* SMBus channel switch selection */ +#define SMB_SWITCH_INTERFACE0 1 +#define SMB_SWITCH_INTERFACE1 2 +#define SMB_SWITCH_INTERFACE2 3 +#define SMB_SWITCH_INTERFACE3 4 +#define SMB_SWITCH_INTERFACE4 5 +#define SMB_SWITCH_INTERFACE5 6 +#define SMB_SWITCH_INTERFACE6 7 +#define SMB_SWITCH_INTERFACE7 8 +#define SMB_SWITCH_INTERFACE8 9 +#define SMB_SWITCH_INTERFACE9 10 +#define SMB_SWITCH_INTERFACE10 11 +#define SMB_SWITCH_INTERFACE11 12 +#define SMB_SWITCH_INTERFACE12 13 + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_I2C_IT51XXX_H_ */ diff --git a/soc/ite/ec/it51xxx/chip_chipregs.h b/soc/ite/ec/it51xxx/chip_chipregs.h index 10f134295668..31c917e5d704 100644 --- a/soc/ite/ec/it51xxx/chip_chipregs.h +++ b/soc/ite/ec/it51xxx/chip_chipregs.h @@ -323,4 +323,16 @@ struct gctrl_it51xxx_regs { #define gctrl_ite_ec_regs gctrl_it51xxx_regs #define GCTRL_ITE_EC_REGS_BASE GCTRL_IT51XXX_REGS_BASE +/** + * + * (42xxh) SMBus Interface for target (SMB) registers + * + */ +#define IT51XXX_SMB_BASE 0xf04200 +/* 0x0a, 0x2a, 0x4a: Slave n Dedicated FIFO Pre-defined Control Register */ +#define SMB_SADFPCTL (IT51XXX_SMB_BASE + 0x0a) +#define SMB_SBDFPCTL (IT51XXX_SMB_BASE + 0x2a) +#define SMB_SCDFPCTL (IT51XXX_SMB_BASE + 0x4a) +#define SMB_HSAPE BIT(1) + #endif /* CHIP_CHIPREGS_H */ diff --git a/soc/ite/ec/it51xxx/soc.c b/soc/ite/ec/it51xxx/soc.c index df691a0784b6..657c31131ed4 100644 --- a/soc/ite/ec/it51xxx/soc.c +++ b/soc/ite/ec/it51xxx/soc.c @@ -116,4 +116,13 @@ void soc_prep_hook(void) /* Switch UART1 and UART2 on without hardware flow control */ gpio_regs->GPIO_GCR1 |= IT51XXX_GPIO_U1CTRL_SIN0_SOUT0_EN | IT51XXX_GPIO_U2CTRL_SIN1_SOUT1_EN; + + /* + * Disable this feature that can detect pre-define hardware target A, B, C through + * I2C0, I2C1, I2C2 respectively. This is for debugging use, so it can be disabled + * to avoid illegal access. + */ + sys_write8(sys_read8(SMB_SADFPCTL) & ~SMB_HSAPE, SMB_SADFPCTL); + sys_write8(sys_read8(SMB_SBDFPCTL) & ~SMB_HSAPE, SMB_SBDFPCTL); + sys_write8(sys_read8(SMB_SCDFPCTL) & ~SMB_HSAPE, SMB_SCDFPCTL); } diff --git a/tests/drivers/i2c/i2c_target_api/boards/it515xx_evb.conf b/tests/drivers/i2c/i2c_target_api/boards/it515xx_evb.conf new file mode 100644 index 000000000000..70e009fae68a --- /dev/null +++ b/tests/drivers/i2c/i2c_target_api/boards/it515xx_evb.conf @@ -0,0 +1 @@ +CONFIG_I2C_VIRTUAL=n diff --git a/tests/drivers/i2c/i2c_target_api/boards/it515xx_evb.overlay b/tests/drivers/i2c/i2c_target_api/boards/it515xx_evb.overlay new file mode 100644 index 000000000000..cf6ee240fdcd --- /dev/null +++ b/tests/drivers/i2c/i2c_target_api/boards/it515xx_evb.overlay @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2025 ITE Corporation. All Rights Reserved. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* Target */ +&i2c0 { + status = "okay"; + clock-frequency = ; + pinctrl-0 = <&i2c0_clk_gpf2_default + &i2c0_data_gpf3_default>; + pinctrl-names = "default"; + + target-enable; + target-shared-fifo-mode; + + eeprom0: eeprom@52 { + compatible = "zephyr,i2c-target-eeprom"; + reg = <0x52>; + size = <256>; + }; +}; + +&i2c1 { + /delete-property/ fifo-enable; /* FIFO2 */ +}; + +/* HOST */ +&i2c4 { + status = "okay"; + clock-frequency = ; + pinctrl-0 = <&i2c4_clk_gpe0_default + &i2c4_data_gpe7_default>; + pinctrl-names = "default"; + + fifo-enable; /* FIFO2 */ + + eeprom1: eeprom@54 { + compatible = "zephyr,i2c-target-eeprom"; + reg = <0x54>; + size = <256>; + }; +};