Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755413AbbGCNNa (ORCPT ); Fri, 3 Jul 2015 09:13:30 -0400 Received: from mailout4.samsung.com ([203.254.224.34]:42313 "EHLO mailout4.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755273AbbGCNNU (ORCPT ); Fri, 3 Jul 2015 09:13:20 -0400 X-AuditID: cbfee61a-f79516d000006302-24-55968a6b564a From: Jacek Anaszewski To: linux-leds@vger.kernel.org Cc: linux-kernel@vger.kernel.org, cooloney@gmail.com, rpurdie@rpsys.net, stsp@users.sourceforge.net, pavel@ucw.cz, sakari.ailus@linux.intel.com, andreas.werner@men.de, andrew@lunn.ch, ospite@studenti.unina.it, anemo@mba.ocn.ne.jp, ben@simtec.co.uk, bootc@bootc.net, dmurphy@ti.com, daniel.jeong@ti.com, daniel@zonque.org, davem@davemloft.net, fabio.baltieri@gmail.com, balbi@ti.com, florian@openwrt.org, gshark.jeong@gmail.com, g.liakhovetski@gmx.de, ingi2.kim@samsung.com, dl9pf@gmx.de, johan@kernel.org, lenz@cs.wisc.edu, jogo@openwrt.org, q1.kim@samsung.com, kris@krisk.org, kristoffer.ericson@gmail.com, linus.walleij@linaro.org, broonie@kernel.org, michael.hennerich@analog.com, milo.kim@ti.com, nm127@freemail.hu, ncase@xes-inc.com, neilb@suse.de, nick.forbes@incepta.com, lost.distance@yahoo.com, p.meerwald@bct-electronic.com, n0-1@freewrt.org, philippe.retornaz@epfl.ch, raph@8d.com, rpurdie@openedhand.com, rod@whitby.id.au, dave@sr71.net, giometti@linux.it, bigeasy@linutronix.de, shuahkhan@gmail.com, sguinot@lacie.com, kyungmin.park@samsung.com, Jacek Anaszewski Subject: [PATCH/RFC v3 2/7] leds: Improve asynchronous path of setting brightness Date: Fri, 03 Jul 2015 15:10:47 +0200 Message-id: <1435929052-8736-3-git-send-email-j.anaszewski@samsung.com> X-Mailer: git-send-email 1.7.9.5 In-reply-to: <1435929052-8736-1-git-send-email-j.anaszewski@samsung.com> References: <1435929052-8736-1-git-send-email-j.anaszewski@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAAzXSf0yMcRwH8L7P831+dHPbs0s8Ms1uY+Z3W398TEyIr2nG0j9t5OLRNf24 3RHZTIWt7pJ+23JyqM6FQkl1bnQ51HWrllqhRJKlFZV0RXHMf+/P+/P6/PfhacV1xo+PiT8u aeNVsUpWhp2z/cKaWH1B+Pqfvygw2LIwtPTYaSjJ3Q/1786C2TmOoaAth4Y7jhDIf/+RBUdt NgWPqwdoSP01hCHF8oQCY8t5DHkzRgYMzioGzk0dhcnRZgyj94soePR6loZcq56Bmu4JFi52 DCJ4U97EQmpXBgPuyjQOihpFcKUOc+BoqGMg76eZgvY6IwsPh8sRTGVWs5DVUMmBebocw8jI DIaBS/Uc2K4lY/jhmqNhuMbJwIzBiiHTvgh6mhwstLscGO5/KKRgoPk1ghcvGylw2/posNYN MDBWNUlBxUcZfHdvgfTMArwlkMxV3kBkqCOY3Ortoci4pRSTjukymlRZuilSeuE2TYrTpjjy fWyII7WFPRz5+u0gKSp5SpMHZeksye3MYIilvY8ibzsfs3uXR8iCjkixMYmSdt3mQzL17OAF SpO97JTJeZlLRm3+euTNi0KgmOPqQv/yArG1t4LVIxmvEG4g8Zl1CP8b3Ei822JjPIoVAkT3 5y+UHvH8fMFfrG1O8hhaGOFFk6UBeXofIUxsm9N4OBaWiRO27r+ncmGnOPtoDnuIKCwVjTlB ntpbIOLV6TTOkxV/SHVKBcpCchPyKkO+kuawRhcVHRewVqeK052Ij157OCHuAfr7OJ/8apAl GexI4JFynrzVmR+uYFSJuqQ4OxJ5WjlfPhhWEK6QH1ElnZa0CZHaE7GSzo4W81i5UN6YEBqu EKJVx6VjkqSRtP+3FO/tl4yKAz8ZS73ORpCEvMRIM7OxsKv2Yd2qfrvBdNK8rzd4+pXacRNX nIm6t/25LYT47uryyduGFgT4m58EJQVGhoUeSF1R3L9hqxesuRK9q3dJhCFKfTetxqrJf9vm nb7nTMzm1s/q+g+NoWO6TUpf1+k3aHR1dolkiMlO2W3aMaFarcQ6tSpgJa3VqX4DBT7TMDQD AAA= Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 4865 Lines: 138 led_set_brightness_async function didn't set the brightness in an asynchronous way in all cases. It was mistakenly assuming that all LED subsystem drivers use work queue in their brightness_set op, whereas only half of them does that. Modify the function to assure setting brightness asynchronously in all cases by using existing set_brightness_delayed work queue. The work queue is now made using led_set_brightness_sync for setting brightness. This modification changes the initial purpose of the work queue, which was used for setting brightness only if blink timer was active. In order to keep this functionality a LED_BLINK_DISABLE flag is being introduced, as well as a new 'new_brightness_value' field is being added to the struct led_classdev. All these improvements entail changes in the led_brightness_set function. Signed-off-by: Jacek Anaszewski --- drivers/leds/led-class.c | 14 +++++++++----- drivers/leds/led-core.c | 20 ++++++++++++++++---- drivers/leds/leds.h | 9 +++------ include/linux/leds.h | 2 ++ 4 files changed, 30 insertions(+), 15 deletions(-) diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index beabfbc..b8decf7 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -121,10 +121,10 @@ static void led_timer_function(unsigned long data) brightness = led_get_brightness(led_cdev); if (!brightness) { /* Time to switch the LED on. */ - if (led_cdev->delayed_set_value) { + if (led_cdev->new_brightness_value) { led_cdev->blink_brightness = - led_cdev->delayed_set_value; - led_cdev->delayed_set_value = 0; + led_cdev->new_brightness_value; + led_cdev->new_brightness_value = 0; } brightness = led_cdev->blink_brightness; delay = led_cdev->blink_delay_on; @@ -161,9 +161,13 @@ static void set_brightness_delayed(struct work_struct *ws) struct led_classdev *led_cdev = container_of(ws, struct led_classdev, set_brightness_work); - led_stop_software_blink(led_cdev); + if (led_cdev->flags & LED_BLINK_DISABLE) { + led_stop_software_blink(led_cdev); + led_cdev->flags &= ~LED_BLINK_DISABLE; + return; + } - led_set_brightness_async(led_cdev, led_cdev->delayed_set_value); + led_set_brightness_sync(led_cdev, led_cdev->delayed_set_value); } /** diff --git a/drivers/leds/led-core.c b/drivers/leds/led-core.c index 549de7e..16fe995 100644 --- a/drivers/leds/led-core.c +++ b/drivers/leds/led-core.c @@ -119,11 +119,23 @@ void led_set_brightness(struct led_classdev *led_cdev, { int ret = 0; - /* delay brightness if soft-blink is active */ + /* + * In case blinking is on delay brightness setting + * until the next timer tick. + */ if (led_cdev->blink_delay_on || led_cdev->blink_delay_off) { - led_cdev->delayed_set_value = brightness; - if (brightness == LED_OFF) - schedule_work(&led_cdev->set_brightness_work); + led_cdev->new_brightness_value = brightness; + + /* New brightness will be set on next timer tick. */ + if (brightness != LED_OFF) + return; + /* + * If need to disable soft blinking delegate this to the + * work queue task to avoid problems in case we are + * called from hard irq context. + */ + led_cdev->flags |= LED_BLINK_DISABLE; + led_set_brightness_async(led_cdev, brightness); return; } diff --git a/drivers/leds/leds.h b/drivers/leds/leds.h index 1c026c9..ca38f6a 100644 --- a/drivers/leds/leds.h +++ b/drivers/leds/leds.h @@ -17,13 +17,10 @@ #include static inline void led_set_brightness_async(struct led_classdev *led_cdev, - enum led_brightness value) + enum led_brightness value) { - value = min(value, led_cdev->max_brightness); - led_cdev->brightness = value; - - if (!(led_cdev->flags & LED_SUSPENDED)) - led_cdev->brightness_set(led_cdev, value); + led_cdev->delayed_set_value = value; + schedule_work(&led_cdev->set_brightness_work); } static inline int led_get_brightness(struct led_classdev *led_cdev) diff --git a/include/linux/leds.h b/include/linux/leds.h index 9b62a3c..bf4a938 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h @@ -48,6 +48,7 @@ struct led_classdev { #define SET_BRIGHTNESS_ASYNC (1 << 21) #define SET_BRIGHTNESS_SYNC (1 << 22) #define LED_DEV_CAP_FLASH (1 << 23) +#define LED_BLINK_DISABLE (1 << 24) /* Set LED brightness level */ /* Must not sleep, use a workqueue if needed */ @@ -87,6 +88,7 @@ struct led_classdev { struct work_struct set_brightness_work; int delayed_set_value; + int new_brightness_value; #ifdef CONFIG_LEDS_TRIGGERS /* Protects the trigger data below */ -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/