LED updates for 4.15rc1
-----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAABCAAGBQJaC1RFAAoJEL1qUBy3i3wm2+sP/0vzsOFyu57V9Af4f7VCRrml fZfk83u+/pCafnRrC7ttnNkrZplQ2t675Plpfr6cs8iIFU91IwLw83MeuVkr8wCB 3Cm+VElq/RBke36ZUaJGvrathSVmhmYc/cZk2rCfiozlOSUbByy/RGJJKmvV5ydA sdVS4V7WtcZrDgiJtCY9ci5/OUpjl+BuAh9m4b2n3+fnhSRJTnMR2Xz35HLNOO/c TE8AJtedehjiiy3zYv9QHy5EQJ1OJVTVN4lhhsKhYb5FfWvNdwWrkLeT6uSFWZ0l UTx/cvTb0CxYUijr2RgutkQ1hW/+/VumcW1HK0st+Nj1ODuZ2u6VQ0NkTAjCRBPP v/QZo2t4UrVfymjR1e67oW1c7ljEy3DVpIU2IfJA27c9OfGoAOlH653C7WVZFjyc IBSbalMnpwINxX3fDlavl92P1iGEL0x9711dY/SUqxMA1qmejxHERR0jJB1EdY2I 6I4APnXSOGQBjgPH3AIFcqMYcmTV6NucQsS48OPY5WGt+BzDxJL7XC3Xh3hdRNPt c/pv2x2YOWjnpYUjGJnCcmilrIbTUyahhLIS+zuvykHpo5rYt1jmpPYqTEZibWJy iINAaOnxELkRGXJP4CX1QG/t64pazLuC3d/WF5GA3+AMIUpzNrmhDrRBySEsSQez 1aquAvFavNywtLZ43bVv =T2rn -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
6a77d86655
14 changed files with 627 additions and 31 deletions
|
@ -4,6 +4,10 @@ leds-blinkm.txt
|
||||||
- Driver for BlinkM LED-devices.
|
- Driver for BlinkM LED-devices.
|
||||||
leds-class.txt
|
leds-class.txt
|
||||||
- documents LED handling under Linux.
|
- documents LED handling under Linux.
|
||||||
|
leds-class-flash.txt
|
||||||
|
- documents flash LED handling under Linux.
|
||||||
|
leds-lm3556.txt
|
||||||
|
- notes on how to use the leds-lm3556 driver.
|
||||||
leds-lp3944.txt
|
leds-lp3944.txt
|
||||||
- notes on how to use the leds-lp3944 driver.
|
- notes on how to use the leds-lp3944 driver.
|
||||||
leds-lp5521.txt
|
leds-lp5521.txt
|
||||||
|
@ -16,7 +20,13 @@ leds-lp55xx.txt
|
||||||
- description about lp55xx common driver.
|
- description about lp55xx common driver.
|
||||||
leds-lm3556.txt
|
leds-lm3556.txt
|
||||||
- notes on how to use the leds-lm3556 driver.
|
- notes on how to use the leds-lm3556 driver.
|
||||||
|
leds-mlxcpld.txt
|
||||||
|
- notes on how to use the leds-mlxcpld driver.
|
||||||
ledtrig-oneshot.txt
|
ledtrig-oneshot.txt
|
||||||
- One-shot LED trigger for both sporadic and dense events.
|
- One-shot LED trigger for both sporadic and dense events.
|
||||||
ledtrig-transient.txt
|
ledtrig-transient.txt
|
||||||
- LED Transient Trigger, one shot timer activation.
|
- LED Transient Trigger, one shot timer activation.
|
||||||
|
ledtrig-usbport.txt
|
||||||
|
- notes on how to use the drivers/usb/core/ledtrig-usbport.c trigger.
|
||||||
|
uleds.txt
|
||||||
|
- notes on how to use the uleds driver.
|
||||||
|
|
|
@ -57,6 +57,16 @@ config LEDS_AAT1290
|
||||||
depends on PINCTRL
|
depends on PINCTRL
|
||||||
help
|
help
|
||||||
This option enables support for the LEDs on the AAT1290.
|
This option enables support for the LEDs on the AAT1290.
|
||||||
|
config LEDS_APU
|
||||||
|
tristate "Front panel LED support for PC Engines APU/APU2 boards"
|
||||||
|
depends on LEDS_CLASS
|
||||||
|
depends on X86 && DMI
|
||||||
|
help
|
||||||
|
This driver makes the PC Engines APU/APU2 front panel LEDs
|
||||||
|
accessible from userspace programs through the LED subsystem.
|
||||||
|
|
||||||
|
To compile this driver as a module, choose M here: the
|
||||||
|
module will be called leds-apu.
|
||||||
|
|
||||||
config LEDS_AS3645A
|
config LEDS_AS3645A
|
||||||
tristate "AS3645A LED flash controller support"
|
tristate "AS3645A LED flash controller support"
|
||||||
|
|
|
@ -9,6 +9,7 @@ obj-$(CONFIG_LEDS_TRIGGERS) += led-triggers.o
|
||||||
# LED Platform Drivers
|
# LED Platform Drivers
|
||||||
obj-$(CONFIG_LEDS_88PM860X) += leds-88pm860x.o
|
obj-$(CONFIG_LEDS_88PM860X) += leds-88pm860x.o
|
||||||
obj-$(CONFIG_LEDS_AAT1290) += leds-aat1290.o
|
obj-$(CONFIG_LEDS_AAT1290) += leds-aat1290.o
|
||||||
|
obj-$(CONFIG_LEDS_APU) += leds-apu.o
|
||||||
obj-$(CONFIG_LEDS_AS3645A) += leds-as3645a.o
|
obj-$(CONFIG_LEDS_AS3645A) += leds-as3645a.o
|
||||||
obj-$(CONFIG_LEDS_BCM6328) += leds-bcm6328.o
|
obj-$(CONFIG_LEDS_BCM6328) += leds-bcm6328.o
|
||||||
obj-$(CONFIG_LEDS_BCM6358) += leds-bcm6358.o
|
obj-$(CONFIG_LEDS_BCM6358) += leds-bcm6358.o
|
||||||
|
|
|
@ -45,9 +45,9 @@ static int __led_set_brightness_blocking(struct led_classdev *led_cdev,
|
||||||
return led_cdev->brightness_set_blocking(led_cdev, value);
|
return led_cdev->brightness_set_blocking(led_cdev, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void led_timer_function(unsigned long data)
|
static void led_timer_function(struct timer_list *t)
|
||||||
{
|
{
|
||||||
struct led_classdev *led_cdev = (void *)data;
|
struct led_classdev *led_cdev = from_timer(led_cdev, t, blink_timer);
|
||||||
unsigned long brightness;
|
unsigned long brightness;
|
||||||
unsigned long delay;
|
unsigned long delay;
|
||||||
|
|
||||||
|
@ -178,8 +178,7 @@ void led_init_core(struct led_classdev *led_cdev)
|
||||||
{
|
{
|
||||||
INIT_WORK(&led_cdev->set_brightness_work, set_brightness_delayed);
|
INIT_WORK(&led_cdev->set_brightness_work, set_brightness_delayed);
|
||||||
|
|
||||||
setup_timer(&led_cdev->blink_timer, led_timer_function,
|
timer_setup(&led_cdev->blink_timer, led_timer_function, 0);
|
||||||
(unsigned long)led_cdev);
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(led_init_core);
|
EXPORT_SYMBOL_GPL(led_init_core);
|
||||||
|
|
||||||
|
|
278
drivers/leds/leds-apu.c
Normal file
278
drivers/leds/leds-apu.c
Normal file
|
@ -0,0 +1,278 @@
|
||||||
|
/*
|
||||||
|
* drivers/leds/leds-apu.c
|
||||||
|
* Copyright (C) 2017 Alan Mizrahi, alan at mizrahi dot com dot ve
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the names of the copyright holders nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* Alternatively, this software may be distributed under the terms of the
|
||||||
|
* GNU General Public License ("GPL") version 2 as published by the Free
|
||||||
|
* Software Foundation.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/dmi.h>
|
||||||
|
#include <linux/err.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/leds.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
|
||||||
|
#define APU1_FCH_ACPI_MMIO_BASE 0xFED80000
|
||||||
|
#define APU1_FCH_GPIO_BASE (APU1_FCH_ACPI_MMIO_BASE + 0x01BD)
|
||||||
|
#define APU1_LEDON 0x08
|
||||||
|
#define APU1_LEDOFF 0xC8
|
||||||
|
#define APU1_NUM_GPIO 3
|
||||||
|
#define APU1_IOSIZE sizeof(u8)
|
||||||
|
|
||||||
|
#define APU2_FCH_ACPI_MMIO_BASE 0xFED80000
|
||||||
|
#define APU2_FCH_GPIO_BASE (APU2_FCH_ACPI_MMIO_BASE + 0x1500)
|
||||||
|
#define APU2_GPIO_BIT_WRITE 22
|
||||||
|
#define APU2_APU2_NUM_GPIO 4
|
||||||
|
#define APU2_IOSIZE sizeof(u32)
|
||||||
|
|
||||||
|
/* LED access parameters */
|
||||||
|
struct apu_param {
|
||||||
|
void __iomem *addr; /* for ioread/iowrite */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* LED private data */
|
||||||
|
struct apu_led_priv {
|
||||||
|
struct led_classdev cdev;
|
||||||
|
struct apu_param param;
|
||||||
|
};
|
||||||
|
#define cdev_to_priv(c) container_of(c, struct apu_led_priv, cdev)
|
||||||
|
|
||||||
|
/* LED profile */
|
||||||
|
struct apu_led_profile {
|
||||||
|
const char *name;
|
||||||
|
enum led_brightness brightness;
|
||||||
|
unsigned long offset; /* for devm_ioremap */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Supported platform types */
|
||||||
|
enum apu_led_platform_types {
|
||||||
|
APU1_LED_PLATFORM,
|
||||||
|
APU2_LED_PLATFORM,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct apu_led_pdata {
|
||||||
|
struct platform_device *pdev;
|
||||||
|
struct apu_led_priv *pled;
|
||||||
|
const struct apu_led_profile *profile;
|
||||||
|
enum apu_led_platform_types platform;
|
||||||
|
int num_led_instances;
|
||||||
|
int iosize; /* for devm_ioremap() */
|
||||||
|
spinlock_t lock;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct apu_led_pdata *apu_led;
|
||||||
|
|
||||||
|
static const struct apu_led_profile apu1_led_profile[] = {
|
||||||
|
{ "apu:green:1", LED_ON, APU1_FCH_GPIO_BASE + 0 * APU1_IOSIZE },
|
||||||
|
{ "apu:green:2", LED_OFF, APU1_FCH_GPIO_BASE + 1 * APU1_IOSIZE },
|
||||||
|
{ "apu:green:3", LED_OFF, APU1_FCH_GPIO_BASE + 2 * APU1_IOSIZE },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct apu_led_profile apu2_led_profile[] = {
|
||||||
|
{ "apu2:green:1", LED_ON, APU2_FCH_GPIO_BASE + 68 * APU2_IOSIZE },
|
||||||
|
{ "apu2:green:2", LED_OFF, APU2_FCH_GPIO_BASE + 69 * APU2_IOSIZE },
|
||||||
|
{ "apu2:green:3", LED_OFF, APU2_FCH_GPIO_BASE + 70 * APU2_IOSIZE },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct dmi_system_id apu_led_dmi_table[] __initconst = {
|
||||||
|
{
|
||||||
|
.ident = "apu",
|
||||||
|
.matches = {
|
||||||
|
DMI_MATCH(DMI_SYS_VENDOR, "PC Engines"),
|
||||||
|
DMI_MATCH(DMI_PRODUCT_NAME, "APU")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ident = "apu2",
|
||||||
|
.matches = {
|
||||||
|
DMI_MATCH(DMI_SYS_VENDOR, "PC Engines"),
|
||||||
|
DMI_MATCH(DMI_BOARD_NAME, "APU2")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(dmi, apu_led_dmi_table);
|
||||||
|
|
||||||
|
static void apu1_led_brightness_set(struct led_classdev *led, enum led_brightness value)
|
||||||
|
{
|
||||||
|
struct apu_led_priv *pled = cdev_to_priv(led);
|
||||||
|
|
||||||
|
spin_lock(&apu_led->lock);
|
||||||
|
iowrite8(value ? APU1_LEDON : APU1_LEDOFF, pled->param.addr);
|
||||||
|
spin_unlock(&apu_led->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void apu2_led_brightness_set(struct led_classdev *led, enum led_brightness value)
|
||||||
|
{
|
||||||
|
struct apu_led_priv *pled = cdev_to_priv(led);
|
||||||
|
u32 value_new;
|
||||||
|
|
||||||
|
spin_lock(&apu_led->lock);
|
||||||
|
|
||||||
|
value_new = ioread32(pled->param.addr);
|
||||||
|
|
||||||
|
if (value)
|
||||||
|
value_new &= ~BIT(APU2_GPIO_BIT_WRITE);
|
||||||
|
else
|
||||||
|
value_new |= BIT(APU2_GPIO_BIT_WRITE);
|
||||||
|
|
||||||
|
iowrite32(value_new, pled->param.addr);
|
||||||
|
|
||||||
|
spin_unlock(&apu_led->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int apu_led_config(struct device *dev, struct apu_led_pdata *apuld)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
apu_led->pled = devm_kzalloc(dev,
|
||||||
|
sizeof(struct apu_led_priv) * apu_led->num_led_instances,
|
||||||
|
GFP_KERNEL);
|
||||||
|
|
||||||
|
if (!apu_led->pled)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
for (i = 0; i < apu_led->num_led_instances; i++) {
|
||||||
|
struct apu_led_priv *pled = &apu_led->pled[i];
|
||||||
|
struct led_classdev *led_cdev = &pled->cdev;
|
||||||
|
|
||||||
|
led_cdev->name = apu_led->profile[i].name;
|
||||||
|
led_cdev->brightness = apu_led->profile[i].brightness;
|
||||||
|
led_cdev->max_brightness = 1;
|
||||||
|
led_cdev->flags = LED_CORE_SUSPENDRESUME;
|
||||||
|
if (apu_led->platform == APU1_LED_PLATFORM)
|
||||||
|
led_cdev->brightness_set = apu1_led_brightness_set;
|
||||||
|
else if (apu_led->platform == APU2_LED_PLATFORM)
|
||||||
|
led_cdev->brightness_set = apu2_led_brightness_set;
|
||||||
|
|
||||||
|
pled->param.addr = devm_ioremap(dev,
|
||||||
|
apu_led->profile[i].offset, apu_led->iosize);
|
||||||
|
if (!pled->param.addr) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = led_classdev_register(dev, led_cdev);
|
||||||
|
if (err)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
led_cdev->brightness_set(led_cdev, apu_led->profile[i].brightness);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error:
|
||||||
|
while (i-- > 0)
|
||||||
|
led_classdev_unregister(&apu_led->pled[i].cdev);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __init apu_led_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
apu_led = devm_kzalloc(&pdev->dev, sizeof(*apu_led), GFP_KERNEL);
|
||||||
|
|
||||||
|
if (!apu_led)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
apu_led->pdev = pdev;
|
||||||
|
|
||||||
|
if (dmi_match(DMI_BOARD_NAME, "APU")) {
|
||||||
|
apu_led->profile = apu1_led_profile;
|
||||||
|
apu_led->platform = APU1_LED_PLATFORM;
|
||||||
|
apu_led->num_led_instances = ARRAY_SIZE(apu1_led_profile);
|
||||||
|
apu_led->iosize = APU1_IOSIZE;
|
||||||
|
} else if (dmi_match(DMI_BOARD_NAME, "APU2")) {
|
||||||
|
apu_led->profile = apu2_led_profile;
|
||||||
|
apu_led->platform = APU2_LED_PLATFORM;
|
||||||
|
apu_led->num_led_instances = ARRAY_SIZE(apu2_led_profile);
|
||||||
|
apu_led->iosize = APU2_IOSIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
spin_lock_init(&apu_led->lock);
|
||||||
|
return apu_led_config(&pdev->dev, apu_led);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct platform_driver apu_led_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = KBUILD_MODNAME,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init apu_led_init(void)
|
||||||
|
{
|
||||||
|
struct platform_device *pdev;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (!dmi_match(DMI_SYS_VENDOR, "PC Engines")) {
|
||||||
|
pr_err("No PC Engines board detected\n");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
if (!(dmi_match(DMI_PRODUCT_NAME, "APU") || dmi_match(DMI_PRODUCT_NAME, "APU2"))) {
|
||||||
|
pr_err("Unknown PC Engines board: %s\n",
|
||||||
|
dmi_get_system_info(DMI_PRODUCT_NAME));
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
pdev = platform_device_register_simple(KBUILD_MODNAME, -1, NULL, 0);
|
||||||
|
if (IS_ERR(pdev)) {
|
||||||
|
pr_err("Device allocation failed\n");
|
||||||
|
return PTR_ERR(pdev);
|
||||||
|
}
|
||||||
|
|
||||||
|
err = platform_driver_probe(&apu_led_driver, apu_led_probe);
|
||||||
|
if (err) {
|
||||||
|
pr_err("Probe platform driver failed\n");
|
||||||
|
platform_device_unregister(pdev);
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit apu_led_exit(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < apu_led->num_led_instances; i++)
|
||||||
|
led_classdev_unregister(&apu_led->pled[i].cdev);
|
||||||
|
|
||||||
|
platform_device_unregister(apu_led->pdev);
|
||||||
|
platform_driver_unregister(&apu_led_driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(apu_led_init);
|
||||||
|
module_exit(apu_led_exit);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Alan Mizrahi");
|
||||||
|
MODULE_DESCRIPTION("PC Engines APU family LED driver");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
||||||
|
MODULE_ALIAS("platform:leds_apu");
|
|
@ -323,7 +323,7 @@ static int lp5523_init_program_engine(struct lp55xx_chip *chip)
|
||||||
|
|
||||||
if (status != LP5523_ENG_STATUS_MASK) {
|
if (status != LP5523_ENG_STATUS_MASK) {
|
||||||
dev_err(&chip->cl->dev,
|
dev_err(&chip->cl->dev,
|
||||||
"cound not configure LED engine, status = 0x%.2x\n",
|
"could not configure LED engine, status = 0x%.2x\n",
|
||||||
status);
|
status);
|
||||||
ret = -1;
|
ret = -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,6 +61,10 @@
|
||||||
#define PCA955X_LS_BLINK0 0x2 /* Blink at PWM0 rate */
|
#define PCA955X_LS_BLINK0 0x2 /* Blink at PWM0 rate */
|
||||||
#define PCA955X_LS_BLINK1 0x3 /* Blink at PWM1 rate */
|
#define PCA955X_LS_BLINK1 0x3 /* Blink at PWM1 rate */
|
||||||
|
|
||||||
|
#define PCA955X_GPIO_INPUT LED_OFF
|
||||||
|
#define PCA955X_GPIO_HIGH LED_OFF
|
||||||
|
#define PCA955X_GPIO_LOW LED_FULL
|
||||||
|
|
||||||
enum pca955x_type {
|
enum pca955x_type {
|
||||||
pca9550,
|
pca9550,
|
||||||
pca9551,
|
pca9551,
|
||||||
|
@ -329,9 +333,9 @@ static int pca955x_set_value(struct gpio_chip *gc, unsigned int offset,
|
||||||
struct pca955x_led *led = &pca955x->leds[offset];
|
struct pca955x_led *led = &pca955x->leds[offset];
|
||||||
|
|
||||||
if (val)
|
if (val)
|
||||||
return pca955x_led_set(&led->led_cdev, LED_FULL);
|
return pca955x_led_set(&led->led_cdev, PCA955X_GPIO_HIGH);
|
||||||
else
|
|
||||||
return pca955x_led_set(&led->led_cdev, LED_OFF);
|
return pca955x_led_set(&led->led_cdev, PCA955X_GPIO_LOW);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pca955x_gpio_set_value(struct gpio_chip *gc, unsigned int offset,
|
static void pca955x_gpio_set_value(struct gpio_chip *gc, unsigned int offset,
|
||||||
|
@ -355,8 +359,11 @@ static int pca955x_gpio_get_value(struct gpio_chip *gc, unsigned int offset)
|
||||||
static int pca955x_gpio_direction_input(struct gpio_chip *gc,
|
static int pca955x_gpio_direction_input(struct gpio_chip *gc,
|
||||||
unsigned int offset)
|
unsigned int offset)
|
||||||
{
|
{
|
||||||
/* To use as input ensure pin is not driven */
|
struct pca955x *pca955x = gpiochip_get_data(gc);
|
||||||
return pca955x_set_value(gc, offset, 0);
|
struct pca955x_led *led = &pca955x->leds[offset];
|
||||||
|
|
||||||
|
/* To use as input ensure pin is not driven. */
|
||||||
|
return pca955x_led_set(&led->led_cdev, PCA955X_GPIO_INPUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pca955x_gpio_direction_output(struct gpio_chip *gc,
|
static int pca955x_gpio_direction_output(struct gpio_chip *gc,
|
||||||
|
|
|
@ -715,7 +715,7 @@ tca6507_led_dt_init(struct i2c_client *client)
|
||||||
if (of_property_match_string(child, "compatible", "gpio") >= 0)
|
if (of_property_match_string(child, "compatible", "gpio") >= 0)
|
||||||
led.flags |= TCA6507_MAKE_GPIO;
|
led.flags |= TCA6507_MAKE_GPIO;
|
||||||
ret = of_property_read_u32(child, "reg", ®);
|
ret = of_property_read_u32(child, "reg", ®);
|
||||||
if (ret != 0 || reg < 0 || reg >= NUM_LEDS)
|
if (ret != 0 || reg >= NUM_LEDS)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
tca_leds[reg] = led;
|
tca_leds[reg] = led;
|
||||||
|
|
|
@ -77,6 +77,15 @@ config LEDS_TRIGGER_CPU
|
||||||
|
|
||||||
If unsure, say N.
|
If unsure, say N.
|
||||||
|
|
||||||
|
config LEDS_TRIGGER_ACTIVITY
|
||||||
|
tristate "LED activity Trigger"
|
||||||
|
depends on LEDS_TRIGGERS
|
||||||
|
help
|
||||||
|
This allows LEDs to be controlled by a immediate CPU usage.
|
||||||
|
The flash frequency and duty cycle varies from faint flashes to
|
||||||
|
intense brightness depending on the instant CPU load.
|
||||||
|
If unsure, say N.
|
||||||
|
|
||||||
config LEDS_TRIGGER_GPIO
|
config LEDS_TRIGGER_GPIO
|
||||||
tristate "LED GPIO Trigger"
|
tristate "LED GPIO Trigger"
|
||||||
depends on LEDS_TRIGGERS
|
depends on LEDS_TRIGGERS
|
||||||
|
|
|
@ -7,6 +7,7 @@ obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT) += ledtrig-heartbeat.o
|
||||||
obj-$(CONFIG_LEDS_TRIGGER_BACKLIGHT) += ledtrig-backlight.o
|
obj-$(CONFIG_LEDS_TRIGGER_BACKLIGHT) += ledtrig-backlight.o
|
||||||
obj-$(CONFIG_LEDS_TRIGGER_GPIO) += ledtrig-gpio.o
|
obj-$(CONFIG_LEDS_TRIGGER_GPIO) += ledtrig-gpio.o
|
||||||
obj-$(CONFIG_LEDS_TRIGGER_CPU) += ledtrig-cpu.o
|
obj-$(CONFIG_LEDS_TRIGGER_CPU) += ledtrig-cpu.o
|
||||||
|
obj-$(CONFIG_LEDS_TRIGGER_ACTIVITY) += ledtrig-activity.o
|
||||||
obj-$(CONFIG_LEDS_TRIGGER_DEFAULT_ON) += ledtrig-default-on.o
|
obj-$(CONFIG_LEDS_TRIGGER_DEFAULT_ON) += ledtrig-default-on.o
|
||||||
obj-$(CONFIG_LEDS_TRIGGER_TRANSIENT) += ledtrig-transient.o
|
obj-$(CONFIG_LEDS_TRIGGER_TRANSIENT) += ledtrig-transient.o
|
||||||
obj-$(CONFIG_LEDS_TRIGGER_CAMERA) += ledtrig-camera.o
|
obj-$(CONFIG_LEDS_TRIGGER_CAMERA) += ledtrig-camera.o
|
||||||
|
|
275
drivers/leds/trigger/ledtrig-activity.c
Normal file
275
drivers/leds/trigger/ledtrig-activity.c
Normal file
|
@ -0,0 +1,275 @@
|
||||||
|
/*
|
||||||
|
* Activity LED trigger
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Willy Tarreau <w@1wt.eu>
|
||||||
|
* Partially based on Atsushi Nemoto's ledtrig-heartbeat.c.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/kernel_stat.h>
|
||||||
|
#include <linux/leds.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/reboot.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/timer.h>
|
||||||
|
#include "../leds.h"
|
||||||
|
|
||||||
|
static int panic_detected;
|
||||||
|
|
||||||
|
struct activity_data {
|
||||||
|
struct timer_list timer;
|
||||||
|
struct led_classdev *led_cdev;
|
||||||
|
u64 last_used;
|
||||||
|
u64 last_boot;
|
||||||
|
int time_left;
|
||||||
|
int state;
|
||||||
|
int invert;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void led_activity_function(struct timer_list *t)
|
||||||
|
{
|
||||||
|
struct activity_data *activity_data = from_timer(activity_data, t,
|
||||||
|
timer);
|
||||||
|
struct led_classdev *led_cdev = activity_data->led_cdev;
|
||||||
|
struct timespec boot_time;
|
||||||
|
unsigned int target;
|
||||||
|
unsigned int usage;
|
||||||
|
int delay;
|
||||||
|
u64 curr_used;
|
||||||
|
u64 curr_boot;
|
||||||
|
s32 diff_used;
|
||||||
|
s32 diff_boot;
|
||||||
|
int cpus;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (test_and_clear_bit(LED_BLINK_BRIGHTNESS_CHANGE, &led_cdev->work_flags))
|
||||||
|
led_cdev->blink_brightness = led_cdev->new_blink_brightness;
|
||||||
|
|
||||||
|
if (unlikely(panic_detected)) {
|
||||||
|
/* full brightness in case of panic */
|
||||||
|
led_set_brightness_nosleep(led_cdev, led_cdev->blink_brightness);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
get_monotonic_boottime(&boot_time);
|
||||||
|
|
||||||
|
cpus = 0;
|
||||||
|
curr_used = 0;
|
||||||
|
|
||||||
|
for_each_possible_cpu(i) {
|
||||||
|
curr_used += kcpustat_cpu(i).cpustat[CPUTIME_USER]
|
||||||
|
+ kcpustat_cpu(i).cpustat[CPUTIME_NICE]
|
||||||
|
+ kcpustat_cpu(i).cpustat[CPUTIME_SYSTEM]
|
||||||
|
+ kcpustat_cpu(i).cpustat[CPUTIME_SOFTIRQ]
|
||||||
|
+ kcpustat_cpu(i).cpustat[CPUTIME_IRQ];
|
||||||
|
cpus++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We come here every 100ms in the worst case, so that's 100M ns of
|
||||||
|
* cumulated time. By dividing by 2^16, we get the time resolution
|
||||||
|
* down to 16us, ensuring we won't overflow 32-bit computations below
|
||||||
|
* even up to 3k CPUs, while keeping divides cheap on smaller systems.
|
||||||
|
*/
|
||||||
|
curr_boot = timespec_to_ns(&boot_time) * cpus;
|
||||||
|
diff_boot = (curr_boot - activity_data->last_boot) >> 16;
|
||||||
|
diff_used = (curr_used - activity_data->last_used) >> 16;
|
||||||
|
activity_data->last_boot = curr_boot;
|
||||||
|
activity_data->last_used = curr_used;
|
||||||
|
|
||||||
|
if (diff_boot <= 0 || diff_used < 0)
|
||||||
|
usage = 0;
|
||||||
|
else if (diff_used >= diff_boot)
|
||||||
|
usage = 100;
|
||||||
|
else
|
||||||
|
usage = 100 * diff_used / diff_boot;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now we know the total boot_time multiplied by the number of CPUs, and
|
||||||
|
* the total idle+wait time for all CPUs. We'll compare how they evolved
|
||||||
|
* since last call. The % of overall CPU usage is :
|
||||||
|
*
|
||||||
|
* 1 - delta_idle / delta_boot
|
||||||
|
*
|
||||||
|
* What we want is that when the CPU usage is zero, the LED must blink
|
||||||
|
* slowly with very faint flashes that are detectable but not disturbing
|
||||||
|
* (typically 10ms every second, or 10ms ON, 990ms OFF). Then we want
|
||||||
|
* blinking frequency to increase up to the point where the load is
|
||||||
|
* enough to saturate one core in multi-core systems or 50% in single
|
||||||
|
* core systems. At this point it should reach 10 Hz with a 10/90 duty
|
||||||
|
* cycle (10ms ON, 90ms OFF). After this point, the blinking frequency
|
||||||
|
* remains stable (10 Hz) and only the duty cycle increases to report
|
||||||
|
* the activity, up to the point where we have 90ms ON, 10ms OFF when
|
||||||
|
* all cores are saturated. It's important that the LED never stays in
|
||||||
|
* a steady state so that it's easy to distinguish an idle or saturated
|
||||||
|
* machine from a hung one.
|
||||||
|
*
|
||||||
|
* This gives us :
|
||||||
|
* - a target CPU usage of min(50%, 100%/#CPU) for a 10% duty cycle
|
||||||
|
* (10ms ON, 90ms OFF)
|
||||||
|
* - below target :
|
||||||
|
* ON_ms = 10
|
||||||
|
* OFF_ms = 90 + (1 - usage/target) * 900
|
||||||
|
* - above target :
|
||||||
|
* ON_ms = 10 + (usage-target)/(100%-target) * 80
|
||||||
|
* OFF_ms = 90 - (usage-target)/(100%-target) * 80
|
||||||
|
*
|
||||||
|
* In order to keep a good responsiveness, we cap the sleep time to
|
||||||
|
* 100 ms and keep track of the sleep time left. This allows us to
|
||||||
|
* quickly change it if needed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
activity_data->time_left -= 100;
|
||||||
|
if (activity_data->time_left <= 0) {
|
||||||
|
activity_data->time_left = 0;
|
||||||
|
activity_data->state = !activity_data->state;
|
||||||
|
led_set_brightness_nosleep(led_cdev,
|
||||||
|
(activity_data->state ^ activity_data->invert) ?
|
||||||
|
led_cdev->blink_brightness : LED_OFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
target = (cpus > 1) ? (100 / cpus) : 50;
|
||||||
|
|
||||||
|
if (usage < target)
|
||||||
|
delay = activity_data->state ?
|
||||||
|
10 : /* ON */
|
||||||
|
990 - 900 * usage / target; /* OFF */
|
||||||
|
else
|
||||||
|
delay = activity_data->state ?
|
||||||
|
10 + 80 * (usage - target) / (100 - target) : /* ON */
|
||||||
|
90 - 80 * (usage - target) / (100 - target); /* OFF */
|
||||||
|
|
||||||
|
|
||||||
|
if (!activity_data->time_left || delay <= activity_data->time_left)
|
||||||
|
activity_data->time_left = delay;
|
||||||
|
|
||||||
|
delay = min_t(int, activity_data->time_left, 100);
|
||||||
|
mod_timer(&activity_data->timer, jiffies + msecs_to_jiffies(delay));
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t led_invert_show(struct device *dev,
|
||||||
|
struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||||
|
struct activity_data *activity_data = led_cdev->trigger_data;
|
||||||
|
|
||||||
|
return sprintf(buf, "%u\n", activity_data->invert);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t led_invert_store(struct device *dev,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
const char *buf, size_t size)
|
||||||
|
{
|
||||||
|
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||||
|
struct activity_data *activity_data = led_cdev->trigger_data;
|
||||||
|
unsigned long state;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = kstrtoul(buf, 0, &state);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
activity_data->invert = !!state;
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DEVICE_ATTR(invert, 0644, led_invert_show, led_invert_store);
|
||||||
|
|
||||||
|
static void activity_activate(struct led_classdev *led_cdev)
|
||||||
|
{
|
||||||
|
struct activity_data *activity_data;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
activity_data = kzalloc(sizeof(*activity_data), GFP_KERNEL);
|
||||||
|
if (!activity_data)
|
||||||
|
return;
|
||||||
|
|
||||||
|
led_cdev->trigger_data = activity_data;
|
||||||
|
rc = device_create_file(led_cdev->dev, &dev_attr_invert);
|
||||||
|
if (rc) {
|
||||||
|
kfree(led_cdev->trigger_data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
activity_data->led_cdev = led_cdev;
|
||||||
|
timer_setup(&activity_data->timer, led_activity_function, 0);
|
||||||
|
if (!led_cdev->blink_brightness)
|
||||||
|
led_cdev->blink_brightness = led_cdev->max_brightness;
|
||||||
|
led_activity_function(&activity_data->timer);
|
||||||
|
set_bit(LED_BLINK_SW, &led_cdev->work_flags);
|
||||||
|
led_cdev->activated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void activity_deactivate(struct led_classdev *led_cdev)
|
||||||
|
{
|
||||||
|
struct activity_data *activity_data = led_cdev->trigger_data;
|
||||||
|
|
||||||
|
if (led_cdev->activated) {
|
||||||
|
del_timer_sync(&activity_data->timer);
|
||||||
|
device_remove_file(led_cdev->dev, &dev_attr_invert);
|
||||||
|
kfree(activity_data);
|
||||||
|
clear_bit(LED_BLINK_SW, &led_cdev->work_flags);
|
||||||
|
led_cdev->activated = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct led_trigger activity_led_trigger = {
|
||||||
|
.name = "activity",
|
||||||
|
.activate = activity_activate,
|
||||||
|
.deactivate = activity_deactivate,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int activity_reboot_notifier(struct notifier_block *nb,
|
||||||
|
unsigned long code, void *unused)
|
||||||
|
{
|
||||||
|
led_trigger_unregister(&activity_led_trigger);
|
||||||
|
return NOTIFY_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int activity_panic_notifier(struct notifier_block *nb,
|
||||||
|
unsigned long code, void *unused)
|
||||||
|
{
|
||||||
|
panic_detected = 1;
|
||||||
|
return NOTIFY_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct notifier_block activity_reboot_nb = {
|
||||||
|
.notifier_call = activity_reboot_notifier,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct notifier_block activity_panic_nb = {
|
||||||
|
.notifier_call = activity_panic_notifier,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init activity_init(void)
|
||||||
|
{
|
||||||
|
int rc = led_trigger_register(&activity_led_trigger);
|
||||||
|
|
||||||
|
if (!rc) {
|
||||||
|
atomic_notifier_chain_register(&panic_notifier_list,
|
||||||
|
&activity_panic_nb);
|
||||||
|
register_reboot_notifier(&activity_reboot_nb);
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit activity_exit(void)
|
||||||
|
{
|
||||||
|
unregister_reboot_notifier(&activity_reboot_nb);
|
||||||
|
atomic_notifier_chain_unregister(&panic_notifier_list,
|
||||||
|
&activity_panic_nb);
|
||||||
|
led_trigger_unregister(&activity_led_trigger);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(activity_init);
|
||||||
|
module_exit(activity_exit);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Willy Tarreau <w@1wt.eu>");
|
||||||
|
MODULE_DESCRIPTION("Activity LED trigger");
|
||||||
|
MODULE_LICENSE("GPL");
|
|
@ -25,19 +25,23 @@
|
||||||
static int panic_heartbeats;
|
static int panic_heartbeats;
|
||||||
|
|
||||||
struct heartbeat_trig_data {
|
struct heartbeat_trig_data {
|
||||||
|
struct led_classdev *led_cdev;
|
||||||
unsigned int phase;
|
unsigned int phase;
|
||||||
unsigned int period;
|
unsigned int period;
|
||||||
struct timer_list timer;
|
struct timer_list timer;
|
||||||
unsigned int invert;
|
unsigned int invert;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void led_heartbeat_function(unsigned long data)
|
static void led_heartbeat_function(struct timer_list *t)
|
||||||
{
|
{
|
||||||
struct led_classdev *led_cdev = (struct led_classdev *) data;
|
struct heartbeat_trig_data *heartbeat_data =
|
||||||
struct heartbeat_trig_data *heartbeat_data = led_cdev->trigger_data;
|
from_timer(heartbeat_data, t, timer);
|
||||||
|
struct led_classdev *led_cdev;
|
||||||
unsigned long brightness = LED_OFF;
|
unsigned long brightness = LED_OFF;
|
||||||
unsigned long delay = 0;
|
unsigned long delay = 0;
|
||||||
|
|
||||||
|
led_cdev = heartbeat_data->led_cdev;
|
||||||
|
|
||||||
if (unlikely(panic_heartbeats)) {
|
if (unlikely(panic_heartbeats)) {
|
||||||
led_set_brightness_nosleep(led_cdev, LED_OFF);
|
led_set_brightness_nosleep(led_cdev, LED_OFF);
|
||||||
return;
|
return;
|
||||||
|
@ -127,18 +131,18 @@ static void heartbeat_trig_activate(struct led_classdev *led_cdev)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
led_cdev->trigger_data = heartbeat_data;
|
led_cdev->trigger_data = heartbeat_data;
|
||||||
|
heartbeat_data->led_cdev = led_cdev;
|
||||||
rc = device_create_file(led_cdev->dev, &dev_attr_invert);
|
rc = device_create_file(led_cdev->dev, &dev_attr_invert);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
kfree(led_cdev->trigger_data);
|
kfree(led_cdev->trigger_data);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setup_timer(&heartbeat_data->timer,
|
timer_setup(&heartbeat_data->timer, led_heartbeat_function, 0);
|
||||||
led_heartbeat_function, (unsigned long) led_cdev);
|
|
||||||
heartbeat_data->phase = 0;
|
heartbeat_data->phase = 0;
|
||||||
if (!led_cdev->blink_brightness)
|
if (!led_cdev->blink_brightness)
|
||||||
led_cdev->blink_brightness = led_cdev->max_brightness;
|
led_cdev->blink_brightness = led_cdev->max_brightness;
|
||||||
led_heartbeat_function(heartbeat_data->timer.data);
|
led_heartbeat_function(&heartbeat_data->timer);
|
||||||
set_bit(LED_BLINK_SW, &led_cdev->work_flags);
|
set_bit(LED_BLINK_SW, &led_cdev->work_flags);
|
||||||
led_cdev->activated = true;
|
led_cdev->activated = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,12 +33,14 @@ struct transient_trig_data {
|
||||||
int restore_state;
|
int restore_state;
|
||||||
unsigned long duration;
|
unsigned long duration;
|
||||||
struct timer_list timer;
|
struct timer_list timer;
|
||||||
|
struct led_classdev *led_cdev;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void transient_timer_function(unsigned long data)
|
static void transient_timer_function(struct timer_list *t)
|
||||||
{
|
{
|
||||||
struct led_classdev *led_cdev = (struct led_classdev *) data;
|
struct transient_trig_data *transient_data =
|
||||||
struct transient_trig_data *transient_data = led_cdev->trigger_data;
|
from_timer(transient_data, t, timer);
|
||||||
|
struct led_classdev *led_cdev = transient_data->led_cdev;
|
||||||
|
|
||||||
transient_data->activate = 0;
|
transient_data->activate = 0;
|
||||||
led_set_brightness_nosleep(led_cdev, transient_data->restore_state);
|
led_set_brightness_nosleep(led_cdev, transient_data->restore_state);
|
||||||
|
@ -169,6 +171,7 @@ static void transient_trig_activate(struct led_classdev *led_cdev)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
led_cdev->trigger_data = tdata;
|
led_cdev->trigger_data = tdata;
|
||||||
|
tdata->led_cdev = led_cdev;
|
||||||
|
|
||||||
rc = device_create_file(led_cdev->dev, &dev_attr_activate);
|
rc = device_create_file(led_cdev->dev, &dev_attr_activate);
|
||||||
if (rc)
|
if (rc)
|
||||||
|
@ -182,8 +185,7 @@ static void transient_trig_activate(struct led_classdev *led_cdev)
|
||||||
if (rc)
|
if (rc)
|
||||||
goto err_out_state;
|
goto err_out_state;
|
||||||
|
|
||||||
setup_timer(&tdata->timer, transient_timer_function,
|
timer_setup(&tdata->timer, transient_timer_function, 0);
|
||||||
(unsigned long) led_cdev);
|
|
||||||
led_cdev->activated = true;
|
led_cdev->activated = true;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -40,16 +40,16 @@ struct led_classdev {
|
||||||
int flags;
|
int flags;
|
||||||
|
|
||||||
/* Lower 16 bits reflect status */
|
/* Lower 16 bits reflect status */
|
||||||
#define LED_SUSPENDED (1 << 0)
|
#define LED_SUSPENDED BIT(0)
|
||||||
#define LED_UNREGISTERING (1 << 1)
|
#define LED_UNREGISTERING BIT(1)
|
||||||
/* Upper 16 bits reflect control information */
|
/* Upper 16 bits reflect control information */
|
||||||
#define LED_CORE_SUSPENDRESUME (1 << 16)
|
#define LED_CORE_SUSPENDRESUME BIT(16)
|
||||||
#define LED_SYSFS_DISABLE (1 << 17)
|
#define LED_SYSFS_DISABLE BIT(17)
|
||||||
#define LED_DEV_CAP_FLASH (1 << 18)
|
#define LED_DEV_CAP_FLASH BIT(18)
|
||||||
#define LED_HW_PLUGGABLE (1 << 19)
|
#define LED_HW_PLUGGABLE BIT(19)
|
||||||
#define LED_PANIC_INDICATOR (1 << 20)
|
#define LED_PANIC_INDICATOR BIT(20)
|
||||||
#define LED_BRIGHT_HW_CHANGED (1 << 21)
|
#define LED_BRIGHT_HW_CHANGED BIT(21)
|
||||||
#define LED_RETAIN_AT_SHUTDOWN (1 << 22)
|
#define LED_RETAIN_AT_SHUTDOWN BIT(22)
|
||||||
|
|
||||||
/* set_brightness_work / blink_timer flags, atomic, private. */
|
/* set_brightness_work / blink_timer flags, atomic, private. */
|
||||||
unsigned long work_flags;
|
unsigned long work_flags;
|
||||||
|
|
Loading…
Add table
Reference in a new issue