diff --git a/arch/arm/boot/dts/rp1.dtsi b/arch/arm/boot/dts/rp1.dtsi index c10c6cdf8f98ec..5219ca372bff16 100644 --- a/arch/arm/boot/dts/rp1.dtsi +++ b/arch/arm/boot/dts/rp1.dtsi @@ -305,12 +305,8 @@ compatible = "snps,designware-i2c"; interrupts = ; clocks = <&rp1_clocks RP1_CLK_SYS>; - snps,ss_hcnt = <978>; - snps,ss_lcnt = <990>; - snps,fs_hcnt = <200>; - snps,fs_lcnt = <268>; - snps,fp_hcnt = <60>; - snps,fp_lcnt = <107>; + i2c-scl-rising-time-ns = <65>; + i2c-scl-falling-time-ns = <100>; status = "disabled"; }; @@ -319,12 +315,8 @@ compatible = "snps,designware-i2c"; interrupts = ; clocks = <&rp1_clocks RP1_CLK_SYS>; - snps,ss_hcnt = <978>; - snps,ss_lcnt = <990>; - snps,fs_hcnt = <200>; - snps,fs_lcnt = <268>; - snps,fp_hcnt = <60>; - snps,fp_lcnt = <107>; + i2c-scl-rising-time-ns = <65>; + i2c-scl-falling-time-ns = <100>; status = "disabled"; }; @@ -333,12 +325,8 @@ compatible = "snps,designware-i2c"; interrupts = ; clocks = <&rp1_clocks RP1_CLK_SYS>; - snps,ss_hcnt = <978>; - snps,ss_lcnt = <990>; - snps,fs_hcnt = <200>; - snps,fs_lcnt = <268>; - snps,fp_hcnt = <60>; - snps,fp_lcnt = <107>; + i2c-scl-rising-time-ns = <65>; + i2c-scl-falling-time-ns = <100>; status = "disabled"; }; @@ -347,12 +335,8 @@ compatible = "snps,designware-i2c"; interrupts = ; clocks = <&rp1_clocks RP1_CLK_SYS>; - snps,ss_hcnt = <978>; - snps,ss_lcnt = <990>; - snps,fs_hcnt = <200>; - snps,fs_lcnt = <268>; - snps,fp_hcnt = <60>; - snps,fp_lcnt = <107>; + i2c-scl-rising-time-ns = <65>; + i2c-scl-falling-time-ns = <100>; status = "disabled"; }; @@ -361,12 +345,8 @@ compatible = "snps,designware-i2c"; interrupts = ; clocks = <&rp1_clocks RP1_CLK_SYS>; - snps,ss_hcnt = <978>; - snps,ss_lcnt = <990>; - snps,fs_hcnt = <200>; - snps,fs_lcnt = <268>; - snps,fp_hcnt = <60>; - snps,fp_lcnt = <107>; + i2c-scl-rising-time-ns = <65>; + i2c-scl-falling-time-ns = <100>; status = "disabled"; }; @@ -375,12 +355,8 @@ compatible = "snps,designware-i2c"; interrupts = ; clocks = <&rp1_clocks RP1_CLK_SYS>; - snps,ss_hcnt = <978>; - snps,ss_lcnt = <990>; - snps,fs_hcnt = <200>; - snps,fs_lcnt = <268>; - snps,fp_hcnt = <60>; - snps,fp_lcnt = <107>; + i2c-scl-rising-time-ns = <65>; + i2c-scl-falling-time-ns = <100>; status = "disabled"; }; @@ -389,12 +365,8 @@ compatible = "snps,designware-i2c"; interrupts = ; clocks = <&rp1_clocks RP1_CLK_SYS>; - snps,ss_hcnt = <978>; - snps,ss_lcnt = <990>; - snps,fs_hcnt = <200>; - snps,fs_lcnt = <268>; - snps,fp_hcnt = <60>; - snps,fp_lcnt = <107>; + i2c-scl-rising-time-ns = <65>; + i2c-scl-falling-time-ns = <100>; status = "disabled"; }; diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c index ad98c85ec2e7a4..fd9d2d57f8b820 100644 --- a/drivers/i2c/busses/i2c-designware-common.c +++ b/drivers/i2c/busses/i2c-designware-common.c @@ -318,6 +318,9 @@ void i2c_dw_adjust_bus_speed(struct dw_i2c_dev *dev) { u32 acpi_speed = i2c_dw_acpi_round_bus_speed(dev->dev); struct i2c_timings *t = &dev->timings; + u32 wanted_speed; + u32 legal_speed = 0; + int i; /* * Find bus speed from the "clock-frequency" device property, ACPI @@ -329,6 +332,30 @@ void i2c_dw_adjust_bus_speed(struct dw_i2c_dev *dev) t->bus_freq_hz = max(t->bus_freq_hz, acpi_speed); else t->bus_freq_hz = I2C_MAX_FAST_MODE_FREQ; + + wanted_speed = t->bus_freq_hz; + + /* For unsupported speeds, scale down the lowest speed which is faster. */ + for (i = 0; i < ARRAY_SIZE(supported_speeds); i++) { + /* supported speeds is in decreasing order */ + if (wanted_speed == supported_speeds[i]) { + legal_speed = 0; + break; + } + if (wanted_speed > supported_speeds[i]) + break; + + legal_speed = supported_speeds[i]; + } + + if (legal_speed) { + /* + * Pretend this was the requested speed, but preserve the preferred + * speed so the clock counts can be scaled. + */ + t->bus_freq_hz = legal_speed; + dev->wanted_bus_speed = wanted_speed; + } } EXPORT_SYMBOL_GPL(i2c_dw_adjust_bus_speed); diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index e0233d845029a0..c59348491f5e6e 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -287,6 +287,7 @@ struct dw_i2c_dev { u16 fp_lcnt; u16 hs_hcnt; u16 hs_lcnt; + u32 wanted_bus_speed; int (*acquire_lock)(void); void (*release_lock)(void); int semaphore_idx; diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c index de3c10e0f7a1aa..e3ecf0bf592e67 100644 --- a/drivers/i2c/busses/i2c-designware-master.c +++ b/drivers/i2c/busses/i2c-designware-master.c @@ -37,6 +37,22 @@ 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 = dev->wanted_bus_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) { u32 comp_param1; @@ -44,6 +60,7 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev) struct i2c_timings *t = &dev->timings; const char *fp_str = ""; u32 ic_clk; + u32 hcnt, lcnt; int ret; ret = i2c_dw_acquire_lock(dev); @@ -59,6 +76,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); @@ -74,6 +94,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); @@ -124,6 +146,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); @@ -152,6 +176,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); } diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 692ada42194e8b..74182db03a88b3 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -132,18 +132,9 @@ static int mscc_twi_set_sda_hold_time(struct dw_i2c_dev *dev) return 0; } -static void dw_i2c_read_of_cnt(struct device_node *np, const char *name, u16 *pval) -{ - u32 val; - - if (!of_property_read_u32(np, name, &val)) - *pval = (u16)val; -} - static int dw_i2c_of_configure(struct platform_device *pdev) { struct dw_i2c_dev *dev = platform_get_drvdata(pdev); - struct device_node *np = pdev->dev.of_node; switch (dev->flags & MODEL_MASK) { case MODEL_MSCC_OCELOT: @@ -155,15 +146,6 @@ static int dw_i2c_of_configure(struct platform_device *pdev) break; } - dw_i2c_read_of_cnt(np, "snps,ss_hcnt", &dev->ss_hcnt); - dw_i2c_read_of_cnt(np, "snps,ss_lcnt", &dev->ss_lcnt); - dw_i2c_read_of_cnt(np, "snps,fs_hcnt", &dev->fs_hcnt); - dw_i2c_read_of_cnt(np, "snps,fs_lcnt", &dev->fs_lcnt); - dw_i2c_read_of_cnt(np, "snps,fp_hcnt", &dev->fp_hcnt); - dw_i2c_read_of_cnt(np, "snps,fp_lcnt", &dev->fp_lcnt); - dw_i2c_read_of_cnt(np, "snps,hs_hcnt", &dev->hs_hcnt); - dw_i2c_read_of_cnt(np, "snps,hs_lcnt", &dev->hs_lcnt); - return 0; }