From: Peter Ujfalusi <peter.ujfalusi@ti.com>
To: Florian Vaussard <florian.vaussard@epfl.ch>
Cc: Bryan Wu <cooloney@gmail.com>, Richard Purdie <rpurdie@rpsys.net>,
Thierry Reding <thierry.reding@avionic-design.de>,
<linux-leds@vger.kernel.org>,
<linux-arm-kernel@lists.infradead.org>,
<linux-kernel@vger.kernel.org>
Subject: Re: [PATCH v2 3/3] leds: leds-pwm: Defer led_pwm_set() if PWM can sleep
Date: Fri, 25 Jan 2013 14:52:10 +0100 [thread overview]
Message-ID: <51028E0A.5000009@ti.com> (raw)
In-Reply-To: <1359121471-21457-4-git-send-email-florian.vaussard@epfl.ch>
On 01/25/2013 02:44 PM, Florian Vaussard wrote:
> Call to led_pwm_set() can happen inside atomic context, like triggers.
> If the PWM call can sleep, defer using a worker.
>
> Signed-off-by: Florian Vaussard <florian.vaussard@epfl.ch>
Reviewed-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
> ---
> drivers/leds/leds-pwm.c | 50 +++++++++++++++++++++++++++++++++++++++-------
> 1 files changed, 42 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c
> index a1ea5f6..70effa7 100644
> --- a/drivers/leds/leds-pwm.c
> +++ b/drivers/leds/leds-pwm.c
> @@ -23,12 +23,16 @@
> #include <linux/pwm.h>
> #include <linux/leds_pwm.h>
> #include <linux/slab.h>
> +#include <linux/workqueue.h>
>
> struct led_pwm_data {
> struct led_classdev cdev;
> struct pwm_device *pwm;
> + struct work_struct work;
> unsigned int active_low;
> unsigned int period;
> + int duty;
> + unsigned can_sleep:1;
> };
>
> struct led_pwm_priv {
> @@ -36,6 +40,26 @@ struct led_pwm_priv {
> struct led_pwm_data leds[0];
> };
>
> +static void __led_pwm_set(struct led_pwm_data *led_dat)
> +{
> + int new_duty = led_dat->duty;
> +
> + pwm_config(led_dat->pwm, new_duty, led_dat->period);
> +
> + if (new_duty == 0)
> + pwm_disable(led_dat->pwm);
> + else
> + pwm_enable(led_dat->pwm);
> +}
> +
> +static void led_pwm_work(struct work_struct *work)
> +{
> + struct led_pwm_data *led_dat =
> + container_of(work, struct led_pwm_data, work);
> +
> + __led_pwm_set(led_dat);
> +}
> +
> static void led_pwm_set(struct led_classdev *led_cdev,
> enum led_brightness brightness)
> {
> @@ -44,13 +68,12 @@ static void led_pwm_set(struct led_classdev *led_cdev,
> unsigned int max = led_dat->cdev.max_brightness;
> unsigned int period = led_dat->period;
>
> - if (brightness == 0) {
> - pwm_config(led_dat->pwm, 0, period);
> - pwm_disable(led_dat->pwm);
> - } else {
> - pwm_config(led_dat->pwm, brightness * period / max, period);
> - pwm_enable(led_dat->pwm);
> - }
> + led_dat->duty = brightness * period / max;
> +
> + if (led_dat->can_sleep)
> + schedule_work(&led_dat->work);
> + else
> + __led_pwm_set(led_dat);
> }
>
> static inline size_t sizeof_pwm_leds_priv(int num_leds)
> @@ -100,6 +123,10 @@ static struct led_pwm_priv *led_pwm_create_of(struct platform_device *pdev)
> led_dat->cdev.brightness = LED_OFF;
> led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
>
> + led_dat->can_sleep = pwm_cansleep(led_dat->pwm);
> + if (led_dat->can_sleep)
> + INIT_WORK(&led_dat->work, led_pwm_work);
> +
> ret = led_classdev_register(&pdev->dev, &led_dat->cdev);
> if (ret < 0) {
> dev_err(&pdev->dev, "failed to register for %s\n",
> @@ -153,6 +180,10 @@ static int led_pwm_probe(struct platform_device *pdev)
> led_dat->cdev.max_brightness = cur_led->max_brightness;
> led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
>
> + led_dat->can_sleep = pwm_cansleep(led_dat->pwm);
> + if (led_dat->can_sleep)
> + INIT_WORK(&led_dat->work, led_pwm_work);
> +
> ret = led_classdev_register(&pdev->dev, &led_dat->cdev);
> if (ret < 0)
> goto err;
> @@ -180,8 +211,11 @@ static int led_pwm_remove(struct platform_device *pdev)
> struct led_pwm_priv *priv = platform_get_drvdata(pdev);
> int i;
>
> - for (i = 0; i < priv->num_leds; i++)
> + for (i = 0; i < priv->num_leds; i++) {
> led_classdev_unregister(&priv->leds[i].cdev);
> + if (priv->leds[i].can_sleep)
> + cancel_work_sync(&priv->leds[i].work);
> + }
>
> return 0;
> }
>
--
Péter
prev parent reply other threads:[~2013-01-25 13:52 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-01-25 13:44 [PATCH v2 0/3] leds-pwm: Defer PWM calls if PWM can sleep Florian Vaussard
2013-01-25 13:44 ` [PATCH v2 1/3] pwm: Add pwm_cansleep() as exported API to users Florian Vaussard
2013-01-25 13:51 ` Peter Ujfalusi
2013-01-26 5:40 ` Thierry Reding
2013-01-28 8:45 ` Peter Ujfalusi
2013-01-28 9:36 ` Florian Vaussard
2013-01-28 9:57 ` Thierry Reding
2013-01-28 10:57 ` Florian Vaussard
2013-01-28 13:16 ` Thierry Reding
2013-01-28 15:01 ` Russell King - ARM Linux
2013-01-28 15:46 ` Florian Vaussard
2013-01-25 13:44 ` [PATCH v2 2/3] pwm: Add can_sleep property to drivers Florian Vaussard
2013-01-25 13:51 ` Peter Ujfalusi
2013-01-25 13:44 ` [PATCH v2 3/3] leds: leds-pwm: Defer led_pwm_set() if PWM can sleep Florian Vaussard
2013-01-25 13:52 ` Peter Ujfalusi [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=51028E0A.5000009@ti.com \
--to=peter.ujfalusi@ti.com \
--cc=cooloney@gmail.com \
--cc=florian.vaussard@epfl.ch \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-leds@vger.kernel.org \
--cc=rpurdie@rpsys.net \
--cc=thierry.reding@avionic-design.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox