Skip to content

Commit

Permalink
i2c: designware: Use SCL rise and fall times in DT
Browse files Browse the repository at this point in the history
Calculate the HCNT and LCNT values for all modes using the rise and
fall times of SCL, the aim being a 50/50 mark/space ratio.

Signed-off-by: Phil Elwell <[email protected]>
  • Loading branch information
pelwell committed Jan 29, 2024
1 parent 7624c6f commit a29c58e
Showing 1 changed file with 26 additions and 0 deletions.
26 changes: 26 additions & 0 deletions drivers/i2c/busses/i2c-designware-master.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,30 @@ static void i2c_dw_configure_fifo_master(struct dw_i2c_dev *dev)
regmap_write(dev->map, DW_IC_CON, dev->master_cfg);
}

static u16 clock_calc(struct dw_i2c_dev *dev, bool want_high)
{
struct i2c_timings *t = &dev->timings;
u32 wanted_speed = t->bus_freq_hz;
u32 clk_khz = i2c_dw_clk_rate(dev);
u32 extra_ns = want_high ? t->scl_fall_ns : t->scl_rise_ns;
u32 extra_cycles = (u32)((u64)clk_khz * extra_ns / 1000000);
u32 period = ((u64)clk_khz * 1000 + wanted_speed - 1) / wanted_speed;
u32 cycles = (period + want_high)/2 - extra_cycles;

if (cycles > 0xffff)
cycles = 0xffff;

return (u16)cycles;
}

static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev)
{
unsigned int comp_param1;
u32 sda_falling_time, scl_falling_time;
struct i2c_timings *t = &dev->timings;
const char *fp_str = "";
u32 ic_clk;
u32 hcnt, lcnt;
int ret;

ret = i2c_dw_acquire_lock(dev);
Expand All @@ -60,6 +77,9 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev)
sda_falling_time = t->sda_fall_ns ?: 300; /* ns */
scl_falling_time = t->scl_fall_ns ?: 300; /* ns */

hcnt = clock_calc(dev, true);
lcnt = clock_calc(dev, false);

/* Calculate SCL timing parameters for standard mode if not set */
if (!dev->ss_hcnt || !dev->ss_lcnt) {
ic_clk = i2c_dw_clk_rate(dev);
Expand All @@ -75,6 +95,8 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev)
scl_falling_time,
0); /* No offset */
}
dev->ss_hcnt = hcnt;
dev->ss_lcnt = lcnt;
dev_dbg(dev->dev, "Standard Mode HCNT:LCNT = %d:%d\n",
dev->ss_hcnt, dev->ss_lcnt);

Expand Down Expand Up @@ -125,6 +147,8 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev)
scl_falling_time,
0); /* No offset */
}
dev->fs_hcnt = hcnt;
dev->fs_lcnt = lcnt;
dev_dbg(dev->dev, "Fast Mode%s HCNT:LCNT = %d:%d\n",
fp_str, dev->fs_hcnt, dev->fs_lcnt);

Expand Down Expand Up @@ -153,6 +177,8 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev)
scl_falling_time,
0); /* No offset */
}
dev->hs_hcnt = hcnt;
dev->hs_lcnt = lcnt;
dev_dbg(dev->dev, "High Speed Mode HCNT:LCNT = %d:%d\n",
dev->hs_hcnt, dev->hs_lcnt);
}
Expand Down

0 comments on commit a29c58e

Please sign in to comment.