* [PATCH 0/2] pwm: lpss: Atomic PWM support for LPSS @ 2018-09-11 17:45 Hans de Goede 2018-09-11 17:45 ` [PATCH 1/2] pwm: lpss: Add pwm_lpss_get_put_runtime_pm helper function Hans de Goede 2018-09-11 17:45 ` [PATCH 2/2] pwm: lpss: Add get_state callback Hans de Goede 0 siblings, 2 replies; 8+ messages in thread From: Hans de Goede @ 2018-09-11 17:45 UTC (permalink / raw) To: Thierry Reding, Andy Shevchenko; +Cc: Hans de Goede, linux-pwm, linux-acpi Hi All, This is an old series which got burried under a bunch of other stuff, but now that I'm touching the LPSS pwm code anyways I thought I would brush of the dust and submit it again. I believe that this version addresses all the remarks of previous reviews. Since it has been a long time I've lost track of which version of the series this is, so I'm resetting the versioning of the series to 1. Regards, Hans ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 1/2] pwm: lpss: Add pwm_lpss_get_put_runtime_pm helper function 2018-09-11 17:45 [PATCH 0/2] pwm: lpss: Atomic PWM support for LPSS Hans de Goede @ 2018-09-11 17:45 ` Hans de Goede 2018-09-24 9:16 ` Andy Shevchenko 2018-09-11 17:45 ` [PATCH 2/2] pwm: lpss: Add get_state callback Hans de Goede 1 sibling, 1 reply; 8+ messages in thread From: Hans de Goede @ 2018-09-11 17:45 UTC (permalink / raw) To: Thierry Reding, Andy Shevchenko; +Cc: Hans de Goede, linux-pwm, linux-acpi Add a helper function to properly get / put the pwm's runtime_pm reference when changing from enabled to disable or vice versa. And use this to ensure the pwm's runtime_pm reference is properly released on remove. Signed-off-by: Hans de Goede <hdegoede@redhat.com> --- drivers/pwm/pwm-lpss.c | 47 +++++++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c index e602835fd6de..d39158800baa 100644 --- a/drivers/pwm/pwm-lpss.c +++ b/drivers/pwm/pwm-lpss.c @@ -120,43 +120,58 @@ static inline void pwm_lpss_cond_enable(struct pwm_device *pwm, bool cond) pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_ENABLE); } +static void pwm_lpss_get_put_runtime_pm(struct pwm_chip *chip, + bool old_enabled, bool new_enabled) +{ + if (new_enabled == old_enabled) + return; + + if (new_enabled) + pm_runtime_get(chip->dev); + else + pm_runtime_put(chip->dev); +} + static int pwm_lpss_apply(struct pwm_chip *chip, struct pwm_device *pwm, struct pwm_state *state) { struct pwm_lpss_chip *lpwm = to_lpwm(chip); - int ret; + int ret = 0; + + pm_runtime_get_sync(chip->dev); if (state->enabled) { if (!pwm_is_enabled(pwm)) { - pm_runtime_get_sync(chip->dev); ret = pwm_lpss_is_updating(pwm); - if (ret) { - pm_runtime_put(chip->dev); - return ret; - } + if (ret) + goto out; + pwm_lpss_prepare(lpwm, pwm, state->duty_cycle, state->period); pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_SW_UPDATE); pwm_lpss_cond_enable(pwm, lpwm->info->bypass == false); ret = pwm_lpss_wait_for_update(pwm); - if (ret) { - pm_runtime_put(chip->dev); - return ret; - } + if (ret) + goto out; + pwm_lpss_cond_enable(pwm, lpwm->info->bypass == true); } else { ret = pwm_lpss_is_updating(pwm); if (ret) - return ret; + goto out; + pwm_lpss_prepare(lpwm, pwm, state->duty_cycle, state->period); pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_SW_UPDATE); - return pwm_lpss_wait_for_update(pwm); + ret = pwm_lpss_wait_for_update(pwm); } } else if (pwm_is_enabled(pwm)) { pwm_lpss_write(pwm, pwm_lpss_read(pwm) & ~PWM_ENABLE); - pm_runtime_put(chip->dev); } - return 0; + pwm_lpss_get_put_runtime_pm(chip, pwm_is_enabled(pwm), state->enabled); + +out: + pm_runtime_put(chip->dev); + return ret; } static const struct pwm_ops pwm_lpss_ops = { @@ -205,6 +220,10 @@ EXPORT_SYMBOL_GPL(pwm_lpss_probe); int pwm_lpss_remove(struct pwm_lpss_chip *lpwm) { + bool enabled = pwm_is_enabled(&lpwm->chip.pwms[0]); + + pwm_lpss_get_put_runtime_pm(&lpwm->chip, enabled, false); + return pwmchip_remove(&lpwm->chip); } EXPORT_SYMBOL_GPL(pwm_lpss_remove); -- 2.19.0.rc0 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH 1/2] pwm: lpss: Add pwm_lpss_get_put_runtime_pm helper function 2018-09-11 17:45 ` [PATCH 1/2] pwm: lpss: Add pwm_lpss_get_put_runtime_pm helper function Hans de Goede @ 2018-09-24 9:16 ` Andy Shevchenko 2018-09-24 9:58 ` Hans de Goede 0 siblings, 1 reply; 8+ messages in thread From: Andy Shevchenko @ 2018-09-24 9:16 UTC (permalink / raw) To: Hans de Goede; +Cc: Thierry Reding, linux-pwm, linux-acpi On Tue, Sep 11, 2018 at 07:45:32PM +0200, Hans de Goede wrote: > Add a helper function to properly get / put the pwm's runtime_pm > reference when changing from enabled to disable or vice versa. > > And use this to ensure the pwm's runtime_pm reference is properly > released on remove. > Can you provide a test sequence to reproduce the issue? > Signed-off-by: Hans de Goede <hdegoede@redhat.com> > --- > drivers/pwm/pwm-lpss.c | 47 +++++++++++++++++++++++++++++------------- > 1 file changed, 33 insertions(+), 14 deletions(-) > > diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c > index e602835fd6de..d39158800baa 100644 > --- a/drivers/pwm/pwm-lpss.c > +++ b/drivers/pwm/pwm-lpss.c > @@ -120,43 +120,58 @@ static inline void pwm_lpss_cond_enable(struct pwm_device *pwm, bool cond) > pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_ENABLE); > } > > +static void pwm_lpss_get_put_runtime_pm(struct pwm_chip *chip, > + bool old_enabled, bool new_enabled) > +{ > + if (new_enabled == old_enabled) > + return; > + > + if (new_enabled) > + pm_runtime_get(chip->dev); > + else > + pm_runtime_put(chip->dev); > +} > + > static int pwm_lpss_apply(struct pwm_chip *chip, struct pwm_device *pwm, > struct pwm_state *state) > { > struct pwm_lpss_chip *lpwm = to_lpwm(chip); > - int ret; > + int ret = 0; > + > + pm_runtime_get_sync(chip->dev); > > if (state->enabled) { > if (!pwm_is_enabled(pwm)) { > - pm_runtime_get_sync(chip->dev); > ret = pwm_lpss_is_updating(pwm); > - if (ret) { > - pm_runtime_put(chip->dev); > - return ret; > - } > + if (ret) > + goto out; > + > pwm_lpss_prepare(lpwm, pwm, state->duty_cycle, state->period); > pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_SW_UPDATE); > pwm_lpss_cond_enable(pwm, lpwm->info->bypass == false); > ret = pwm_lpss_wait_for_update(pwm); > - if (ret) { > - pm_runtime_put(chip->dev); > - return ret; > - } > + if (ret) > + goto out; > + > pwm_lpss_cond_enable(pwm, lpwm->info->bypass == true); > } else { > ret = pwm_lpss_is_updating(pwm); > if (ret) > - return ret; > + goto out; > + > pwm_lpss_prepare(lpwm, pwm, state->duty_cycle, state->period); > pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_SW_UPDATE); > - return pwm_lpss_wait_for_update(pwm); > + ret = pwm_lpss_wait_for_update(pwm); > } > } else if (pwm_is_enabled(pwm)) { > pwm_lpss_write(pwm, pwm_lpss_read(pwm) & ~PWM_ENABLE); > - pm_runtime_put(chip->dev); > } > > - return 0; > + pwm_lpss_get_put_runtime_pm(chip, pwm_is_enabled(pwm), state->enabled); > + > +out: > + pm_runtime_put(chip->dev); > + return ret; > } > > static const struct pwm_ops pwm_lpss_ops = { > @@ -205,6 +220,10 @@ EXPORT_SYMBOL_GPL(pwm_lpss_probe); > > int pwm_lpss_remove(struct pwm_lpss_chip *lpwm) > { > + bool enabled = pwm_is_enabled(&lpwm->chip.pwms[0]); > + > + pwm_lpss_get_put_runtime_pm(&lpwm->chip, enabled, false); > + > return pwmchip_remove(&lpwm->chip); > } > EXPORT_SYMBOL_GPL(pwm_lpss_remove); > -- > 2.19.0.rc0 > -- With Best Regards, Andy Shevchenko ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 1/2] pwm: lpss: Add pwm_lpss_get_put_runtime_pm helper function 2018-09-24 9:16 ` Andy Shevchenko @ 2018-09-24 9:58 ` Hans de Goede 2018-09-24 10:05 ` Andy Shevchenko 0 siblings, 1 reply; 8+ messages in thread From: Hans de Goede @ 2018-09-24 9:58 UTC (permalink / raw) To: Andy Shevchenko; +Cc: Thierry Reding, linux-pwm, linux-acpi Hi, On 24-09-18 11:16, Andy Shevchenko wrote: > On Tue, Sep 11, 2018 at 07:45:32PM +0200, Hans de Goede wrote: >> Add a helper function to properly get / put the pwm's runtime_pm >> reference when changing from enabled to disable or vice versa. >> >> And use this to ensure the pwm's runtime_pm reference is properly >> released on remove. >> > > Can you provide a test sequence to reproduce the issue? This patch is mostly a preparation patch for adding the get_state callback to make the driver fully support the pwm-atomic model. When I first tried to upstream the get_state code about a year ago, there was some not pretty code in there to deal with getting the runtime pm reference if the backlight was already enabled when the driver loads. One of the review requests was to factor out the code dealing with getting/putting the runtime_pm reference when changing state from enabled to disabled or the other way around. That is the mean reason for this commit. When writing this I noticed that if we rmmod the driver while the backlight has been enabled through the driver (e.g. through the sysfs interface) that we then leak the runtime-pm reference which we get when we enable the pwm. Note the purpose of adding a get_state callback is to have the i915 driver eventually read back the backlight state at boot and avoid the backlight always jumping to 100% brightness at boot which causes an ugly visual flicker. Regards, Hans > >> Signed-off-by: Hans de Goede <hdegoede@redhat.com> >> --- >> drivers/pwm/pwm-lpss.c | 47 +++++++++++++++++++++++++++++------------- >> 1 file changed, 33 insertions(+), 14 deletions(-) >> >> diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c >> index e602835fd6de..d39158800baa 100644 >> --- a/drivers/pwm/pwm-lpss.c >> +++ b/drivers/pwm/pwm-lpss.c >> @@ -120,43 +120,58 @@ static inline void pwm_lpss_cond_enable(struct pwm_device *pwm, bool cond) >> pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_ENABLE); >> } >> >> +static void pwm_lpss_get_put_runtime_pm(struct pwm_chip *chip, >> + bool old_enabled, bool new_enabled) >> +{ >> + if (new_enabled == old_enabled) >> + return; >> + >> + if (new_enabled) >> + pm_runtime_get(chip->dev); >> + else >> + pm_runtime_put(chip->dev); >> +} >> + >> static int pwm_lpss_apply(struct pwm_chip *chip, struct pwm_device *pwm, >> struct pwm_state *state) >> { >> struct pwm_lpss_chip *lpwm = to_lpwm(chip); >> - int ret; >> + int ret = 0; >> + >> + pm_runtime_get_sync(chip->dev); >> >> if (state->enabled) { >> if (!pwm_is_enabled(pwm)) { >> - pm_runtime_get_sync(chip->dev); >> ret = pwm_lpss_is_updating(pwm); >> - if (ret) { >> - pm_runtime_put(chip->dev); >> - return ret; >> - } >> + if (ret) >> + goto out; >> + >> pwm_lpss_prepare(lpwm, pwm, state->duty_cycle, state->period); >> pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_SW_UPDATE); >> pwm_lpss_cond_enable(pwm, lpwm->info->bypass == false); >> ret = pwm_lpss_wait_for_update(pwm); >> - if (ret) { >> - pm_runtime_put(chip->dev); >> - return ret; >> - } >> + if (ret) >> + goto out; >> + >> pwm_lpss_cond_enable(pwm, lpwm->info->bypass == true); >> } else { >> ret = pwm_lpss_is_updating(pwm); >> if (ret) >> - return ret; >> + goto out; >> + >> pwm_lpss_prepare(lpwm, pwm, state->duty_cycle, state->period); >> pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_SW_UPDATE); >> - return pwm_lpss_wait_for_update(pwm); >> + ret = pwm_lpss_wait_for_update(pwm); >> } >> } else if (pwm_is_enabled(pwm)) { >> pwm_lpss_write(pwm, pwm_lpss_read(pwm) & ~PWM_ENABLE); >> - pm_runtime_put(chip->dev); >> } >> >> - return 0; >> + pwm_lpss_get_put_runtime_pm(chip, pwm_is_enabled(pwm), state->enabled); >> + >> +out: >> + pm_runtime_put(chip->dev); >> + return ret; >> } >> >> static const struct pwm_ops pwm_lpss_ops = { >> @@ -205,6 +220,10 @@ EXPORT_SYMBOL_GPL(pwm_lpss_probe); >> >> int pwm_lpss_remove(struct pwm_lpss_chip *lpwm) >> { >> + bool enabled = pwm_is_enabled(&lpwm->chip.pwms[0]); >> + >> + pwm_lpss_get_put_runtime_pm(&lpwm->chip, enabled, false); >> + >> return pwmchip_remove(&lpwm->chip); >> } >> EXPORT_SYMBOL_GPL(pwm_lpss_remove); >> -- >> 2.19.0.rc0 >> > ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 1/2] pwm: lpss: Add pwm_lpss_get_put_runtime_pm helper function 2018-09-24 9:58 ` Hans de Goede @ 2018-09-24 10:05 ` Andy Shevchenko 2018-09-24 12:13 ` Hans de Goede 0 siblings, 1 reply; 8+ messages in thread From: Andy Shevchenko @ 2018-09-24 10:05 UTC (permalink / raw) To: Hans de Goede; +Cc: Thierry Reding, linux-pwm, linux-acpi On Mon, Sep 24, 2018 at 11:58:42AM +0200, Hans de Goede wrote: > Hi, > > On 24-09-18 11:16, Andy Shevchenko wrote: > > On Tue, Sep 11, 2018 at 07:45:32PM +0200, Hans de Goede wrote: > > > Add a helper function to properly get / put the pwm's runtime_pm > > > reference when changing from enabled to disable or vice versa. > > > > > > And use this to ensure the pwm's runtime_pm reference is properly > > > released on remove. > > > > > > > Can you provide a test sequence to reproduce the issue? > > This patch is mostly a preparation patch for adding the get_state > callback to make the driver fully support the pwm-atomic model. > > When I first tried to upstream the get_state code about a year > ago, there was some not pretty code in there to deal with getting > the runtime pm reference if the backlight was already enabled when > the driver loads. One of the review requests was to factor out the > code dealing with getting/putting the runtime_pm reference when > changing state from enabled to disabled or the other way around. > That is the mean reason for this commit. > > When writing this I noticed that if we rmmod the driver while > the backlight has been enabled through the driver (e.g. through > the sysfs interface) that we then leak the runtime-pm reference > which we get when we enable the pwm. > > Note the purpose of adding a get_state callback is to have the i915 > driver eventually read back the backlight state at boot and avoid > the backlight always jumping to 100% brightness at boot which > causes an ugly visual flicker. Thanks. I'm just wondering if we can leave pwm_lpss_apply() untouched and use a new helper for ->remove() and ->get_state() only. > > > --- a/drivers/pwm/pwm-lpss.c > > > +++ b/drivers/pwm/pwm-lpss.c > > > @@ -120,43 +120,58 @@ static inline void pwm_lpss_cond_enable(struct pwm_device *pwm, bool cond) > > > pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_ENABLE); > > > } > > > +static void pwm_lpss_get_put_runtime_pm(struct pwm_chip *chip, > > > + bool old_enabled, bool new_enabled) > > > +{ > > > + if (new_enabled == old_enabled) > > > + return; > > > + > > > + if (new_enabled) > > > + pm_runtime_get(chip->dev); > > > + else > > > + pm_runtime_put(chip->dev); > > > +} > > > + > > > static int pwm_lpss_apply(struct pwm_chip *chip, struct pwm_device *pwm, > > > struct pwm_state *state) > > > { > > > struct pwm_lpss_chip *lpwm = to_lpwm(chip); > > > - int ret; > > > + int ret = 0; > > > + > > > + pm_runtime_get_sync(chip->dev); > > > if (state->enabled) { > > > if (!pwm_is_enabled(pwm)) { > > > - pm_runtime_get_sync(chip->dev); > > > ret = pwm_lpss_is_updating(pwm); > > > - if (ret) { > > > - pm_runtime_put(chip->dev); > > > - return ret; > > > - } > > > + if (ret) > > > + goto out; > > > + > > > pwm_lpss_prepare(lpwm, pwm, state->duty_cycle, state->period); > > > pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_SW_UPDATE); > > > pwm_lpss_cond_enable(pwm, lpwm->info->bypass == false); > > > ret = pwm_lpss_wait_for_update(pwm); > > > - if (ret) { > > > - pm_runtime_put(chip->dev); > > > - return ret; > > > - } > > > + if (ret) > > > + goto out; > > > + > > > pwm_lpss_cond_enable(pwm, lpwm->info->bypass == true); > > > } else { > > > ret = pwm_lpss_is_updating(pwm); > > > if (ret) > > > - return ret; > > > + goto out; > > > + > > > pwm_lpss_prepare(lpwm, pwm, state->duty_cycle, state->period); > > > pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_SW_UPDATE); > > > - return pwm_lpss_wait_for_update(pwm); > > > + ret = pwm_lpss_wait_for_update(pwm); > > > } > > > } else if (pwm_is_enabled(pwm)) { > > > pwm_lpss_write(pwm, pwm_lpss_read(pwm) & ~PWM_ENABLE); > > > - pm_runtime_put(chip->dev); > > > } > > > - return 0; > > > + pwm_lpss_get_put_runtime_pm(chip, pwm_is_enabled(pwm), state->enabled); > > > + > > > +out: > > > + pm_runtime_put(chip->dev); > > > + return ret; > > > } > > > static const struct pwm_ops pwm_lpss_ops = { > > > @@ -205,6 +220,10 @@ EXPORT_SYMBOL_GPL(pwm_lpss_probe); > > > int pwm_lpss_remove(struct pwm_lpss_chip *lpwm) > > > { > > > + bool enabled = pwm_is_enabled(&lpwm->chip.pwms[0]); > > > + > > > + pwm_lpss_get_put_runtime_pm(&lpwm->chip, enabled, false); > > > + > > > return pwmchip_remove(&lpwm->chip); > > > } > > > EXPORT_SYMBOL_GPL(pwm_lpss_remove); -- With Best Regards, Andy Shevchenko ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 1/2] pwm: lpss: Add pwm_lpss_get_put_runtime_pm helper function 2018-09-24 10:05 ` Andy Shevchenko @ 2018-09-24 12:13 ` Hans de Goede 2018-09-24 13:22 ` Andy Shevchenko 0 siblings, 1 reply; 8+ messages in thread From: Hans de Goede @ 2018-09-24 12:13 UTC (permalink / raw) To: Andy Shevchenko; +Cc: Thierry Reding, linux-pwm, linux-acpi Hi, On 24-09-18 12:05, Andy Shevchenko wrote: > On Mon, Sep 24, 2018 at 11:58:42AM +0200, Hans de Goede wrote: >> Hi, >> >> On 24-09-18 11:16, Andy Shevchenko wrote: >>> On Tue, Sep 11, 2018 at 07:45:32PM +0200, Hans de Goede wrote: >>>> Add a helper function to properly get / put the pwm's runtime_pm >>>> reference when changing from enabled to disable or vice versa. >>>> >>>> And use this to ensure the pwm's runtime_pm reference is properly >>>> released on remove. >>>> >>> >>> Can you provide a test sequence to reproduce the issue? >> >> This patch is mostly a preparation patch for adding the get_state >> callback to make the driver fully support the pwm-atomic model. >> >> When I first tried to upstream the get_state code about a year >> ago, there was some not pretty code in there to deal with getting >> the runtime pm reference if the backlight was already enabled when >> the driver loads. One of the review requests was to factor out the >> code dealing with getting/putting the runtime_pm reference when >> changing state from enabled to disabled or the other way around. >> That is the mean reason for this commit. >> >> When writing this I noticed that if we rmmod the driver while >> the backlight has been enabled through the driver (e.g. through >> the sysfs interface) that we then leak the runtime-pm reference >> which we get when we enable the pwm. >> >> Note the purpose of adding a get_state callback is to have the i915 >> driver eventually read back the backlight state at boot and avoid >> the backlight always jumping to 100% brightness at boot which >> causes an ugly visual flicker. > > Thanks. > > I'm just wondering if we can leave pwm_lpss_apply() untouched and use a new helper for ->remove() and ->get_state() only. The idea was to have a single place doing the pm_runtime_get() and pm_runtime_put() calls. Leaving pwm_lpss_apply() as is and this not using this helper there is fine with me, but then we might just as well directly do the [un]ref directly in >remove() and ->get_state() as well, that is just 2 lines (instead of 1) for each. I'm not against leaving pwm_lpss_apply() as is, but then we might just as well drop this patch, so do you want to drop this patch for v2 ? Also do you have any remarks on the patch adding the get_stage callback before I send out a v2? Regards, Hans >>>> --- a/drivers/pwm/pwm-lpss.c >>>> +++ b/drivers/pwm/pwm-lpss.c >>>> @@ -120,43 +120,58 @@ static inline void pwm_lpss_cond_enable(struct pwm_device *pwm, bool cond) >>>> pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_ENABLE); >>>> } >>>> +static void pwm_lpss_get_put_runtime_pm(struct pwm_chip *chip, >>>> + bool old_enabled, bool new_enabled) >>>> +{ >>>> + if (new_enabled == old_enabled) >>>> + return; >>>> + >>>> + if (new_enabled) >>>> + pm_runtime_get(chip->dev); >>>> + else >>>> + pm_runtime_put(chip->dev); >>>> +} >>>> + >>>> static int pwm_lpss_apply(struct pwm_chip *chip, struct pwm_device *pwm, >>>> struct pwm_state *state) >>>> { >>>> struct pwm_lpss_chip *lpwm = to_lpwm(chip); >>>> - int ret; >>>> + int ret = 0; >>>> + >>>> + pm_runtime_get_sync(chip->dev); >>>> if (state->enabled) { >>>> if (!pwm_is_enabled(pwm)) { >>>> - pm_runtime_get_sync(chip->dev); >>>> ret = pwm_lpss_is_updating(pwm); >>>> - if (ret) { >>>> - pm_runtime_put(chip->dev); >>>> - return ret; >>>> - } >>>> + if (ret) >>>> + goto out; >>>> + >>>> pwm_lpss_prepare(lpwm, pwm, state->duty_cycle, state->period); >>>> pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_SW_UPDATE); >>>> pwm_lpss_cond_enable(pwm, lpwm->info->bypass == false); >>>> ret = pwm_lpss_wait_for_update(pwm); >>>> - if (ret) { >>>> - pm_runtime_put(chip->dev); >>>> - return ret; >>>> - } >>>> + if (ret) >>>> + goto out; >>>> + >>>> pwm_lpss_cond_enable(pwm, lpwm->info->bypass == true); >>>> } else { >>>> ret = pwm_lpss_is_updating(pwm); >>>> if (ret) >>>> - return ret; >>>> + goto out; >>>> + >>>> pwm_lpss_prepare(lpwm, pwm, state->duty_cycle, state->period); >>>> pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_SW_UPDATE); >>>> - return pwm_lpss_wait_for_update(pwm); >>>> + ret = pwm_lpss_wait_for_update(pwm); >>>> } >>>> } else if (pwm_is_enabled(pwm)) { >>>> pwm_lpss_write(pwm, pwm_lpss_read(pwm) & ~PWM_ENABLE); >>>> - pm_runtime_put(chip->dev); >>>> } >>>> - return 0; >>>> + pwm_lpss_get_put_runtime_pm(chip, pwm_is_enabled(pwm), state->enabled); >>>> + >>>> +out: >>>> + pm_runtime_put(chip->dev); >>>> + return ret; >>>> } >>>> static const struct pwm_ops pwm_lpss_ops = { >>>> @@ -205,6 +220,10 @@ EXPORT_SYMBOL_GPL(pwm_lpss_probe); >>>> int pwm_lpss_remove(struct pwm_lpss_chip *lpwm) >>>> { >>>> + bool enabled = pwm_is_enabled(&lpwm->chip.pwms[0]); >>>> + >>>> + pwm_lpss_get_put_runtime_pm(&lpwm->chip, enabled, false); >>>> + >>>> return pwmchip_remove(&lpwm->chip); >>>> } >>>> EXPORT_SYMBOL_GPL(pwm_lpss_remove); > ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 1/2] pwm: lpss: Add pwm_lpss_get_put_runtime_pm helper function 2018-09-24 12:13 ` Hans de Goede @ 2018-09-24 13:22 ` Andy Shevchenko 0 siblings, 0 replies; 8+ messages in thread From: Andy Shevchenko @ 2018-09-24 13:22 UTC (permalink / raw) To: Hans de Goede; +Cc: Thierry Reding, linux-pwm, linux-acpi On Mon, Sep 24, 2018 at 02:13:03PM +0200, Hans de Goede wrote: > On 24-09-18 12:05, Andy Shevchenko wrote: > > On Mon, Sep 24, 2018 at 11:58:42AM +0200, Hans de Goede wrote: > > Thanks. > > I'm just wondering if we can leave pwm_lpss_apply() untouched and use a new helper for ->remove() and ->get_state() only. > > The idea was to have a single place doing the pm_runtime_get() and > pm_runtime_put() calls. Leaving pwm_lpss_apply() as is and this not > using this helper there is fine with me, but then we might just as > well directly do the [un]ref directly in >remove() and ->get_state() > as well, that is just 2 lines (instead of 1) for each. > > I'm not against leaving pwm_lpss_apply() as is, but then we might > just as well drop this patch, so do you want to drop this patch > for v2 ? I would prefer not to change ->apply(). So, please, modify (I guess we still need some pm calls in ->remove()). Perhaps it would also require Fixes tag to be applied. > > Also do you have any remarks on the patch adding the get_stage > callback before I send out a v2? No, looks sane, just same comment as above per pm calls. -- With Best Regards, Andy Shevchenko ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 2/2] pwm: lpss: Add get_state callback 2018-09-11 17:45 [PATCH 0/2] pwm: lpss: Atomic PWM support for LPSS Hans de Goede 2018-09-11 17:45 ` [PATCH 1/2] pwm: lpss: Add pwm_lpss_get_put_runtime_pm helper function Hans de Goede @ 2018-09-11 17:45 ` Hans de Goede 1 sibling, 0 replies; 8+ messages in thread From: Hans de Goede @ 2018-09-11 17:45 UTC (permalink / raw) To: Thierry Reding, Andy Shevchenko; +Cc: Hans de Goede, linux-pwm, linux-acpi Add a get_state callback so that the initial state correctly reflects the actual hardware state. Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Hans de Goede <hdegoede@redhat.com> Acked-by: Jani Nikula <jani.nikula@intel.com> --- drivers/pwm/pwm-lpss.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c index d39158800baa..882a71f1a66c 100644 --- a/drivers/pwm/pwm-lpss.c +++ b/drivers/pwm/pwm-lpss.c @@ -174,8 +174,41 @@ static int pwm_lpss_apply(struct pwm_chip *chip, struct pwm_device *pwm, return ret; } +/* This function gets called once from pwmchip_add to get the initial state */ +static void pwm_lpss_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) +{ + struct pwm_lpss_chip *lpwm = to_lpwm(chip); + unsigned long base_unit_range; + unsigned long long base_unit, freq, on_time_div; + u32 ctrl; + + base_unit_range = BIT(lpwm->info->base_unit_bits); + + ctrl = pwm_lpss_read(pwm); + on_time_div = 255 - (ctrl & PWM_ON_TIME_DIV_MASK); + base_unit = (ctrl >> PWM_BASE_UNIT_SHIFT) & (base_unit_range - 1); + + freq = base_unit * lpwm->info->clk_rate; + do_div(freq, base_unit_range); + if (freq == 0) + state->period = NSEC_PER_SEC; + else + state->period = NSEC_PER_SEC / (unsigned long)freq; + + on_time_div *= state->period; + do_div(on_time_div, 255); + state->duty_cycle = on_time_div; + + state->polarity = PWM_POLARITY_NORMAL; + state->enabled = !!(ctrl & PWM_ENABLE); + + pwm_lpss_get_put_runtime_pm(chip, false, state->enabled); +} + static const struct pwm_ops pwm_lpss_ops = { .apply = pwm_lpss_apply, + .get_state = pwm_lpss_get_state, .owner = THIS_MODULE, }; -- 2.19.0.rc0 ^ permalink raw reply related [flat|nested] 8+ messages in thread
end of thread, other threads:[~2018-09-24 13:22 UTC | newest] Thread overview: 8+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2018-09-11 17:45 [PATCH 0/2] pwm: lpss: Atomic PWM support for LPSS Hans de Goede 2018-09-11 17:45 ` [PATCH 1/2] pwm: lpss: Add pwm_lpss_get_put_runtime_pm helper function Hans de Goede 2018-09-24 9:16 ` Andy Shevchenko 2018-09-24 9:58 ` Hans de Goede 2018-09-24 10:05 ` Andy Shevchenko 2018-09-24 12:13 ` Hans de Goede 2018-09-24 13:22 ` Andy Shevchenko 2018-09-11 17:45 ` [PATCH 2/2] pwm: lpss: Add get_state callback Hans de Goede
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.