ledtrig-timer.c (3383B)
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 18static 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 26static 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; 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 43static 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 51static 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; 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 68static DEVICE_ATTR(delay_on, 0644, led_delay_on_show, led_delay_on_store); 69static DEVICE_ATTR(delay_off, 0644, led_delay_off_show, led_delay_off_store); 70 71static struct attribute *timer_trig_attrs[] = { 72 &dev_attr_delay_on.attr, 73 &dev_attr_delay_off.attr, 74 NULL 75}; 76ATTRIBUTE_GROUPS(timer_trig); 77 78static 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 98out: 99 kfree(pattern); 100} 101 102static 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 124static void timer_trig_deactivate(struct led_classdev *led_cdev) 125{ 126 /* Stop blinking */ 127 led_set_brightness(led_cdev, LED_OFF); 128} 129 130static 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}; 136module_led_trigger(timer_led_trigger); 137 138MODULE_AUTHOR("Richard Purdie <rpurdie@openedhand.com>"); 139MODULE_DESCRIPTION("Timer LED trigger"); 140MODULE_LICENSE("GPL v2");