Re: [PATCH V2 2/6] pwm: sprd: Improve the pwm backlight control function

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

 



On Thu, 25 Jan 2024 at 11:09, Wenhua Lin <Wenhua.Lin@xxxxxxxxxx> wrote:
>
> The pwm-sprd driver support only 8-bit linear control of backlight. Now,
> new requests of supporting 9-bit, 10-bit, 11-bit and 12-bit linear
> control of backlight are proposed. Besides, different channels of pwm
> could be configured into different linear control of backlight. Thus,
> sprd,mod attribute is introduced into dts for every channel of pwm
> device. This attribute would determine the value of MOD and eventually
> realize the new requirements.
>
> Signed-off-by: Wenhua Lin <Wenhua.Lin@xxxxxxxxxx>
> ---
>  drivers/pwm/pwm-sprd.c | 42 ++++++++++++++++++++++++++++++++++--------
>  1 file changed, 34 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/pwm/pwm-sprd.c b/drivers/pwm/pwm-sprd.c
> index bc1e3ed13528..cc54aa77c7e6 100644
> --- a/drivers/pwm/pwm-sprd.c
> +++ b/drivers/pwm/pwm-sprd.c
> @@ -18,7 +18,8 @@
>  #define SPRD_PWM_DUTY          0x8
>  #define SPRD_PWM_ENABLE                0x18
>
> -#define SPRD_PWM_MOD_MAX       GENMASK(7, 0)
> +#define SPRD_PWM_MOD_MAX       GENMASK(15, 0)
> +#define SPRD_PWM_MOD_DEFAULT   GENMASK(9, 0)
>  #define SPRD_PWM_DUTY_MSK      GENMASK(15, 0)
>  #define SPRD_PWM_PRESCALE_MSK  GENMASK(7, 0)
>  #define SPRD_PWM_ENABLE_BIT    BIT(0)
> @@ -43,6 +44,7 @@ struct sprd_pwm_chip {
>         const struct sprd_pwm_data *pdata;
>         int num_pwms;
>         struct sprd_pwm_chn chn[SPRD_PWM_CHN_NUM];
> +       u32 mod[SPRD_PWM_CHN_NUM];
>  };
>
>  static const struct sprd_pwm_data ums512_data = {
> @@ -120,7 +122,7 @@ static int sprd_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
>          */
>         val = sprd_pwm_read(spc, pwm->hwpwm, SPRD_PWM_PRESCALE);
>         prescale = val & SPRD_PWM_PRESCALE_MSK;
> -       tmp = (prescale + 1) * NSEC_PER_SEC * SPRD_PWM_MOD_MAX;
> +       tmp = (prescale + 1) * NSEC_PER_SEC * spc->mod[pwm->hwpwm];
>         state->period = DIV_ROUND_CLOSEST_ULL(tmp, chn->clk_rate);
>
>         val = sprd_pwm_read(spc, pwm->hwpwm, SPRD_PWM_DUTY);
> @@ -140,7 +142,7 @@ static int sprd_pwm_config(struct sprd_pwm_chip *spc, struct pwm_device *pwm,
>                            int duty_ns, int period_ns)
>  {
>         struct sprd_pwm_chn *chn = &spc->chn[pwm->hwpwm];
> -       u32 prescale, duty;
> +       u32 prescale, duty, mod;
>         u64 tmp;
>
>         /*
> @@ -148,16 +150,21 @@ static int sprd_pwm_config(struct sprd_pwm_chip *spc, struct pwm_device *pwm,
>          * The period length is (PRESCALE + 1) * MOD counter steps.
>          * The duty cycle length is (PRESCALE + 1) * DUTY counter steps.
>          *
> -        * To keep the maths simple we're always using MOD = SPRD_PWM_MOD_MAX.
> +        * The value for MOD is obtained from dts.
>          * The value for PRESCALE is selected such that the resulting period
>          * gets the maximal length not bigger than the requested one with the
> -        * given settings (MOD = SPRD_PWM_MOD_MAX and input clock).
> +        * given settings (MOD and input clock).
>          */
> -       duty = duty_ns * SPRD_PWM_MOD_MAX / period_ns;
> +       mod = spc->mod[pwm->hwpwm];
> +       duty = duty_ns * mod / period_ns;
>
>         tmp = (u64)chn->clk_rate * period_ns;
>         do_div(tmp, NSEC_PER_SEC);
> -       prescale = DIV_ROUND_CLOSEST_ULL(tmp, SPRD_PWM_MOD_MAX) - 1;
> +       prescale = DIV_ROUND_CLOSEST_ULL(tmp, mod);
> +       if (prescale < 1)
> +               prescale = 1;
> +       prescale--;
> +
>         if (prescale > SPRD_PWM_PRESCALE_MSK)
>                 prescale = SPRD_PWM_PRESCALE_MSK;
>
> @@ -170,7 +177,7 @@ static int sprd_pwm_config(struct sprd_pwm_chip *spc, struct pwm_device *pwm,
>          * before changing a new configuration to avoid mixed settings.
>          */
>         sprd_pwm_write(spc, pwm->hwpwm, SPRD_PWM_PRESCALE, prescale);
> -       sprd_pwm_write(spc, pwm->hwpwm, SPRD_PWM_MOD, SPRD_PWM_MOD_MAX);
> +       sprd_pwm_write(spc, pwm->hwpwm, SPRD_PWM_MOD, mod);
>         sprd_pwm_write(spc, pwm->hwpwm, SPRD_PWM_DUTY, duty);
>
>         return 0;
> @@ -263,6 +270,21 @@ static int sprd_pwm_clk_init(struct sprd_pwm_chip *spc)
>         return 0;
>  }
>
> +static int sprd_pwm_get_mod(struct platform_device *pdev)
> +{
> +       int i, ret;
> +       struct sprd_pwm_chip *spc = platform_get_drvdata(pdev);

Before using platform_get_drvdata(), you have to call
platform_set_drvdata, otherwise spc is NULL here and it will cause a
crash.

> +
> +       ret = of_property_read_u32_array(pdev->dev.of_node,
> +                                        "sprd,mod", spc->mod, spc->num_pwms);
> +       if (ret) {


> +               for (i = 0; i < spc->num_pwms; i++)
> +                       spc->mod[i] = SPRD_PWM_MOD_DEFAULT;
> +       }
> +
> +       return ret;
> +}
> +
>  static int sprd_pwm_probe(struct platform_device *pdev)
>  {
>         struct sprd_pwm_chip *spc;
> @@ -288,6 +310,10 @@ static int sprd_pwm_probe(struct platform_device *pdev)
>         if (ret)
>                 return ret;
>
> +       ret = sprd_pwm_get_mod(pdev);
> +       if (ret)
> +               dev_info(&pdev->dev, "get pwm mod failed! Use default setting\n");
> +
>         spc->chip.dev = &pdev->dev;
>         spc->chip.ops = &sprd_pwm_ops;
>         spc->chip.npwm = spc->num_pwms;
> --
> 2.17.1
>




[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]


  Powered by Linux