|
@@ -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)
|