[PATCH] backlight: pwm_bl: switch to using "atomic" PWM API
Enric Balletbo i Serra
enric.balletbo at collabora.com
Fri Jul 27 15:03:13 UTC 2018
Hi Daniel,
Thanks for reviewing the patch.
On 27/07/18 13:32, Daniel Thompson wrote:
> On 26/07/18 10:15, Enric Balletbo i Serra wrote:
>> The "atomic" API allows us to configure PWM period and duty_cycle and
>> enable it in one call.
>>
>> The patch also moves the pwm_init_state just before any use of the
>> pwm_state struct, this fixes a potential bug where pwm_get_state
>> can be called before pwm_init_state.
>>
>> Signed-off-by: Enric Balletbo i Serra <enric.balletbo at collabora.com>
>> ---
>>
>> drivers/video/backlight/pwm_bl.c | 48 ++++++++++++++++++++------------
>> 1 file changed, 30 insertions(+), 18 deletions(-)
>>
>> diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
>> index bdfcc0a71db1..2c734d55d607 100644
>> --- a/drivers/video/backlight/pwm_bl.c
>> +++ b/drivers/video/backlight/pwm_bl.c
>> @@ -46,7 +46,8 @@ struct pwm_bl_data {
>> void (*exit)(struct device *);
>> };
>> -static void pwm_backlight_power_on(struct pwm_bl_data *pb, int brightness)
>> +static void pwm_backlight_power_on(struct pwm_bl_data *pb,
>> + struct pwm_state *state)
>> {
>> int err;
>> @@ -57,7 +58,8 @@ static void pwm_backlight_power_on(struct pwm_bl_data *pb,
>> int brightness)
>> if (err < 0)
>> dev_err(pb->dev, "failed to enable power supply\n");
>> - pwm_enable(pb->pwm);
>> + state->enabled = true;
>> + pwm_apply_state(pb->pwm, state);
>> if (pb->post_pwm_on_delay)
>> msleep(pb->post_pwm_on_delay);
>> @@ -70,6 +72,8 @@ static void pwm_backlight_power_on(struct pwm_bl_data *pb,
>> int brightness)
>> static void pwm_backlight_power_off(struct pwm_bl_data *pb)
>> {
>> + struct pwm_state state;
>> +
>> if (!pb->enabled)
>> return;
>> @@ -79,8 +83,11 @@ static void pwm_backlight_power_off(struct pwm_bl_data *pb)
>> if (pb->pwm_off_delay)
>> msleep(pb->pwm_off_delay);
>> - pwm_config(pb->pwm, 0, pb->period);
>> - pwm_disable(pb->pwm);
>> + pwm_get_state(pb->pwm, &state);
>> + state.enabled = false;
>> + state.period = pb->period;
>> + state.duty_cycle = 0;
>> + pwm_apply_state(pb->pwm, &state);
>> regulator_disable(pb->power_supply);
>> pb->enabled = false;
>> @@ -106,6 +113,7 @@ static int pwm_backlight_update_status(struct
>> backlight_device *bl)
>> {
>> struct pwm_bl_data *pb = bl_get_data(bl);
>> int brightness = bl->props.brightness;
>> + struct pwm_state state;
>> int duty_cycle;
>> if (bl->props.power != FB_BLANK_UNBLANK ||
>> @@ -118,8 +126,13 @@ static int pwm_backlight_update_status(struct
>> backlight_device *bl)
>> if (brightness > 0) {
>> duty_cycle = compute_duty_cycle(pb, brightness);
>> - pwm_config(pb->pwm, duty_cycle, pb->period);
>> - pwm_backlight_power_on(pb, brightness);
>> + pwm_get_state(pb->pwm, &state);
>> + state.duty_cycle = duty_cycle;
>> + state.period = pb->period;
>> + if (!state.enabled)
>> + pwm_backlight_power_on(pb, &state);
>> + else
>> + pwm_apply_state(pb->pwm, &state);
>> } else
>> pwm_backlight_power_off(pb);
>> @@ -447,7 +460,6 @@ static int pwm_backlight_probe(struct platform_device
>> *pdev)
>> struct device_node *node = pdev->dev.of_node;
>> struct pwm_bl_data *pb;
>> struct pwm_state state;
>> - struct pwm_args pargs;
>> unsigned int i;
>> int ret;
>> @@ -539,10 +551,17 @@ static int pwm_backlight_probe(struct platform_device
>> *pdev)
>> dev_dbg(&pdev->dev, "got pwm for backlight\n");
>> - if (!data->levels) {
>> - /* Get the PWM period (in nanoseconds) */
>> - pwm_get_state(pb->pwm, &state);
>> + /* Sync up PWM state and ensure it is off. */
>> + pwm_init_state(pb->pwm, &state);
>> + state.enabled = false;
>> + ret = pwm_apply_state(pb->pwm, &state);
>
> Why do we ensure the PWM is off? Does this cause backlight flickers or make some
> of the code in pwm_backlight_initial_power_state() unreachable?
>
No, I think that I can just remove that line.
>
>> + if (ret) {
>> + dev_err(&pdev->dev, "failed to apply initial PWM state: %d\n",
>> + ret);
>> + goto err_alloc;
>> + }
>> + if (!data->levels) {
>> ret = pwm_backlight_brightness_default(&pdev->dev, data,
>> state.period);
>> if (ret < 0) {
>> @@ -559,20 +578,13 @@ static int pwm_backlight_probe(struct platform_device
>> *pdev)
>> pb->levels = data->levels;
>> }
>> - /*
>> - * FIXME: pwm_apply_args() should be removed when switching to
>> - * the atomic PWM API.
>> - */
>> - pwm_apply_args(pb->pwm);
>> -
>> /*
>> * The DT case will set the pwm_period_ns field to 0 and store the
>> * period, parsed from the DT, in the PWM device. For the non-DT case,
>> * set the period from platform data if it has not already been set
>> * via the PWM lookup table.
>> */
>> - pwm_get_args(pb->pwm, &pargs);
>> - pb->period = pargs.period;
>> + pb->period = state.period;
>> if (!pb->period && (data->pwm_period_ns > 0))
>> pb->period = data->pwm_period_ns;
>
> Could we have delayed applying the state until we know what the period is
> supposed to be? No other call to pwm_apply_state() has its error value
> checked... so if there are problems with the period we could detect them here.
>
Yes, I can move this code before 'if (!data->levels)' and call pwm_apply_state
after.
> Note also that we can guarantee the period is set before the probe completes
> then I think pb->period could be removed entirely. It was only really being
> carried around to help with calls to pwm_config() and these no longer exist.
>
Right, I think that I can also remove pb->period. I'll send a second version soon.
Thanks,
Enric
>
> Daniel.
>
More information about the dri-devel
mailing list