1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * LED Kernel Timer Trigger 4 * 5 * Copyright 2005-2006 Openedhand Ltd. 6 * 7 * Author: Richard Purdie <rpurdie@openedhand.com> 8 */ 9 10 #include <linux/module.h> 11 #include <linux/kernel.h> 12 #include <linux/init.h> 13 #include <linux/device.h> 14 #include <linux/ctype.h> 15 #include <linux/slab.h> 16 #include <linux/leds.h> 17 18 static ssize_t led_delay_on_show(struct device *dev, 19 struct device_attribute *attr, char *buf) 20 { 21 struct led_classdev *led_cdev = led_trigger_get_led(dev); 22 23 return sprintf(buf, "%lu\n", led_cdev->blink_delay_on); 24 } 25 26 static ssize_t led_delay_on_store(struct device *dev, 27 struct device_attribute *attr, const char *buf, size_t size) 28 { 29 struct led_classdev *led_cdev = led_trigger_get_led(dev); 30 unsigned long state; 31 ssize_t ret = -EINVAL; 32 33 ret = kstrtoul(buf, 10, &state); 34 if (ret) 35 return ret; 36 37 led_blink_set(led_cdev, &state, &led_cdev->blink_delay_off); 38 led_cdev->blink_delay_on = state; 39 40 return size; 41 } 42 43 static ssize_t led_delay_off_show(struct device *dev, 44 struct device_attribute *attr, char *buf) 45 { 46 struct led_classdev *led_cdev = led_trigger_get_led(dev); 47 48 return sprintf(buf, "%lu\n", led_cdev->blink_delay_off); 49 } 50 51 static ssize_t led_delay_off_store(struct device *dev, 52 struct device_attribute *attr, const char *buf, size_t size) 53 { 54 struct led_classdev *led_cdev = led_trigger_get_led(dev); 55 unsigned long state; 56 ssize_t ret = -EINVAL; 57 58 ret = kstrtoul(buf, 10, &state); 59 if (ret) 60 return ret; 61 62 led_blink_set(led_cdev, &led_cdev->blink_delay_on, &state); 63 led_cdev->blink_delay_off = state; 64 65 return size; 66 } 67 68 static DEVICE_ATTR(delay_on, 0644, led_delay_on_show, led_delay_on_store); 69 static DEVICE_ATTR(delay_off, 0644, led_delay_off_show, led_delay_off_store); 70 71 static struct attribute *timer_trig_attrs[] = { 72 &dev_attr_delay_on.attr, 73 &dev_attr_delay_off.attr, 74 NULL 75 }; 76 ATTRIBUTE_GROUPS(timer_trig); 77 78 static void pattern_init(struct led_classdev *led_cdev) 79 { 80 u32 *pattern; 81 unsigned int size = 0; 82 83 pattern = led_get_default_pattern(led_cdev, &size); 84 if (!pattern) 85 return; 86 87 if (size != 2) { 88 dev_warn(led_cdev->dev, 89 "Expected 2 but got %u values for delays pattern\n", 90 size); 91 goto out; 92 } 93 94 led_cdev->blink_delay_on = pattern[0]; 95 led_cdev->blink_delay_off = pattern[1]; 96 /* led_blink_set() called by caller */ 97 98 out: 99 kfree(pattern); 100 } 101 102 static int timer_trig_activate(struct led_classdev *led_cdev) 103 { 104 if (led_cdev->flags & LED_INIT_DEFAULT_TRIGGER) { 105 pattern_init(led_cdev); 106 /* 107 * Mark as initialized even on pattern_init() error because 108 * any consecutive call to it would produce the same error. 109 */ 110 led_cdev->flags &= ~LED_INIT_DEFAULT_TRIGGER; 111 } 112 113 /* 114 * If "set brightness to 0" is pending in workqueue, we don't 115 * want that to be reordered after blink_set() 116 */ 117 flush_work(&led_cdev->set_brightness_work); 118 led_blink_set(led_cdev, &led_cdev->blink_delay_on, 119 &led_cdev->blink_delay_off); 120 121 return 0; 122 } 123 124 static void timer_trig_deactivate(struct led_classdev *led_cdev) 125 { 126 /* Stop blinking */ 127 led_set_brightness(led_cdev, LED_OFF); 128 } 129 130 static struct led_trigger timer_led_trigger = { 131 .name = "timer", 132 .activate = timer_trig_activate, 133 .deactivate = timer_trig_deactivate, 134 .groups = timer_trig_groups, 135 }; 136 module_led_trigger(timer_led_trigger); 137 138 MODULE_AUTHOR("Richard Purdie <rpurdie@openedhand.com>"); 139 MODULE_DESCRIPTION("Timer LED trigger"); 140 MODULE_LICENSE("GPL v2"); 141