On Mon 25 Oct 01:42 PDT 2021, Uwe Kleine-K?nig wrote:

> Hello,
> 
> [replaced Andrzej Hajda's email address with his new one]
> 
> On Wed, Sep 29, 2021 at 10:05:57PM -0500, Bjorn Andersson wrote:
> > The SN65DSI86 provides the ability to supply a PWM signal on GPIO 4,
> > with the primary purpose of controlling the backlight of the attached
> > panel. Add an implementation that exposes this using the standard PWM
> > framework, to allow e.g. pwm-backlight to expose this to the user.
> 
> Sorry for the long delay in reviewing this.
> 

No worries, glad to hear from you again.

> > Signed-off-by: Bjorn Andersson <bjorn.anders...@linaro.org>
> > ---
> > 
[..]
> > +static int ti_sn_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
> > +                      const struct pwm_state *state)
> > +{
> > +   struct ti_sn65dsi86 *pdata = pwm_chip_to_ti_sn_bridge(chip);
> > +   unsigned int pwm_en_inv;
> > +   unsigned int backlight;
> > +   unsigned int pre_div;
> > +   unsigned int scale;
> > +   u64 period_max;
> > +   u64 period;
> > +   int ret;
> > +
> > +   if (!pdata->pwm_enabled) {
> > +           ret = pm_runtime_get_sync(pdata->dev);
> > +           if (ret < 0) {
> > +                   pm_runtime_put_sync(pdata->dev);
> > +                   return ret;
> > +           }
> > +   }
> > +
> > +   if (state->enabled) {
> > +           if (!pdata->pwm_enabled) {
> > +                   /*
> > +                    * The chip might have been powered down while we
> > +                    * didn't hold a PM runtime reference, so mux in the
> > +                    * PWM function on the GPIO pin again.
> > +                    */
> > +                   ret = regmap_update_bits(pdata->regmap, 
> > SN_GPIO_CTRL_REG,
> > +                                            SN_GPIO_MUX_MASK << (2 * 
> > SN_PWM_GPIO_IDX),
> > +                                            SN_GPIO_MUX_SPECIAL << (2 * 
> > SN_PWM_GPIO_IDX));
> > +                   if (ret) {
> > +                           dev_err(pdata->dev, "failed to mux in PWM 
> > function\n");
> > +                           goto out;
> > +                   }
> > +           }
> > +
> > +           /*
> > +            * Per the datasheet the PWM frequency is given by:
> > +            *
> > +            *                          REFCLK_FREQ
> > +            *   PWM_FREQ = -----------------------------------
> > +            *               PWM_PRE_DIV * BACKLIGHT_SCALE + 1
> > +            *
> > +            * However, after careful review the author is convinced that
> > +            * the documentation has lost some parenthesis around
> > +            * "BACKLIGHT_SCALE + 1".
> > +            * With that the formula can be written:
> > +            *
> > +            *   T_pwm * REFCLK_FREQ = PWM_PRE_DIV * (BACKLIGHT_SCALE + 1)
> 
> For my understanding: T_pwm = period length = 1 / PWM_FREQ, right? Maybe
> it's a good idea to state this more explicitly?
> 

Correct. I've improved the comment accordingly.

> > +            * In order to keep BACKLIGHT_SCALE within its 16 bits,
> > +            * PWM_PRE_DIV must be:
> > +            *
> > +            *                     T_pwm * REFCLK_FREQ
> > +            *   PWM_PRE_DIV >= -------------------------
> > +            *                   BACKLIGHT_SCALE_MAX + 1
> > +            *
> > +            * To simplify the search and to favour higher resolution of
> > +            * the duty cycle over accuracy of the period, the lowest
> > +            * possible PWM_PRE_DIV is used. Finally the scale is
> > +            * calculated as:
> > +            *
> > +            *                      T_pwm * REFCLK_FREQ
> > +            *   BACKLIGHT_SCALE = ---------------------- - 1
> > +            *                          PWM_PRE_DIV
> > +            *
> > +            * Here T_pwm is represented in seconds, so appropriate scaling
> > +            * to nanoseconds is necessary.
> > +            */
> > +
> > +           /* Minimum T_pwm is 1 / REFCLK_FREQ */
> > +           if (state->period <= NSEC_PER_SEC / pdata->pwm_refclk_freq) {
> > +                   ret = -EINVAL;
> > +                   goto out;
> > +           }
> > +
> > +           /*
> > +            * Maximum T_pwm is 255 * (65535 + 1) / REFCLK_FREQ
> > +            * Limit period to this to avoid overflows
> > +            */
> > +           period_max = div_u64((u64)NSEC_PER_SEC * 255 * (65535 + 1),
> > +                                pdata->pwm_refclk_freq);
> > +           if (period > period_max)
> 
> period is uninitialized here. This must be
> 
>               if (state->period > period_max)
> 
> . Alternatively to the if you could use
> 
>               period = min(state->period, period_max);
> 

Yes of course.

> 
> Apart from this I'm happy with your patch set now.
> 

Thank you.

> > +                   period = period_max;
> > +           else
> > +                   period = state->period;
> > +
> > +           pre_div = DIV64_U64_ROUND_UP(period * pdata->pwm_refclk_freq,
> > +                                        (u64)NSEC_PER_SEC * 
> > (BACKLIGHT_SCALE_MAX + 1));
> > +           scale = div64_u64(period * pdata->pwm_refclk_freq, 
> > (u64)NSEC_PER_SEC * pre_div) - 1;
> 
> After thinking a while about this---I think I stumbled about this
> calculation already in earlier revisions of this patch set---I think I
> now understood it. I never saw something like this before because other
> drivers with similar HW conditions would pick:
> 
>       pre_div = div64_u64(period * pdata->pwm_refclk_freq,
>                           (u64)NSEC_PER_SEC * (BACKLIGHT_SCALE_MAX + 1));
> 
> and then scale = BACKLIGHT_SCALE_MAX. This latter approach weights high
> resolution of duty_cycle still higher over period exactness than your
> approach.

Interesting.

> For me both approaches are fine.
> 

Thanks, I'll respin with the two minor things above and leave the math
as is now :)

Regards,
Bjorn

> Best regards
> Uwe
> 
> -- 
> Pengutronix e.K.                           | Uwe Kleine-König            |
> Industrial Linux Solutions                 | https://www.pengutronix.de/ |


Reply via email to