From aa3cce169737a07e636b8ec2ba6f0039a4438e76 Mon Sep 17 00:00:00 2001 From: Youngmin Nam Date: Sat, 4 Jul 2015 16:33:38 +0900 Subject: [PATCH] i2c: exynos5: Change HSI2C timing parameter setting routine This patch modifies HSI2C timing parameter setting routine following H/W guide. Change-Id: I10aa37c76dab1237a99ded8a7e8258c98f8a0c58 Signed-off-by: Youngmin Nam --- drivers/i2c/busses/i2c-exynos5.c | 35 ++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c index 1f22174d47f8..35ebbecc6a8d 100644 --- a/drivers/i2c/busses/i2c-exynos5.c +++ b/drivers/i2c/busses/i2c-exynos5.c @@ -404,6 +404,7 @@ static int exynos5_i2c_set_timing(struct exynos5_i2c *i2c, bool hs_timings) u32 i2c_timing_sla; unsigned int t_start_su, t_start_hd; unsigned int t_stop_su; + unsigned int t_sda_su; unsigned int t_data_su, t_data_hd; unsigned int t_scl_l, t_scl_h; unsigned int t_sr_release; @@ -414,15 +415,21 @@ static int exynos5_i2c_set_timing(struct exynos5_i2c *i2c, bool hs_timings) i2c->hs_clock : i2c->fs_clock; /* - * FPCLK / FI2C = - * (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2) + {(FLT_CYCLE + 3) % - * (CLK_DIV + 1)} * 2 + * FPCLK / FI2C = (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2) + + * {(FLT_CYCLE + 3) - (FLT_CYCLE + 3) % (CLK_DIV + 1)} * 2 */ t_ftl_cycle = (readl(i2c->regs + HSI2C_CONF) >> 16) & 0x7; + + /* + * utemp0 = (FPCLK / FI2C) - (FLT_CYCLE + 3) * 2 + */ utemp0 = (clkin / op_clk) - (t_ftl_cycle + 3) * 2; /* CLK_DIV max is 256 */ for (div = 0; div < 256; div++) { + /* + * utemp1 = (TSCLK_L + TSCLK_H + 2) + */ utemp1 = (utemp0 + ((t_ftl_cycle + 3) % (div + 1)) * 2) / (div + 1); if ((utemp1 < 512) && (utemp1 > 4)) { @@ -433,19 +440,29 @@ static int exynos5_i2c_set_timing(struct exynos5_i2c *i2c, bool hs_timings) return -EINVAL; } } - t_scl_l = clk_cycle / 2; - t_scl_h = clk_cycle / 2; + + if (mode == HSI2C_HIGH_SPD) + t_scl_h = ((clk_cycle + 10) / 3) - 5; + else + t_scl_h = clk_cycle / 2; + + t_scl_l = clk_cycle - t_scl_h; t_start_su = t_scl_l; t_start_hd = t_scl_l; t_stop_su = t_scl_l; + t_sda_su = t_scl_l; t_data_su = t_scl_l / 2; t_data_hd = t_scl_l / 2; t_sr_release = clk_cycle; - i2c_timing_s1 = t_start_su << 24 | t_start_hd << 16 | t_stop_su << 8; - i2c_timing_s2 = t_data_su << 24 | t_scl_l << 8 | t_scl_h << 0; - i2c_timing_s3 = div << 16 | t_sr_release << 0; - i2c_timing_sla = t_data_hd << 0; + if (mode == HSI2C_HIGH_SPD) + i2c_timing_s1 = t_start_su << 24 | t_start_hd << 16 | t_stop_su << 8 | t_sda_su; + else + i2c_timing_s1 = t_start_su << 24 | t_start_hd << 16 | t_stop_su << 8; + + i2c_timing_s2 = (0xF << 16) | t_data_su << 24 | t_scl_l << 8 | t_scl_h; + i2c_timing_s3 = (div << 16) | t_sr_release; + i2c_timing_sla = t_data_hd; dev_dbg(i2c->dev, "tSTART_SU: %X, tSTART_HD: %X, tSTOP_SU: %X\n", t_start_su, t_start_hd, t_stop_su); -- 2.20.1