Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'leds_for_4.15rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/j.anaszewski/linux-leds

Pull LED updates from Jacek Anaszewski:
"New LED class driver:
- add a driver for PC Engines APU/APU2 LEDs

New LED trigger:
- add a system activity LED trigger

LED core improvements:
- replace flags bit shift with BIT() macros

Convert timers to use timer_setup() in:
- led-core
- ledtrig-activity
- ledtrig-heartbeat
- ledtrig-transient

LED class drivers fixes:
- lp55xx: fix spelling mistake: 'cound' -> 'could'
- tca6507: Remove unnecessary reg check
- pca955x: Don't invert requested value in pca955x_gpio_set_value()

LED documentation improvements:
- update 00-INDEX file"

* tag 'leds_for_4.15rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/j.anaszewski/linux-leds:
leds: Add driver for PC Engines APU/APU2 LEDs
leds: lp55xx: fix spelling mistake: 'cound' -> 'could'
leds: Convert timers to use timer_setup()
Documentation: leds: Update 00-INDEX file
leds: tca6507: Remove unnecessary reg check
leds: ledtrig-heartbeat: Convert timers to use timer_setup()
leds: Replace flags bit shift with BIT() macros
leds: pca955x: Don't invert requested value in pca955x_gpio_set_value()
leds: ledtrig-activity: Add a system activity LED trigger

