Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 173851
b: refs/heads/master
c: d60c7e8
h: refs/heads/master
i:
  173849: 305a5cf
  173847: bc9a45e
v: v3
  • Loading branch information
Shinya Kuribayashi authored and Ben Dooks committed Dec 9, 2009
1 parent 4b82872 commit 540c72a
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 10 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 6d2ea4875f7e5e495526bdfd32bce093cb130276
refs/heads/master: d60c7e81dda2041302791c6a5261bd0c74d60fba
93 changes: 84 additions & 9 deletions trunk/drivers/i2c/busses/i2c-designware.c
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,61 @@ struct dw_i2c_dev {
unsigned int rx_fifo_depth;
};

static u32
i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset)
{
/*
* DesignWare I2C core doesn't seem to have solid strategy to meet
* the tHD;STA timing spec. Configuring _HCNT based on tHIGH spec
* will result in violation of the tHD;STA spec.
*/
if (cond)
/*
* Conditional expression:
*
* IC_[FS]S_SCL_HCNT + (1+4+3) >= IC_CLK * tHIGH
*
* This is based on the DW manuals, and represents an ideal
* configuration. The resulting I2C bus speed will be
* faster than any of the others.
*
* If your hardware is free from tHD;STA issue, try this one.
*/
return (ic_clk * tSYMBOL + 5000) / 10000 - 8 + offset;
else
/*
* Conditional expression:
*
* IC_[FS]S_SCL_HCNT + 3 >= IC_CLK * (tHD;STA + tf)
*
* This is just experimental rule; the tHD;STA period turned
* out to be proportinal to (_HCNT + 3). With this setting,
* we could meet both tHIGH and tHD;STA timing specs.
*
* If unsure, you'd better to take this alternative.
*
* The reason why we need to take into account "tf" here,
* is the same as described in i2c_dw_scl_lcnt().
*/
return (ic_clk * (tSYMBOL + tf) + 5000) / 10000 - 3 + offset;
}

static u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset)
{
/*
* Conditional expression:
*
* IC_[FS]S_SCL_LCNT + 1 >= IC_CLK * (tLOW + tf)
*
* DW I2C core starts counting the SCL CNTs for the LOW period
* of the SCL clock (tLOW) as soon as it pulls the SCL line.
* In order to meet the tLOW timing spec, we need to take into
* account the fall time of SCL signal (tf). Default tf value
* should be 0.3 us, for safety.
*/
return ((ic_clk * (tLOW + tf) + 5000) / 10000) - 1 + offset;
}

/**
* i2c_dw_init() - initialize the designware i2c master hardware
* @dev: device private data
Expand All @@ -207,20 +262,40 @@ struct dw_i2c_dev {
static void i2c_dw_init(struct dw_i2c_dev *dev)
{
u32 input_clock_khz = clk_get_rate(dev->clk) / 1000;
u32 ic_con;
u32 ic_con, hcnt, lcnt;

/* Disable the adapter */
writel(0, dev->base + DW_IC_ENABLE);

/* set standard and fast speed deviders for high/low periods */
writel((input_clock_khz * 40 / 10000)+1, /* std speed high, 4us */
dev->base + DW_IC_SS_SCL_HCNT);
writel((input_clock_khz * 47 / 10000)+1, /* std speed low, 4.7us */
dev->base + DW_IC_SS_SCL_LCNT);
writel((input_clock_khz * 6 / 10000)+1, /* fast speed high, 0.6us */
dev->base + DW_IC_FS_SCL_HCNT);
writel((input_clock_khz * 13 / 10000)+1, /* fast speed low, 1.3us */
dev->base + DW_IC_FS_SCL_LCNT);

/* Standard-mode */
hcnt = i2c_dw_scl_hcnt(input_clock_khz,
40, /* tHD;STA = tHIGH = 4.0 us */
3, /* tf = 0.3 us */
0, /* 0: DW default, 1: Ideal */
0); /* No offset */
lcnt = i2c_dw_scl_lcnt(input_clock_khz,
47, /* tLOW = 4.7 us */
3, /* tf = 0.3 us */
0); /* No offset */
writel(hcnt, dev->base + DW_IC_SS_SCL_HCNT);
writel(lcnt, dev->base + DW_IC_SS_SCL_LCNT);
dev_dbg(dev->dev, "Standard-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt);

/* Fast-mode */
hcnt = i2c_dw_scl_hcnt(input_clock_khz,
6, /* tHD;STA = tHIGH = 0.6 us */
3, /* tf = 0.3 us */
0, /* 0: DW default, 1: Ideal */
0); /* No offset */
lcnt = i2c_dw_scl_lcnt(input_clock_khz,
13, /* tLOW = 1.3 us */
3, /* tf = 0.3 us */
0); /* No offset */
writel(hcnt, dev->base + DW_IC_FS_SCL_HCNT);
writel(lcnt, dev->base + DW_IC_FS_SCL_LCNT);
dev_dbg(dev->dev, "Fast-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt);

/* configure the i2c master */
ic_con = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE |
Expand Down

0 comments on commit 540c72a

Please sign in to comment.