Message ID | 1452774699-57455-4-git-send-email-david.wu@rock-chips.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Thu, Jan 14, 2016 at 2:31 PM, David Wu <david.wu@rock-chips.com> wrote: > There was an timing issue about "repeated start" time at the I2C > controller of version0, controller appears to drop SDA at .875x (7/8) > programmed clk high. The rule(.875x) isn't enough to meet tSU;STA > requirements on 100k's Standard-mode. To resolve this issue, > data_upd_st, start_setup_cnt and stop_setup_cnt configs for I2C > timing information are added, new rules are designed to calculate > the timing information at new v1. > --- a/drivers/i2c/busses/i2c-rk3x.c > +++ b/drivers/i2c/busses/i2c-rk3x.c > @@ -58,10 +58,15 @@ enum { > #define REG_CON_LASTACK BIT(5) /* 1: send NACK after last received byte */ > #define REG_CON_ACTACK BIT(6) /* 1: stop if NACK is received */ > > +#define REG_CON_SDA_CNT(cnt) ((cnt) << 8) > +#define REG_CON_STA_CNT(cnt) ((cnt) << 12) > +#define REG_CON_STO_CNT(cnt) ((cnt) << 14) > + > #define VERSION_MASK GENMASK(31, 16) > #define VERSION_SHIFT 16 > > #define RK3X_I2C_V0 0x0 > +#define RK3X_I2C_V1 0x1 > > /* REG_MRXADDR bits */ > #define REG_MRXADDR_VALID(x) BIT(24 + (x)) /* [x*8+7:x*8] of MRX[R]ADDR valid */ > @@ -99,10 +104,16 @@ struct rk3x_i2c_soc_data { > * struct rk3x_priv_i2c_timings - rk3x I2C timing information > * @div_low: Divider output for low > * @div_high: Divider output for high > + * @thd_sda_count: SDA update point config used to adjust sda setup/hold time > + * @tsu_sta_count: Start setup config for setup start time and hold start time > + * @tsu_sto_count: Stop setup config for setup stop time > */ > struct rk3x_priv_i2c_timings { > unsigned long div_low; > unsigned long div_high; > + unsigned int thd_sda_count; > + unsigned int tsu_sta_count; > + unsigned int tsu_sto_count; > }; And in this (or even separate) patch makes sense to introduce extension structure, which is struct rk3x_priv_i2c_timings. > struct rk3x_i2c_ops { > @@ -154,6 +165,13 @@ static inline u32 i2c_readl(struct rk3x_i2c *i2c, unsigned int offset) > return readl(i2c->regs + offset); > } > > +static inline u32 rk3x_i2c_get_con_count(struct rk3x_i2c *i2c) > +{ > + return REG_CON_SDA_CNT(i2c->t_priv.thd_sda_count) | > + REG_CON_STA_CNT(i2c->t_priv.tsu_sta_count) | > + REG_CON_STO_CNT(i2c->t_priv.tsu_sto_count); > +} > + > /* Reset all interrupt pending bits */ > static inline void rk3x_i2c_clean_ipd(struct rk3x_i2c *i2c) > { > @@ -165,13 +183,13 @@ static inline void rk3x_i2c_clean_ipd(struct rk3x_i2c *i2c) > */ > static void rk3x_i2c_start(struct rk3x_i2c *i2c) > { > - u32 val; > + u32 val = rk3x_i2c_get_con_count(i2c); > > rk3x_i2c_clean_ipd(i2c); > i2c_writel(i2c, REG_INT_START, REG_IEN); > > /* enable adapter with correct mode, send START condition */ > - val = REG_CON_EN | REG_CON_MOD(i2c->mode) | REG_CON_START; > + val = val | REG_CON_EN | REG_CON_MOD(i2c->mode) | REG_CON_START; > > /* if we want to react to NACK, set ACTACK bit */ > if (!(i2c->msg->flags & I2C_M_IGNORE_NAK)) > @@ -212,7 +230,7 @@ static void rk3x_i2c_stop(struct rk3x_i2c *i2c, int error) > * get the intended effect by resetting its internal state > * and issuing an ordinary START. > */ > - i2c_writel(i2c, 0, REG_CON); > + i2c_writel(i2c, rk3x_i2c_get_con_count(i2c), REG_CON); > > /* signal that we are finished with the current msg */ > wake_up(&i2c->wait); > @@ -630,6 +648,211 @@ static int rk3x_i2c_v0_calc_clock(unsigned long clk_rate, > return ret; > } > > +/** > + * Calculate timing clock info values for desired SCL frequency > + * > + * @clk_rate: I2C input clock rate > + * @t_input: Known I2C timing information > + * @t_output: Caculated rk3x private timing information that would > + * be written into regs > + * Returns: 0 on success, -EINVAL if the goal SCL rate is too slow. In that case > + * a best-effort divider value is returned in divs. If the target rate is > + * too high, we silently use the highest possible rate. > + * The following formulas are v1's method to calculate clock. > + * > + * l = divl + 1; > + * h = divh + 1; > + * s = data_upd_st + 1; > + * u = start_setup_cnt + 1; > + * p = stop_setup_cnt + 1; > + * T = Tclk_i2c; > + > + * tHigh = 8 * h * T; > + * tLow = 8 * l * T; > + > + * tHD;sda = (l * s + 1) * T; > + * tSU;sda = [(8 - s) * l + 1] * T; > + * tI2C = 8 * (l + h) * T; > + > + * tSU;sta = (8h * u + 1) * T; > + * tHD;sta = [8h * (u + 1) - 1] * T; > + * tSU;sto = (8h * p + 1) * T; > + */ > +static int rk3x_i2c_v1_calc_clock(unsigned long clk_rate, > + struct i2c_timings *t_input, > + struct rk3x_priv_i2c_timings *t_output) > +{ I see some similarities with existing code for v0. Can be refactored? > + unsigned long spec_min_low_ns, spec_min_high_ns; > + unsigned long spec_min_setup_start_ns, spec_min_stop_setup_ns; > + unsigned long spec_min_data_setup_ns, spec_max_data_hold_ns; > + > + unsigned long min_low_ns, min_high_ns, min_total_ns; > + unsigned long min_setup_start_ns, min_setup_data_ns; > + unsigned long min_stop_setup_ns, max_hold_data_ns; > + > + unsigned long clk_rate_khz, scl_rate_khz; > + > + unsigned long min_low_div, min_high_div; > + > + unsigned long min_div_for_hold, min_total_div; > + unsigned long extra_div, extra_low_div; > + unsigned long data_hd_cnt; > + > + int ret = 0; > + > + /* Support standard-mode and fast-mode */ > + if (WARN_ON(t_input->bus_freq_hz > 400000)) > + t_input->bus_freq_hz = 400000; > + > + /* prevent scl_rate_khz from becoming 0 */ > + if (WARN_ON(t_input->bus_freq_hz < 1000)) > + t_input->bus_freq_hz = 1000; > + > + /* > + * min_low_ns: The minimum number of ns we need to hold low to > + * meet I2C specification, should include fall time. > + * min_high_ns: The minimum number of ns we need to hold high to > + * meet I2C specification, should include rise time. > + */ > + if (t_input->bus_freq_hz <= 100000) { > + spec_min_low_ns = 4700; > + spec_min_high_ns = 4000; > + > + spec_min_setup_start_ns = 4700; > + spec_min_stop_setup_ns = 4000; > + > + spec_min_data_setup_ns = 250; > + spec_max_data_hold_ns = 3450; > + } else if (t_input->bus_freq_hz <= 400000) { > + spec_min_low_ns = 1300; > + spec_min_high_ns = 600; > + > + spec_min_setup_start_ns = 600; > + spec_min_stop_setup_ns = 600; > + > + spec_min_data_setup_ns = 100; > + spec_max_data_hold_ns = 900; > + } > + > + /* caculate min-divh and min-divl */ > + clk_rate_khz = DIV_ROUND_UP(clk_rate, 1000); > + scl_rate_khz = t_input->bus_freq_hz / 1000; > + min_total_div = DIV_ROUND_UP(clk_rate_khz, scl_rate_khz * 8); > + > + min_high_ns = t_input->scl_rise_ns + spec_min_high_ns; > + min_high_div = DIV_ROUND_UP(clk_rate_khz * min_high_ns, 8 * 1000000); > + > + min_low_ns = t_input->scl_fall_ns + spec_min_low_ns; > + min_low_div = DIV_ROUND_UP(clk_rate_khz * min_low_ns, 8 * 1000000); > + > + /* Final divh and divl must be greater than 0, otherwise the > + * hardware would not output the i2c clk. > + */ > + if (min_high_div <= 1) > + min_high_div = 2; > + if (min_low_div <= 1) > + min_low_div = 2; > + > + /* These are the min dividers needed for min hold times. */ > + min_div_for_hold = (min_low_div + min_high_div); > + min_total_ns = min_low_ns + min_high_ns; > + > + /* > + * This is the maximum divider so we don't go over the maximum. > + * We don't round up here (we round down) since this is a maximum. > + */ > + if (min_div_for_hold >= min_total_div) { > + /* > + * Time needed to meet hold requirements is important. > + * Just use that. > + */ > + t_output->div_low = min_low_div; > + t_output->div_high = min_high_div; > + } else { > + /* > + * We've got to distribute some time among the low and high > + * so we don't run too fast. > + * We'll try to split things up by the scale of min_low_div and > + * min_high_div, biasing slightly towards having a higher div > + * for low (spend more time low). > + */ > + extra_div = min_total_div - min_div_for_hold; > + extra_low_div = DIV_ROUND_UP(min_low_div * extra_div, > + min_div_for_hold); > + > + t_output->div_low = min_low_div + extra_low_div; > + t_output->div_high = min_high_div + (extra_div - extra_low_div); > + } > + > + /* > + * calculate sda data hold count by the rules, thd_sda_count:3 > + * is a appropriate value to reduce calculated times. > + * tHD;sda = (l * s + 1) * T > + * tSU;sda = ((8 - s) * l + 1) * T > + */ > + for (data_hd_cnt = 3; data_hd_cnt >= 0; data_hd_cnt--) { > + max_hold_data_ns = DIV_ROUND_UP((data_hd_cnt > + * (t_output->div_low) + 1) > + * 1000000, clk_rate_khz); > + min_setup_data_ns = DIV_ROUND_UP(((8 - data_hd_cnt) > + * (t_output->div_low) + 1) > + * 1000000, clk_rate_khz); > + if ((max_hold_data_ns < spec_max_data_hold_ns) && > + (min_setup_data_ns > spec_min_data_setup_ns)) { > + t_output->thd_sda_count = data_hd_cnt; > + break; > + } > + } > + > + /* > + * calculate start setup count, and we aren't care tHD;STA. > + * If the start setup count meets the rule of tSU;sta, it also > + * meets the rule of tHD;STA. > + * tSU;sta = (8h * u + 1) * T > + * tHD;sta = [8h * (u + 1) - 1] * T > + */ > + min_setup_start_ns = t_input->scl_rise_ns + spec_min_setup_start_ns; > + t_output->tsu_sta_count = DIV_ROUND_UP(clk_rate_khz * min_setup_start_ns > + - 1000000, 8 * 1000000 * (t_output->div_high)); > + > + /* > + * calculate start setup count by the rule: > + * tSU;sto =(8h * p + 1) * T > + */ > + min_stop_setup_ns = t_input->scl_rise_ns + spec_min_stop_setup_ns; > + t_output->tsu_sto_count = DIV_ROUND_UP(clk_rate_khz * min_stop_setup_ns > + - 1000000, 8 * 1000000 * (t_output->div_high)); > + > + /* > + * Adjust to the fact that the hardware has an implicit "+1". > + * NOTE: Above calculations always produce div_low > 0 and div_high > 0. > + */ > + t_output->div_low -= 1; > + t_output->div_high -= 1; > + > + /* Maximum divider supported by hw is 0xffff */ > + if (t_output->div_low > 0xffff) { > + t_output->div_low = 0xffff; > + ret = -EINVAL; > + } > + > + if (t_output->div_high > 0xffff) { > + t_output->div_high = 0xffff; > + ret = -EINVAL; > + } > + > + /* > + * Adjust to the fact that the hardware has an implicit "+1". > + * NOTE: Above calculations always produce thd_sda_count > 0, > + * tsu_sta_count > 0 and tsu_sta_count > 0. > + */ > + t_output->thd_sda_count -= 1; > + t_output->tsu_sta_count -= 1; > + t_output->tsu_sto_count -= 1; > + > + return ret; > +} > + > static void rk3x_i2c_adapt_div(struct rk3x_i2c *i2c, unsigned long clk_rate) > { > u64 t_low_ns, t_high_ns; > @@ -829,7 +1052,8 @@ static int rk3x_i2c_xfer(struct i2c_adapter *adap, > > /* Force a STOP condition without interrupt */ > i2c_writel(i2c, 0, REG_IEN); > - i2c_writel(i2c, REG_CON_EN | REG_CON_STOP, REG_CON); > + i2c_writel(i2c, rk3x_i2c_get_con_count(i2c) | > + REG_CON_EN | REG_CON_STOP, REG_CON); > > i2c->state = STATE_IDLE; > > @@ -969,7 +1193,9 @@ static int rk3x_i2c_probe(struct platform_device *pdev) > platform_set_drvdata(pdev, i2c); > > version = (readl(i2c->regs + REG_CON) & VERSION_MASK) >> VERSION_SHIFT; > - if (version == RK3X_I2C_V0) > + if (version == RK3X_I2C_V1) > + i2c->ops.calc_clock = rk3x_i2c_v1_calc_clock; > + else > i2c->ops.calc_clock = rk3x_i2c_v0_calc_clock; Perhaps time to use switch-case: switch ((value & MASK) >> SHIFT) { case V1: v1(); break; case V0: default: v0(); break; }
Hi, On Thu, Jan 14, 2016 at 4:31 AM, David Wu <david.wu@rock-chips.com> wrote: > There was an timing issue about "repeated start" time at the I2C > controller of version0, controller appears to drop SDA at .875x (7/8) > programmed clk high. The rule(.875x) isn't enough to meet tSU;STA > requirements on 100k's Standard-mode. To resolve this issue, > data_upd_st, start_setup_cnt and stop_setup_cnt configs for I2C > timing information are added, new rules are designed to calculate > the timing information at new v1. I'm curious: does new hardware behave differently and that's why you need v1? ...or does old and new hardware behave the same and you're just introducing v1 so you don't mess with how old boards are working? From the description it sounds as if the old code had problems as 100k too... If the new controller is different, I'd probably reword like the following (you'd have to re-wordwrap): There was an timing issue about "repeated start" time at the I2C controller of version0, controller appears to drop SDA at .875x (7/8) programmed clk high. On version 1 of the controller, the rule(.875x) isn't enough to meet tSU;STA requirements on 100k's Standard-mode. To resolve this issue, data_upd_st, start_setup_cnt and stop_setup_cnt configs for I2C timing information are added, new rules are designed to calculate the timing information at new v1. -Doug
Hi Doug? ? 2016/1/15 0:12, Doug Anderson ??: > Hi, > > On Thu, Jan 14, 2016 at 4:31 AM, David Wu <david.wu@rock-chips.com> wrote: >> There was an timing issue about "repeated start" time at the I2C >> controller of version0, controller appears to drop SDA at .875x (7/8) >> programmed clk high. The rule(.875x) isn't enough to meet tSU;STA >> requirements on 100k's Standard-mode. To resolve this issue, >> data_upd_st, start_setup_cnt and stop_setup_cnt configs for I2C >> timing information are added, new rules are designed to calculate >> the timing information at new v1. > I'm curious: does new hardware behave differently and that's why you > need v1? Yes , i didn't describe clearly about difference between old and new. Old and new hardware behave the same except some timing rules. v0 is the same with the v1 for tHigh and tLow : tHigh = 8 * divh * pclk_cycle; tLow = 8 * divl * pclk_cycle; v0 rules' difference: start setup? 7/8 * tHigh + 1 pclk cycle start hold : 2 * ?7/8 * tHigh? - 1 pclk cycle stop setup : 7/8 * tHigh + 1 pclk cycle data setup: 1/2 tLow - 1 pclk cycle data hold : 1/2 tLow + 1 pclk cycle For 100k's example: spec_min_low_ns = 4700; spec_min_high_ns = 4000; spec_min_setup_start_ns = 4700; We could calculate the timing info by the rules of v0, and ignore effect of the pclk cycle here. tSU;sta >=4700; tHigh_min = tSU;sta * 8/7 >= 5372ns; tHigh_min = max(tHigh_min, spec_min_high_ns) = 5372ns; We get the final scl clk rate is 99k(1000000000 / (5372ns + 4700ns)), it looks ok for the 100k Standard mode. But the timing point of repeat start and low time is very critical, it is dangerous to some slave devices which are perhaps not so specified. So need to give some time margin for them, that would increase the cycle time and reduce the clk rate, the final rate we get may be 97k or 96k. In fact, we must think about scl rise time and scl fall time, and get final clk may be 93k or less. After that, we get about 7 percent lost at clk rate, it would reduce the efficiency of i2c transfer. In other words, we could say there is a timing issue about "repeat start" time when we want accurate 100k's rate, it is short to meet I2C spec requirements. 3.4M clk rate also has the same issue. The start_setup count is added to fix this issue, tHigh is not need to considered of "repeat start" time. After divs calculated, the count would be calculated to meet i2c spec. v1 rule: start setup? tHigh + 1 pclk cycle start hold: [8h * (u + 1) - 1] * T; tSU;sto = (8h * p + 1) * T; --------------------------------------------------------------------------------------------------------------- The data_upd_st is added for the Data set-up time and Data hold time on Highspeed mode. For 1.7M's example on v0: tHD;DAT = 1/2 tLow? tHD;DAT <= spec_max_data_hold_ns = 150ns tLow <= 2 * tHD;DAT <= 300ns; tLow >= spec_min_low_ns = 320ns; According to these, we could not get a value for tLow, need changes for the rule: tHD;DAT = 1/2 tLow. Cut the tLow into eight euqal parts?the range of data_upd_st is 1 ~ 7. It seems that v1 rule could resolve the issue. v1 rule: tHD;sda = n/8 * tLow; tSU;sda = [(8 - n)/8 * tLow; 3.4M clk rate also has the same issue. > ...or does old and new hardware behave the same and you're > just introducing v1 so you don't mess with how old boards are working? The registers of counts added would not effect old boards. No matter what values of count was written in regs, that old i2c controller didn't care, it worked by original timing rule. After picking this patch, pmic-rk818 and touchscreen-gt911 worked well on the rk3368 sdk board which use old method. > > >From the description it sounds as if the old code had problems as 100k too... > > If the new controller is different, I'd probably reword like the > following (you'd have to re-wordwrap): > > There was an timing issue about "repeated start" time at the I2C > controller of version0, controller appears to drop SDA at .875x (7/8) > programmed clk high. On version 1 of the controller, the rule(.875x) > isn't enough to meet tSU;STA > requirements on 100k's Standard-mode. To resolve this issue, > data_upd_st, start_setup_cnt and stop_setup_cnt configs for I2C > timing information are added, new rules are designed to calculate > the timing information at new v1. There was an timing issue about "repeated start" time at the I2C controller of version0, controller appears to drop SDA at .875x (7/8) programmed clk high. On version 1 of the controller, the rule(.875x) isn't enough to meet tSU;STA requirements on 100k's Standard-mode. To resolve this issue,data_upd_st, start_setup_cnt and stop_setup_cnt configs for I2C timing information are added, new rules are designed to calculate the timing information at new v1. > -Doug > > >
diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c index 185e0f9..b7229a7 100644 --- a/drivers/i2c/busses/i2c-rk3x.c +++ b/drivers/i2c/busses/i2c-rk3x.c @@ -58,10 +58,15 @@ enum { #define REG_CON_LASTACK BIT(5) /* 1: send NACK after last received byte */ #define REG_CON_ACTACK BIT(6) /* 1: stop if NACK is received */ +#define REG_CON_SDA_CNT(cnt) ((cnt) << 8) +#define REG_CON_STA_CNT(cnt) ((cnt) << 12) +#define REG_CON_STO_CNT(cnt) ((cnt) << 14) + #define VERSION_MASK GENMASK(31, 16) #define VERSION_SHIFT 16 #define RK3X_I2C_V0 0x0 +#define RK3X_I2C_V1 0x1 /* REG_MRXADDR bits */ #define REG_MRXADDR_VALID(x) BIT(24 + (x)) /* [x*8+7:x*8] of MRX[R]ADDR valid */ @@ -99,10 +104,16 @@ struct rk3x_i2c_soc_data { * struct rk3x_priv_i2c_timings - rk3x I2C timing information * @div_low: Divider output for low * @div_high: Divider output for high + * @thd_sda_count: SDA update point config used to adjust sda setup/hold time + * @tsu_sta_count: Start setup config for setup start time and hold start time + * @tsu_sto_count: Stop setup config for setup stop time */ struct rk3x_priv_i2c_timings { unsigned long div_low; unsigned long div_high; + unsigned int thd_sda_count; + unsigned int tsu_sta_count; + unsigned int tsu_sto_count; }; struct rk3x_i2c_ops { @@ -154,6 +165,13 @@ static inline u32 i2c_readl(struct rk3x_i2c *i2c, unsigned int offset) return readl(i2c->regs + offset); } +static inline u32 rk3x_i2c_get_con_count(struct rk3x_i2c *i2c) +{ + return REG_CON_SDA_CNT(i2c->t_priv.thd_sda_count) | + REG_CON_STA_CNT(i2c->t_priv.tsu_sta_count) | + REG_CON_STO_CNT(i2c->t_priv.tsu_sto_count); +} + /* Reset all interrupt pending bits */ static inline void rk3x_i2c_clean_ipd(struct rk3x_i2c *i2c) { @@ -165,13 +183,13 @@ static inline void rk3x_i2c_clean_ipd(struct rk3x_i2c *i2c) */ static void rk3x_i2c_start(struct rk3x_i2c *i2c) { - u32 val; + u32 val = rk3x_i2c_get_con_count(i2c); rk3x_i2c_clean_ipd(i2c); i2c_writel(i2c, REG_INT_START, REG_IEN); /* enable adapter with correct mode, send START condition */ - val = REG_CON_EN | REG_CON_MOD(i2c->mode) | REG_CON_START; + val = val | REG_CON_EN | REG_CON_MOD(i2c->mode) | REG_CON_START; /* if we want to react to NACK, set ACTACK bit */ if (!(i2c->msg->flags & I2C_M_IGNORE_NAK)) @@ -212,7 +230,7 @@ static void rk3x_i2c_stop(struct rk3x_i2c *i2c, int error) * get the intended effect by resetting its internal state * and issuing an ordinary START. */ - i2c_writel(i2c, 0, REG_CON); + i2c_writel(i2c, rk3x_i2c_get_con_count(i2c), REG_CON); /* signal that we are finished with the current msg */ wake_up(&i2c->wait); @@ -630,6 +648,211 @@ static int rk3x_i2c_v0_calc_clock(unsigned long clk_rate, return ret; } +/** + * Calculate timing clock info values for desired SCL frequency + * + * @clk_rate: I2C input clock rate + * @t_input: Known I2C timing information + * @t_output: Caculated rk3x private timing information that would + * be written into regs + * Returns: 0 on success, -EINVAL if the goal SCL rate is too slow. In that case + * a best-effort divider value is returned in divs. If the target rate is + * too high, we silently use the highest possible rate. + * The following formulas are v1's method to calculate clock. + * + * l = divl + 1; + * h = divh + 1; + * s = data_upd_st + 1; + * u = start_setup_cnt + 1; + * p = stop_setup_cnt + 1; + * T = Tclk_i2c; + + * tHigh = 8 * h * T; + * tLow = 8 * l * T; + + * tHD;sda = (l * s + 1) * T; + * tSU;sda = [(8 - s) * l + 1] * T; + * tI2C = 8 * (l + h) * T; + + * tSU;sta = (8h * u + 1) * T; + * tHD;sta = [8h * (u + 1) - 1] * T; + * tSU;sto = (8h * p + 1) * T; + */ +static int rk3x_i2c_v1_calc_clock(unsigned long clk_rate, + struct i2c_timings *t_input, + struct rk3x_priv_i2c_timings *t_output) +{ + unsigned long spec_min_low_ns, spec_min_high_ns; + unsigned long spec_min_setup_start_ns, spec_min_stop_setup_ns; + unsigned long spec_min_data_setup_ns, spec_max_data_hold_ns; + + unsigned long min_low_ns, min_high_ns, min_total_ns; + unsigned long min_setup_start_ns, min_setup_data_ns; + unsigned long min_stop_setup_ns, max_hold_data_ns; + + unsigned long clk_rate_khz, scl_rate_khz; + + unsigned long min_low_div, min_high_div; + + unsigned long min_div_for_hold, min_total_div; + unsigned long extra_div, extra_low_div; + unsigned long data_hd_cnt; + + int ret = 0; + + /* Support standard-mode and fast-mode */ + if (WARN_ON(t_input->bus_freq_hz > 400000)) + t_input->bus_freq_hz = 400000; + + /* prevent scl_rate_khz from becoming 0 */ + if (WARN_ON(t_input->bus_freq_hz < 1000)) + t_input->bus_freq_hz = 1000; + + /* + * min_low_ns: The minimum number of ns we need to hold low to + * meet I2C specification, should include fall time. + * min_high_ns: The minimum number of ns we need to hold high to + * meet I2C specification, should include rise time. + */ + if (t_input->bus_freq_hz <= 100000) { + spec_min_low_ns = 4700; + spec_min_high_ns = 4000; + + spec_min_setup_start_ns = 4700; + spec_min_stop_setup_ns = 4000; + + spec_min_data_setup_ns = 250; + spec_max_data_hold_ns = 3450; + } else if (t_input->bus_freq_hz <= 400000) { + spec_min_low_ns = 1300; + spec_min_high_ns = 600; + + spec_min_setup_start_ns = 600; + spec_min_stop_setup_ns = 600; + + spec_min_data_setup_ns = 100; + spec_max_data_hold_ns = 900; + } + + /* caculate min-divh and min-divl */ + clk_rate_khz = DIV_ROUND_UP(clk_rate, 1000); + scl_rate_khz = t_input->bus_freq_hz / 1000; + min_total_div = DIV_ROUND_UP(clk_rate_khz, scl_rate_khz * 8); + + min_high_ns = t_input->scl_rise_ns + spec_min_high_ns; + min_high_div = DIV_ROUND_UP(clk_rate_khz * min_high_ns, 8 * 1000000); + + min_low_ns = t_input->scl_fall_ns + spec_min_low_ns; + min_low_div = DIV_ROUND_UP(clk_rate_khz * min_low_ns, 8 * 1000000); + + /* Final divh and divl must be greater than 0, otherwise the + * hardware would not output the i2c clk. + */ + if (min_high_div <= 1) + min_high_div = 2; + if (min_low_div <= 1) + min_low_div = 2; + + /* These are the min dividers needed for min hold times. */ + min_div_for_hold = (min_low_div + min_high_div); + min_total_ns = min_low_ns + min_high_ns; + + /* + * This is the maximum divider so we don't go over the maximum. + * We don't round up here (we round down) since this is a maximum. + */ + if (min_div_for_hold >= min_total_div) { + /* + * Time needed to meet hold requirements is important. + * Just use that. + */ + t_output->div_low = min_low_div; + t_output->div_high = min_high_div; + } else { + /* + * We've got to distribute some time among the low and high + * so we don't run too fast. + * We'll try to split things up by the scale of min_low_div and + * min_high_div, biasing slightly towards having a higher div + * for low (spend more time low). + */ + extra_div = min_total_div - min_div_for_hold; + extra_low_div = DIV_ROUND_UP(min_low_div * extra_div, + min_div_for_hold); + + t_output->div_low = min_low_div + extra_low_div; + t_output->div_high = min_high_div + (extra_div - extra_low_div); + } + + /* + * calculate sda data hold count by the rules, thd_sda_count:3 + * is a appropriate value to reduce calculated times. + * tHD;sda = (l * s + 1) * T + * tSU;sda = ((8 - s) * l + 1) * T + */ + for (data_hd_cnt = 3; data_hd_cnt >= 0; data_hd_cnt--) { + max_hold_data_ns = DIV_ROUND_UP((data_hd_cnt + * (t_output->div_low) + 1) + * 1000000, clk_rate_khz); + min_setup_data_ns = DIV_ROUND_UP(((8 - data_hd_cnt) + * (t_output->div_low) + 1) + * 1000000, clk_rate_khz); + if ((max_hold_data_ns < spec_max_data_hold_ns) && + (min_setup_data_ns > spec_min_data_setup_ns)) { + t_output->thd_sda_count = data_hd_cnt; + break; + } + } + + /* + * calculate start setup count, and we aren't care tHD;STA. + * If the start setup count meets the rule of tSU;sta, it also + * meets the rule of tHD;STA. + * tSU;sta = (8h * u + 1) * T + * tHD;sta = [8h * (u + 1) - 1] * T + */ + min_setup_start_ns = t_input->scl_rise_ns + spec_min_setup_start_ns; + t_output->tsu_sta_count = DIV_ROUND_UP(clk_rate_khz * min_setup_start_ns + - 1000000, 8 * 1000000 * (t_output->div_high)); + + /* + * calculate start setup count by the rule: + * tSU;sto =(8h * p + 1) * T + */ + min_stop_setup_ns = t_input->scl_rise_ns + spec_min_stop_setup_ns; + t_output->tsu_sto_count = DIV_ROUND_UP(clk_rate_khz * min_stop_setup_ns + - 1000000, 8 * 1000000 * (t_output->div_high)); + + /* + * Adjust to the fact that the hardware has an implicit "+1". + * NOTE: Above calculations always produce div_low > 0 and div_high > 0. + */ + t_output->div_low -= 1; + t_output->div_high -= 1; + + /* Maximum divider supported by hw is 0xffff */ + if (t_output->div_low > 0xffff) { + t_output->div_low = 0xffff; + ret = -EINVAL; + } + + if (t_output->div_high > 0xffff) { + t_output->div_high = 0xffff; + ret = -EINVAL; + } + + /* + * Adjust to the fact that the hardware has an implicit "+1". + * NOTE: Above calculations always produce thd_sda_count > 0, + * tsu_sta_count > 0 and tsu_sta_count > 0. + */ + t_output->thd_sda_count -= 1; + t_output->tsu_sta_count -= 1; + t_output->tsu_sto_count -= 1; + + return ret; +} + static void rk3x_i2c_adapt_div(struct rk3x_i2c *i2c, unsigned long clk_rate) { u64 t_low_ns, t_high_ns; @@ -829,7 +1052,8 @@ static int rk3x_i2c_xfer(struct i2c_adapter *adap, /* Force a STOP condition without interrupt */ i2c_writel(i2c, 0, REG_IEN); - i2c_writel(i2c, REG_CON_EN | REG_CON_STOP, REG_CON); + i2c_writel(i2c, rk3x_i2c_get_con_count(i2c) | + REG_CON_EN | REG_CON_STOP, REG_CON); i2c->state = STATE_IDLE; @@ -969,7 +1193,9 @@ static int rk3x_i2c_probe(struct platform_device *pdev) platform_set_drvdata(pdev, i2c); version = (readl(i2c->regs + REG_CON) & VERSION_MASK) >> VERSION_SHIFT; - if (version == RK3X_I2C_V0) + if (version == RK3X_I2C_V1) + i2c->ops.calc_clock = rk3x_i2c_v1_calc_clock; + else i2c->ops.calc_clock = rk3x_i2c_v0_calc_clock; ret = clk_prepare(i2c->clk);
There was an timing issue about "repeated start" time at the I2C controller of version0, controller appears to drop SDA at .875x (7/8) programmed clk high. The rule(.875x) isn't enough to meet tSU;STA requirements on 100k's Standard-mode. To resolve this issue, data_upd_st, start_setup_cnt and stop_setup_cnt configs for I2C timing information are added, new rules are designed to calculate the timing information at new v1. There are two examples for clocks calculated by the rules, not contain hardware elements like scl_rise time, scl_fall time and sda_rise time: 1. Standard-mode: Source Pclk: 80M, Target scl: 100K, Final scl: 100K; Tpclk = 12.5ns; divl = 53, divh = 45; l = 54, h = 46; tLow = 5.400us, tHigh = 4.600us; start_setup_cnt = 1, stop_setup_cnt = 0; u = 2, p = 1; tSU;sta = (8h * u + 1) * T = 9.2125us; tHD;sta = [8h * (u + 1) - 1] * T = 13.7875us; tSU;sto = (8h * p + 1) * T = 4.6125; data_upd_st = 2; s = data_upd_st + 1 = 3; tHD;sda = (l * s + 1) * T = 2.038us; tSU;sda = [(8 - s) * l + 1] * T = 3.388us; 2. Fast-mode: Source Pclk: 80M, Target scl: 400K, Final scl: 400K; Tpclk = 12.5ns; divl = 16, divh = 7; l = 17, h = 8; tLow = 1.7us, tHigh = 0.8us; start_setup_cnt = stop_setup_cnt = 0; u = p = 1; tSU;sta = (8h * u + 1) * T = 0.8125us; tHD;sta = [8h * (u + 1) - 1] * T = 1.5875us; tSU;sto = (8h * p + 1) * T = 0.8125us; data_upd_st = 2; s = data_upd_st + 1 = 3; tHD;sda = (l * s + 1) * T = 650ns; tSU;sda = [(8 - l) * s + 1] * T = 1075ns; It seemed the rules make the timing meet the I2C spec requirements both Standard-mode and Fast-mode. Signed-off-by: David Wu <david.wu@rock-chips.com> --- changes in v3: - Add more comments - Calculate counts behind divh and divl changes in v2: - split patch to three patches(Heiko) drivers/i2c/busses/i2c-rk3x.c | 236 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 231 insertions(+), 5 deletions(-)