Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1173913AbdDXUAW (ORCPT ); Mon, 24 Apr 2017 16:00:22 -0400 Received: from mail-wm0-f67.google.com ([74.125.82.67]:33420 "EHLO mail-wm0-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1170819AbdDXUAC (ORCPT ); Mon, 24 Apr 2017 16:00:02 -0400 Subject: Re: [PATCH] led: ledtrig-transient: replace timer_list with hrtimer To: David Lin , rpurdie@rpsys.net, pavel@ucw.cz References: <20170424044254.145192-1-dtwlin@google.com> Cc: robh@kernel.org, romlem@google.com, joelaf@google.com, stable@vger.kernel.org, linux-leds@vger.kernel.org, linux-kernel@vger.kernel.org From: Jacek Anaszewski X-Enigmail-Draft-Status: N1110 Message-ID: Date: Mon, 24 Apr 2017 21:59:11 +0200 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Icedove/45.5.1 MIME-Version: 1.0 In-Reply-To: <20170424044254.145192-1-dtwlin@google.com> Content-Type: text/plain; charset=windows-1252 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 5129 Lines: 135 Hi David, Thanks for the patch. Unfortunately we cannot switch to using hr timers just like that without introducing side effects for many devices. We had similar attempt of increasing timer tirgger accuracy two years ago [0]. In short words, for drivers that can sleep while setting brightness and/or are using a bus like I2C you will not be able to enforce 1ms delay period. I recommend you to go through the thread [0] so that we had a well defined ground for the discussion on how to address this issue properly. Alternatively, in order to avoid all quirks related to LED subsystem, I'd propose to implement this feature in the GPIO subsystem, which seems to be more suitable place for it. [0] https://lkml.org/lkml/2015/4/28/260 Best regards, Jacek Anaszewski On 04/24/2017 06:42 AM, David Lin wrote: > This patch replaces the kernel timer used by led transient trigger as an > one-shot timer with an hrtimer. As Android is moving away from the > obsoleted timed_output to ledtrig-transient for the vibrator HAL, > ledtrig-transient needs to be able to handle the "duration" property to > millisecond precision as modern haptic actuators can be driven in > precisely one cycle (~1 ms) in order to provide a crisp and subtle > feedback. > > Cc: Richard Purdie > Cc: Jacek Anaszewski > Cc: Pavel Machek > Cc: Rob Herring > Cc: Rom Lemarchand > Cc: Joel Fernandes > Cc: stable@vger.kernel.org > Signed-off-by: David Lin > --- > drivers/leds/trigger/ledtrig-transient.c | 29 +++++++++++++++++------------ > 1 file changed, 17 insertions(+), 12 deletions(-) > > diff --git a/drivers/leds/trigger/ledtrig-transient.c b/drivers/leds/trigger/ledtrig-transient.c > index 7e6011bd3646..94bb3bfc46e9 100644 > --- a/drivers/leds/trigger/ledtrig-transient.c > +++ b/drivers/leds/trigger/ledtrig-transient.c > @@ -23,25 +23,28 @@ > #include > #include > #include > -#include > +#include > #include > #include "../leds.h" > > struct transient_trig_data { > + struct led_classdev *led_cdev; > int activate; > int state; > int restore_state; > unsigned long duration; > - struct timer_list timer; > + struct hrtimer timer; > }; > > -static void transient_timer_function(unsigned long data) > +static enum hrtimer_restart transient_timer_function(struct hrtimer *timer) > { > - struct led_classdev *led_cdev = (struct led_classdev *) data; > - struct transient_trig_data *transient_data = led_cdev->trigger_data; > + struct transient_trig_data *transient_data = > + container_of(timer, struct transient_trig_data, timer); > > transient_data->activate = 0; > - led_set_brightness_nosleep(led_cdev, transient_data->restore_state); > + led_set_brightness_nosleep(transient_data->led_cdev, > + transient_data->restore_state); > + return HRTIMER_NORESTART; > } > > static ssize_t transient_activate_show(struct device *dev, > @@ -70,7 +73,7 @@ static ssize_t transient_activate_store(struct device *dev, > > /* cancel the running timer */ > if (state == 0 && transient_data->activate == 1) { > - del_timer(&transient_data->timer); > + hrtimer_cancel(&transient_data->timer); > transient_data->activate = state; > led_set_brightness_nosleep(led_cdev, > transient_data->restore_state); > @@ -84,8 +87,9 @@ static ssize_t transient_activate_store(struct device *dev, > led_set_brightness_nosleep(led_cdev, transient_data->state); > transient_data->restore_state = > (transient_data->state == LED_FULL) ? LED_OFF : LED_FULL; > - mod_timer(&transient_data->timer, > - jiffies + msecs_to_jiffies(transient_data->duration)); > + hrtimer_start(&transient_data->timer, > + ms_to_ktime(transient_data->duration), > + HRTIMER_MODE_REL); > } > > /* state == 0 && transient_data->activate == 0 > @@ -168,6 +172,7 @@ static void transient_trig_activate(struct led_classdev *led_cdev) > "unable to allocate transient trigger\n"); > return; > } > + tdata->led_cdev = led_cdev; > led_cdev->trigger_data = tdata; > > rc = device_create_file(led_cdev->dev, &dev_attr_activate); > @@ -182,8 +187,8 @@ static void transient_trig_activate(struct led_classdev *led_cdev) > if (rc) > goto err_out_state; > > - setup_timer(&tdata->timer, transient_timer_function, > - (unsigned long) led_cdev); > + hrtimer_init(&tdata->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); > + tdata->timer.function = transient_timer_function; > led_cdev->activated = true; > > return; > @@ -203,7 +208,7 @@ static void transient_trig_deactivate(struct led_classdev *led_cdev) > struct transient_trig_data *transient_data = led_cdev->trigger_data; > > if (led_cdev->activated) { > - del_timer_sync(&transient_data->timer); > + hrtimer_cancel(&transient_data->timer); > led_set_brightness_nosleep(led_cdev, > transient_data->restore_state); > device_remove_file(led_cdev->dev, &dev_attr_activate); >