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:
Linus Torvalds 2018-08-14 13:07:22 -07:00
commit c07b3682cd
28 changed files with 641 additions and 619 deletions

View File

@ -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),

View File

@ -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

View File

@ -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";
};
};

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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");

View File

@ -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;

View File

@ -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. */

View File

@ -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.

View File

@ -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");

View File

@ -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");

View File

@ -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");

View File

@ -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");

View File

@ -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");

View File

@ -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");

View File

@ -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)

View File

@ -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");

View File

@ -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");

View File

@ -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");

View File

@ -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

View File

@ -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) { \

View File

@ -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)

View File

@ -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;

View File

@ -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;

View File

@ -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)

View File

@ -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)