summary refs log tree commit diff
path: root/drivers/leds/led-core.c
diff options
context:
space:
mode:
authorJacek Anaszewski <j.anaszewski@samsung.com>2015-09-28 14:38:04 +0200
committerJacek Anaszewski <j.anaszewski@samsung.com>2015-11-03 08:59:22 +0100
commit757b06ae04b3b6c8958ab067e879a8865d076d2a (patch)
treec210be20cf1c644e2c156acf216f2734526c8cfa /drivers/leds/led-core.c
parent22a16873d38829570677871a22cf77f00445206f (diff)
downloadlinux-757b06ae04b3b6c8958ab067e879a8865d076d2a.tar.gz
leds: core: Move LED core callbacks out of led-class.c
Since the API for controlling LED brightness and blinking is defined in
the LED core, move the related timer and work callbacks to the led-core.c,
and initialize them through a new led_core_init API.

Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
Acked-by: Andrew Lunn <andrew@lunn.ch>
Acked-by: Pavel Machek <pavel@ucw.cz>
Diffstat (limited to 'drivers/leds/led-core.c')
-rw-r--r--drivers/leds/led-core.c73
1 files changed, 73 insertions, 0 deletions
diff --git a/drivers/leds/led-core.c b/drivers/leds/led-core.c
index 549de7e24cfd..c1c3af089634 100644
--- a/drivers/leds/led-core.c
+++ b/drivers/leds/led-core.c
@@ -25,6 +25,70 @@ EXPORT_SYMBOL_GPL(leds_list_lock);
 LIST_HEAD(leds_list);
 EXPORT_SYMBOL_GPL(leds_list);
 
+static void led_timer_function(unsigned long data)
+{
+	struct led_classdev *led_cdev = (void *)data;
+	unsigned long brightness;
+	unsigned long delay;
+
+	if (!led_cdev->blink_delay_on || !led_cdev->blink_delay_off) {
+		led_set_brightness_async(led_cdev, LED_OFF);
+		return;
+	}
+
+	if (led_cdev->flags & LED_BLINK_ONESHOT_STOP) {
+		led_cdev->flags &= ~LED_BLINK_ONESHOT_STOP;
+		return;
+	}
+
+	brightness = led_get_brightness(led_cdev);
+	if (!brightness) {
+		/* Time to switch the LED on. */
+		if (led_cdev->delayed_set_value) {
+			led_cdev->blink_brightness =
+					led_cdev->delayed_set_value;
+			led_cdev->delayed_set_value = 0;
+		}
+		brightness = led_cdev->blink_brightness;
+		delay = led_cdev->blink_delay_on;
+	} else {
+		/* Store the current brightness value to be able
+		 * to restore it when the delay_off period is over.
+		 */
+		led_cdev->blink_brightness = brightness;
+		brightness = LED_OFF;
+		delay = led_cdev->blink_delay_off;
+	}
+
+	led_set_brightness_async(led_cdev, brightness);
+
+	/* Return in next iteration if led is in one-shot mode and we are in
+	 * the final blink state so that the led is toggled each delay_on +
+	 * delay_off milliseconds in worst case.
+	 */
+	if (led_cdev->flags & LED_BLINK_ONESHOT) {
+		if (led_cdev->flags & LED_BLINK_INVERT) {
+			if (brightness)
+				led_cdev->flags |= LED_BLINK_ONESHOT_STOP;
+		} else {
+			if (!brightness)
+				led_cdev->flags |= LED_BLINK_ONESHOT_STOP;
+		}
+	}
+
+	mod_timer(&led_cdev->blink_timer, jiffies + msecs_to_jiffies(delay));
+}
+
+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);
+
+	led_set_brightness_async(led_cdev, led_cdev->delayed_set_value);
+}
+
 static void led_set_software_blink(struct led_classdev *led_cdev,
 				   unsigned long delay_on,
 				   unsigned long delay_off)
@@ -72,6 +136,15 @@ static void led_blink_setup(struct led_classdev *led_cdev,
 	led_set_software_blink(led_cdev, *delay_on, *delay_off);
 }
 
+void led_init_core(struct led_classdev *led_cdev)
+{
+	INIT_WORK(&led_cdev->set_brightness_work, set_brightness_delayed);
+
+	setup_timer(&led_cdev->blink_timer, led_timer_function,
+		    (unsigned long)led_cdev);
+}
+EXPORT_SYMBOL_GPL(led_init_core);
+
 void led_blink_set(struct led_classdev *led_cdev,
 		   unsigned long *delay_on,
 		   unsigned long *delay_off)