Skip to content

Commit

Permalink
media: tc358746: improve calculation of the D-PHY timing registers
Browse files Browse the repository at this point in the history
When calculating D-PHY registers, using data rates that are not multiples
of 16 can lead to precision loss in division operations. This can result in
register values that produce timing violations against the MIPI standard.

An example:
cfg->hs_clk_rate = 294MHz
hf_clk = 18

If the desired value in cfg->init is 100us, which is the minimum allowed
value, then the LINEINITCNT register is calculated as 1799. But since the
actual clock is 18.375MHz instead of 18MHz, this setting results in a time
that is shorter than 100us and thus violates the standard. The correct
value for LINEINITCNT would be 1837.

Improve the precision of calculations by using Hz instead of MHz as unit.

Signed-off-by: Matthias Fend <matthias.fend@emfend.at>
Reviewed-by: Marco Felsch <m.felsch@pengutronix.de>
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
  • Loading branch information
Matthias Fend authored and Hans Verkuil committed Feb 25, 2025
1 parent 44967f0 commit 78d7265
Showing 1 changed file with 7 additions and 12 deletions.
19 changes: 7 additions & 12 deletions drivers/media/i2c/tc358746.c
Original file line number Diff line number Diff line change
Expand Up @@ -485,24 +485,20 @@ static int tc358746_apply_misc_config(struct tc358746 *tc358746)
return err;
}

/* Use MHz as base so the div needs no u64 */
static u32 tc358746_cfg_to_cnt(unsigned int cfg_val,
unsigned int clk_mhz,
unsigned int time_base)
static u32 tc358746_cfg_to_cnt(unsigned long cfg_val, unsigned long clk_hz,
unsigned long long time_base)
{
return DIV_ROUND_UP(cfg_val * clk_mhz, time_base);
return div64_u64((u64)cfg_val * clk_hz + time_base - 1, time_base);
}

static u32 tc358746_ps_to_cnt(unsigned int cfg_val,
unsigned int clk_mhz)
static u32 tc358746_ps_to_cnt(unsigned long cfg_val, unsigned long clk_hz)
{
return tc358746_cfg_to_cnt(cfg_val, clk_mhz, USEC_PER_SEC);
return tc358746_cfg_to_cnt(cfg_val, clk_hz, PSEC_PER_SEC);
}

static u32 tc358746_us_to_cnt(unsigned int cfg_val,
unsigned int clk_mhz)
static u32 tc358746_us_to_cnt(unsigned long cfg_val, unsigned long clk_hz)
{
return tc358746_cfg_to_cnt(cfg_val, clk_mhz, 1);
return tc358746_cfg_to_cnt(cfg_val, clk_hz, USEC_PER_SEC);
}

static int tc358746_apply_dphy_config(struct tc358746 *tc358746)
Expand All @@ -517,7 +513,6 @@ static int tc358746_apply_dphy_config(struct tc358746 *tc358746)

/* The hs_byte_clk is also called SYSCLK in the excel sheet */
hs_byte_clk = cfg->hs_clk_rate / 8;
hs_byte_clk /= HZ_PER_MHZ;
hf_clk = hs_byte_clk / 2;

val = tc358746_us_to_cnt(cfg->init, hf_clk) - 1;
Expand Down

0 comments on commit 78d7265

Please sign in to comment.