LED updates for 4.19-rc1
-----BEGIN PGP SIGNATURE----- iJEEABYIADkWIQQUwxxKyE5l/npt8ARiEGxRG/Sl2wUCW3HajRscamFjZWsuYW5h c3pld3NraUBnbWFpbC5jb20ACgkQYhBsURv0pdvxAwEA+qS5O9ByxlhT+BUC4ck6 nIy0ITOCXP8ySoo8VVhzjikBAPrb9lFYGvHqzKN4dYtnSILPmlTSf1t1flng2Zev NfoE =lNwq -----END PGP SIGNATURE----- Merge tag 'leds-for-4.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/j.anaszewski/linux-leds Pull LED updates from Jacek Anaszewski: "LED triggers improvements make the biggest part of this pull request. The most striking ones, that allowed for nice cleanups in the triggers are: - centralized handling of creation and removal of trigger sysfs attributes via attribute group - addition of module_led_trigger() helper The other things that need to be mentioned: New features and improvements to existing LED class drivers: - lt3593: add DT support, switch to gpiod interface - lm3692x: support LED sync configuration, change OF calls to fwnode calls - apu: modify PC Engines apu/apu2 driver to support apu3 Change in the drivers/net/can/led.c: - mark led trigger as broken since it's in the way for the further cleanups. It implements a subset of the netdev trigger and an Ack is needed from someone who can actually test and confirm that the netdev trigger works for can devices" * tag 'leds-for-4.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/j.anaszewski/linux-leds: (32 commits) leds: ns2: Change unsigned to unsigned int usb: simplify usbport trigger leds: gpio trigger: simplifications from core changes leds: backlight trigger: simplifications from core changes leds: activity trigger: simplifications from core changes leds: default-on trigger: make use of module_led_trigger() leds: heartbeat trigger: simplifications from core changes leds: oneshot trigger: simplifications from core changes leds: transient trigger: simplifications from core changes leds: timer trigger: simplifications from core changes leds: netdev trigger: simplifications from core changes leds: triggers: new function led_set_trigger_data() leds: triggers: define module_led_trigger helper leds: triggers: handle .trigger_data and .activated() in the core leds: triggers: add device attribute support leds: triggers: let struct led_trigger::activate() return an error code leds: triggers: make the MODULE_LICENSE string match the actual license leds: lm3692x: Support LED sync configuration dt: bindings: lm3692x: Update binding for LED sync control leds: lm3692x: Change DT calls to fwnode calls ...
This commit is contained in:
Коммит
c07b3682cd
|
@ -31,7 +31,7 @@ Optional properties for child nodes:
|
|||
"backlight" - LED will act as a back-light, controlled by the framebuffer
|
||||
system
|
||||
"default-on" - LED will turn on (but for leds-gpio see "default-state"
|
||||
property in Documentation/devicetree/bindings/gpio/led.txt)
|
||||
property in Documentation/devicetree/bindings/leds/leds-gpio.txt)
|
||||
"heartbeat" - LED "double" flashes at a load average based rate
|
||||
"disk-activity" - LED indicates disk activity
|
||||
"ide-disk" - LED indicates IDE disk activity (deprecated),
|
||||
|
|
|
@ -20,7 +20,10 @@ Optional properties:
|
|||
- vled-supply : LED supply
|
||||
|
||||
Required child properties:
|
||||
- reg : 0
|
||||
- reg : 0 - Will enable all LED sync paths
|
||||
1 - Will enable the LED1 sync
|
||||
2 - Will enable the LED2 sync
|
||||
3 - Will enable the LED3 sync (LM36923 only)
|
||||
|
||||
Optional child properties:
|
||||
- label : see Documentation/devicetree/bindings/leds/common.txt
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
Bindings for Linear Technologies LT3593 LED controller
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "lltc,lt3593".
|
||||
- lltc,ctrl-gpios: A handle to the GPIO that is connected to the 'CTRL'
|
||||
pin of the chip.
|
||||
|
||||
The hardware supports only one LED. The properties of this LED are
|
||||
configured in a sub-node in the device node.
|
||||
|
||||
Optional sub-node properties:
|
||||
- label: A label for the LED. If none is given, the LED will be
|
||||
named "lt3595::".
|
||||
- linux,default-trigger: The default trigger for the LED.
|
||||
See Documentation/devicetree/bindings/leds/common.txt
|
||||
- default-state: The initial state of the LED.
|
||||
See Documentation/devicetree/bindings/leds/common.txt
|
||||
|
||||
If multiple chips of this type are found in a design, each one needs to
|
||||
be handled by its own device node.
|
||||
|
||||
Example:
|
||||
|
||||
led-controller {
|
||||
compatible = "lltc,lt3593";
|
||||
lltc,ctrl-gpios = <&gpio 0 GPIO_ACTIVE_HIGH>;
|
||||
|
||||
led {
|
||||
label = "white:backlight";
|
||||
default-state = "on";
|
||||
};
|
||||
};
|
|
@ -57,12 +57,13 @@ config LEDS_AAT1290
|
|||
depends on PINCTRL
|
||||
help
|
||||
This option enables support for the LEDs on the AAT1290.
|
||||
|
||||
config LEDS_APU
|
||||
tristate "Front panel LED support for PC Engines APU/APU2 boards"
|
||||
tristate "Front panel LED support for PC Engines APU/APU2/APU3 boards"
|
||||
depends on LEDS_CLASS
|
||||
depends on X86 && DMI
|
||||
help
|
||||
This driver makes the PC Engines APU/APU2 front panel LEDs
|
||||
This driver makes the PC Engines APU/APU2/APU3 front panel LEDs
|
||||
accessible from userspace programs through the LED subsystem.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
|
|
|
@ -103,15 +103,16 @@ ssize_t led_trigger_show(struct device *dev, struct device_attribute *attr,
|
|||
EXPORT_SYMBOL_GPL(led_trigger_show);
|
||||
|
||||
/* Caller must ensure led_cdev->trigger_lock held */
|
||||
void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig)
|
||||
int led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig)
|
||||
{
|
||||
unsigned long flags;
|
||||
char *event = NULL;
|
||||
char *envp[2];
|
||||
const char *name;
|
||||
int ret;
|
||||
|
||||
if (!led_cdev->trigger && !trig)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
name = trig ? trig->name : "none";
|
||||
event = kasprintf(GFP_KERNEL, "TRIGGER=%s", name);
|
||||
|
@ -126,7 +127,10 @@ void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig)
|
|||
led_stop_software_blink(led_cdev);
|
||||
if (led_cdev->trigger->deactivate)
|
||||
led_cdev->trigger->deactivate(led_cdev);
|
||||
device_remove_groups(led_cdev->dev, led_cdev->trigger->groups);
|
||||
led_cdev->trigger = NULL;
|
||||
led_cdev->trigger_data = NULL;
|
||||
led_cdev->activated = false;
|
||||
led_set_brightness(led_cdev, LED_OFF);
|
||||
}
|
||||
if (trig) {
|
||||
|
@ -134,8 +138,20 @@ void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig)
|
|||
list_add_tail(&led_cdev->trig_list, &trig->led_cdevs);
|
||||
write_unlock_irqrestore(&trig->leddev_list_lock, flags);
|
||||
led_cdev->trigger = trig;
|
||||
|
||||
if (trig->activate)
|
||||
trig->activate(led_cdev);
|
||||
ret = trig->activate(led_cdev);
|
||||
else
|
||||
ret = 0;
|
||||
|
||||
if (ret)
|
||||
goto err_activate;
|
||||
|
||||
ret = device_add_groups(led_cdev->dev, trig->groups);
|
||||
if (ret) {
|
||||
dev_err(led_cdev->dev, "Failed to add trigger attributes\n");
|
||||
goto err_add_groups;
|
||||
}
|
||||
}
|
||||
|
||||
if (event) {
|
||||
|
@ -146,6 +162,23 @@ void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig)
|
|||
"%s: Error sending uevent\n", __func__);
|
||||
kfree(event);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_add_groups:
|
||||
|
||||
if (trig->deactivate)
|
||||
trig->deactivate(led_cdev);
|
||||
err_activate:
|
||||
|
||||
led_cdev->trigger = NULL;
|
||||
led_cdev->trigger_data = NULL;
|
||||
write_lock_irqsave(&led_cdev->trigger->leddev_list_lock, flags);
|
||||
list_del(&led_cdev->trig_list);
|
||||
write_unlock_irqrestore(&led_cdev->trigger->leddev_list_lock, flags);
|
||||
led_set_brightness(led_cdev, LED_OFF);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(led_trigger_set);
|
||||
|
||||
|
|
|
@ -102,6 +102,13 @@ static const struct apu_led_profile apu2_led_profile[] = {
|
|||
{ "apu2:green:3", LED_OFF, APU2_FCH_GPIO_BASE + 70 * APU2_IOSIZE },
|
||||
};
|
||||
|
||||
/* Same as apu2_led_profile, but with "3" in the LED names. */
|
||||
static const struct apu_led_profile apu3_led_profile[] = {
|
||||
{ "apu3:green:1", LED_ON, APU2_FCH_GPIO_BASE + 68 * APU2_IOSIZE },
|
||||
{ "apu3:green:2", LED_OFF, APU2_FCH_GPIO_BASE + 69 * APU2_IOSIZE },
|
||||
{ "apu3:green:3", LED_OFF, APU2_FCH_GPIO_BASE + 70 * APU2_IOSIZE },
|
||||
};
|
||||
|
||||
static const struct dmi_system_id apu_led_dmi_table[] __initconst = {
|
||||
{
|
||||
.ident = "apu",
|
||||
|
@ -134,6 +141,30 @@ static const struct dmi_system_id apu_led_dmi_table[] __initconst = {
|
|||
DMI_MATCH(DMI_BOARD_NAME, "PC Engines apu2")
|
||||
}
|
||||
},
|
||||
/* PC Engines APU3 with "Legacy" bios < 4.0.8 */
|
||||
{
|
||||
.ident = "apu3",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "PC Engines"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "APU3")
|
||||
}
|
||||
},
|
||||
/* PC Engines APU3 with "Legacy" bios >= 4.0.8 */
|
||||
{
|
||||
.ident = "apu3",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "PC Engines"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "apu3")
|
||||
}
|
||||
},
|
||||
/* PC Engines APU2 with "Mainline" bios */
|
||||
{
|
||||
.ident = "apu3",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "PC Engines"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "PC Engines apu3")
|
||||
}
|
||||
},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(dmi, apu_led_dmi_table);
|
||||
|
@ -235,6 +266,14 @@ static int __init apu_led_probe(struct platform_device *pdev)
|
|||
apu_led->platform = APU2_LED_PLATFORM;
|
||||
apu_led->num_led_instances = ARRAY_SIZE(apu2_led_profile);
|
||||
apu_led->iosize = APU2_IOSIZE;
|
||||
} else if (dmi_match(DMI_BOARD_NAME, "APU3") ||
|
||||
dmi_match(DMI_BOARD_NAME, "apu3") ||
|
||||
dmi_match(DMI_BOARD_NAME, "PC Engines apu3")) {
|
||||
apu_led->profile = apu3_led_profile;
|
||||
/* Otherwise identical to APU2. */
|
||||
apu_led->platform = APU2_LED_PLATFORM;
|
||||
apu_led->num_led_instances = ARRAY_SIZE(apu3_led_profile);
|
||||
apu_led->iosize = APU2_IOSIZE;
|
||||
}
|
||||
|
||||
spin_lock_init(&apu_led->lock);
|
||||
|
@ -259,7 +298,10 @@ static int __init apu_led_init(void)
|
|||
if (!(dmi_match(DMI_PRODUCT_NAME, "APU") ||
|
||||
dmi_match(DMI_PRODUCT_NAME, "APU2") ||
|
||||
dmi_match(DMI_PRODUCT_NAME, "apu2") ||
|
||||
dmi_match(DMI_PRODUCT_NAME, "PC Engines apu2"))) {
|
||||
dmi_match(DMI_PRODUCT_NAME, "PC Engines apu2") ||
|
||||
dmi_match(DMI_PRODUCT_NAME, "APU3") ||
|
||||
dmi_match(DMI_PRODUCT_NAME, "apu3") ||
|
||||
dmi_match(DMI_PRODUCT_NAME, "PC Engines apu3"))) {
|
||||
pr_err("Unknown PC Engines board: %s\n",
|
||||
dmi_get_system_info(DMI_PRODUCT_NAME));
|
||||
return -ENODEV;
|
||||
|
|
|
@ -1,17 +1,6 @@
|
|||
/*
|
||||
* TI lm3692x LED Driver
|
||||
*
|
||||
* Copyright (C) 2017 Texas Instruments
|
||||
*
|
||||
* Author: Dan Murphy <dmurphy@ti.com>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Data sheet is located
|
||||
* http://www.ti.com/lit/ds/snvsa29/snvsa29.pdf
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// TI LM3692x LED chip family driver
|
||||
// Copyright (C) 2017-18 Texas Instruments Incorporated - http://www.ti.com/
|
||||
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/i2c.h>
|
||||
|
@ -26,6 +15,9 @@
|
|||
#include <linux/slab.h>
|
||||
#include <uapi/linux/uleds.h>
|
||||
|
||||
#define LM36922_MODEL 0
|
||||
#define LM36923_MODEL 1
|
||||
|
||||
#define LM3692X_REV 0x0
|
||||
#define LM3692X_RESET 0x1
|
||||
#define LM3692X_EN 0x10
|
||||
|
@ -44,6 +36,9 @@
|
|||
#define LM3692X_DEVICE_EN BIT(0)
|
||||
#define LM3692X_LED1_EN BIT(1)
|
||||
#define LM3692X_LED2_EN BIT(2)
|
||||
#define LM36923_LED3_EN BIT(3)
|
||||
#define LM3692X_ENABLE_MASK (LM3692X_DEVICE_EN | LM3692X_LED1_EN | \
|
||||
LM3692X_LED2_EN | LM36923_LED3_EN)
|
||||
|
||||
/* Brightness Control Bits */
|
||||
#define LM3692X_BL_ADJ_POL BIT(0)
|
||||
|
@ -109,6 +104,8 @@
|
|||
* @enable_gpio - VDDIO/EN gpio to enable communication interface
|
||||
* @regulator - LED supply regulator pointer
|
||||
* @label - LED label
|
||||
* @led_enable - LED sync to be enabled
|
||||
* @model_id - Current device model ID enumerated
|
||||
*/
|
||||
struct lm3692x_led {
|
||||
struct mutex lock;
|
||||
|
@ -118,6 +115,8 @@ struct lm3692x_led {
|
|||
struct gpio_desc *enable_gpio;
|
||||
struct regulator *regulator;
|
||||
char label[LED_MAX_NAME_SIZE];
|
||||
int led_enable;
|
||||
int model_id;
|
||||
};
|
||||
|
||||
static const struct reg_default lm3692x_reg_defs[] = {
|
||||
|
@ -200,6 +199,7 @@ out:
|
|||
|
||||
static int lm3692x_init(struct lm3692x_led *led)
|
||||
{
|
||||
int enable_state;
|
||||
int ret;
|
||||
|
||||
if (led->regulator) {
|
||||
|
@ -226,9 +226,25 @@ static int lm3692x_init(struct lm3692x_led *led)
|
|||
|
||||
/*
|
||||
* For glitch free operation, the following data should
|
||||
* only be written while device enable bit is 0
|
||||
* only be written while LEDx enable bits are 0 and the device enable
|
||||
* bit is set to 1.
|
||||
* per Section 7.5.14 of the data sheet
|
||||
*/
|
||||
ret = regmap_write(led->regmap, LM3692X_EN, LM3692X_DEVICE_EN);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
/* Set the brightness to 0 so when enabled the LEDs do not come
|
||||
* on with full brightness.
|
||||
*/
|
||||
ret = regmap_write(led->regmap, LM3692X_BRT_MSB, 0);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = regmap_write(led->regmap, LM3692X_BRT_LSB, 0);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = regmap_write(led->regmap, LM3692X_PWM_CTRL,
|
||||
LM3692X_PWM_FILTER_100 | LM3692X_PWM_SAMP_24MHZ);
|
||||
if (ret)
|
||||
|
@ -258,6 +274,38 @@ static int lm3692x_init(struct lm3692x_led *led)
|
|||
if (ret)
|
||||
goto out;
|
||||
|
||||
switch (led->led_enable) {
|
||||
case 0:
|
||||
default:
|
||||
if (led->model_id == LM36923_MODEL)
|
||||
enable_state = LM3692X_LED1_EN | LM3692X_LED2_EN |
|
||||
LM36923_LED3_EN;
|
||||
else
|
||||
enable_state = LM3692X_LED1_EN | LM3692X_LED2_EN;
|
||||
|
||||
break;
|
||||
case 1:
|
||||
enable_state = LM3692X_LED1_EN;
|
||||
break;
|
||||
case 2:
|
||||
enable_state = LM3692X_LED2_EN;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
if (led->model_id == LM36923_MODEL) {
|
||||
enable_state = LM36923_LED3_EN;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = -EINVAL;
|
||||
dev_err(&led->client->dev,
|
||||
"LED3 sync not available on this device\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = regmap_update_bits(led->regmap, LM3692X_EN, LM3692X_ENABLE_MASK,
|
||||
enable_state | LM3692X_DEVICE_EN);
|
||||
|
||||
return ret;
|
||||
out:
|
||||
dev_err(&led->client->dev, "Fail writing initialization values\n");
|
||||
|
@ -274,52 +322,75 @@ out:
|
|||
|
||||
return ret;
|
||||
}
|
||||
static int lm3692x_probe_dt(struct lm3692x_led *led)
|
||||
{
|
||||
struct fwnode_handle *child = NULL;
|
||||
const char *name;
|
||||
int ret;
|
||||
|
||||
led->enable_gpio = devm_gpiod_get_optional(&led->client->dev,
|
||||
"enable", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(led->enable_gpio)) {
|
||||
ret = PTR_ERR(led->enable_gpio);
|
||||
dev_err(&led->client->dev, "Failed to get enable gpio: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
led->regulator = devm_regulator_get(&led->client->dev, "vled");
|
||||
if (IS_ERR(led->regulator))
|
||||
led->regulator = NULL;
|
||||
|
||||
child = device_get_next_child_node(&led->client->dev, child);
|
||||
if (!child) {
|
||||
dev_err(&led->client->dev, "No LED Child node\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
fwnode_property_read_string(child, "linux,default-trigger",
|
||||
&led->led_dev.default_trigger);
|
||||
|
||||
ret = fwnode_property_read_string(child, "label", &name);
|
||||
if (ret)
|
||||
snprintf(led->label, sizeof(led->label),
|
||||
"%s::", led->client->name);
|
||||
else
|
||||
snprintf(led->label, sizeof(led->label),
|
||||
"%s:%s", led->client->name, name);
|
||||
|
||||
ret = fwnode_property_read_u32(child, "reg", &led->led_enable);
|
||||
if (ret) {
|
||||
dev_err(&led->client->dev, "reg DT property missing\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
led->led_dev.name = led->label;
|
||||
|
||||
ret = devm_led_classdev_register(&led->client->dev, &led->led_dev);
|
||||
if (ret) {
|
||||
dev_err(&led->client->dev, "led register err: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
led->led_dev.dev->of_node = to_of_node(child);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lm3692x_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
int ret;
|
||||
struct lm3692x_led *led;
|
||||
struct device_node *np = client->dev.of_node;
|
||||
struct device_node *child_node;
|
||||
const char *name;
|
||||
int ret;
|
||||
|
||||
led = devm_kzalloc(&client->dev, sizeof(*led), GFP_KERNEL);
|
||||
if (!led)
|
||||
return -ENOMEM;
|
||||
|
||||
for_each_available_child_of_node(np, child_node) {
|
||||
led->led_dev.default_trigger = of_get_property(child_node,
|
||||
"linux,default-trigger",
|
||||
NULL);
|
||||
|
||||
ret = of_property_read_string(child_node, "label", &name);
|
||||
if (!ret)
|
||||
snprintf(led->label, sizeof(led->label),
|
||||
"%s:%s", id->name, name);
|
||||
else
|
||||
snprintf(led->label, sizeof(led->label),
|
||||
"%s::backlight_cluster", id->name);
|
||||
};
|
||||
|
||||
led->enable_gpio = devm_gpiod_get_optional(&client->dev,
|
||||
"enable", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(led->enable_gpio)) {
|
||||
ret = PTR_ERR(led->enable_gpio);
|
||||
dev_err(&client->dev, "Failed to get enable gpio: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
led->regulator = devm_regulator_get(&client->dev, "vled");
|
||||
if (IS_ERR(led->regulator))
|
||||
led->regulator = NULL;
|
||||
|
||||
led->client = client;
|
||||
led->led_dev.name = led->label;
|
||||
led->led_dev.brightness_set_blocking = lm3692x_brightness_set;
|
||||
|
||||
mutex_init(&led->lock);
|
||||
|
||||
led->client = client;
|
||||
led->led_dev.brightness_set_blocking = lm3692x_brightness_set;
|
||||
led->model_id = id->driver_data;
|
||||
i2c_set_clientdata(client, led);
|
||||
|
||||
led->regmap = devm_regmap_init_i2c(client, &lm3692x_regmap_config);
|
||||
|
@ -330,15 +401,13 @@ static int lm3692x_probe(struct i2c_client *client,
|
|||
return ret;
|
||||
}
|
||||
|
||||
ret = lm3692x_init(led);
|
||||
ret = lm3692x_probe_dt(led);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_led_classdev_register(&client->dev, &led->led_dev);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "led register err: %d\n", ret);
|
||||
ret = lm3692x_init(led);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -348,6 +417,12 @@ static int lm3692x_remove(struct i2c_client *client)
|
|||
struct lm3692x_led *led = i2c_get_clientdata(client);
|
||||
int ret;
|
||||
|
||||
ret = regmap_update_bits(led->regmap, LM3692X_EN, LM3692X_DEVICE_EN, 0);
|
||||
if (ret) {
|
||||
dev_err(&led->client->dev, "Failed to disable regulator\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (led->enable_gpio)
|
||||
gpiod_direction_output(led->enable_gpio, 0);
|
||||
|
||||
|
@ -364,8 +439,8 @@ static int lm3692x_remove(struct i2c_client *client)
|
|||
}
|
||||
|
||||
static const struct i2c_device_id lm3692x_id[] = {
|
||||
{ "lm36922", 0 },
|
||||
{ "lm36923", 1 },
|
||||
{ "lm36922", LM36922_MODEL },
|
||||
{ "lm36923", LM36923_MODEL },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, lm3692x_id);
|
||||
|
|
|
@ -1,32 +1,21 @@
|
|||
/*
|
||||
* LEDs driver for LT3593 controllers
|
||||
*
|
||||
* See the datasheet at http://cds.linear.com/docs/Datasheet/3593f.pdf
|
||||
*
|
||||
* Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
|
||||
*
|
||||
* Based on leds-gpio.c,
|
||||
*
|
||||
* Copyright (C) 2007 8D Technologies inc.
|
||||
* Raphael Assenat <raph@8d.com>
|
||||
* Copyright (C) 2008 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2009,2018 Daniel Mack <daniel@zonque.org>
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <uapi/linux/uleds.h>
|
||||
|
||||
struct lt3593_led_data {
|
||||
char name[LED_MAX_NAME_SIZE];
|
||||
struct led_classdev cdev;
|
||||
unsigned gpio;
|
||||
struct gpio_desc *gpiod;
|
||||
};
|
||||
|
||||
static int lt3593_led_set(struct led_classdev *led_cdev,
|
||||
|
@ -46,137 +35,168 @@ static int lt3593_led_set(struct led_classdev *led_cdev,
|
|||
*/
|
||||
|
||||
if (value == 0) {
|
||||
gpio_set_value_cansleep(led_dat->gpio, 0);
|
||||
gpiod_set_value_cansleep(led_dat->gpiod, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pulses = 32 - (value * 32) / 255;
|
||||
|
||||
if (pulses == 0) {
|
||||
gpio_set_value_cansleep(led_dat->gpio, 0);
|
||||
gpiod_set_value_cansleep(led_dat->gpiod, 0);
|
||||
mdelay(1);
|
||||
gpio_set_value_cansleep(led_dat->gpio, 1);
|
||||
gpiod_set_value_cansleep(led_dat->gpiod, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
gpio_set_value_cansleep(led_dat->gpio, 1);
|
||||
gpiod_set_value_cansleep(led_dat->gpiod, 1);
|
||||
|
||||
while (pulses--) {
|
||||
gpio_set_value_cansleep(led_dat->gpio, 0);
|
||||
gpiod_set_value_cansleep(led_dat->gpiod, 0);
|
||||
udelay(1);
|
||||
gpio_set_value_cansleep(led_dat->gpio, 1);
|
||||
gpiod_set_value_cansleep(led_dat->gpiod, 1);
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int create_lt3593_led(const struct gpio_led *template,
|
||||
struct lt3593_led_data *led_dat, struct device *parent)
|
||||
static struct lt3593_led_data *lt3593_led_probe_pdata(struct device *dev)
|
||||
{
|
||||
struct gpio_led_platform_data *pdata = dev_get_platdata(dev);
|
||||
const struct gpio_led *template = &pdata->leds[0];
|
||||
struct lt3593_led_data *led_data;
|
||||
int ret, state;
|
||||
|
||||
/* skip leds on GPIOs that aren't available */
|
||||
if (!gpio_is_valid(template->gpio)) {
|
||||
dev_info(parent, "%s: skipping unavailable LT3593 LED at gpio %d (%s)\n",
|
||||
KBUILD_MODNAME, template->gpio, template->name);
|
||||
return 0;
|
||||
}
|
||||
if (pdata->num_leds != 1)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
led_dat->cdev.name = template->name;
|
||||
led_dat->cdev.default_trigger = template->default_trigger;
|
||||
led_dat->gpio = template->gpio;
|
||||
led_data = devm_kzalloc(dev, sizeof(*led_data), GFP_KERNEL);
|
||||
if (!led_data)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
led_dat->cdev.brightness_set_blocking = lt3593_led_set;
|
||||
led_data->cdev.name = template->name;
|
||||
led_data->cdev.default_trigger = template->default_trigger;
|
||||
led_data->cdev.brightness_set_blocking = lt3593_led_set;
|
||||
|
||||
state = (template->default_state == LEDS_GPIO_DEFSTATE_ON);
|
||||
led_dat->cdev.brightness = state ? LED_FULL : LED_OFF;
|
||||
led_data->cdev.brightness = state ? LED_FULL : LED_OFF;
|
||||
|
||||
if (!template->retain_state_suspended)
|
||||
led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
|
||||
led_data->cdev.flags |= LED_CORE_SUSPENDRESUME;
|
||||
|
||||
ret = devm_gpio_request_one(parent, template->gpio, state ?
|
||||
ret = devm_gpio_request_one(dev, template->gpio, state ?
|
||||
GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW,
|
||||
template->name);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return ERR_PTR(ret);
|
||||
|
||||
ret = led_classdev_register(parent, &led_dat->cdev);
|
||||
led_data->gpiod = gpio_to_desc(template->gpio);
|
||||
if (!led_data->gpiod)
|
||||
return ERR_PTR(-EPROBE_DEFER);
|
||||
|
||||
ret = devm_led_classdev_register(dev, &led_data->cdev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return ERR_PTR(ret);
|
||||
|
||||
dev_info(parent, "%s: registered LT3593 LED '%s' at GPIO %d\n",
|
||||
KBUILD_MODNAME, template->name, template->gpio);
|
||||
dev_info(dev, "registered LT3593 LED '%s' at GPIO %d\n",
|
||||
template->name, template->gpio);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void delete_lt3593_led(struct lt3593_led_data *led)
|
||||
{
|
||||
if (!gpio_is_valid(led->gpio))
|
||||
return;
|
||||
|
||||
led_classdev_unregister(&led->cdev);
|
||||
return led_data;
|
||||
}
|
||||
|
||||
static int lt3593_led_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct gpio_led_platform_data *pdata = dev_get_platdata(&pdev->dev);
|
||||
struct lt3593_led_data *leds_data;
|
||||
int i, ret = 0;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct lt3593_led_data *led_data;
|
||||
struct fwnode_handle *child;
|
||||
int ret, state = LEDS_GPIO_DEFSTATE_OFF;
|
||||
enum gpiod_flags flags = GPIOD_OUT_LOW;
|
||||
const char *tmp;
|
||||
|
||||
if (!pdata)
|
||||
return -EBUSY;
|
||||
if (dev_get_platdata(dev)) {
|
||||
led_data = lt3593_led_probe_pdata(dev);
|
||||
if (IS_ERR(led_data))
|
||||
return PTR_ERR(led_data);
|
||||
|
||||
leds_data = devm_kcalloc(&pdev->dev,
|
||||
pdata->num_leds, sizeof(struct lt3593_led_data),
|
||||
GFP_KERNEL);
|
||||
if (!leds_data)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < pdata->num_leds; i++) {
|
||||
ret = create_lt3593_led(&pdata->leds[i], &leds_data[i],
|
||||
&pdev->dev);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
goto out;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, leds_data);
|
||||
if (!dev->of_node)
|
||||
return -ENODEV;
|
||||
|
||||
return 0;
|
||||
led_data = devm_kzalloc(dev, sizeof(*led_data), GFP_KERNEL);
|
||||
if (!led_data)
|
||||
return -ENOMEM;
|
||||
|
||||
err:
|
||||
for (i = i - 1; i >= 0; i--)
|
||||
delete_lt3593_led(&leds_data[i]);
|
||||
if (device_get_child_node_count(dev) != 1) {
|
||||
dev_err(dev, "Device must have exactly one LED sub-node.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
led_data->gpiod = devm_gpiod_get(dev, "lltc,ctrl", 0);
|
||||
if (IS_ERR(led_data->gpiod))
|
||||
return PTR_ERR(led_data->gpiod);
|
||||
|
||||
static int lt3593_led_remove(struct platform_device *pdev)
|
||||
{
|
||||
int i;
|
||||
struct gpio_led_platform_data *pdata = dev_get_platdata(&pdev->dev);
|
||||
struct lt3593_led_data *leds_data;
|
||||
child = device_get_next_child_node(dev, NULL);
|
||||
|
||||
leds_data = platform_get_drvdata(pdev);
|
||||
ret = fwnode_property_read_string(child, "label", &tmp);
|
||||
if (ret < 0)
|
||||
snprintf(led_data->name, sizeof(led_data->name),
|
||||
"lt3593::");
|
||||
else
|
||||
snprintf(led_data->name, sizeof(led_data->name),
|
||||
"lt3593:%s", tmp);
|
||||
|
||||
for (i = 0; i < pdata->num_leds; i++)
|
||||
delete_lt3593_led(&leds_data[i]);
|
||||
fwnode_property_read_string(child, "linux,default-trigger",
|
||||
&led_data->cdev.default_trigger);
|
||||
|
||||
if (!fwnode_property_read_string(child, "default-state", &tmp)) {
|
||||
if (!strcmp(tmp, "keep")) {
|
||||
state = LEDS_GPIO_DEFSTATE_KEEP;
|
||||
flags = GPIOD_ASIS;
|
||||
} else if (!strcmp(tmp, "on")) {
|
||||
state = LEDS_GPIO_DEFSTATE_ON;
|
||||
flags = GPIOD_OUT_HIGH;
|
||||
}
|
||||
}
|
||||
|
||||
led_data->cdev.name = led_data->name;
|
||||
led_data->cdev.brightness_set_blocking = lt3593_led_set;
|
||||
led_data->cdev.brightness = state ? LED_FULL : LED_OFF;
|
||||
|
||||
ret = devm_led_classdev_register(dev, &led_data->cdev);
|
||||
if (ret < 0) {
|
||||
fwnode_handle_put(child);
|
||||
return ret;
|
||||
}
|
||||
|
||||
led_data->cdev.dev->of_node = dev->of_node;
|
||||
|
||||
out:
|
||||
platform_set_drvdata(pdev, led_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id of_lt3593_leds_match[] = {
|
||||
{ .compatible = "lltc,lt3593", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, of_lt3593_leds_match);
|
||||
#endif
|
||||
|
||||
static struct platform_driver lt3593_led_driver = {
|
||||
.probe = lt3593_led_probe,
|
||||
.remove = lt3593_led_remove,
|
||||
.driver = {
|
||||
.name = "leds-lt3593",
|
||||
.of_match_table = of_match_ptr(of_lt3593_leds_match),
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(lt3593_led_driver);
|
||||
|
||||
MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
|
||||
MODULE_AUTHOR("Daniel Mack <daniel@zonque.org>");
|
||||
MODULE_DESCRIPTION("LED driver for LT3593 controllers");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("platform:leds-lt3593");
|
||||
|
|
|
@ -268,7 +268,7 @@ static int max8997_led_probe(struct platform_device *pdev)
|
|||
mode = pdata->led_pdata->mode[led->id];
|
||||
brightness = pdata->led_pdata->brightness[led->id];
|
||||
|
||||
max8997_led_set_mode(led, pdata->led_pdata->mode[led->id]);
|
||||
max8997_led_set_mode(led, mode);
|
||||
|
||||
if (brightness > led->cdev.max_brightness)
|
||||
brightness = led->cdev.max_brightness;
|
||||
|
|
|
@ -42,8 +42,8 @@
|
|||
|
||||
struct ns2_led_data {
|
||||
struct led_classdev cdev;
|
||||
unsigned cmd;
|
||||
unsigned slow;
|
||||
unsigned int cmd;
|
||||
unsigned int slow;
|
||||
bool can_sleep;
|
||||
unsigned char sata; /* True when SATA mode active. */
|
||||
rwlock_t rw_lock; /* Lock GPIOs. */
|
||||
|
|
|
@ -10,7 +10,6 @@ if LEDS_TRIGGERS
|
|||
|
||||
config LEDS_TRIGGER_TIMER
|
||||
tristate "LED Timer Trigger"
|
||||
depends on LEDS_TRIGGERS
|
||||
help
|
||||
This allows LEDs to be controlled by a programmable timer
|
||||
via sysfs. Some LED hardware can be programmed to start
|
||||
|
@ -21,7 +20,6 @@ config LEDS_TRIGGER_TIMER
|
|||
|
||||
config LEDS_TRIGGER_ONESHOT
|
||||
tristate "LED One-shot Trigger"
|
||||
depends on LEDS_TRIGGERS
|
||||
help
|
||||
This allows LEDs to blink in one-shot pulses with parameters
|
||||
controlled via sysfs. It's useful to notify the user on
|
||||
|
@ -36,7 +34,6 @@ config LEDS_TRIGGER_ONESHOT
|
|||
config LEDS_TRIGGER_DISK
|
||||
bool "LED Disk Trigger"
|
||||
depends on IDE_GD_ATA || ATA
|
||||
depends on LEDS_TRIGGERS
|
||||
help
|
||||
This allows LEDs to be controlled by disk activity.
|
||||
If unsure, say Y.
|
||||
|
@ -44,14 +41,12 @@ config LEDS_TRIGGER_DISK
|
|||
config LEDS_TRIGGER_MTD
|
||||
bool "LED MTD (NAND/NOR) Trigger"
|
||||
depends on MTD
|
||||
depends on LEDS_TRIGGERS
|
||||
help
|
||||
This allows LEDs to be controlled by MTD activity.
|
||||
If unsure, say N.
|
||||
|
||||
config LEDS_TRIGGER_HEARTBEAT
|
||||
tristate "LED Heartbeat Trigger"
|
||||
depends on LEDS_TRIGGERS
|
||||
help
|
||||
This allows LEDs to be controlled by a CPU load average.
|
||||
The flash frequency is a hyperbolic function of the 1-minute
|
||||
|
@ -60,7 +55,6 @@ config LEDS_TRIGGER_HEARTBEAT
|
|||
|
||||
config LEDS_TRIGGER_BACKLIGHT
|
||||
tristate "LED backlight Trigger"
|
||||
depends on LEDS_TRIGGERS
|
||||
help
|
||||
This allows LEDs to be controlled as a backlight device: they
|
||||
turn off and on when the display is blanked and unblanked.
|
||||
|
@ -69,7 +63,6 @@ config LEDS_TRIGGER_BACKLIGHT
|
|||
|
||||
config LEDS_TRIGGER_CPU
|
||||
bool "LED CPU Trigger"
|
||||
depends on LEDS_TRIGGERS
|
||||
help
|
||||
This allows LEDs to be controlled by active CPUs. This shows
|
||||
the active CPUs across an array of LEDs so you can see which
|
||||
|
@ -79,7 +72,6 @@ config LEDS_TRIGGER_CPU
|
|||
|
||||
config LEDS_TRIGGER_ACTIVITY
|
||||
tristate "LED activity Trigger"
|
||||
depends on LEDS_TRIGGERS
|
||||
help
|
||||
This allows LEDs to be controlled by an immediate CPU usage.
|
||||
The flash frequency and duty cycle varies from faint flashes to
|
||||
|
@ -88,7 +80,6 @@ config LEDS_TRIGGER_ACTIVITY
|
|||
|
||||
config LEDS_TRIGGER_GPIO
|
||||
tristate "LED GPIO Trigger"
|
||||
depends on LEDS_TRIGGERS
|
||||
depends on GPIOLIB || COMPILE_TEST
|
||||
help
|
||||
This allows LEDs to be controlled by gpio events. It's good
|
||||
|
@ -101,7 +92,6 @@ config LEDS_TRIGGER_GPIO
|
|||
|
||||
config LEDS_TRIGGER_DEFAULT_ON
|
||||
tristate "LED Default ON Trigger"
|
||||
depends on LEDS_TRIGGERS
|
||||
help
|
||||
This allows LEDs to be initialised in the ON state.
|
||||
If unsure, say Y.
|
||||
|
@ -111,7 +101,6 @@ comment "iptables trigger is under Netfilter config (LED target)"
|
|||
|
||||
config LEDS_TRIGGER_TRANSIENT
|
||||
tristate "LED Transient Trigger"
|
||||
depends on LEDS_TRIGGERS
|
||||
help
|
||||
This allows one time activation of a transient state on
|
||||
GPIO/PWM based hardware.
|
||||
|
@ -119,7 +108,6 @@ config LEDS_TRIGGER_TRANSIENT
|
|||
|
||||
config LEDS_TRIGGER_CAMERA
|
||||
tristate "LED Camera Flash/Torch Trigger"
|
||||
depends on LEDS_TRIGGERS
|
||||
help
|
||||
This allows LEDs to be controlled as a camera flash/torch device.
|
||||
This enables direct flash/torch on/off by the driver, kernel space.
|
||||
|
@ -127,7 +115,6 @@ config LEDS_TRIGGER_CAMERA
|
|||
|
||||
config LEDS_TRIGGER_PANIC
|
||||
bool "LED Panic Trigger"
|
||||
depends on LEDS_TRIGGERS
|
||||
help
|
||||
This allows LEDs to be configured to blink on a kernel panic.
|
||||
Enabling this option will allow to mark certain LEDs as panic indicators,
|
||||
|
@ -137,7 +124,7 @@ config LEDS_TRIGGER_PANIC
|
|||
|
||||
config LEDS_TRIGGER_NETDEV
|
||||
tristate "LED Netdev Trigger"
|
||||
depends on NET && LEDS_TRIGGERS
|
||||
depends on NET
|
||||
help
|
||||
This allows LEDs to be controlled by network device activity.
|
||||
If unsure, say Y.
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
* 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>
|
||||
|
@ -37,7 +37,6 @@ 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;
|
||||
|
@ -57,8 +56,6 @@ static void led_activity_function(struct timer_list *t)
|
|||
return;
|
||||
}
|
||||
|
||||
get_monotonic_boottime(&boot_time);
|
||||
|
||||
cpus = 0;
|
||||
curr_used = 0;
|
||||
|
||||
|
@ -76,7 +73,7 @@ static void led_activity_function(struct timer_list *t)
|
|||
* 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;
|
||||
curr_boot = ktime_get_boot_ns() * 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;
|
||||
|
@ -155,8 +152,7 @@ static void led_activity_function(struct timer_list *t)
|
|||
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;
|
||||
struct activity_data *activity_data = led_trigger_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%u\n", activity_data->invert);
|
||||
}
|
||||
|
@ -165,8 +161,7 @@ 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;
|
||||
struct activity_data *activity_data = led_trigger_get_drvdata(dev);
|
||||
unsigned long state;
|
||||
int ret;
|
||||
|
||||
|
@ -181,21 +176,21 @@ static ssize_t led_invert_store(struct device *dev,
|
|||
|
||||
static DEVICE_ATTR(invert, 0644, led_invert_show, led_invert_store);
|
||||
|
||||
static void activity_activate(struct led_classdev *led_cdev)
|
||||
static struct attribute *activity_led_attrs[] = {
|
||||
&dev_attr_invert.attr,
|
||||
NULL
|
||||
};
|
||||
ATTRIBUTE_GROUPS(activity_led);
|
||||
|
||||
static int 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;
|
||||
return -ENOMEM;
|
||||
|
||||
led_cdev->trigger_data = activity_data;
|
||||
rc = device_create_file(led_cdev->dev, &dev_attr_invert);
|
||||
if (rc) {
|
||||
kfree(led_cdev->trigger_data);
|
||||
return;
|
||||
}
|
||||
led_set_trigger_data(led_cdev, activity_data);
|
||||
|
||||
activity_data->led_cdev = led_cdev;
|
||||
timer_setup(&activity_data->timer, led_activity_function, 0);
|
||||
|
@ -203,26 +198,24 @@ static void activity_activate(struct led_classdev *led_cdev)
|
|||
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;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void activity_deactivate(struct led_classdev *led_cdev)
|
||||
{
|
||||
struct activity_data *activity_data = led_cdev->trigger_data;
|
||||
struct activity_data *activity_data = led_get_trigger_data(led_cdev);
|
||||
|
||||
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;
|
||||
}
|
||||
del_timer_sync(&activity_data->timer);
|
||||
kfree(activity_data);
|
||||
clear_bit(LED_BLINK_SW, &led_cdev->work_flags);
|
||||
}
|
||||
|
||||
static struct led_trigger activity_led_trigger = {
|
||||
.name = "activity",
|
||||
.activate = activity_activate,
|
||||
.deactivate = activity_deactivate,
|
||||
.groups = activity_led_groups,
|
||||
};
|
||||
|
||||
static int activity_reboot_notifier(struct notifier_block *nb,
|
||||
|
@ -272,4 +265,4 @@ module_exit(activity_exit);
|
|||
|
||||
MODULE_AUTHOR("Willy Tarreau <w@1wt.eu>");
|
||||
MODULE_DESCRIPTION("Activity LED trigger");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -64,8 +64,7 @@ static int fb_notifier_callback(struct notifier_block *p,
|
|||
static ssize_t bl_trig_invert_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct led_classdev *led = dev_get_drvdata(dev);
|
||||
struct bl_trig_notifier *n = led->trigger_data;
|
||||
struct bl_trig_notifier *n = led_trigger_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%u\n", n->invert);
|
||||
}
|
||||
|
@ -73,8 +72,8 @@ static ssize_t bl_trig_invert_show(struct device *dev,
|
|||
static ssize_t bl_trig_invert_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t num)
|
||||
{
|
||||
struct led_classdev *led = dev_get_drvdata(dev);
|
||||
struct bl_trig_notifier *n = led->trigger_data;
|
||||
struct led_classdev *led = led_trigger_get_led(dev);
|
||||
struct bl_trig_notifier *n = led_trigger_get_drvdata(dev);
|
||||
unsigned long invert;
|
||||
int ret;
|
||||
|
||||
|
@ -97,22 +96,22 @@ static ssize_t bl_trig_invert_store(struct device *dev,
|
|||
}
|
||||
static DEVICE_ATTR(inverted, 0644, bl_trig_invert_show, bl_trig_invert_store);
|
||||
|
||||
static void bl_trig_activate(struct led_classdev *led)
|
||||
static struct attribute *bl_trig_attrs[] = {
|
||||
&dev_attr_inverted.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(bl_trig);
|
||||
|
||||
static int bl_trig_activate(struct led_classdev *led)
|
||||
{
|
||||
int ret;
|
||||
|
||||
struct bl_trig_notifier *n;
|
||||
|
||||
n = kzalloc(sizeof(struct bl_trig_notifier), GFP_KERNEL);
|
||||
led->trigger_data = n;
|
||||
if (!n) {
|
||||
dev_err(led->dev, "unable to allocate backlight trigger\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ret = device_create_file(led->dev, &dev_attr_inverted);
|
||||
if (ret)
|
||||
goto err_invert;
|
||||
if (!n)
|
||||
return -ENOMEM;
|
||||
led_set_trigger_data(led, n);
|
||||
|
||||
n->led = led;
|
||||
n->brightness = led->brightness;
|
||||
|
@ -122,46 +121,25 @@ static void bl_trig_activate(struct led_classdev *led)
|
|||
ret = fb_register_client(&n->notifier);
|
||||
if (ret)
|
||||
dev_err(led->dev, "unable to register backlight trigger\n");
|
||||
led->activated = true;
|
||||
|
||||
return;
|
||||
|
||||
err_invert:
|
||||
led->trigger_data = NULL;
|
||||
kfree(n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bl_trig_deactivate(struct led_classdev *led)
|
||||
{
|
||||
struct bl_trig_notifier *n =
|
||||
(struct bl_trig_notifier *) led->trigger_data;
|
||||
struct bl_trig_notifier *n = led_get_trigger_data(led);
|
||||
|
||||
if (led->activated) {
|
||||
device_remove_file(led->dev, &dev_attr_inverted);
|
||||
fb_unregister_client(&n->notifier);
|
||||
kfree(n);
|
||||
led->activated = false;
|
||||
}
|
||||
fb_unregister_client(&n->notifier);
|
||||
kfree(n);
|
||||
}
|
||||
|
||||
static struct led_trigger bl_led_trigger = {
|
||||
.name = "backlight",
|
||||
.activate = bl_trig_activate,
|
||||
.deactivate = bl_trig_deactivate
|
||||
.deactivate = bl_trig_deactivate,
|
||||
.groups = bl_trig_groups,
|
||||
};
|
||||
|
||||
static int __init bl_trig_init(void)
|
||||
{
|
||||
return led_trigger_register(&bl_led_trigger);
|
||||
}
|
||||
|
||||
static void __exit bl_trig_exit(void)
|
||||
{
|
||||
led_trigger_unregister(&bl_led_trigger);
|
||||
}
|
||||
|
||||
module_init(bl_trig_init);
|
||||
module_exit(bl_trig_exit);
|
||||
module_led_trigger(bl_led_trigger);
|
||||
|
||||
MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
|
||||
MODULE_DESCRIPTION("Backlight emulation LED trigger");
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
* 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/module.h>
|
||||
|
@ -54,4 +53,4 @@ module_exit(ledtrig_camera_exit);
|
|||
|
||||
MODULE_DESCRIPTION("LED Trigger for Camera Flash/Torch Control");
|
||||
MODULE_AUTHOR("Milo Kim");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
* 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/module.h>
|
||||
|
@ -17,29 +16,18 @@
|
|||
#include <linux/leds.h>
|
||||
#include "../leds.h"
|
||||
|
||||
static void defon_trig_activate(struct led_classdev *led_cdev)
|
||||
static int defon_trig_activate(struct led_classdev *led_cdev)
|
||||
{
|
||||
led_set_brightness_nosleep(led_cdev, led_cdev->max_brightness);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct led_trigger defon_led_trigger = {
|
||||
.name = "default-on",
|
||||
.activate = defon_trig_activate,
|
||||
};
|
||||
|
||||
static int __init defon_trig_init(void)
|
||||
{
|
||||
return led_trigger_register(&defon_led_trigger);
|
||||
}
|
||||
|
||||
static void __exit defon_trig_exit(void)
|
||||
{
|
||||
led_trigger_unregister(&defon_led_trigger);
|
||||
}
|
||||
|
||||
module_init(defon_trig_init);
|
||||
module_exit(defon_trig_exit);
|
||||
module_led_trigger(defon_led_trigger);
|
||||
|
||||
MODULE_AUTHOR("Nick Forbes <nick.forbes@incepta.com>");
|
||||
MODULE_DESCRIPTION("Default-ON LED trigger");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
* 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/module.h>
|
||||
|
@ -29,7 +28,7 @@ struct gpio_trig_data {
|
|||
static irqreturn_t gpio_trig_irq(int irq, void *_led)
|
||||
{
|
||||
struct led_classdev *led = _led;
|
||||
struct gpio_trig_data *gpio_data = led->trigger_data;
|
||||
struct gpio_trig_data *gpio_data = led_get_trigger_data(led);
|
||||
int tmp;
|
||||
|
||||
tmp = gpio_get_value_cansleep(gpio_data->gpio);
|
||||
|
@ -52,8 +51,7 @@ static irqreturn_t gpio_trig_irq(int irq, void *_led)
|
|||
static ssize_t gpio_trig_brightness_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct led_classdev *led = dev_get_drvdata(dev);
|
||||
struct gpio_trig_data *gpio_data = led->trigger_data;
|
||||
struct gpio_trig_data *gpio_data = led_trigger_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%u\n", gpio_data->desired_brightness);
|
||||
}
|
||||
|
@ -61,8 +59,7 @@ static ssize_t gpio_trig_brightness_show(struct device *dev,
|
|||
static ssize_t gpio_trig_brightness_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t n)
|
||||
{
|
||||
struct led_classdev *led = dev_get_drvdata(dev);
|
||||
struct gpio_trig_data *gpio_data = led->trigger_data;
|
||||
struct gpio_trig_data *gpio_data = led_trigger_get_drvdata(dev);
|
||||
unsigned desired_brightness;
|
||||
int ret;
|
||||
|
||||
|
@ -82,8 +79,7 @@ static DEVICE_ATTR(desired_brightness, 0644, gpio_trig_brightness_show,
|
|||
static ssize_t gpio_trig_inverted_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct led_classdev *led = dev_get_drvdata(dev);
|
||||
struct gpio_trig_data *gpio_data = led->trigger_data;
|
||||
struct gpio_trig_data *gpio_data = led_trigger_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%u\n", gpio_data->inverted);
|
||||
}
|
||||
|
@ -91,8 +87,8 @@ static ssize_t gpio_trig_inverted_show(struct device *dev,
|
|||
static ssize_t gpio_trig_inverted_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t n)
|
||||
{
|
||||
struct led_classdev *led = dev_get_drvdata(dev);
|
||||
struct gpio_trig_data *gpio_data = led->trigger_data;
|
||||
struct led_classdev *led = led_trigger_get_led(dev);
|
||||
struct gpio_trig_data *gpio_data = led_trigger_get_drvdata(dev);
|
||||
unsigned long inverted;
|
||||
int ret;
|
||||
|
||||
|
@ -116,8 +112,7 @@ static DEVICE_ATTR(inverted, 0644, gpio_trig_inverted_show,
|
|||
static ssize_t gpio_trig_gpio_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct led_classdev *led = dev_get_drvdata(dev);
|
||||
struct gpio_trig_data *gpio_data = led->trigger_data;
|
||||
struct gpio_trig_data *gpio_data = led_trigger_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%u\n", gpio_data->gpio);
|
||||
}
|
||||
|
@ -125,8 +120,8 @@ static ssize_t gpio_trig_gpio_show(struct device *dev,
|
|||
static ssize_t gpio_trig_gpio_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t n)
|
||||
{
|
||||
struct led_classdev *led = dev_get_drvdata(dev);
|
||||
struct gpio_trig_data *gpio_data = led->trigger_data;
|
||||
struct led_classdev *led = led_trigger_get_led(dev);
|
||||
struct gpio_trig_data *gpio_data = led_trigger_get_drvdata(dev);
|
||||
unsigned gpio;
|
||||
int ret;
|
||||
|
||||
|
@ -163,76 +158,45 @@ static ssize_t gpio_trig_gpio_store(struct device *dev,
|
|||
}
|
||||
static DEVICE_ATTR(gpio, 0644, gpio_trig_gpio_show, gpio_trig_gpio_store);
|
||||
|
||||
static void gpio_trig_activate(struct led_classdev *led)
|
||||
static struct attribute *gpio_trig_attrs[] = {
|
||||
&dev_attr_desired_brightness.attr,
|
||||
&dev_attr_inverted.attr,
|
||||
&dev_attr_gpio.attr,
|
||||
NULL
|
||||
};
|
||||
ATTRIBUTE_GROUPS(gpio_trig);
|
||||
|
||||
static int gpio_trig_activate(struct led_classdev *led)
|
||||
{
|
||||
struct gpio_trig_data *gpio_data;
|
||||
int ret;
|
||||
|
||||
gpio_data = kzalloc(sizeof(*gpio_data), GFP_KERNEL);
|
||||
if (!gpio_data)
|
||||
return;
|
||||
|
||||
ret = device_create_file(led->dev, &dev_attr_gpio);
|
||||
if (ret)
|
||||
goto err_gpio;
|
||||
|
||||
ret = device_create_file(led->dev, &dev_attr_inverted);
|
||||
if (ret)
|
||||
goto err_inverted;
|
||||
|
||||
ret = device_create_file(led->dev, &dev_attr_desired_brightness);
|
||||
if (ret)
|
||||
goto err_brightness;
|
||||
return -ENOMEM;
|
||||
|
||||
gpio_data->led = led;
|
||||
led->trigger_data = gpio_data;
|
||||
led->activated = true;
|
||||
led_set_trigger_data(led, gpio_data);
|
||||
|
||||
return;
|
||||
|
||||
err_brightness:
|
||||
device_remove_file(led->dev, &dev_attr_inverted);
|
||||
|
||||
err_inverted:
|
||||
device_remove_file(led->dev, &dev_attr_gpio);
|
||||
|
||||
err_gpio:
|
||||
kfree(gpio_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gpio_trig_deactivate(struct led_classdev *led)
|
||||
{
|
||||
struct gpio_trig_data *gpio_data = led->trigger_data;
|
||||
struct gpio_trig_data *gpio_data = led_get_trigger_data(led);
|
||||
|
||||
if (led->activated) {
|
||||
device_remove_file(led->dev, &dev_attr_gpio);
|
||||
device_remove_file(led->dev, &dev_attr_inverted);
|
||||
device_remove_file(led->dev, &dev_attr_desired_brightness);
|
||||
if (gpio_data->gpio != 0)
|
||||
free_irq(gpio_to_irq(gpio_data->gpio), led);
|
||||
kfree(gpio_data);
|
||||
led->activated = false;
|
||||
}
|
||||
if (gpio_data->gpio != 0)
|
||||
free_irq(gpio_to_irq(gpio_data->gpio), led);
|
||||
kfree(gpio_data);
|
||||
}
|
||||
|
||||
static struct led_trigger gpio_led_trigger = {
|
||||
.name = "gpio",
|
||||
.activate = gpio_trig_activate,
|
||||
.deactivate = gpio_trig_deactivate,
|
||||
.groups = gpio_trig_groups,
|
||||
};
|
||||
|
||||
static int __init gpio_trig_init(void)
|
||||
{
|
||||
return led_trigger_register(&gpio_led_trigger);
|
||||
}
|
||||
module_init(gpio_trig_init);
|
||||
|
||||
static void __exit gpio_trig_exit(void)
|
||||
{
|
||||
led_trigger_unregister(&gpio_led_trigger);
|
||||
}
|
||||
module_exit(gpio_trig_exit);
|
||||
module_led_trigger(gpio_led_trigger);
|
||||
|
||||
MODULE_AUTHOR("Felipe Balbi <me@felipebalbi.com>");
|
||||
MODULE_DESCRIPTION("GPIO LED trigger");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
* 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/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
|
@ -96,8 +96,8 @@ static void led_heartbeat_function(struct timer_list *t)
|
|||
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 heartbeat_trig_data *heartbeat_data = led_cdev->trigger_data;
|
||||
struct heartbeat_trig_data *heartbeat_data =
|
||||
led_trigger_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%u\n", heartbeat_data->invert);
|
||||
}
|
||||
|
@ -105,8 +105,8 @@ static ssize_t led_invert_show(struct device *dev,
|
|||
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 heartbeat_trig_data *heartbeat_data = led_cdev->trigger_data;
|
||||
struct heartbeat_trig_data *heartbeat_data =
|
||||
led_trigger_get_drvdata(dev);
|
||||
unsigned long state;
|
||||
int ret;
|
||||
|
||||
|
@ -121,22 +121,22 @@ static ssize_t led_invert_store(struct device *dev,
|
|||
|
||||
static DEVICE_ATTR(invert, 0644, led_invert_show, led_invert_store);
|
||||
|
||||
static void heartbeat_trig_activate(struct led_classdev *led_cdev)
|
||||
static struct attribute *heartbeat_trig_attrs[] = {
|
||||
&dev_attr_invert.attr,
|
||||
NULL
|
||||
};
|
||||
ATTRIBUTE_GROUPS(heartbeat_trig);
|
||||
|
||||
static int heartbeat_trig_activate(struct led_classdev *led_cdev)
|
||||
{
|
||||
struct heartbeat_trig_data *heartbeat_data;
|
||||
int rc;
|
||||
|
||||
heartbeat_data = kzalloc(sizeof(*heartbeat_data), GFP_KERNEL);
|
||||
if (!heartbeat_data)
|
||||
return;
|
||||
return -ENOMEM;
|
||||
|
||||
led_cdev->trigger_data = heartbeat_data;
|
||||
led_set_trigger_data(led_cdev, heartbeat_data);
|
||||
heartbeat_data->led_cdev = led_cdev;
|
||||
rc = device_create_file(led_cdev->dev, &dev_attr_invert);
|
||||
if (rc) {
|
||||
kfree(led_cdev->trigger_data);
|
||||
return;
|
||||
}
|
||||
|
||||
timer_setup(&heartbeat_data->timer, led_heartbeat_function, 0);
|
||||
heartbeat_data->phase = 0;
|
||||
|
@ -144,26 +144,25 @@ static void heartbeat_trig_activate(struct led_classdev *led_cdev)
|
|||
led_cdev->blink_brightness = led_cdev->max_brightness;
|
||||
led_heartbeat_function(&heartbeat_data->timer);
|
||||
set_bit(LED_BLINK_SW, &led_cdev->work_flags);
|
||||
led_cdev->activated = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void heartbeat_trig_deactivate(struct led_classdev *led_cdev)
|
||||
{
|
||||
struct heartbeat_trig_data *heartbeat_data = led_cdev->trigger_data;
|
||||
struct heartbeat_trig_data *heartbeat_data =
|
||||
led_get_trigger_data(led_cdev);
|
||||
|
||||
if (led_cdev->activated) {
|
||||
del_timer_sync(&heartbeat_data->timer);
|
||||
device_remove_file(led_cdev->dev, &dev_attr_invert);
|
||||
kfree(heartbeat_data);
|
||||
clear_bit(LED_BLINK_SW, &led_cdev->work_flags);
|
||||
led_cdev->activated = false;
|
||||
}
|
||||
del_timer_sync(&heartbeat_data->timer);
|
||||
kfree(heartbeat_data);
|
||||
clear_bit(LED_BLINK_SW, &led_cdev->work_flags);
|
||||
}
|
||||
|
||||
static struct led_trigger heartbeat_led_trigger = {
|
||||
.name = "heartbeat",
|
||||
.activate = heartbeat_trig_activate,
|
||||
.deactivate = heartbeat_trig_deactivate,
|
||||
.groups = heartbeat_trig_groups,
|
||||
};
|
||||
|
||||
static int heartbeat_reboot_notifier(struct notifier_block *nb,
|
||||
|
@ -213,4 +212,4 @@ module_exit(heartbeat_trig_exit);
|
|||
|
||||
MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
|
||||
MODULE_DESCRIPTION("Heartbeat LED trigger");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -94,8 +94,7 @@ static void set_baseline_state(struct led_netdev_data *trigger_data)
|
|||
static ssize_t device_name_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct led_netdev_data *trigger_data = led_cdev->trigger_data;
|
||||
struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev);
|
||||
ssize_t len;
|
||||
|
||||
spin_lock_bh(&trigger_data->lock);
|
||||
|
@ -109,8 +108,7 @@ static ssize_t device_name_store(struct device *dev,
|
|||
struct device_attribute *attr, const char *buf,
|
||||
size_t size)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct led_netdev_data *trigger_data = led_cdev->trigger_data;
|
||||
struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev);
|
||||
|
||||
if (size >= IFNAMSIZ)
|
||||
return -EINVAL;
|
||||
|
@ -150,8 +148,7 @@ static DEVICE_ATTR_RW(device_name);
|
|||
static ssize_t netdev_led_attr_show(struct device *dev, char *buf,
|
||||
enum netdev_led_attr attr)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct led_netdev_data *trigger_data = led_cdev->trigger_data;
|
||||
struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev);
|
||||
int bit;
|
||||
|
||||
switch (attr) {
|
||||
|
@ -174,8 +171,7 @@ static ssize_t netdev_led_attr_show(struct device *dev, char *buf,
|
|||
static ssize_t netdev_led_attr_store(struct device *dev, const char *buf,
|
||||
size_t size, enum netdev_led_attr attr)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct led_netdev_data *trigger_data = led_cdev->trigger_data;
|
||||
struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev);
|
||||
unsigned long state;
|
||||
int ret;
|
||||
int bit;
|
||||
|
@ -255,8 +251,7 @@ static DEVICE_ATTR_RW(rx);
|
|||
static ssize_t interval_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct led_netdev_data *trigger_data = led_cdev->trigger_data;
|
||||
struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%u\n",
|
||||
jiffies_to_msecs(atomic_read(&trigger_data->interval)));
|
||||
|
@ -266,8 +261,7 @@ static ssize_t interval_store(struct device *dev,
|
|||
struct device_attribute *attr, const char *buf,
|
||||
size_t size)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct led_netdev_data *trigger_data = led_cdev->trigger_data;
|
||||
struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev);
|
||||
unsigned long value;
|
||||
int ret;
|
||||
|
||||
|
@ -288,15 +282,23 @@ static ssize_t interval_store(struct device *dev,
|
|||
|
||||
static DEVICE_ATTR_RW(interval);
|
||||
|
||||
static struct attribute *netdev_trig_attrs[] = {
|
||||
&dev_attr_device_name.attr,
|
||||
&dev_attr_link.attr,
|
||||
&dev_attr_rx.attr,
|
||||
&dev_attr_tx.attr,
|
||||
&dev_attr_interval.attr,
|
||||
NULL
|
||||
};
|
||||
ATTRIBUTE_GROUPS(netdev_trig);
|
||||
|
||||
static int netdev_trig_notify(struct notifier_block *nb,
|
||||
unsigned long evt, void *dv)
|
||||
{
|
||||
struct net_device *dev =
|
||||
netdev_notifier_info_to_dev((struct netdev_notifier_info *)dv);
|
||||
struct led_netdev_data *trigger_data = container_of(nb,
|
||||
struct
|
||||
led_netdev_data,
|
||||
notifier);
|
||||
struct led_netdev_data *trigger_data =
|
||||
container_of(nb, struct led_netdev_data, notifier);
|
||||
|
||||
if (evt != NETDEV_UP && evt != NETDEV_DOWN && evt != NETDEV_CHANGE
|
||||
&& evt != NETDEV_REGISTER && evt != NETDEV_UNREGISTER
|
||||
|
@ -342,10 +344,8 @@ static int netdev_trig_notify(struct notifier_block *nb,
|
|||
/* here's the real work! */
|
||||
static void netdev_trig_work(struct work_struct *work)
|
||||
{
|
||||
struct led_netdev_data *trigger_data = container_of(work,
|
||||
struct
|
||||
led_netdev_data,
|
||||
work.work);
|
||||
struct led_netdev_data *trigger_data =
|
||||
container_of(work, struct led_netdev_data, work.work);
|
||||
struct rtnl_link_stats64 *dev_stats;
|
||||
unsigned int new_activity;
|
||||
struct rtnl_link_stats64 temp;
|
||||
|
@ -388,14 +388,14 @@ static void netdev_trig_work(struct work_struct *work)
|
|||
(atomic_read(&trigger_data->interval)*2));
|
||||
}
|
||||
|
||||
static void netdev_trig_activate(struct led_classdev *led_cdev)
|
||||
static int netdev_trig_activate(struct led_classdev *led_cdev)
|
||||
{
|
||||
struct led_netdev_data *trigger_data;
|
||||
int rc;
|
||||
|
||||
trigger_data = kzalloc(sizeof(struct led_netdev_data), GFP_KERNEL);
|
||||
if (!trigger_data)
|
||||
return;
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&trigger_data->lock);
|
||||
|
||||
|
@ -412,69 +412,34 @@ static void netdev_trig_activate(struct led_classdev *led_cdev)
|
|||
atomic_set(&trigger_data->interval, msecs_to_jiffies(50));
|
||||
trigger_data->last_activity = 0;
|
||||
|
||||
led_cdev->trigger_data = trigger_data;
|
||||
led_set_trigger_data(led_cdev, trigger_data);
|
||||
|
||||
rc = device_create_file(led_cdev->dev, &dev_attr_device_name);
|
||||
if (rc)
|
||||
goto err_out;
|
||||
rc = device_create_file(led_cdev->dev, &dev_attr_link);
|
||||
if (rc)
|
||||
goto err_out_device_name;
|
||||
rc = device_create_file(led_cdev->dev, &dev_attr_rx);
|
||||
if (rc)
|
||||
goto err_out_link;
|
||||
rc = device_create_file(led_cdev->dev, &dev_attr_tx);
|
||||
if (rc)
|
||||
goto err_out_rx;
|
||||
rc = device_create_file(led_cdev->dev, &dev_attr_interval);
|
||||
if (rc)
|
||||
goto err_out_tx;
|
||||
rc = register_netdevice_notifier(&trigger_data->notifier);
|
||||
if (rc)
|
||||
goto err_out_interval;
|
||||
return;
|
||||
kfree(trigger_data);
|
||||
|
||||
err_out_interval:
|
||||
device_remove_file(led_cdev->dev, &dev_attr_interval);
|
||||
err_out_tx:
|
||||
device_remove_file(led_cdev->dev, &dev_attr_tx);
|
||||
err_out_rx:
|
||||
device_remove_file(led_cdev->dev, &dev_attr_rx);
|
||||
err_out_link:
|
||||
device_remove_file(led_cdev->dev, &dev_attr_link);
|
||||
err_out_device_name:
|
||||
device_remove_file(led_cdev->dev, &dev_attr_device_name);
|
||||
err_out:
|
||||
led_cdev->trigger_data = NULL;
|
||||
kfree(trigger_data);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void netdev_trig_deactivate(struct led_classdev *led_cdev)
|
||||
{
|
||||
struct led_netdev_data *trigger_data = led_cdev->trigger_data;
|
||||
struct led_netdev_data *trigger_data = led_get_trigger_data(led_cdev);
|
||||
|
||||
if (trigger_data) {
|
||||
unregister_netdevice_notifier(&trigger_data->notifier);
|
||||
unregister_netdevice_notifier(&trigger_data->notifier);
|
||||
|
||||
device_remove_file(led_cdev->dev, &dev_attr_device_name);
|
||||
device_remove_file(led_cdev->dev, &dev_attr_link);
|
||||
device_remove_file(led_cdev->dev, &dev_attr_rx);
|
||||
device_remove_file(led_cdev->dev, &dev_attr_tx);
|
||||
device_remove_file(led_cdev->dev, &dev_attr_interval);
|
||||
cancel_delayed_work_sync(&trigger_data->work);
|
||||
|
||||
cancel_delayed_work_sync(&trigger_data->work);
|
||||
if (trigger_data->net_dev)
|
||||
dev_put(trigger_data->net_dev);
|
||||
|
||||
if (trigger_data->net_dev)
|
||||
dev_put(trigger_data->net_dev);
|
||||
|
||||
kfree(trigger_data);
|
||||
}
|
||||
kfree(trigger_data);
|
||||
}
|
||||
|
||||
static struct led_trigger netdev_led_trigger = {
|
||||
.name = "netdev",
|
||||
.activate = netdev_trig_activate,
|
||||
.deactivate = netdev_trig_deactivate,
|
||||
.groups = netdev_trig_groups,
|
||||
};
|
||||
|
||||
static int __init netdev_trig_init(void)
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
* 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/module.h>
|
||||
|
@ -29,8 +28,8 @@ struct oneshot_trig_data {
|
|||
static ssize_t led_shot(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t size)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct oneshot_trig_data *oneshot_data = led_cdev->trigger_data;
|
||||
struct led_classdev *led_cdev = led_trigger_get_led(dev);
|
||||
struct oneshot_trig_data *oneshot_data = led_trigger_get_drvdata(dev);
|
||||
|
||||
led_blink_set_oneshot(led_cdev,
|
||||
&led_cdev->blink_delay_on, &led_cdev->blink_delay_off,
|
||||
|
@ -42,8 +41,7 @@ static ssize_t led_shot(struct device *dev,
|
|||
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 oneshot_trig_data *oneshot_data = led_cdev->trigger_data;
|
||||
struct oneshot_trig_data *oneshot_data = led_trigger_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%u\n", oneshot_data->invert);
|
||||
}
|
||||
|
@ -51,8 +49,8 @@ static ssize_t led_invert_show(struct device *dev,
|
|||
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 oneshot_trig_data *oneshot_data = led_cdev->trigger_data;
|
||||
struct led_classdev *led_cdev = led_trigger_get_led(dev);
|
||||
struct oneshot_trig_data *oneshot_data = led_trigger_get_drvdata(dev);
|
||||
unsigned long state;
|
||||
int ret;
|
||||
|
||||
|
@ -73,7 +71,7 @@ static ssize_t led_invert_store(struct device *dev,
|
|||
static ssize_t led_delay_on_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct led_classdev *led_cdev = led_trigger_get_led(dev);
|
||||
|
||||
return sprintf(buf, "%lu\n", led_cdev->blink_delay_on);
|
||||
}
|
||||
|
@ -81,7 +79,7 @@ static ssize_t led_delay_on_show(struct device *dev,
|
|||
static ssize_t led_delay_on_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t size)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct led_classdev *led_cdev = led_trigger_get_led(dev);
|
||||
unsigned long state;
|
||||
int ret;
|
||||
|
||||
|
@ -93,10 +91,11 @@ static ssize_t led_delay_on_store(struct device *dev,
|
|||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t led_delay_off_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct led_classdev *led_cdev = led_trigger_get_led(dev);
|
||||
|
||||
return sprintf(buf, "%lu\n", led_cdev->blink_delay_off);
|
||||
}
|
||||
|
@ -104,7 +103,7 @@ static ssize_t led_delay_off_show(struct device *dev,
|
|||
static ssize_t led_delay_off_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t size)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct led_classdev *led_cdev = led_trigger_get_led(dev);
|
||||
unsigned long state;
|
||||
int ret;
|
||||
|
||||
|
@ -122,59 +121,36 @@ static DEVICE_ATTR(delay_off, 0644, led_delay_off_show, led_delay_off_store);
|
|||
static DEVICE_ATTR(invert, 0644, led_invert_show, led_invert_store);
|
||||
static DEVICE_ATTR(shot, 0200, NULL, led_shot);
|
||||
|
||||
static void oneshot_trig_activate(struct led_classdev *led_cdev)
|
||||
static struct attribute *oneshot_trig_attrs[] = {
|
||||
&dev_attr_delay_on.attr,
|
||||
&dev_attr_delay_off.attr,
|
||||
&dev_attr_invert.attr,
|
||||
&dev_attr_shot.attr,
|
||||
NULL
|
||||
};
|
||||
ATTRIBUTE_GROUPS(oneshot_trig);
|
||||
|
||||
static int oneshot_trig_activate(struct led_classdev *led_cdev)
|
||||
{
|
||||
struct oneshot_trig_data *oneshot_data;
|
||||
int rc;
|
||||
|
||||
oneshot_data = kzalloc(sizeof(*oneshot_data), GFP_KERNEL);
|
||||
if (!oneshot_data)
|
||||
return;
|
||||
return -ENOMEM;
|
||||
|
||||
led_cdev->trigger_data = oneshot_data;
|
||||
|
||||
rc = device_create_file(led_cdev->dev, &dev_attr_delay_on);
|
||||
if (rc)
|
||||
goto err_out_trig_data;
|
||||
rc = device_create_file(led_cdev->dev, &dev_attr_delay_off);
|
||||
if (rc)
|
||||
goto err_out_delayon;
|
||||
rc = device_create_file(led_cdev->dev, &dev_attr_invert);
|
||||
if (rc)
|
||||
goto err_out_delayoff;
|
||||
rc = device_create_file(led_cdev->dev, &dev_attr_shot);
|
||||
if (rc)
|
||||
goto err_out_invert;
|
||||
led_set_trigger_data(led_cdev, oneshot_data);
|
||||
|
||||
led_cdev->blink_delay_on = DEFAULT_DELAY;
|
||||
led_cdev->blink_delay_off = DEFAULT_DELAY;
|
||||
|
||||
led_cdev->activated = true;
|
||||
|
||||
return;
|
||||
|
||||
err_out_invert:
|
||||
device_remove_file(led_cdev->dev, &dev_attr_invert);
|
||||
err_out_delayoff:
|
||||
device_remove_file(led_cdev->dev, &dev_attr_delay_off);
|
||||
err_out_delayon:
|
||||
device_remove_file(led_cdev->dev, &dev_attr_delay_on);
|
||||
err_out_trig_data:
|
||||
kfree(led_cdev->trigger_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void oneshot_trig_deactivate(struct led_classdev *led_cdev)
|
||||
{
|
||||
struct oneshot_trig_data *oneshot_data = led_cdev->trigger_data;
|
||||
struct oneshot_trig_data *oneshot_data = led_get_trigger_data(led_cdev);
|
||||
|
||||
if (led_cdev->activated) {
|
||||
device_remove_file(led_cdev->dev, &dev_attr_delay_on);
|
||||
device_remove_file(led_cdev->dev, &dev_attr_delay_off);
|
||||
device_remove_file(led_cdev->dev, &dev_attr_invert);
|
||||
device_remove_file(led_cdev->dev, &dev_attr_shot);
|
||||
kfree(oneshot_data);
|
||||
led_cdev->activated = false;
|
||||
}
|
||||
kfree(oneshot_data);
|
||||
|
||||
/* Stop blinking */
|
||||
led_set_brightness(led_cdev, LED_OFF);
|
||||
|
@ -184,20 +160,9 @@ static struct led_trigger oneshot_led_trigger = {
|
|||
.name = "oneshot",
|
||||
.activate = oneshot_trig_activate,
|
||||
.deactivate = oneshot_trig_deactivate,
|
||||
.groups = oneshot_trig_groups,
|
||||
};
|
||||
|
||||
static int __init oneshot_trig_init(void)
|
||||
{
|
||||
return led_trigger_register(&oneshot_led_trigger);
|
||||
}
|
||||
|
||||
static void __exit oneshot_trig_exit(void)
|
||||
{
|
||||
led_trigger_unregister(&oneshot_led_trigger);
|
||||
}
|
||||
|
||||
module_init(oneshot_trig_init);
|
||||
module_exit(oneshot_trig_exit);
|
||||
module_led_trigger(oneshot_led_trigger);
|
||||
|
||||
MODULE_AUTHOR("Fabio Baltieri <fabio.baltieri@gmail.com>");
|
||||
MODULE_DESCRIPTION("One-shot LED trigger");
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
* 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/module.h>
|
||||
|
@ -21,7 +20,7 @@
|
|||
static ssize_t led_delay_on_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct led_classdev *led_cdev = led_trigger_get_led(dev);
|
||||
|
||||
return sprintf(buf, "%lu\n", led_cdev->blink_delay_on);
|
||||
}
|
||||
|
@ -29,7 +28,7 @@ static ssize_t led_delay_on_show(struct device *dev,
|
|||
static ssize_t led_delay_on_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t size)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct led_classdev *led_cdev = led_trigger_get_led(dev);
|
||||
unsigned long state;
|
||||
ssize_t ret = -EINVAL;
|
||||
|
||||
|
@ -46,7 +45,7 @@ static ssize_t led_delay_on_store(struct device *dev,
|
|||
static ssize_t led_delay_off_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct led_classdev *led_cdev = led_trigger_get_led(dev);
|
||||
|
||||
return sprintf(buf, "%lu\n", led_cdev->blink_delay_off);
|
||||
}
|
||||
|
@ -54,7 +53,7 @@ static ssize_t led_delay_off_show(struct device *dev,
|
|||
static ssize_t led_delay_off_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t size)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct led_classdev *led_cdev = led_trigger_get_led(dev);
|
||||
unsigned long state;
|
||||
ssize_t ret = -EINVAL;
|
||||
|
||||
|
@ -71,37 +70,23 @@ static ssize_t led_delay_off_store(struct device *dev,
|
|||
static DEVICE_ATTR(delay_on, 0644, led_delay_on_show, led_delay_on_store);
|
||||
static DEVICE_ATTR(delay_off, 0644, led_delay_off_show, led_delay_off_store);
|
||||
|
||||
static void timer_trig_activate(struct led_classdev *led_cdev)
|
||||
static struct attribute *timer_trig_attrs[] = {
|
||||
&dev_attr_delay_on.attr,
|
||||
&dev_attr_delay_off.attr,
|
||||
NULL
|
||||
};
|
||||
ATTRIBUTE_GROUPS(timer_trig);
|
||||
|
||||
static int timer_trig_activate(struct led_classdev *led_cdev)
|
||||
{
|
||||
int rc;
|
||||
|
||||
led_cdev->trigger_data = NULL;
|
||||
|
||||
rc = device_create_file(led_cdev->dev, &dev_attr_delay_on);
|
||||
if (rc)
|
||||
return;
|
||||
rc = device_create_file(led_cdev->dev, &dev_attr_delay_off);
|
||||
if (rc)
|
||||
goto err_out_delayon;
|
||||
|
||||
led_blink_set(led_cdev, &led_cdev->blink_delay_on,
|
||||
&led_cdev->blink_delay_off);
|
||||
led_cdev->activated = true;
|
||||
|
||||
return;
|
||||
|
||||
err_out_delayon:
|
||||
device_remove_file(led_cdev->dev, &dev_attr_delay_on);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void timer_trig_deactivate(struct led_classdev *led_cdev)
|
||||
{
|
||||
if (led_cdev->activated) {
|
||||
device_remove_file(led_cdev->dev, &dev_attr_delay_on);
|
||||
device_remove_file(led_cdev->dev, &dev_attr_delay_off);
|
||||
led_cdev->activated = false;
|
||||
}
|
||||
|
||||
/* Stop blinking */
|
||||
led_set_brightness(led_cdev, LED_OFF);
|
||||
}
|
||||
|
@ -110,21 +95,10 @@ static struct led_trigger timer_led_trigger = {
|
|||
.name = "timer",
|
||||
.activate = timer_trig_activate,
|
||||
.deactivate = timer_trig_deactivate,
|
||||
.groups = timer_trig_groups,
|
||||
};
|
||||
|
||||
static int __init timer_trig_init(void)
|
||||
{
|
||||
return led_trigger_register(&timer_led_trigger);
|
||||
}
|
||||
|
||||
static void __exit timer_trig_exit(void)
|
||||
{
|
||||
led_trigger_unregister(&timer_led_trigger);
|
||||
}
|
||||
|
||||
module_init(timer_trig_init);
|
||||
module_exit(timer_trig_exit);
|
||||
module_led_trigger(timer_led_trigger);
|
||||
|
||||
MODULE_AUTHOR("Richard Purdie <rpurdie@openedhand.com>");
|
||||
MODULE_DESCRIPTION("Timer LED trigger");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -42,8 +42,8 @@ static void transient_timer_function(struct timer_list *t)
|
|||
static ssize_t transient_activate_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct transient_trig_data *transient_data = led_cdev->trigger_data;
|
||||
struct transient_trig_data *transient_data =
|
||||
led_trigger_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%d\n", transient_data->activate);
|
||||
}
|
||||
|
@ -51,8 +51,9 @@ static ssize_t transient_activate_show(struct device *dev,
|
|||
static ssize_t transient_activate_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t size)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct transient_trig_data *transient_data = led_cdev->trigger_data;
|
||||
struct led_classdev *led_cdev = led_trigger_get_led(dev);
|
||||
struct transient_trig_data *transient_data =
|
||||
led_trigger_get_drvdata(dev);
|
||||
unsigned long state;
|
||||
ssize_t ret;
|
||||
|
||||
|
@ -94,8 +95,7 @@ static ssize_t transient_activate_store(struct device *dev,
|
|||
static ssize_t transient_duration_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct transient_trig_data *transient_data = led_cdev->trigger_data;
|
||||
struct transient_trig_data *transient_data = led_trigger_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%lu\n", transient_data->duration);
|
||||
}
|
||||
|
@ -103,8 +103,8 @@ static ssize_t transient_duration_show(struct device *dev,
|
|||
static ssize_t transient_duration_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t size)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct transient_trig_data *transient_data = led_cdev->trigger_data;
|
||||
struct transient_trig_data *transient_data =
|
||||
led_trigger_get_drvdata(dev);
|
||||
unsigned long state;
|
||||
ssize_t ret;
|
||||
|
||||
|
@ -119,8 +119,8 @@ static ssize_t transient_duration_store(struct device *dev,
|
|||
static ssize_t transient_state_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct transient_trig_data *transient_data = led_cdev->trigger_data;
|
||||
struct transient_trig_data *transient_data =
|
||||
led_trigger_get_drvdata(dev);
|
||||
int state;
|
||||
|
||||
state = (transient_data->state == LED_FULL) ? 1 : 0;
|
||||
|
@ -130,8 +130,8 @@ static ssize_t transient_state_show(struct device *dev,
|
|||
static ssize_t transient_state_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t size)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct transient_trig_data *transient_data = led_cdev->trigger_data;
|
||||
struct transient_trig_data *transient_data =
|
||||
led_trigger_get_drvdata(dev);
|
||||
unsigned long state;
|
||||
ssize_t ret;
|
||||
|
||||
|
@ -152,82 +152,46 @@ static DEVICE_ATTR(duration, 0644, transient_duration_show,
|
|||
transient_duration_store);
|
||||
static DEVICE_ATTR(state, 0644, transient_state_show, transient_state_store);
|
||||
|
||||
static void transient_trig_activate(struct led_classdev *led_cdev)
|
||||
static struct attribute *transient_trig_attrs[] = {
|
||||
&dev_attr_activate.attr,
|
||||
&dev_attr_duration.attr,
|
||||
&dev_attr_state.attr,
|
||||
NULL
|
||||
};
|
||||
ATTRIBUTE_GROUPS(transient_trig);
|
||||
|
||||
static int transient_trig_activate(struct led_classdev *led_cdev)
|
||||
{
|
||||
int rc;
|
||||
struct transient_trig_data *tdata;
|
||||
|
||||
tdata = kzalloc(sizeof(struct transient_trig_data), GFP_KERNEL);
|
||||
if (!tdata) {
|
||||
dev_err(led_cdev->dev,
|
||||
"unable to allocate transient trigger\n");
|
||||
return;
|
||||
}
|
||||
led_cdev->trigger_data = tdata;
|
||||
if (!tdata)
|
||||
return -ENOMEM;
|
||||
|
||||
led_set_trigger_data(led_cdev, tdata);
|
||||
tdata->led_cdev = led_cdev;
|
||||
|
||||
rc = device_create_file(led_cdev->dev, &dev_attr_activate);
|
||||
if (rc)
|
||||
goto err_out;
|
||||
|
||||
rc = device_create_file(led_cdev->dev, &dev_attr_duration);
|
||||
if (rc)
|
||||
goto err_out_duration;
|
||||
|
||||
rc = device_create_file(led_cdev->dev, &dev_attr_state);
|
||||
if (rc)
|
||||
goto err_out_state;
|
||||
|
||||
timer_setup(&tdata->timer, transient_timer_function, 0);
|
||||
led_cdev->activated = true;
|
||||
|
||||
return;
|
||||
|
||||
err_out_state:
|
||||
device_remove_file(led_cdev->dev, &dev_attr_duration);
|
||||
err_out_duration:
|
||||
device_remove_file(led_cdev->dev, &dev_attr_activate);
|
||||
err_out:
|
||||
dev_err(led_cdev->dev, "unable to register transient trigger\n");
|
||||
led_cdev->trigger_data = NULL;
|
||||
kfree(tdata);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void transient_trig_deactivate(struct led_classdev *led_cdev)
|
||||
{
|
||||
struct transient_trig_data *transient_data = led_cdev->trigger_data;
|
||||
struct transient_trig_data *transient_data = led_get_trigger_data(led_cdev);
|
||||
|
||||
if (led_cdev->activated) {
|
||||
del_timer_sync(&transient_data->timer);
|
||||
led_set_brightness_nosleep(led_cdev,
|
||||
transient_data->restore_state);
|
||||
device_remove_file(led_cdev->dev, &dev_attr_activate);
|
||||
device_remove_file(led_cdev->dev, &dev_attr_duration);
|
||||
device_remove_file(led_cdev->dev, &dev_attr_state);
|
||||
led_cdev->trigger_data = NULL;
|
||||
led_cdev->activated = false;
|
||||
kfree(transient_data);
|
||||
}
|
||||
del_timer_sync(&transient_data->timer);
|
||||
led_set_brightness_nosleep(led_cdev, transient_data->restore_state);
|
||||
kfree(transient_data);
|
||||
}
|
||||
|
||||
static struct led_trigger transient_trigger = {
|
||||
.name = "transient",
|
||||
.activate = transient_trig_activate,
|
||||
.deactivate = transient_trig_deactivate,
|
||||
.groups = transient_trig_groups,
|
||||
};
|
||||
|
||||
static int __init transient_trig_init(void)
|
||||
{
|
||||
return led_trigger_register(&transient_trigger);
|
||||
}
|
||||
|
||||
static void __exit transient_trig_exit(void)
|
||||
{
|
||||
led_trigger_unregister(&transient_trigger);
|
||||
}
|
||||
|
||||
module_init(transient_trig_init);
|
||||
module_exit(transient_trig_exit);
|
||||
module_led_trigger(transient_trigger);
|
||||
|
||||
MODULE_AUTHOR("Shuah Khan <shuahkhan@gmail.com>");
|
||||
MODULE_DESCRIPTION("Transient LED trigger");
|
||||
|
|
|
@ -73,6 +73,12 @@ config CAN_CALC_BITTIMING
|
|||
config CAN_LEDS
|
||||
bool "Enable LED triggers for Netlink based drivers"
|
||||
depends on LEDS_CLASS
|
||||
# The netdev trigger (LEDS_TRIGGER_NETDEV) should be able to do
|
||||
# everything that this driver is doing. This is marked as broken
|
||||
# because it uses stuff that is intended to be changed or removed.
|
||||
# Please consider switching to the netdev trigger and confirm it
|
||||
# fulfills your needs instead of fixing this driver.
|
||||
depends on BROKEN
|
||||
select LEDS_TRIGGERS
|
||||
---help---
|
||||
This option adds two LED triggers for packet receive and transmit
|
||||
|
|
|
@ -959,7 +959,7 @@ struct kbd_led_trigger {
|
|||
unsigned int mask;
|
||||
};
|
||||
|
||||
static void kbd_led_trigger_activate(struct led_classdev *cdev)
|
||||
static int kbd_led_trigger_activate(struct led_classdev *cdev)
|
||||
{
|
||||
struct kbd_led_trigger *trigger =
|
||||
container_of(cdev->trigger, struct kbd_led_trigger, trigger);
|
||||
|
@ -970,6 +970,8 @@ static void kbd_led_trigger_activate(struct led_classdev *cdev)
|
|||
ledstate & trigger->mask ?
|
||||
LED_FULL : LED_OFF);
|
||||
tasklet_enable(&keyboard_tasklet);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define KBD_LED_TRIGGER(_led_bit, _name) { \
|
||||
|
|
|
@ -113,11 +113,17 @@ static ssize_t usbport_trig_port_store(struct device *dev,
|
|||
static struct attribute *ports_attrs[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group ports_group = {
|
||||
.name = "ports",
|
||||
.attrs = ports_attrs,
|
||||
};
|
||||
|
||||
static const struct attribute_group *ports_groups[] = {
|
||||
&ports_group,
|
||||
NULL
|
||||
};
|
||||
|
||||
/***************************************
|
||||
* Adding & removing ports
|
||||
***************************************/
|
||||
|
@ -298,61 +304,47 @@ static int usbport_trig_notify(struct notifier_block *nb, unsigned long action,
|
|||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static void usbport_trig_activate(struct led_classdev *led_cdev)
|
||||
static int usbport_trig_activate(struct led_classdev *led_cdev)
|
||||
{
|
||||
struct usbport_trig_data *usbport_data;
|
||||
int err;
|
||||
|
||||
usbport_data = kzalloc(sizeof(*usbport_data), GFP_KERNEL);
|
||||
if (!usbport_data)
|
||||
return;
|
||||
return -ENOMEM;
|
||||
usbport_data->led_cdev = led_cdev;
|
||||
|
||||
/* List of ports */
|
||||
INIT_LIST_HEAD(&usbport_data->ports);
|
||||
err = sysfs_create_group(&led_cdev->dev->kobj, &ports_group);
|
||||
if (err)
|
||||
goto err_free;
|
||||
usb_for_each_dev(usbport_data, usbport_trig_add_usb_dev_ports);
|
||||
usbport_trig_update_count(usbport_data);
|
||||
|
||||
/* Notifications */
|
||||
usbport_data->nb.notifier_call = usbport_trig_notify,
|
||||
led_cdev->trigger_data = usbport_data;
|
||||
usbport_data->nb.notifier_call = usbport_trig_notify;
|
||||
led_set_trigger_data(led_cdev, usbport_data);
|
||||
usb_register_notify(&usbport_data->nb);
|
||||
|
||||
led_cdev->activated = true;
|
||||
return;
|
||||
|
||||
err_free:
|
||||
kfree(usbport_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void usbport_trig_deactivate(struct led_classdev *led_cdev)
|
||||
{
|
||||
struct usbport_trig_data *usbport_data = led_cdev->trigger_data;
|
||||
struct usbport_trig_data *usbport_data = led_get_trigger_data(led_cdev);
|
||||
struct usbport_trig_port *port, *tmp;
|
||||
|
||||
if (!led_cdev->activated)
|
||||
return;
|
||||
|
||||
list_for_each_entry_safe(port, tmp, &usbport_data->ports, list) {
|
||||
usbport_trig_remove_port(usbport_data, port);
|
||||
}
|
||||
|
||||
usb_unregister_notify(&usbport_data->nb);
|
||||
|
||||
sysfs_remove_group(&led_cdev->dev->kobj, &ports_group);
|
||||
|
||||
kfree(usbport_data);
|
||||
|
||||
led_cdev->activated = false;
|
||||
}
|
||||
|
||||
static struct led_trigger usbport_led_trigger = {
|
||||
.name = "usbport",
|
||||
.activate = usbport_trig_activate,
|
||||
.deactivate = usbport_trig_deactivate,
|
||||
.groups = ports_groups,
|
||||
};
|
||||
|
||||
static int __init usbport_trig_init(void)
|
||||
|
|
|
@ -253,7 +253,7 @@ static inline bool led_sysfs_is_disabled(struct led_classdev *led_cdev)
|
|||
struct led_trigger {
|
||||
/* Trigger Properties */
|
||||
const char *name;
|
||||
void (*activate)(struct led_classdev *led_cdev);
|
||||
int (*activate)(struct led_classdev *led_cdev);
|
||||
void (*deactivate)(struct led_classdev *led_cdev);
|
||||
|
||||
/* LEDs under control by this trigger (for simple triggers) */
|
||||
|
@ -262,8 +262,19 @@ struct led_trigger {
|
|||
|
||||
/* Link to next registered trigger */
|
||||
struct list_head next_trig;
|
||||
|
||||
const struct attribute_group **groups;
|
||||
};
|
||||
|
||||
/*
|
||||
* Currently the attributes in struct led_trigger::groups are added directly to
|
||||
* the LED device. As this might change in the future, the following
|
||||
* macros abstract getting the LED device and its trigger_data from the dev
|
||||
* parameter passed to the attribute accessor functions.
|
||||
*/
|
||||
#define led_trigger_get_led(dev) ((struct led_classdev *)dev_get_drvdata((dev)))
|
||||
#define led_trigger_get_drvdata(dev) (led_get_trigger_data(led_trigger_get_led(dev)))
|
||||
|
||||
ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count);
|
||||
ssize_t led_trigger_show(struct device *dev, struct device_attribute *attr,
|
||||
|
@ -288,10 +299,16 @@ extern void led_trigger_blink_oneshot(struct led_trigger *trigger,
|
|||
unsigned long *delay_off,
|
||||
int invert);
|
||||
extern void led_trigger_set_default(struct led_classdev *led_cdev);
|
||||
extern void led_trigger_set(struct led_classdev *led_cdev,
|
||||
struct led_trigger *trigger);
|
||||
extern int led_trigger_set(struct led_classdev *led_cdev,
|
||||
struct led_trigger *trigger);
|
||||
extern void led_trigger_remove(struct led_classdev *led_cdev);
|
||||
|
||||
static inline void led_set_trigger_data(struct led_classdev *led_cdev,
|
||||
void *trigger_data)
|
||||
{
|
||||
led_cdev->trigger_data = trigger_data;
|
||||
}
|
||||
|
||||
static inline void *led_get_trigger_data(struct led_classdev *led_cdev)
|
||||
{
|
||||
return led_cdev->trigger_data;
|
||||
|
@ -315,6 +332,10 @@ static inline void *led_get_trigger_data(struct led_classdev *led_cdev)
|
|||
extern void led_trigger_rename_static(const char *name,
|
||||
struct led_trigger *trig);
|
||||
|
||||
#define module_led_trigger(__led_trigger) \
|
||||
module_driver(__led_trigger, led_trigger_register, \
|
||||
led_trigger_unregister)
|
||||
|
||||
#else
|
||||
|
||||
/* Trigger has no members */
|
||||
|
@ -334,9 +355,14 @@ static inline void led_trigger_blink_oneshot(struct led_trigger *trigger,
|
|||
unsigned long *delay_off,
|
||||
int invert) {}
|
||||
static inline void led_trigger_set_default(struct led_classdev *led_cdev) {}
|
||||
static inline void led_trigger_set(struct led_classdev *led_cdev,
|
||||
struct led_trigger *trigger) {}
|
||||
static inline int led_trigger_set(struct led_classdev *led_cdev,
|
||||
struct led_trigger *trigger)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void led_trigger_remove(struct led_classdev *led_cdev) {}
|
||||
static inline void led_set_trigger_data(struct led_classdev *led_cdev) {}
|
||||
static inline void *led_get_trigger_data(struct led_classdev *led_cdev)
|
||||
{
|
||||
return NULL;
|
||||
|
|
|
@ -43,7 +43,7 @@ void hci_leds_update_powered(struct hci_dev *hdev, bool enabled)
|
|||
led_trigger_event(bt_power_led_trigger, enabled ? LED_FULL : LED_OFF);
|
||||
}
|
||||
|
||||
static void power_activate(struct led_classdev *led_cdev)
|
||||
static int power_activate(struct led_classdev *led_cdev)
|
||||
{
|
||||
struct hci_basic_led_trigger *htrig;
|
||||
bool powered;
|
||||
|
@ -52,10 +52,12 @@ static void power_activate(struct led_classdev *led_cdev)
|
|||
powered = test_bit(HCI_UP, &htrig->hdev->flags);
|
||||
|
||||
led_trigger_event(led_cdev->trigger, powered ? LED_FULL : LED_OFF);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct led_trigger *led_allocate_basic(struct hci_dev *hdev,
|
||||
void (*activate)(struct led_classdev *led_cdev),
|
||||
int (*activate)(struct led_classdev *led_cdev),
|
||||
const char *name)
|
||||
{
|
||||
struct hci_basic_led_trigger *htrig;
|
||||
|
|
|
@ -52,13 +52,15 @@ void ieee80211_free_led_names(struct ieee80211_local *local)
|
|||
kfree(local->radio_led.name);
|
||||
}
|
||||
|
||||
static void ieee80211_tx_led_activate(struct led_classdev *led_cdev)
|
||||
static int ieee80211_tx_led_activate(struct led_classdev *led_cdev)
|
||||
{
|
||||
struct ieee80211_local *local = container_of(led_cdev->trigger,
|
||||
struct ieee80211_local,
|
||||
tx_led);
|
||||
|
||||
atomic_inc(&local->tx_led_active);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ieee80211_tx_led_deactivate(struct led_classdev *led_cdev)
|
||||
|
@ -70,13 +72,15 @@ static void ieee80211_tx_led_deactivate(struct led_classdev *led_cdev)
|
|||
atomic_dec(&local->tx_led_active);
|
||||
}
|
||||
|
||||
static void ieee80211_rx_led_activate(struct led_classdev *led_cdev)
|
||||
static int ieee80211_rx_led_activate(struct led_classdev *led_cdev)
|
||||
{
|
||||
struct ieee80211_local *local = container_of(led_cdev->trigger,
|
||||
struct ieee80211_local,
|
||||
rx_led);
|
||||
|
||||
atomic_inc(&local->rx_led_active);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ieee80211_rx_led_deactivate(struct led_classdev *led_cdev)
|
||||
|
@ -88,13 +92,15 @@ static void ieee80211_rx_led_deactivate(struct led_classdev *led_cdev)
|
|||
atomic_dec(&local->rx_led_active);
|
||||
}
|
||||
|
||||
static void ieee80211_assoc_led_activate(struct led_classdev *led_cdev)
|
||||
static int ieee80211_assoc_led_activate(struct led_classdev *led_cdev)
|
||||
{
|
||||
struct ieee80211_local *local = container_of(led_cdev->trigger,
|
||||
struct ieee80211_local,
|
||||
assoc_led);
|
||||
|
||||
atomic_inc(&local->assoc_led_active);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ieee80211_assoc_led_deactivate(struct led_classdev *led_cdev)
|
||||
|
@ -106,13 +112,15 @@ static void ieee80211_assoc_led_deactivate(struct led_classdev *led_cdev)
|
|||
atomic_dec(&local->assoc_led_active);
|
||||
}
|
||||
|
||||
static void ieee80211_radio_led_activate(struct led_classdev *led_cdev)
|
||||
static int ieee80211_radio_led_activate(struct led_classdev *led_cdev)
|
||||
{
|
||||
struct ieee80211_local *local = container_of(led_cdev->trigger,
|
||||
struct ieee80211_local,
|
||||
radio_led);
|
||||
|
||||
atomic_inc(&local->radio_led_active);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ieee80211_radio_led_deactivate(struct led_classdev *led_cdev)
|
||||
|
@ -124,13 +132,15 @@ static void ieee80211_radio_led_deactivate(struct led_classdev *led_cdev)
|
|||
atomic_dec(&local->radio_led_active);
|
||||
}
|
||||
|
||||
static void ieee80211_tpt_led_activate(struct led_classdev *led_cdev)
|
||||
static int ieee80211_tpt_led_activate(struct led_classdev *led_cdev)
|
||||
{
|
||||
struct ieee80211_local *local = container_of(led_cdev->trigger,
|
||||
struct ieee80211_local,
|
||||
tpt_led);
|
||||
|
||||
atomic_inc(&local->tpt_led_active);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ieee80211_tpt_led_deactivate(struct led_classdev *led_cdev)
|
||||
|
|
|
@ -141,13 +141,15 @@ static void rfkill_led_trigger_event(struct rfkill *rfkill)
|
|||
led_trigger_event(trigger, LED_FULL);
|
||||
}
|
||||
|
||||
static void rfkill_led_trigger_activate(struct led_classdev *led)
|
||||
static int rfkill_led_trigger_activate(struct led_classdev *led)
|
||||
{
|
||||
struct rfkill *rfkill;
|
||||
|
||||
rfkill = container_of(led->trigger, struct rfkill, led_trigger);
|
||||
|
||||
rfkill_led_trigger_event(rfkill);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *rfkill_get_led_trigger_name(struct rfkill *rfkill)
|
||||
|
|
Загрузка…
Ссылка в новой задаче