+627 -31
+10
Documentation/leds/00-INDEX
··· 4 4 - Driver for BlinkM LED-devices. 5 5 leds-class.txt 6 6 - documents LED handling under Linux. 7 + leds-class-flash.txt 8 + - documents flash LED handling under Linux. 9 + leds-lm3556.txt 10 + - notes on how to use the leds-lm3556 driver. 7 11 leds-lp3944.txt 8 12 - notes on how to use the leds-lp3944 driver. 9 13 leds-lp5521.txt ··· 20 16 - description about lp55xx common driver. 21 17 leds-lm3556.txt 22 18 - notes on how to use the leds-lm3556 driver. 19 + leds-mlxcpld.txt 20 + - notes on how to use the leds-mlxcpld driver. 23 21 ledtrig-oneshot.txt 24 22 - One-shot LED trigger for both sporadic and dense events. 25 23 ledtrig-transient.txt 26 24 - LED Transient Trigger, one shot timer activation. 25 + ledtrig-usbport.txt 26 + - notes on how to use the drivers/usb/core/ledtrig-usbport.c trigger. 27 + uleds.txt 28 + - notes on how to use the uleds driver.
+10
drivers/leds/Kconfig
··· 57 57 depends on PINCTRL 58 58 help 59 59 This option enables support for the LEDs on the AAT1290. 60 + config LEDS_APU 61 + tristate "Front panel LED support for PC Engines APU/APU2 boards" 62 + depends on LEDS_CLASS 63 + depends on X86 && DMI 64 + help 65 + This driver makes the PC Engines APU/APU2 front panel LEDs 66 + accessible from userspace programs through the LED subsystem. 67 + 68 + To compile this driver as a module, choose M here: the 69 + module will be called leds-apu. 60 70 61 71 config LEDS_AS3645A 62 72 tristate "AS3645A LED flash controller support"
+1
drivers/leds/Makefile
··· 9 9 # LED Platform Drivers 10 10 obj-$(CONFIG_LEDS_88PM860X) += leds-88pm860x.o 11 11 obj-$(CONFIG_LEDS_AAT1290) += leds-aat1290.o 12 + obj-$(CONFIG_LEDS_APU) += leds-apu.o 12 13 obj-$(CONFIG_LEDS_AS3645A) += leds-as3645a.o 13 14 obj-$(CONFIG_LEDS_BCM6328) += leds-bcm6328.o 14 15 obj-$(CONFIG_LEDS_BCM6358) += leds-bcm6358.o
+3 -4
drivers/leds/led-core.c
··· 45 45 return led_cdev->brightness_set_blocking(led_cdev, value); 46 46 } 47 47 48 - static void led_timer_function(unsigned long data) 48 + static void led_timer_function(struct timer_list *t) 49 49 { 50 - struct led_classdev *led_cdev = (void *)data; 50 + struct led_classdev *led_cdev = from_timer(led_cdev, t, blink_timer); 51 51 unsigned long brightness; 52 52 unsigned long delay; 53 53 ··· 178 178 { 179 179 INIT_WORK(&led_cdev->set_brightness_work, set_brightness_delayed); 180 180 181 - setup_timer(&led_cdev->blink_timer, led_timer_function, 182 - (unsigned long)led_cdev); 181 + timer_setup(&led_cdev->blink_timer, led_timer_function, 0); 183 182 } 184 183 EXPORT_SYMBOL_GPL(led_init_core); 185 184
+278
drivers/leds/leds-apu.c
··· 1 + /* 2 + * drivers/leds/leds-apu.c 3 + * Copyright (C) 2017 Alan Mizrahi, alan at mizrahi dot com dot ve 4 + * 5 + * Redistribution and use in source and binary forms, with or without 6 + * modification, are permitted provided that the following conditions are met: 7 + * 8 + * 1. Redistributions of source code must retain the above copyright 9 + * notice, this list of conditions and the following disclaimer. 10 + * 2. Redistributions in binary form must reproduce the above copyright 11 + * notice, this list of conditions and the following disclaimer in the 12 + * documentation and/or other materials provided with the distribution. 13 + * 3. Neither the names of the copyright holders nor the names of its 14 + * contributors may be used to endorse or promote products derived from 15 + * this software without specific prior written permission. 16 + * 17 + * Alternatively, this software may be distributed under the terms of the 18 + * GNU General Public License ("GPL") version 2 as published by the Free 19 + * Software Foundation. 20 + * 21 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 25 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 + * POSSIBILITY OF SUCH DAMAGE. 32 + */ 33 + 34 + #include <linux/dmi.h> 35 + #include <linux/err.h> 36 + #include <linux/init.h> 37 + #include <linux/io.h> 38 + #include <linux/kernel.h> 39 + #include <linux/leds.h> 40 + #include <linux/module.h> 41 + #include <linux/platform_device.h> 42 + 43 + #define APU1_FCH_ACPI_MMIO_BASE 0xFED80000 44 + #define APU1_FCH_GPIO_BASE (APU1_FCH_ACPI_MMIO_BASE + 0x01BD) 45 + #define APU1_LEDON 0x08 46 + #define APU1_LEDOFF 0xC8 47 + #define APU1_NUM_GPIO 3 48 + #define APU1_IOSIZE sizeof(u8) 49 + 50 + #define APU2_FCH_ACPI_MMIO_BASE 0xFED80000 51 + #define APU2_FCH_GPIO_BASE (APU2_FCH_ACPI_MMIO_BASE + 0x1500) 52 + #define APU2_GPIO_BIT_WRITE 22 53 + #define APU2_APU2_NUM_GPIO 4 54 + #define APU2_IOSIZE sizeof(u32) 55 + 56 + /* LED access parameters */ 57 + struct apu_param { 58 + void __iomem *addr; /* for ioread/iowrite */ 59 + }; 60 + 61 + /* LED private data */ 62 + struct apu_led_priv { 63 + struct led_classdev cdev; 64 + struct apu_param param; 65 + }; 66 + #define cdev_to_priv(c) container_of(c, struct apu_led_priv, cdev) 67 + 68 + /* LED profile */ 69 + struct apu_led_profile { 70 + const char *name; 71 + enum led_brightness brightness; 72 + unsigned long offset; /* for devm_ioremap */ 73 + }; 74 + 75 + /* Supported platform types */ 76 + enum apu_led_platform_types { 77 + APU1_LED_PLATFORM, 78 + APU2_LED_PLATFORM, 79 + }; 80 + 81 + struct apu_led_pdata { 82 + struct platform_device *pdev; 83 + struct apu_led_priv *pled; 84 + const struct apu_led_profile *profile; 85 + enum apu_led_platform_types platform; 86 + int num_led_instances; 87 + int iosize; /* for devm_ioremap() */ 88 + spinlock_t lock; 89 + }; 90 + 91 + static struct apu_led_pdata *apu_led; 92 + 93 + static const struct apu_led_profile apu1_led_profile[] = { 94 + { "apu:green:1", LED_ON, APU1_FCH_GPIO_BASE + 0 * APU1_IOSIZE }, 95 + { "apu:green:2", LED_OFF, APU1_FCH_GPIO_BASE + 1 * APU1_IOSIZE }, 96 + { "apu:green:3", LED_OFF, APU1_FCH_GPIO_BASE + 2 * APU1_IOSIZE }, 97 + }; 98 + 99 + static const struct apu_led_profile apu2_led_profile[] = { 100 + { "apu2:green:1", LED_ON, APU2_FCH_GPIO_BASE + 68 * APU2_IOSIZE }, 101 + { "apu2:green:2", LED_OFF, APU2_FCH_GPIO_BASE + 69 * APU2_IOSIZE }, 102 + { "apu2:green:3", LED_OFF, APU2_FCH_GPIO_BASE + 70 * APU2_IOSIZE }, 103 + }; 104 + 105 + static const struct dmi_system_id apu_led_dmi_table[] __initconst = { 106 + { 107 + .ident = "apu", 108 + .matches = { 109 + DMI_MATCH(DMI_SYS_VENDOR, "PC Engines"), 110 + DMI_MATCH(DMI_PRODUCT_NAME, "APU") 111 + } 112 + }, 113 + { 114 + .ident = "apu2", 115 + .matches = { 116 + DMI_MATCH(DMI_SYS_VENDOR, "PC Engines"), 117 + DMI_MATCH(DMI_BOARD_NAME, "APU2") 118 + } 119 + }, 120 + {} 121 + }; 122 + MODULE_DEVICE_TABLE(dmi, apu_led_dmi_table); 123 + 124 + static void apu1_led_brightness_set(struct led_classdev *led, enum led_brightness value) 125 + { 126 + struct apu_led_priv *pled = cdev_to_priv(led); 127 + 128 + spin_lock(&apu_led->lock); 129 + iowrite8(value ? APU1_LEDON : APU1_LEDOFF, pled->param.addr); 130 + spin_unlock(&apu_led->lock); 131 + } 132 + 133 + static void apu2_led_brightness_set(struct led_classdev *led, enum led_brightness value) 134 + { 135 + struct apu_led_priv *pled = cdev_to_priv(led); 136 + u32 value_new; 137 + 138 + spin_lock(&apu_led->lock); 139 + 140 + value_new = ioread32(pled->param.addr); 141 + 142 + if (value) 143 + value_new &= ~BIT(APU2_GPIO_BIT_WRITE); 144 + else 145 + value_new |= BIT(APU2_GPIO_BIT_WRITE); 146 + 147 + iowrite32(value_new, pled->param.addr); 148 + 149 + spin_unlock(&apu_led->lock); 150 + } 151 + 152 + static int apu_led_config(struct device *dev, struct apu_led_pdata *apuld) 153 + { 154 + int i; 155 + int err; 156 + 157 + apu_led->pled = devm_kzalloc(dev, 158 + sizeof(struct apu_led_priv) * apu_led->num_led_instances, 159 + GFP_KERNEL); 160 + 161 + if (!apu_led->pled) 162 + return -ENOMEM; 163 + 164 + for (i = 0; i < apu_led->num_led_instances; i++) { 165 + struct apu_led_priv *pled = &apu_led->pled[i]; 166 + struct led_classdev *led_cdev = &pled->cdev; 167 + 168 + led_cdev->name = apu_led->profile[i].name; 169 + led_cdev->brightness = apu_led->profile[i].brightness; 170 + led_cdev->max_brightness = 1; 171 + led_cdev->flags = LED_CORE_SUSPENDRESUME; 172 + if (apu_led->platform == APU1_LED_PLATFORM) 173 + led_cdev->brightness_set = apu1_led_brightness_set; 174 + else if (apu_led->platform == APU2_LED_PLATFORM) 175 + led_cdev->brightness_set = apu2_led_brightness_set; 176 + 177 + pled->param.addr = devm_ioremap(dev, 178 + apu_led->profile[i].offset, apu_led->iosize); 179 + if (!pled->param.addr) { 180 + err = -ENOMEM; 181 + goto error; 182 + } 183 + 184 + err = led_classdev_register(dev, led_cdev); 185 + if (err) 186 + goto error; 187 + 188 + led_cdev->brightness_set(led_cdev, apu_led->profile[i].brightness); 189 + } 190 + 191 + return 0; 192 + 193 + error: 194 + while (i-- > 0) 195 + led_classdev_unregister(&apu_led->pled[i].cdev); 196 + 197 + return err; 198 + } 199 + 200 + static int __init apu_led_probe(struct platform_device *pdev) 201 + { 202 + apu_led = devm_kzalloc(&pdev->dev, sizeof(*apu_led), GFP_KERNEL); 203 + 204 + if (!apu_led) 205 + return -ENOMEM; 206 + 207 + apu_led->pdev = pdev; 208 + 209 + if (dmi_match(DMI_BOARD_NAME, "APU")) { 210 + apu_led->profile = apu1_led_profile; 211 + apu_led->platform = APU1_LED_PLATFORM; 212 + apu_led->num_led_instances = ARRAY_SIZE(apu1_led_profile); 213 + apu_led->iosize = APU1_IOSIZE; 214 + } else if (dmi_match(DMI_BOARD_NAME, "APU2")) { 215 + apu_led->profile = apu2_led_profile; 216 + apu_led->platform = APU2_LED_PLATFORM; 217 + apu_led->num_led_instances = ARRAY_SIZE(apu2_led_profile); 218 + apu_led->iosize = APU2_IOSIZE; 219 + } 220 + 221 + spin_lock_init(&apu_led->lock); 222 + return apu_led_config(&pdev->dev, apu_led); 223 + } 224 + 225 + static struct platform_driver apu_led_driver = { 226 + .driver = { 227 + .name = KBUILD_MODNAME, 228 + }, 229 + }; 230 + 231 + static int __init apu_led_init(void) 232 + { 233 + struct platform_device *pdev; 234 + int err; 235 + 236 + if (!dmi_match(DMI_SYS_VENDOR, "PC Engines")) { 237 + pr_err("No PC Engines board detected\n"); 238 + return -ENODEV; 239 + } 240 + if (!(dmi_match(DMI_PRODUCT_NAME, "APU") || dmi_match(DMI_PRODUCT_NAME, "APU2"))) { 241 + pr_err("Unknown PC Engines board: %s\n", 242 + dmi_get_system_info(DMI_PRODUCT_NAME)); 243 + return -ENODEV; 244 + } 245 + 246 + pdev = platform_device_register_simple(KBUILD_MODNAME, -1, NULL, 0); 247 + if (IS_ERR(pdev)) { 248 + pr_err("Device allocation failed\n"); 249 + return PTR_ERR(pdev); 250 + } 251 + 252 + err = platform_driver_probe(&apu_led_driver, apu_led_probe); 253 + if (err) { 254 + pr_err("Probe platform driver failed\n"); 255 + platform_device_unregister(pdev); 256 + } 257 + 258 + return err; 259 + } 260 + 261 + static void __exit apu_led_exit(void) 262 + { 263 + int i; 264 + 265 + for (i = 0; i < apu_led->num_led_instances; i++) 266 + led_classdev_unregister(&apu_led->pled[i].cdev); 267 + 268 + platform_device_unregister(apu_led->pdev); 269 + platform_driver_unregister(&apu_led_driver); 270 + } 271 + 272 + module_init(apu_led_init); 273 + module_exit(apu_led_exit); 274 + 275 + MODULE_AUTHOR("Alan Mizrahi"); 276 + MODULE_DESCRIPTION("PC Engines APU family LED driver"); 277 + MODULE_LICENSE("GPL v2"); 278 + MODULE_ALIAS("platform:leds_apu");
+1 -1
drivers/leds/leds-lp5523.c
··· 323 323 324 324 if (status != LP5523_ENG_STATUS_MASK) { 325 325 dev_err(&chip->cl->dev, 326 - "cound not configure LED engine, status = 0x%.2x\n", 326 + "could not configure LED engine, status = 0x%.2x\n", 327 327 status); 328 328 ret = -1; 329 329 }
+12 -5
drivers/leds/leds-pca955x.c
··· 61 61 #define PCA955X_LS_BLINK0 0x2 /* Blink at PWM0 rate */ 62 62 #define PCA955X_LS_BLINK1 0x3 /* Blink at PWM1 rate */ 63 63 64 + #define PCA955X_GPIO_INPUT LED_OFF 65 + #define PCA955X_GPIO_HIGH LED_OFF 66 + #define PCA955X_GPIO_LOW LED_FULL 67 + 64 68 enum pca955x_type { 65 69 pca9550, 66 70 pca9551, ··· 333 329 struct pca955x_led *led = &pca955x->leds[offset]; 334 330 335 331 if (val) 336 - return pca955x_led_set(&led->led_cdev, LED_FULL); 337 - else 338 - return pca955x_led_set(&led->led_cdev, LED_OFF); 332 + return pca955x_led_set(&led->led_cdev, PCA955X_GPIO_HIGH); 333 + 334 + return pca955x_led_set(&led->led_cdev, PCA955X_GPIO_LOW); 339 335 } 340 336 341 337 static void pca955x_gpio_set_value(struct gpio_chip *gc, unsigned int offset, ··· 359 355 static int pca955x_gpio_direction_input(struct gpio_chip *gc, 360 356 unsigned int offset) 361 357 { 362 - /* To use as input ensure pin is not driven */ 363 - return pca955x_set_value(gc, offset, 0); 358 + struct pca955x *pca955x = gpiochip_get_data(gc); 359 + struct pca955x_led *led = &pca955x->leds[offset]; 360 + 361 + /* To use as input ensure pin is not driven. */ 362 + return pca955x_led_set(&led->led_cdev, PCA955X_GPIO_INPUT); 364 363 } 365 364 366 365 static int pca955x_gpio_direction_output(struct gpio_chip *gc,
+1 -1
drivers/leds/leds-tca6507.c
··· 715 715 if (of_property_match_string(child, "compatible", "gpio") >= 0) 716 716 led.flags |= TCA6507_MAKE_GPIO; 717 717 ret = of_property_read_u32(child, "reg", &reg); 718 - if (ret != 0 || reg < 0 || reg >= NUM_LEDS) 718 + if (ret != 0 || reg >= NUM_LEDS) 719 719 continue; 720 720 721 721 tca_leds[reg] = led;
+9
drivers/leds/trigger/Kconfig
··· 77 77 78 78 If unsure, say N. 79 79 80 + config LEDS_TRIGGER_ACTIVITY 81 + tristate "LED activity Trigger" 82 + depends on LEDS_TRIGGERS 83 + help 84 + This allows LEDs to be controlled by a immediate CPU usage. 85 + The flash frequency and duty cycle varies from faint flashes to 86 + intense brightness depending on the instant CPU load. 87 + If unsure, say N. 88 + 80 89 config LEDS_TRIGGER_GPIO 81 90 tristate "LED GPIO Trigger" 82 91 depends on LEDS_TRIGGERS
+1
drivers/leds/trigger/Makefile
··· 7 7 obj-$(CONFIG_LEDS_TRIGGER_BACKLIGHT) += ledtrig-backlight.o 8 8 obj-$(CONFIG_LEDS_TRIGGER_GPIO) += ledtrig-gpio.o 9 9 obj-$(CONFIG_LEDS_TRIGGER_CPU) += ledtrig-cpu.o 10 + obj-$(CONFIG_LEDS_TRIGGER_ACTIVITY) += ledtrig-activity.o 10 11 obj-$(CONFIG_LEDS_TRIGGER_DEFAULT_ON) += ledtrig-default-on.o 11 12 obj-$(CONFIG_LEDS_TRIGGER_TRANSIENT) += ledtrig-transient.o 12 13 obj-$(CONFIG_LEDS_TRIGGER_CAMERA) += ledtrig-camera.o
+275
drivers/leds/trigger/ledtrig-activity.c
··· 1 + /* 2 + * Activity LED trigger 3 + * 4 + * Copyright (C) 2017 Willy Tarreau <w@1wt.eu> 5 + * Partially based on Atsushi Nemoto's ledtrig-heartbeat.c. 6 + * 7 + * This program is free software; you can redistribute it and/or modify 8 + * it under the terms of the GNU General Public License version 2 as 9 + * published by the Free Software Foundation. 10 + * 11 + */ 12 + #include <linux/init.h> 13 + #include <linux/kernel.h> 14 + #include <linux/kernel_stat.h> 15 + #include <linux/leds.h> 16 + #include <linux/module.h> 17 + #include <linux/reboot.h> 18 + #include <linux/sched.h> 19 + #include <linux/slab.h> 20 + #include <linux/timer.h> 21 + #include "../leds.h" 22 + 23 + static int panic_detected; 24 + 25 + struct activity_data { 26 + struct timer_list timer; 27 + struct led_classdev *led_cdev; 28 + u64 last_used; 29 + u64 last_boot; 30 + int time_left; 31 + int state; 32 + int invert; 33 + }; 34 + 35 + static void led_activity_function(struct timer_list *t) 36 + { 37 + struct activity_data *activity_data = from_timer(activity_data, t, 38 + timer); 39 + struct led_classdev *led_cdev = activity_data->led_cdev; 40 + struct timespec boot_time; 41 + unsigned int target; 42 + unsigned int usage; 43 + int delay; 44 + u64 curr_used; 45 + u64 curr_boot; 46 + s32 diff_used; 47 + s32 diff_boot; 48 + int cpus; 49 + int i; 50 + 51 + if (test_and_clear_bit(LED_BLINK_BRIGHTNESS_CHANGE, &led_cdev->work_flags)) 52 + led_cdev->blink_brightness = led_cdev->new_blink_brightness; 53 + 54 + if (unlikely(panic_detected)) { 55 + /* full brightness in case of panic */ 56 + led_set_brightness_nosleep(led_cdev, led_cdev->blink_brightness); 57 + return; 58 + } 59 + 60 + get_monotonic_boottime(&boot_time); 61 + 62 + cpus = 0; 63 + curr_used = 0; 64 + 65 + for_each_possible_cpu(i) { 66 + curr_used += kcpustat_cpu(i).cpustat[CPUTIME_USER] 67 + + kcpustat_cpu(i).cpustat[CPUTIME_NICE] 68 + + kcpustat_cpu(i).cpustat[CPUTIME_SYSTEM] 69 + + kcpustat_cpu(i).cpustat[CPUTIME_SOFTIRQ] 70 + + kcpustat_cpu(i).cpustat[CPUTIME_IRQ]; 71 + cpus++; 72 + } 73 + 74 + /* We come here every 100ms in the worst case, so that's 100M ns of 75 + * cumulated time. By dividing by 2^16, we get the time resolution 76 + * down to 16us, ensuring we won't overflow 32-bit computations below 77 + * even up to 3k CPUs, while keeping divides cheap on smaller systems. 78 + */ 79 + curr_boot = timespec_to_ns(&boot_time) * cpus; 80 + diff_boot = (curr_boot - activity_data->last_boot) >> 16; 81 + diff_used = (curr_used - activity_data->last_used) >> 16; 82 + activity_data->last_boot = curr_boot; 83 + activity_data->last_used = curr_used; 84 + 85 + if (diff_boot <= 0 || diff_used < 0) 86 + usage = 0; 87 + else if (diff_used >= diff_boot) 88 + usage = 100; 89 + else 90 + usage = 100 * diff_used / diff_boot; 91 + 92 + /* 93 + * Now we know the total boot_time multiplied by the number of CPUs, and 94 + * the total idle+wait time for all CPUs. We'll compare how they evolved 95 + * since last call. The % of overall CPU usage is : 96 + * 97 + * 1 - delta_idle / delta_boot 98 + * 99 + * What we want is that when the CPU usage is zero, the LED must blink 100 + * slowly with very faint flashes that are detectable but not disturbing 101 + * (typically 10ms every second, or 10ms ON, 990ms OFF). Then we want 102 + * blinking frequency to increase up to the point where the load is 103 + * enough to saturate one core in multi-core systems or 50% in single 104 + * core systems. At this point it should reach 10 Hz with a 10/90 duty 105 + * cycle (10ms ON, 90ms OFF). After this point, the blinking frequency 106 + * remains stable (10 Hz) and only the duty cycle increases to report 107 + * the activity, up to the point where we have 90ms ON, 10ms OFF when 108 + * all cores are saturated. It's important that the LED never stays in 109 + * a steady state so that it's easy to distinguish an idle or saturated 110 + * machine from a hung one. 111 + * 112 + * This gives us : 113 + * - a target CPU usage of min(50%, 100%/#CPU) for a 10% duty cycle 114 + * (10ms ON, 90ms OFF) 115 + * - below target : 116 + * ON_ms = 10 117 + * OFF_ms = 90 + (1 - usage/target) * 900 118 + * - above target : 119 + * ON_ms = 10 + (usage-target)/(100%-target) * 80 120 + * OFF_ms = 90 - (usage-target)/(100%-target) * 80 121 + * 122 + * In order to keep a good responsiveness, we cap the sleep time to 123 + * 100 ms and keep track of the sleep time left. This allows us to 124 + * quickly change it if needed. 125 + */ 126 + 127 + activity_data->time_left -= 100; 128 + if (activity_data->time_left <= 0) { 129 + activity_data->time_left = 0; 130 + activity_data->state = !activity_data->state; 131 + led_set_brightness_nosleep(led_cdev, 132 + (activity_data->state ^ activity_data->invert) ? 133 + led_cdev->blink_brightness : LED_OFF); 134 + } 135 + 136 + target = (cpus > 1) ? (100 / cpus) : 50; 137 + 138 + if (usage < target) 139 + delay = activity_data->state ? 140 + 10 : /* ON */ 141 + 990 - 900 * usage / target; /* OFF */ 142 + else 143 + delay = activity_data->state ? 144 + 10 + 80 * (usage - target) / (100 - target) : /* ON */ 145 + 90 - 80 * (usage - target) / (100 - target); /* OFF */ 146 + 147 + 148 + if (!activity_data->time_left || delay <= activity_data->time_left) 149 + activity_data->time_left = delay; 150 + 151 + delay = min_t(int, activity_data->time_left, 100); 152 + mod_timer(&activity_data->timer, jiffies + msecs_to_jiffies(delay)); 153 + } 154 + 155 + static ssize_t led_invert_show(struct device *dev, 156 + struct device_attribute *attr, char *buf) 157 + { 158 + struct led_classdev *led_cdev = dev_get_drvdata(dev); 159 + struct activity_data *activity_data = led_cdev->trigger_data; 160 + 161 + return sprintf(buf, "%u\n", activity_data->invert); 162 + } 163 + 164 + static ssize_t led_invert_store(struct device *dev, 165 + struct device_attribute *attr, 166 + const char *buf, size_t size) 167 + { 168 + struct led_classdev *led_cdev = dev_get_drvdata(dev); 169 + struct activity_data *activity_data = led_cdev->trigger_data; 170 + unsigned long state; 171 + int ret; 172 + 173 + ret = kstrtoul(buf, 0, &state); 174 + if (ret) 175 + return ret; 176 + 177 + activity_data->invert = !!state; 178 + 179 + return size; 180 + } 181 + 182 + static DEVICE_ATTR(invert, 0644, led_invert_show, led_invert_store); 183 + 184 + static void activity_activate(struct led_classdev *led_cdev) 185 + { 186 + struct activity_data *activity_data; 187 + int rc; 188 + 189 + activity_data = kzalloc(sizeof(*activity_data), GFP_KERNEL); 190 + if (!activity_data) 191 + return; 192 + 193 + led_cdev->trigger_data = activity_data; 194 + rc = device_create_file(led_cdev->dev, &dev_attr_invert); 195 + if (rc) { 196 + kfree(led_cdev->trigger_data); 197 + return; 198 + } 199 + 200 + activity_data->led_cdev = led_cdev; 201 + timer_setup(&activity_data->timer, led_activity_function, 0); 202 + if (!led_cdev->blink_brightness) 203 + led_cdev->blink_brightness = led_cdev->max_brightness; 204 + led_activity_function(&activity_data->timer); 205 + set_bit(LED_BLINK_SW, &led_cdev->work_flags); 206 + led_cdev->activated = true; 207 + } 208 + 209 + static void activity_deactivate(struct led_classdev *led_cdev) 210 + { 211 + struct activity_data *activity_data = led_cdev->trigger_data; 212 + 213 + if (led_cdev->activated) { 214 + del_timer_sync(&activity_data->timer); 215 + device_remove_file(led_cdev->dev, &dev_attr_invert); 216 + kfree(activity_data); 217 + clear_bit(LED_BLINK_SW, &led_cdev->work_flags); 218 + led_cdev->activated = false; 219 + } 220 + } 221 + 222 + static struct led_trigger activity_led_trigger = { 223 + .name = "activity", 224 + .activate = activity_activate, 225 + .deactivate = activity_deactivate, 226 + }; 227 + 228 + static int activity_reboot_notifier(struct notifier_block *nb, 229 + unsigned long code, void *unused) 230 + { 231 + led_trigger_unregister(&activity_led_trigger); 232 + return NOTIFY_DONE; 233 + } 234 + 235 + static int activity_panic_notifier(struct notifier_block *nb, 236 + unsigned long code, void *unused) 237 + { 238 + panic_detected = 1; 239 + return NOTIFY_DONE; 240 + } 241 + 242 + static struct notifier_block activity_reboot_nb = { 243 + .notifier_call = activity_reboot_notifier, 244 + }; 245 + 246 + static struct notifier_block activity_panic_nb = { 247 + .notifier_call = activity_panic_notifier, 248 + }; 249 + 250 + static int __init activity_init(void) 251 + { 252 + int rc = led_trigger_register(&activity_led_trigger); 253 + 254 + if (!rc) { 255 + atomic_notifier_chain_register(&panic_notifier_list, 256 + &activity_panic_nb); 257 + register_reboot_notifier(&activity_reboot_nb); 258 + } 259 + return rc; 260 + } 261 + 262 + static void __exit activity_exit(void) 263 + { 264 + unregister_reboot_notifier(&activity_reboot_nb); 265 + atomic_notifier_chain_unregister(&panic_notifier_list, 266 + &activity_panic_nb); 267 + led_trigger_unregister(&activity_led_trigger); 268 + } 269 + 270 + module_init(activity_init); 271 + module_exit(activity_exit); 272 + 273 + MODULE_AUTHOR("Willy Tarreau <w@1wt.eu>"); 274 + MODULE_DESCRIPTION("Activity LED trigger"); 275 + MODULE_LICENSE("GPL");
+10 -6
drivers/leds/trigger/ledtrig-heartbeat.c
··· 25 25 static int panic_heartbeats; 26 26 27 27 struct heartbeat_trig_data { 28 + struct led_classdev *led_cdev; 28 29 unsigned int phase; 29 30 unsigned int period; 30 31 struct timer_list timer; 31 32 unsigned int invert; 32 33 }; 33 34 34 - static void led_heartbeat_function(unsigned long data) 35 + static void led_heartbeat_function(struct timer_list *t) 35 36 { 36 - struct led_classdev *led_cdev = (struct led_classdev *) data; 37 - struct heartbeat_trig_data *heartbeat_data = led_cdev->trigger_data; 37 + struct heartbeat_trig_data *heartbeat_data = 38 + from_timer(heartbeat_data, t, timer); 39 + struct led_classdev *led_cdev; 38 40 unsigned long brightness = LED_OFF; 39 41 unsigned long delay = 0; 42 + 43 + led_cdev = heartbeat_data->led_cdev; 40 44 41 45 if (unlikely(panic_heartbeats)) { 42 46 led_set_brightness_nosleep(led_cdev, LED_OFF); ··· 131 127 return; 132 128 133 129 led_cdev->trigger_data = heartbeat_data; 130 + heartbeat_data->led_cdev = led_cdev; 134 131 rc = device_create_file(led_cdev->dev, &dev_attr_invert); 135 132 if (rc) { 136 133 kfree(led_cdev->trigger_data); 137 134 return; 138 135 } 139 136 140 - setup_timer(&heartbeat_data->timer, 141 - led_heartbeat_function, (unsigned long) led_cdev); 137 + timer_setup(&heartbeat_data->timer, led_heartbeat_function, 0); 142 138 heartbeat_data->phase = 0; 143 139 if (!led_cdev->blink_brightness) 144 140 led_cdev->blink_brightness = led_cdev->max_brightness; 145 - led_heartbeat_function(heartbeat_data->timer.data); 141 + led_heartbeat_function(&heartbeat_data->timer); 146 142 set_bit(LED_BLINK_SW, &led_cdev->work_flags); 147 143 led_cdev->activated = true; 148 144 }
+7 -5
drivers/leds/trigger/ledtrig-transient.c
··· 33 33 int restore_state; 34 34 unsigned long duration; 35 35 struct timer_list timer; 36 + struct led_classdev *led_cdev; 36 37 }; 37 38 38 - static void transient_timer_function(unsigned long data) 39 + static void transient_timer_function(struct timer_list *t) 39 40 { 40 - struct led_classdev *led_cdev = (struct led_classdev *) data; 41 - struct transient_trig_data *transient_data = led_cdev->trigger_data; 41 + struct transient_trig_data *transient_data = 42 + from_timer(transient_data, t, timer); 43 + struct led_classdev *led_cdev = transient_data->led_cdev; 42 44 43 45 transient_data->activate = 0; 44 46 led_set_brightness_nosleep(led_cdev, transient_data->restore_state); ··· 171 169 return; 172 170 } 173 171 led_cdev->trigger_data = tdata; 172 + tdata->led_cdev = led_cdev; 174 173 175 174 rc = device_create_file(led_cdev->dev, &dev_attr_activate); 176 175 if (rc) ··· 185 182 if (rc) 186 183 goto err_out_state; 187 184 188 - setup_timer(&tdata->timer, transient_timer_function, 189 - (unsigned long) led_cdev); 185 + timer_setup(&tdata->timer, transient_timer_function, 0); 190 186 led_cdev->activated = true; 191 187 192 188 return;
+9 -9
include/linux/leds.h
··· 40 40 int flags; 41 41 42 42 /* Lower 16 bits reflect status */ 43 - #define LED_SUSPENDED (1 << 0) 44 - #define LED_UNREGISTERING (1 << 1) 43 + #define LED_SUSPENDED BIT(0) 44 + #define LED_UNREGISTERING BIT(1) 45 45 /* Upper 16 bits reflect control information */ 46 - #define LED_CORE_SUSPENDRESUME (1 << 16) 47 - #define LED_SYSFS_DISABLE (1 << 17) 48 - #define LED_DEV_CAP_FLASH (1 << 18) 49 - #define LED_HW_PLUGGABLE (1 << 19) 50 - #define LED_PANIC_INDICATOR (1 << 20) 51 - #define LED_BRIGHT_HW_CHANGED (1 << 21) 52 - #define LED_RETAIN_AT_SHUTDOWN (1 << 22) 46 + #define LED_CORE_SUSPENDRESUME BIT(16) 47 + #define LED_SYSFS_DISABLE BIT(17) 48 + #define LED_DEV_CAP_FLASH BIT(18) 49 + #define LED_HW_PLUGGABLE BIT(19) 50 + #define LED_PANIC_INDICATOR BIT(20) 51 + #define LED_BRIGHT_HW_CHANGED BIT(21) 52 + #define LED_RETAIN_AT_SHUTDOWN BIT(22) 53 53 54 54 /* set_brightness_work / blink_timer flags, atomic, private. */ 55 55 unsigned long work_flags;