mirror of
https://github.com/torvalds/linux
synced 2024-11-05 18:23:50 +00:00
i2c: rk3x: Move spec timing data to "static const" structs
The i2c timing specs are really just constant data. There's no reason to write code to init them, so move them out to structures. This not only is a cleaner solution but it will reduce code duplication when we introduce a new variant of rk3x_i2c_calc_divs() in a future patch. Signed-off-by: David Wu <david.wu@rock-chips.com> Suggested-by: Douglas Anderson <dianders@chromium.org> Reviewed-by: Douglas Anderson <dianders@chromium.org> Tested-by: Heiko Stuebner <heiko@sntech.de> Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
This commit is contained in:
parent
bef358c4fe
commit
b58fd3be40
1 changed files with 54 additions and 27 deletions
|
@ -75,6 +75,34 @@ enum {
|
|||
#define WAIT_TIMEOUT 1000 /* ms */
|
||||
#define DEFAULT_SCL_RATE (100 * 1000) /* Hz */
|
||||
|
||||
/**
|
||||
* struct i2c_spec_values:
|
||||
* @min_low_ns: min LOW period of the SCL clock
|
||||
* @min_high_ns: min HIGH period of the SCL cloc
|
||||
* @min_setup_start_ns: min set-up time for a repeated START conditio
|
||||
* @max_data_hold_ns: max data hold time
|
||||
*/
|
||||
struct i2c_spec_values {
|
||||
unsigned long min_low_ns;
|
||||
unsigned long min_high_ns;
|
||||
unsigned long min_setup_start_ns;
|
||||
unsigned long max_data_hold_ns;
|
||||
};
|
||||
|
||||
static const struct i2c_spec_values standard_mode_spec = {
|
||||
.min_low_ns = 4700,
|
||||
.min_high_ns = 4000,
|
||||
.min_setup_start_ns = 4700,
|
||||
.max_data_hold_ns = 3450,
|
||||
};
|
||||
|
||||
static const struct i2c_spec_values fast_mode_spec = {
|
||||
.min_low_ns = 1300,
|
||||
.min_high_ns = 600,
|
||||
.min_setup_start_ns = 600,
|
||||
.max_data_hold_ns = 900,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct rk3x_i2c_calced_timings:
|
||||
* @div_low: Divider output for low
|
||||
|
@ -459,6 +487,21 @@ static irqreturn_t rk3x_i2c_irq(int irqno, void *dev_id)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get timing values of I2C specification
|
||||
*
|
||||
* @speed: Desired SCL frequency
|
||||
*
|
||||
* Returns: Matched i2c spec values.
|
||||
*/
|
||||
static const struct i2c_spec_values *rk3x_i2c_get_spec(unsigned int speed)
|
||||
{
|
||||
if (speed <= 100000)
|
||||
return &standard_mode_spec;
|
||||
else
|
||||
return &fast_mode_spec;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate divider values for desired SCL frequency
|
||||
*
|
||||
|
@ -474,10 +517,6 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate,
|
|||
struct i2c_timings *t,
|
||||
struct rk3x_i2c_calced_timings *t_calc)
|
||||
{
|
||||
unsigned long spec_min_low_ns, spec_min_high_ns;
|
||||
unsigned long spec_setup_start, spec_max_data_hold_ns;
|
||||
unsigned long data_hold_buffer_ns;
|
||||
|
||||
unsigned long min_low_ns, min_high_ns;
|
||||
unsigned long max_low_ns, min_total_ns;
|
||||
|
||||
|
@ -489,6 +528,8 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate,
|
|||
unsigned long min_div_for_hold, min_total_div;
|
||||
unsigned long extra_div, extra_low_div, ideal_low_div;
|
||||
|
||||
unsigned long data_hold_buffer_ns = 50;
|
||||
const struct i2c_spec_values *spec;
|
||||
int ret = 0;
|
||||
|
||||
/* Only support standard-mode and fast-mode */
|
||||
|
@ -511,22 +552,8 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate,
|
|||
* This is because the i2c host on Rockchip holds the data line
|
||||
* for half the low time.
|
||||
*/
|
||||
if (t->bus_freq_hz <= 100000) {
|
||||
/* Standard-mode */
|
||||
spec_min_low_ns = 4700;
|
||||
spec_setup_start = 4700;
|
||||
spec_min_high_ns = 4000;
|
||||
spec_max_data_hold_ns = 3450;
|
||||
data_hold_buffer_ns = 50;
|
||||
} else {
|
||||
/* Fast-mode */
|
||||
spec_min_low_ns = 1300;
|
||||
spec_setup_start = 600;
|
||||
spec_min_high_ns = 600;
|
||||
spec_max_data_hold_ns = 900;
|
||||
data_hold_buffer_ns = 50;
|
||||
}
|
||||
min_high_ns = t->scl_rise_ns + spec_min_high_ns;
|
||||
spec = rk3x_i2c_get_spec(t->bus_freq_hz);
|
||||
min_high_ns = t->scl_rise_ns + spec->min_high_ns;
|
||||
|
||||
/*
|
||||
* Timings for repeated start:
|
||||
|
@ -536,14 +563,14 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate,
|
|||
* We need to account for those rules in picking our "high" time so
|
||||
* we meet tSU;STA and tHD;STA times.
|
||||
*/
|
||||
min_high_ns = max(min_high_ns,
|
||||
DIV_ROUND_UP((t->scl_rise_ns + spec_setup_start) * 1000, 875));
|
||||
min_high_ns = max(min_high_ns,
|
||||
DIV_ROUND_UP((t->scl_rise_ns + spec_setup_start +
|
||||
t->sda_fall_ns + spec_min_high_ns), 2));
|
||||
min_high_ns = max(min_high_ns, DIV_ROUND_UP(
|
||||
(t->scl_rise_ns + spec->min_setup_start_ns) * 1000, 875));
|
||||
min_high_ns = max(min_high_ns, DIV_ROUND_UP(
|
||||
(t->scl_rise_ns + spec->min_setup_start_ns + t->sda_fall_ns +
|
||||
spec->min_high_ns), 2));
|
||||
|
||||
min_low_ns = t->scl_fall_ns + spec_min_low_ns;
|
||||
max_low_ns = spec_max_data_hold_ns * 2 - data_hold_buffer_ns;
|
||||
min_low_ns = t->scl_fall_ns + spec->min_low_ns;
|
||||
max_low_ns = spec->max_data_hold_ns * 2 - data_hold_buffer_ns;
|
||||
min_total_ns = min_low_ns + min_high_ns;
|
||||
|
||||
/* Adjust to avoid overflow */
|
||||
|
|
Loading…
Reference in a new issue