aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/i2c/busses/i2c-designware.c93
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
199static u32
200i2c_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
238static 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 {
207static void i2c_dw_init(struct dw_i2c_dev *dev) 262static 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 |