From 8993fea685d7178e31f848b5f7233fcf789917a7 Mon Sep 17 00:00:00 2001 From: Corey Wharton Date: Mon, 21 Oct 2024 16:01:49 -0700 Subject: [PATCH] drivers: i2c_dw: add devicetree property to offset clock settings The actual clock speed of the bus is partially determined by the rising/falling edges of the SCL. These settings allow applications to tune the clock based on board characteristics. Signed-off-by: Corey Wharton --- drivers/i2c/i2c_dw.c | 43 ++++++++++------------- drivers/i2c/i2c_dw.h | 2 ++ dts/bindings/i2c/snps,designware-i2c.yaml | 10 ++++++ 3 files changed, 31 insertions(+), 24 deletions(-) diff --git a/drivers/i2c/i2c_dw.c b/drivers/i2c/i2c_dw.c index 5d274dcf0adcd0..cb182dbe17f84c 100644 --- a/drivers/i2c/i2c_dw.c +++ b/drivers/i2c/i2c_dw.c @@ -739,6 +739,7 @@ static int i2c_dw_transfer(const struct device *dev, struct i2c_msg *msgs, uint8 static int i2c_dw_runtime_configure(const struct device *dev, uint32_t config) { struct i2c_dw_dev_config *const dw = dev->data; + const struct i2c_dw_rom_config *const rom = dev->config; uint32_t value = 0U; uint32_t rc = 0U; uint32_t reg_base = get_regs(dev); @@ -752,10 +753,9 @@ static int i2c_dw_runtime_configure(const struct device *dev, uint32_t config) /* Following the directions on DW spec page 59, IC_SS_SCL_LCNT * must have register values larger than IC_FS_SPKLEN + 7 */ - if (I2C_STD_LCNT <= (read_fs_spklen(reg_base) + 7)) { + value = I2C_STD_LCNT + rom->lcnt_offset; + if (value <= (read_fs_spklen(reg_base) + 7)) { value = read_fs_spklen(reg_base) + 8; - } else { - value = I2C_STD_LCNT; } dw->lcnt = value; @@ -763,10 +763,9 @@ static int i2c_dw_runtime_configure(const struct device *dev, uint32_t config) /* Following the directions on DW spec page 59, IC_SS_SCL_HCNT * must have register values larger than IC_FS_SPKLEN + 5 */ - if (I2C_STD_HCNT <= (read_fs_spklen(reg_base) + 5)) { + value = I2C_STD_HCNT + rom->hcnt_offset; + if (value <= (read_fs_spklen(reg_base) + 5)) { value = read_fs_spklen(reg_base) + 6; - } else { - value = I2C_STD_HCNT; } dw->hcnt = value; @@ -776,10 +775,9 @@ static int i2c_dw_runtime_configure(const struct device *dev, uint32_t config) * Following the directions on DW spec page 59, IC_FS_SCL_LCNT * must have register values larger than IC_FS_SPKLEN + 7 */ - if (I2C_FS_LCNT <= (read_fs_spklen(reg_base) + 7)) { + value = I2C_FS_LCNT + rom->lcnt_offset; + if (value <= (read_fs_spklen(reg_base) + 7)) { value = read_fs_spklen(reg_base) + 8; - } else { - value = I2C_FS_LCNT; } dw->lcnt = value; @@ -788,10 +786,9 @@ static int i2c_dw_runtime_configure(const struct device *dev, uint32_t config) * Following the directions on DW spec page 59, IC_FS_SCL_HCNT * must have register values larger than IC_FS_SPKLEN + 5 */ - if (I2C_FS_HCNT <= (read_fs_spklen(reg_base) + 5)) { + value = I2C_FS_HCNT + rom->hcnt_offset; + if (value <= (read_fs_spklen(reg_base) + 5)) { value = read_fs_spklen(reg_base) + 6; - } else { - value = I2C_FS_HCNT; } dw->hcnt = value; @@ -801,10 +798,9 @@ static int i2c_dw_runtime_configure(const struct device *dev, uint32_t config) * Following the directions on DW spec page 59, IC_FS_SCL_LCNT * must have register values larger than IC_FS_SPKLEN + 7 */ - if (I2C_FSP_LCNT <= (read_fs_spklen(reg_base) + 7)) { + value = I2C_FSP_LCNT + rom->lcnt_offset; + if (value <= (read_fs_spklen(reg_base) + 7)) { value = read_fs_spklen(reg_base) + 8; - } else { - value = I2C_FSP_LCNT; } dw->lcnt = value; @@ -813,28 +809,25 @@ static int i2c_dw_runtime_configure(const struct device *dev, uint32_t config) * Following the directions on DW spec page 59, IC_FS_SCL_HCNT * must have register values larger than IC_FS_SPKLEN + 5 */ - if (I2C_FSP_HCNT <= (read_fs_spklen(reg_base) + 5)) { + value = I2C_FSP_HCNT + rom->hcnt_offset; + if (value <= (read_fs_spklen(reg_base) + 5)) { value = read_fs_spklen(reg_base) + 6; - } else { - value = I2C_FSP_HCNT; } dw->hcnt = value; break; case I2C_SPEED_HIGH: if (dw->support_hs_mode) { - if (I2C_HS_LCNT <= (read_hs_spklen(reg_base) + 7)) { + value = I2C_HS_LCNT + rom->lcnt_offset; + if (value <= (read_hs_spklen(reg_base) + 7)) { value = read_hs_spklen(reg_base) + 8; - } else { - value = I2C_HS_LCNT; } dw->lcnt = value; - if (I2C_HS_HCNT <= (read_hs_spklen(reg_base) + 5)) { + value = I2C_HS_HCNT + rom->hcnt_offset; + if (value <= (read_hs_spklen(reg_base) + 5)) { value = read_hs_spklen(reg_base) + 6; - } else { - value = I2C_HS_HCNT; } dw->hcnt = value; @@ -1215,6 +1208,8 @@ static int i2c_dw_initialize(const struct device *dev) static const struct i2c_dw_rom_config i2c_config_dw_##n = { \ I2C_CONFIG_REG_INIT(n).config_func = i2c_config_##n, \ .bitrate = DT_INST_PROP(n, clock_frequency), \ + .lcnt_offset = (int16_t)DT_INST_PROP_OR(n, lcnt_offset, 0), \ + .hcnt_offset = (int16_t)DT_INST_PROP_OR(n, hcnt_offset, 0), \ RESET_DW_CONFIG(n) PINCTRL_DW_CONFIG(n) I2C_DW_INIT_PCIE(n) \ I2C_CONFIG_DMA_INIT(n)}; \ static struct i2c_dw_dev_config i2c_##n##_runtime; \ diff --git a/drivers/i2c/i2c_dw.h b/drivers/i2c/i2c_dw.h index 004cbb0a11076d..2a4f64cd86bdc7 100644 --- a/drivers/i2c/i2c_dw.h +++ b/drivers/i2c/i2c_dw.h @@ -84,6 +84,8 @@ struct i2c_dw_rom_config { DEVICE_MMIO_ROM; i2c_isr_cb_t config_func; uint32_t bitrate; + int16_t lcnt_offset; + int16_t hcnt_offset; #if defined(CONFIG_PINCTRL) const struct pinctrl_dev_config *pcfg; diff --git a/dts/bindings/i2c/snps,designware-i2c.yaml b/dts/bindings/i2c/snps,designware-i2c.yaml index 596558cec0b5f3..770ff98b5fc159 100644 --- a/dts/bindings/i2c/snps,designware-i2c.yaml +++ b/dts/bindings/i2c/snps,designware-i2c.yaml @@ -10,3 +10,13 @@ include: [i2c-controller.yaml, pinctrl-device.yaml, pcie-device.yaml] properties: interrupts: required: true + + lcnt-offset: + type: int + description: | + A fixed offset to apply to the SCL lcnt setting. + + hcnt-offset: + type: int + description: | + A fixed offset to apply to the SCL hcnt setting.