diff options
-rw-r--r-- | drivers/i2c/busses/i2c-designware.c | 93 |
1 files changed, 84 insertions, 9 deletions
diff --git a/drivers/i2c/busses/i2c-designware.c b/drivers/i2c/busses/i2c-designware.c index fd1616b3d2b5..cdfd94e41ccc 100644 --- a/drivers/i2c/busses/i2c-designware.c +++ b/drivers/i2c/busses/i2c-designware.c | |||
@@ -196,6 +196,61 @@ struct dw_i2c_dev { | |||
196 | unsigned int rx_fifo_depth; | 196 | unsigned int rx_fifo_depth; |
197 | }; | 197 | }; |
198 | 198 | ||
199 | static u32 | ||
200 | i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset) | ||
201 | { | ||
202 | /* | ||
203 | * DesignWare I2C core doesn't seem to have solid strategy to meet | ||
204 | * the tHD;STA timing spec. Configuring _HCNT based on tHIGH spec | ||
205 | * will result in violation of the tHD;STA spec. | ||
206 | */ | ||
207 | if (cond) | ||
208 | /* | ||
209 | * Conditional expression: | ||
210 | * | ||
211 | * IC_[FS]S_SCL_HCNT + (1+4+3) >= IC_CLK * tHIGH | ||
212 | * | ||
213 | * This is based on the DW manuals, and represents an ideal | ||
214 | * configuration. The resulting I2C bus speed will be | ||
215 | * faster than any of the others. | ||
216 | * | ||
217 | * If your hardware is free from tHD;STA issue, try this one. | ||
218 | */ | ||
219 | return (ic_clk * tSYMBOL + 5000) / 10000 - 8 + offset; | ||
220 | else | ||
221 | /* | ||
222 | * Conditional expression: | ||
223 | * | ||
224 | * IC_[FS]S_SCL_HCNT + 3 >= IC_CLK * (tHD;STA + tf) | ||
225 | * | ||
226 | * This is just experimental rule; the tHD;STA period turned | ||
227 | * out to be proportinal to (_HCNT + 3). With this setting, | ||
228 | * we could meet both tHIGH and tHD;STA timing specs. | ||
229 | * | ||
230 | * If unsure, you'd better to take this alternative. | ||
231 | * | ||
232 | * The reason why we need to take into account "tf" here, | ||
233 | * is the same as described in i2c_dw_scl_lcnt(). | ||
234 | */ | ||
235 | return (ic_clk * (tSYMBOL + tf) + 5000) / 10000 - 3 + offset; | ||
236 | } | ||
237 | |||
238 | static u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset) | ||
239 | { | ||
240 | /* | ||
241 | * Conditional expression: | ||
242 | * | ||
243 | * IC_[FS]S_SCL_LCNT + 1 >= IC_CLK * (tLOW + tf) | ||
244 | * | ||
245 | * DW I2C core starts counting the SCL CNTs for the LOW period | ||
246 | * of the SCL clock (tLOW) as soon as it pulls the SCL line. | ||
247 | * In order to meet the tLOW timing spec, we need to take into | ||
248 | * account the fall time of SCL signal (tf). Default tf value | ||
249 | * should be 0.3 us, for safety. | ||
250 | */ | ||
251 | return ((ic_clk * (tLOW + tf) + 5000) / 10000) - 1 + offset; | ||
252 | } | ||
253 | |||
199 | /** | 254 | /** |
200 | * i2c_dw_init() - initialize the designware i2c master hardware | 255 | * i2c_dw_init() - initialize the designware i2c master hardware |
201 | * @dev: device private data | 256 | * @dev: device private data |
@@ -207,20 +262,40 @@ struct dw_i2c_dev { | |||
207 | static void i2c_dw_init(struct dw_i2c_dev *dev) | 262 | static void i2c_dw_init(struct dw_i2c_dev *dev) |
208 | { | 263 | { |
209 | u32 input_clock_khz = clk_get_rate(dev->clk) / 1000; | 264 | u32 input_clock_khz = clk_get_rate(dev->clk) / 1000; |
210 | u32 ic_con; | 265 | u32 ic_con, hcnt, lcnt; |
211 | 266 | ||
212 | /* Disable the adapter */ | 267 | /* Disable the adapter */ |
213 | writel(0, dev->base + DW_IC_ENABLE); | 268 | writel(0, dev->base + DW_IC_ENABLE); |
214 | 269 | ||
215 | /* set standard and fast speed deviders for high/low periods */ | 270 | /* set standard and fast speed deviders for high/low periods */ |
216 | writel((input_clock_khz * 40 / 10000)+1, /* std speed high, 4us */ | 271 | |
217 | dev->base + DW_IC_SS_SCL_HCNT); | 272 | /* Standard-mode */ |
218 | writel((input_clock_khz * 47 / 10000)+1, /* std speed low, 4.7us */ | 273 | hcnt = i2c_dw_scl_hcnt(input_clock_khz, |
219 | dev->base + DW_IC_SS_SCL_LCNT); | 274 | 40, /* tHD;STA = tHIGH = 4.0 us */ |
220 | writel((input_clock_khz * 6 / 10000)+1, /* fast speed high, 0.6us */ | 275 | 3, /* tf = 0.3 us */ |
221 | dev->base + DW_IC_FS_SCL_HCNT); | 276 | 0, /* 0: DW default, 1: Ideal */ |
222 | writel((input_clock_khz * 13 / 10000)+1, /* fast speed low, 1.3us */ | 277 | 0); /* No offset */ |
223 | dev->base + DW_IC_FS_SCL_LCNT); | 278 | lcnt = i2c_dw_scl_lcnt(input_clock_khz, |
279 | 47, /* tLOW = 4.7 us */ | ||
280 | 3, /* tf = 0.3 us */ | ||
281 | 0); /* No offset */ | ||
282 | writel(hcnt, dev->base + DW_IC_SS_SCL_HCNT); | ||
283 | writel(lcnt, dev->base + DW_IC_SS_SCL_LCNT); | ||
284 | dev_dbg(dev->dev, "Standard-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt); | ||
285 | |||
286 | /* Fast-mode */ | ||
287 | hcnt = i2c_dw_scl_hcnt(input_clock_khz, | ||
288 | 6, /* tHD;STA = tHIGH = 0.6 us */ | ||
289 | 3, /* tf = 0.3 us */ | ||
290 | 0, /* 0: DW default, 1: Ideal */ | ||
291 | 0); /* No offset */ | ||
292 | lcnt = i2c_dw_scl_lcnt(input_clock_khz, | ||
293 | 13, /* tLOW = 1.3 us */ | ||
294 | 3, /* tf = 0.3 us */ | ||
295 | 0); /* No offset */ | ||
296 | writel(hcnt, dev->base + DW_IC_FS_SCL_HCNT); | ||
297 | writel(lcnt, dev->base + DW_IC_FS_SCL_LCNT); | ||
298 | dev_dbg(dev->dev, "Fast-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt); | ||
224 | 299 | ||
225 | /* configure the i2c master */ | 300 | /* configure the i2c master */ |
226 | ic_con = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE | | 301 | ic_con = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE | |