On 3/6/20 11:09 AM, Patrick Delaunay wrote:
> From: Alain Volmat <[email protected]>
>
> Do not limit to 3 (100KHz, 400KHz, 1MHz) bus frequencies, but
> instead allow for any frequency. Depending on the requested
> frequency (via the clock-frequency DT entry), use the spec
> data from either Standard, Fast or Fast Plus mode.
>
> In order to do so, the driver do not use anymore spec identifier
> by directly handle the requested frequency and from it retrieve
> the corresponding spec data to be used for the computation
> of the timing register.
>
> Signed-off-by: Alain Volmat <[email protected]>
> Reviewed-by: Patrick DELAUNAY <[email protected]>
> Signed-off-by: Patrick Delaunay <[email protected]>
> ---
>
>  drivers/i2c/stm32f7_i2c.c | 105 +++++++++++++++++++++-----------------
>  1 file changed, 59 insertions(+), 46 deletions(-)
>
> diff --git a/drivers/i2c/stm32f7_i2c.c b/drivers/i2c/stm32f7_i2c.c
> index 7d046c1a1e..fc5c1221e1 100644
> --- a/drivers/i2c/stm32f7_i2c.c
> +++ b/drivers/i2c/stm32f7_i2c.c
> @@ -7,10 +7,10 @@
>  #include <clk.h>
>  #include <dm.h>
>  #include <i2c.h>
> -#include <malloc.h>
>  #include <reset.h>
>  
>  #include <dm/device.h>
> +#include <linux/err.h>
>  #include <linux/io.h>
>  
>  /* STM32 I2C registers */
> @@ -145,7 +145,6 @@ struct stm32_i2c_spec {
>  
>  /**
>   * struct stm32_i2c_setup - private I2C timing setup parameters
> - * @speed: I2C speed mode (standard, Fast Plus)
>   * @speed_freq: I2C speed frequency  (Hz)
>   * @clock_src: I2C clock source frequency (Hz)
>   * @rise_time: Rise time (ns)
> @@ -154,7 +153,6 @@ struct stm32_i2c_spec {
>   * @analog_filter: Analog filter delay (On/Off)
>   */
>  struct stm32_i2c_setup {
> -     enum i2c_speed_mode speed;
>       u32 speed_freq;
>       u32 clock_src;
>       u32 rise_time;
> @@ -184,10 +182,11 @@ struct stm32_i2c_priv {
>       struct stm32_i2c_regs *regs;
>       struct clk clk;
>       struct stm32_i2c_setup *setup;
> -     int speed;
> +     u32 speed;
>  };
>  
>  static const struct stm32_i2c_spec i2c_specs[] = {
> +     /* Standard speed - 100 KHz */
>       [IC_SPEED_MODE_STANDARD] = {
>               .rate = I2C_SPEED_STANDARD_RATE,
>               .rate_min = 8000,
> @@ -200,6 +199,7 @@ static const struct stm32_i2c_spec i2c_specs[] = {
>               .l_min = 4700,
>               .h_min = 4000,
>       },
> +     /* Fast speed - 400 KHz */
>       [IC_SPEED_MODE_FAST] = {
>               .rate = I2C_SPEED_FAST_RATE,
>               .rate_min = 320000,
> @@ -212,6 +212,7 @@ static const struct stm32_i2c_spec i2c_specs[] = {
>               .l_min = 1300,
>               .h_min = 600,
>       },
> +     /* Fast Plus Speed - 1 MHz */
>       [IC_SPEED_MODE_FAST_PLUS] = {
>               .rate = I2C_SPEED_FAST_PLUS_RATE,
>               .rate_min = 800000,
> @@ -474,6 +475,7 @@ static int stm32_i2c_xfer(struct udevice *bus, struct 
> i2c_msg *msg,
>  }
>  
>  static int stm32_i2c_compute_solutions(struct stm32_i2c_setup *setup,
> +                                    const struct stm32_i2c_spec *specs,
>                                      struct list_head *solutions)
>  {
>       struct stm32_i2c_timings *v;
> @@ -490,13 +492,13 @@ static int stm32_i2c_compute_solutions(struct 
> stm32_i2c_setup *setup,
>       af_delay_max = setup->analog_filter ?
>                      STM32_I2C_ANALOG_FILTER_DELAY_MAX : 0;
>  
> -     sdadel_min = i2c_specs[setup->speed].hddat_min + setup->fall_time -
> +     sdadel_min = specs->hddat_min + setup->fall_time -
>                    af_delay_min - (setup->dnf + 3) * i2cclk;
>  
> -     sdadel_max = i2c_specs[setup->speed].vddat_max - setup->rise_time -
> +     sdadel_max = specs->vddat_max - setup->rise_time -
>                    af_delay_max - (setup->dnf + 4) * i2cclk;
>  
> -     scldel_min = setup->rise_time + i2c_specs[setup->speed].sudat_min;
> +     scldel_min = setup->rise_time + specs->sudat_min;
>  
>       if (sdadel_min < 0)
>               sdadel_min = 0;
> @@ -548,6 +550,7 @@ static int stm32_i2c_compute_solutions(struct 
> stm32_i2c_setup *setup,
>  }
>  
>  static int stm32_i2c_choose_solution(struct stm32_i2c_setup *setup,
> +                                  const struct stm32_i2c_spec *specs,
>                                    struct list_head *solutions,
>                                    struct stm32_i2c_timings *s)
>  {
> @@ -570,8 +573,8 @@ static int stm32_i2c_choose_solution(struct 
> stm32_i2c_setup *setup,
>       dnf_delay = setup->dnf * i2cclk;
>  
>       tsync = af_delay_min + dnf_delay + (2 * i2cclk);
> -     clk_max = STM32_NSEC_PER_SEC / i2c_specs[setup->speed].rate_min;
> -     clk_min = STM32_NSEC_PER_SEC / i2c_specs[setup->speed].rate_max;
> +     clk_max = STM32_NSEC_PER_SEC / specs->rate_min;
> +     clk_min = STM32_NSEC_PER_SEC / specs->rate_max;
>  
>       /*
>        * Among Prescaler possibilities discovered above figures out SCL Low
> @@ -589,7 +592,7 @@ static int stm32_i2c_choose_solution(struct 
> stm32_i2c_setup *setup,
>               for (l = 0; l < STM32_SCLL_MAX; l++) {
>                       u32 tscl_l = (l + 1) * prescaler + tsync;
>  
> -                     if ((tscl_l < i2c_specs[setup->speed].l_min) ||
> +                     if (tscl_l < specs->l_min ||
>                           (i2cclk >=
>                            ((tscl_l - af_delay_min - dnf_delay) / 4))) {
>                               continue;
> @@ -601,7 +604,7 @@ static int stm32_i2c_choose_solution(struct 
> stm32_i2c_setup *setup,
>                                          setup->rise_time + setup->fall_time;
>  
>                               if ((tscl >= clk_min) && (tscl <= clk_max) &&
> -                                 (tscl_h >= i2c_specs[setup->speed].h_min) &&
> +                                 (tscl_h >= specs->h_min) &&
>                                   (i2cclk < tscl_h)) {
>                                       u32 clk_error;
>  
> @@ -630,26 +633,40 @@ static int stm32_i2c_choose_solution(struct 
> stm32_i2c_setup *setup,
>       return ret;
>  }
>  
> +static const struct stm32_i2c_spec *get_specs(u32 rate)
> +{
> +     unsigned int i;
> +
> +     for (i = 0; i < ARRAY_SIZE(i2c_specs); i++)
> +             if (rate <= i2c_specs[i].rate)
> +                     return &i2c_specs[i];
> +
> +     /* NOT REACHED */
> +     return ERR_PTR(-EINVAL);
> +}
> +
>  static int stm32_i2c_compute_timing(struct stm32_i2c_priv *i2c_priv,
>                                   struct stm32_i2c_setup *setup,
>                                   struct stm32_i2c_timings *output)
>  {
> +     const struct stm32_i2c_spec *specs;
>       struct stm32_i2c_timings *v, *_v;
>       struct list_head solutions;
>       int ret;
>  
> -     if (setup->speed >= ARRAY_SIZE(i2c_specs)) {
> -             pr_err("%s: speed out of bound {%d/%d}\n", __func__,
> -                    setup->speed, ARRAY_SIZE(i2c_specs) - 1);
> +     specs = get_specs(setup->speed_freq);
> +     if (specs == ERR_PTR(-EINVAL)) {
> +             pr_err("%s: speed out of bound {%d}\n", __func__,
> +                    setup->speed_freq);
>               return -EINVAL;
>       }
>  
> -     if ((setup->rise_time > i2c_specs[setup->speed].rise_max) ||
> -         (setup->fall_time > i2c_specs[setup->speed].fall_max)) {
> +     if (setup->rise_time > specs->rise_max ||
> +         setup->fall_time > specs->fall_max) {
>               pr_err("%s :timings out of bound Rise{%d>%d}/Fall{%d>%d}\n",
>                      __func__,
> -                    setup->rise_time, i2c_specs[setup->speed].rise_max,
> -                    setup->fall_time, i2c_specs[setup->speed].fall_max);
> +                    setup->rise_time, specs->rise_max,
> +                    setup->fall_time, specs->fall_max);
>               return -EINVAL;
>       }
>  
> @@ -659,18 +676,12 @@ static int stm32_i2c_compute_timing(struct 
> stm32_i2c_priv *i2c_priv,
>               return -EINVAL;
>       }
>  
> -     if (setup->speed_freq > i2c_specs[setup->speed].rate) {
> -             pr_err("%s: Freq {%d/%d}\n", __func__,
> -                    setup->speed_freq, i2c_specs[setup->speed].rate);
> -             return -EINVAL;
> -     }
> -
>       INIT_LIST_HEAD(&solutions);
> -     ret = stm32_i2c_compute_solutions(setup, &solutions);
> +     ret = stm32_i2c_compute_solutions(setup, specs, &solutions);
>       if (ret)
>               goto exit;
>  
> -     ret = stm32_i2c_choose_solution(setup, &solutions, output);
> +     ret = stm32_i2c_choose_solution(setup, specs, &solutions, output);
>       if (ret)
>               goto exit;
>  
> @@ -689,14 +700,24 @@ exit:
>       return ret;
>  }
>  
> +static u32 get_lower_rate(u32 rate)
> +{
> +     int i;
> +
> +     for (i = ARRAY_SIZE(i2c_specs) - 1; i >= 0; i--)
> +             if (rate > i2c_specs[i].rate)
> +                     return i2c_specs[i].rate;
> +
> +     return i2c_specs[0].rate;
> +}
> +
>  static int stm32_i2c_setup_timing(struct stm32_i2c_priv *i2c_priv,
>                                 struct stm32_i2c_timings *timing)
>  {
>       struct stm32_i2c_setup *setup = i2c_priv->setup;
>       int ret = 0;
>  
> -     setup->speed = i2c_priv->speed;
> -     setup->speed_freq = i2c_specs[setup->speed].rate;
> +     setup->speed_freq = i2c_priv->speed;
>       setup->clock_src = clk_get_rate(&i2c_priv->clk);
>  
>       if (!setup->clock_src) {
> @@ -709,13 +730,11 @@ static int stm32_i2c_setup_timing(struct stm32_i2c_priv 
> *i2c_priv,
>               if (ret) {
>                       debug("%s: failed to compute I2C timings.\n",
>                             __func__);
> -                     if (i2c_priv->speed > IC_SPEED_MODE_STANDARD) {
> -                             i2c_priv->speed--;
> -                             setup->speed = i2c_priv->speed;
> +                     if (setup->speed_freq > I2C_SPEED_STANDARD_RATE) {
>                               setup->speed_freq =
> -                                     i2c_specs[setup->speed].rate;
> +                                     get_lower_rate(setup->speed_freq);
>                               debug("%s: downgrade I2C Speed Freq to (%i)\n",
> -                                   __func__, i2c_specs[setup->speed].rate);
> +                                   __func__, setup->speed_freq);
>                       } else {
>                               break;
>                       }
> @@ -727,13 +746,15 @@ static int stm32_i2c_setup_timing(struct stm32_i2c_priv 
> *i2c_priv,
>               return ret;
>       }
>  
> -     debug("%s: I2C Speed(%i), Freq(%i), Clk Source(%i)\n", __func__,
> -           setup->speed, setup->speed_freq, setup->clock_src);
> +     debug("%s: I2C Freq(%i), Clk Source(%i)\n", __func__,
> +           setup->speed_freq, setup->clock_src);
>       debug("%s: I2C Rise(%i) and Fall(%i) Time\n", __func__,
>             setup->rise_time, setup->fall_time);
>       debug("%s: I2C Analog Filter(%s), DNF(%i)\n", __func__,
>             setup->analog_filter ? "On" : "Off", setup->dnf);
>  
> +     i2c_priv->speed = setup->speed_freq;
> +
>       return 0;
>  }
>  
> @@ -773,21 +794,13 @@ static int stm32_i2c_set_bus_speed(struct udevice *bus, 
> unsigned int speed)
>  {
>       struct stm32_i2c_priv *i2c_priv = dev_get_priv(bus);
>  
> -     switch (speed) {
> -     case I2C_SPEED_STANDARD_RATE:
> -             i2c_priv->speed = IC_SPEED_MODE_STANDARD;
> -             break;
> -     case I2C_SPEED_FAST_RATE:
> -             i2c_priv->speed = IC_SPEED_MODE_FAST;
> -             break;
> -     case I2C_SPEED_FAST_PLUS_RATE:
> -             i2c_priv->speed = IC_SPEED_MODE_FAST_PLUS;
> -             break;
> -     default:
> +     if (speed > I2C_SPEED_FAST_PLUS_RATE) {
>               debug("%s: Speed %d not supported\n", __func__, speed);
>               return -EINVAL;
>       }
>  
> +     i2c_priv->speed = speed;
> +
>       return stm32_i2c_hw_config(i2c_priv);
>  }
>  

Acked-by: Patrice Chotard <[email protected]>

Thanks

Patrice

Reply via email to