Re: [PATCH v2 4/4] pwm: rcar: improve calculation of divider

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Shimoda-san,

On Tue, Jan 8, 2019 at 4:31 AM Yoshihiro Shimoda
<yoshihiro.shimoda.uh@xxxxxxxxxxx> wrote:
> The rcar_pwm_get_clock_division() has a loop to calculate the divider,
> but the value of div should be calculatable without a loop. So,
> this patch improves it.
>
> This algorithm is suggested by Uwe Kleine-König and Laurent Pinchart.
>
> Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@xxxxxxxxxxx>
> ---
>  drivers/pwm/pwm-rcar.c | 16 +++++++---------
>  1 file changed, 7 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/pwm/pwm-rcar.c b/drivers/pwm/pwm-rcar.c
> index 6dbb70c..0498a93 100644
> --- a/drivers/pwm/pwm-rcar.c
> +++ b/drivers/pwm/pwm-rcar.c
> @@ -8,6 +8,8 @@
>  #include <linux/clk.h>
>  #include <linux/err.h>
>  #include <linux/io.h>
> +#include <linux/log2.h>
> +#include <linux/math64.h>
>  #include <linux/module.h>
>  #include <linux/of.h>
>  #include <linux/platform_device.h>
> @@ -68,19 +70,15 @@ static void rcar_pwm_update(struct rcar_pwm_chip *rp, u32 mask, u32 data,
>  static int rcar_pwm_get_clock_division(struct rcar_pwm_chip *rp, int period_ns)
>  {
>         unsigned long clk_rate = clk_get_rate(rp->clk);
> -       unsigned long long max; /* max cycle / nanoseconds */
> -       unsigned int div;
> +       u64 div, tmp;
>
>         if (clk_rate == 0)
>                 return -EINVAL;
>
> -       for (div = 0; div <= RCAR_PWM_MAX_DIVISION; div++) {
> -               max = (unsigned long long)NSEC_PER_SEC * RCAR_PWM_MAX_CYCLE *
> -                       (1 << div);
> -               do_div(max, clk_rate);
> -               if (period_ns <= max)
> -                       break;
> -       }
> +       div = NSEC_PER_SEC * RCAR_PWM_MAX_CYCLE;

As we have:

    #define NSEC_PER_SEC    1000000000L
    #define RCAR_PWM_MAX_CYCLE      1023

NSEC_PER_SEC is 64-bit on arm64, and 32-bit on arm32.

Hence you should use

    div = (u64)NSEC_PER_SEC * RCAR_PWM_MAX_CYCLE;

to avoid overflow on arm32.

> +       tmp = (u64)period_ns * clk_rate + div - 1;
> +       tmp = div64_u64(tmp, div);
> +       div = ilog2(tmp - 1) + 1;
>
>         return (div <= RCAR_PWM_MAX_DIVISION) ? div : -ERANGE;
>  }

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@xxxxxxxxxxxxxx

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds



[Index of Archives]     [Linux Samsung SOC]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]

  Powered by Linux