From 8a7a76c80043879b891ad2c291aa0fd8166a48d6 Mon Sep 17 00:00:00 2001 From: Dan Murphy Date: Wed, 15 Nov 2017 13:52:12 -0600 Subject: leds: lp8860: Fix linuxdoc format for structure Fix the linuxdoc format defining the lp8860 structure. Signed-off-by: Dan Murphy Signed-off-by: Jacek Anaszewski --- drivers/leds/leds-lp8860.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/leds') diff --git a/drivers/leds/leds-lp8860.c b/drivers/leds/leds-lp8860.c index 3e70775a2d54..91b6c5fbd361 100644 --- a/drivers/leds/leds-lp8860.c +++ b/drivers/leds/leds-lp8860.c @@ -98,7 +98,7 @@ * @enable_gpio - VDDIO/EN gpio to enable communication interface * @regulator - LED supply regulator pointer * @label - LED label -**/ + */ struct lp8860_led { struct mutex lock; struct i2c_client *client; -- cgit v1.2.3 From b12ef03a38b20e1bfaa163ed1632625fedd570ee Mon Sep 17 00:00:00 2001 From: Dan Murphy Date: Wed, 15 Nov 2017 13:52:13 -0600 Subject: leds: lp8860: Add regulator enable during init Add the regulator enable call during initialization. If init fails then disable the regulator. Also during init the gpio gets set low even on a passing case so add if everything passes then return. Signed-off-by: Dan Murphy Signed-off-by: Jacek Anaszewski --- drivers/leds/leds-lp8860.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) (limited to 'drivers/leds') diff --git a/drivers/leds/leds-lp8860.c b/drivers/leds/leds-lp8860.c index 91b6c5fbd361..f91a4fe25168 100644 --- a/drivers/leds/leds-lp8860.c +++ b/drivers/leds/leds-lp8860.c @@ -247,6 +247,15 @@ static int lp8860_init(struct lp8860_led *led) unsigned int read_buf; int ret, i, reg_count; + if (led->regulator) { + ret = regulator_enable(led->regulator); + if (ret) { + dev_err(&led->client->dev, + "Failed to enable regulator\n"); + return ret; + } + } + if (led->enable_gpio) gpiod_direction_output(led->enable_gpio, 1); @@ -282,12 +291,25 @@ static int lp8860_init(struct lp8860_led *led) ret = regmap_write(led->regmap, LP8860_EEPROM_CNTRL, LP8860_PROGRAM_EEPROM); - if (ret) + if (ret) { dev_err(&led->client->dev, "Failed programming EEPROM\n"); + goto out; + } + + return ret; + out: if (ret) if (led->enable_gpio) gpiod_direction_output(led->enable_gpio, 0); + + if (led->regulator) { + ret = regulator_disable(led->regulator); + if (ret) + dev_err(&led->client->dev, + "Failed to disable regulator\n"); + } + return ret; } -- cgit v1.2.3 From e82e34ba30ca0cc716c213fcc995586d9dd644ee Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sat, 18 Nov 2017 18:22:46 -0200 Subject: leds: pwm: Remove unneeded header file There is nothing provided by that is used here, so remove this unneeded header file. Signed-off-by: Fabio Estevam Signed-off-by: Jacek Anaszewski --- drivers/leds/leds-pwm.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/leds') diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c index 8d456dc6c5bf..df80c89ebe7f 100644 --- a/drivers/leds/leds-pwm.c +++ b/drivers/leds/leds-pwm.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3 From a72d3b5dc68dea113c10bc31404cebe834eb0e49 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 30 Nov 2017 14:36:41 +0100 Subject: ledtrig-activity: Grammar s/a immediate/an immediate/ Fixes: 7df4f9a9f0667ee6 ("leds: ledtrig-activity: Add a system activity LED trigger") Signed-off-by: Geert Uytterhoeven Signed-off-by: Jacek Anaszewski --- drivers/leds/trigger/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/leds') diff --git a/drivers/leds/trigger/Kconfig b/drivers/leds/trigger/Kconfig index bb090216b4dc..6dac48c457d1 100644 --- a/drivers/leds/trigger/Kconfig +++ b/drivers/leds/trigger/Kconfig @@ -81,7 +81,7 @@ config LEDS_TRIGGER_ACTIVITY tristate "LED activity Trigger" depends on LEDS_TRIGGERS help - This allows LEDs to be controlled by a immediate CPU usage. + This allows LEDs to be controlled by an immediate CPU usage. The flash frequency and duty cycle varies from faint flashes to intense brightness depending on the instant CPU load. If unsure, say N. -- cgit v1.2.3 From e0d422987936958b41999f62ea64f1dd0102606f Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 4 Dec 2017 15:45:29 +0100 Subject: leds: blinkm: avoid uninitialized data use gcc-8 reports missing error handling in blinkm_detect, when blinkm() fails, tmpargs[] is uninitialized: drivers/leds/leds-blinkm.c: In function 'blinkm_detect': drivers/leds/leds-blinkm.c:555:6: error: 'tmpargs' may be used uninitialized in this function [-Werror=maybe-uninitialized] This adds a missing error checks. Signed-off-by: Arnd Bergmann Signed-off-by: Jacek Anaszewski --- drivers/leds/leds-blinkm.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/leds') diff --git a/drivers/leds/leds-blinkm.c b/drivers/leds/leds-blinkm.c index d03ed6b4176b..851c1920b63c 100644 --- a/drivers/leds/leds-blinkm.c +++ b/drivers/leds/leds-blinkm.c @@ -549,8 +549,12 @@ static int blinkm_detect(struct i2c_client *client, struct i2c_board_info *info) /* make sure the blinkM is balanced (read/writes) */ while (count > 0) { ret = blinkm_write(client, BLM_GET_ADDR, NULL); + if (ret) + return ret; usleep_range(5000, 10000); ret = blinkm_read(client, BLM_GET_ADDR, tmpargs); + if (ret) + return ret; usleep_range(5000, 10000); if (tmpargs[0] == 0x09) count = 0; -- cgit v1.2.3 From 06f502f57d0d7728f9fa0f157ec5e4111ddb98f6 Mon Sep 17 00:00:00 2001 From: Ben Whitten Date: Sun, 10 Dec 2017 21:17:55 +0000 Subject: leds: trigger: Introduce a NETDEV trigger This commit introduces a NETDEV trigger for named device activity. Available triggers are link, rx, and tx. Signed-off-by: Ben Whitten Acked-by: Pavel Machek Signed-off-by: Jacek Anaszewski --- .../ABI/testing/sysfs-class-led-trigger-netdev | 45 ++ drivers/leds/trigger/Kconfig | 7 + drivers/leds/trigger/Makefile | 1 + drivers/leds/trigger/ledtrig-netdev.c | 496 +++++++++++++++++++++ 4 files changed, 549 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-class-led-trigger-netdev create mode 100644 drivers/leds/trigger/ledtrig-netdev.c (limited to 'drivers/leds') diff --git a/Documentation/ABI/testing/sysfs-class-led-trigger-netdev b/Documentation/ABI/testing/sysfs-class-led-trigger-netdev new file mode 100644 index 000000000000..451af6d6768c --- /dev/null +++ b/Documentation/ABI/testing/sysfs-class-led-trigger-netdev @@ -0,0 +1,45 @@ +What: /sys/class/leds//device_name +Date: Dec 2017 +KernelVersion: 4.16 +Contact: linux-leds@vger.kernel.org +Description: + Specifies the network device name to monitor. + +What: /sys/class/leds//interval +Date: Dec 2017 +KernelVersion: 4.16 +Contact: linux-leds@vger.kernel.org +Description: + Specifies the duration of the LED blink in milliseconds. + Defaults to 50 ms. + +What: /sys/class/leds//link +Date: Dec 2017 +KernelVersion: 4.16 +Contact: linux-leds@vger.kernel.org +Description: + Signal the link state of the named network device. + If set to 0 (default), the LED's normal state is off. + If set to 1, the LED's normal state reflects the link state + of the named network device. + Setting this value also immediately changes the LED state. + +What: /sys/class/leds//tx +Date: Dec 2017 +KernelVersion: 4.16 +Contact: linux-leds@vger.kernel.org +Description: + Signal transmission of data on the named network device. + If set to 0 (default), the LED will not blink on transmission. + If set to 1, the LED will blink for the milliseconds specified + in interval to signal transmission. + +What: /sys/class/leds//rx +Date: Dec 2017 +KernelVersion: 4.16 +Contact: linux-leds@vger.kernel.org +Description: + Signal reception of data on the named network device. + If set to 0 (default), the LED will not blink on reception. + If set to 1, the LED will blink for the milliseconds specified + in interval to signal reception. diff --git a/drivers/leds/trigger/Kconfig b/drivers/leds/trigger/Kconfig index 6dac48c457d1..a2559b4fdfff 100644 --- a/drivers/leds/trigger/Kconfig +++ b/drivers/leds/trigger/Kconfig @@ -135,4 +135,11 @@ config LEDS_TRIGGER_PANIC a different trigger. If unsure, say Y. +config LEDS_TRIGGER_NETDEV + tristate "LED Netdev Trigger" + depends on NET && LEDS_TRIGGERS + help + This allows LEDs to be controlled by network device activity. + If unsure, say Y. + endif # LEDS_TRIGGERS diff --git a/drivers/leds/trigger/Makefile b/drivers/leds/trigger/Makefile index 4a8b6cff7761..f3cfe1950538 100644 --- a/drivers/leds/trigger/Makefile +++ b/drivers/leds/trigger/Makefile @@ -12,3 +12,4 @@ obj-$(CONFIG_LEDS_TRIGGER_DEFAULT_ON) += ledtrig-default-on.o obj-$(CONFIG_LEDS_TRIGGER_TRANSIENT) += ledtrig-transient.o obj-$(CONFIG_LEDS_TRIGGER_CAMERA) += ledtrig-camera.o obj-$(CONFIG_LEDS_TRIGGER_PANIC) += ledtrig-panic.o +obj-$(CONFIG_LEDS_TRIGGER_NETDEV) += ledtrig-netdev.o diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c new file mode 100644 index 000000000000..6df4781a6308 --- /dev/null +++ b/drivers/leds/trigger/ledtrig-netdev.c @@ -0,0 +1,496 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright 2017 Ben Whitten +// Copyright 2007 Oliver Jowett +// +// LED Kernel Netdev Trigger +// +// Toggles the LED to reflect the link and traffic state of a named net device +// +// Derived from ledtrig-timer.c which is: +// Copyright 2005-2006 Openedhand Ltd. +// Author: Richard Purdie + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../leds.h" + +/* + * Configurable sysfs attributes: + * + * device_name - network device name to monitor + * interval - duration of LED blink, in milliseconds + * link - LED's normal state reflects whether the link is up + * (has carrier) or not + * tx - LED blinks on transmitted data + * rx - LED blinks on receive data + * + */ + +struct led_netdev_data { + spinlock_t lock; + + struct delayed_work work; + struct notifier_block notifier; + + struct led_classdev *led_cdev; + struct net_device *net_dev; + + char device_name[IFNAMSIZ]; + atomic_t interval; + unsigned int last_activity; + + unsigned long mode; +#define NETDEV_LED_LINK 0 +#define NETDEV_LED_TX 1 +#define NETDEV_LED_RX 2 +#define NETDEV_LED_MODE_LINKUP 3 +}; + +enum netdev_led_attr { + NETDEV_ATTR_LINK, + NETDEV_ATTR_TX, + NETDEV_ATTR_RX +}; + +static void set_baseline_state(struct led_netdev_data *trigger_data) +{ + int current_brightness; + struct led_classdev *led_cdev = trigger_data->led_cdev; + + current_brightness = led_cdev->brightness; + if (current_brightness) + led_cdev->blink_brightness = current_brightness; + if (!led_cdev->blink_brightness) + led_cdev->blink_brightness = led_cdev->max_brightness; + + if (!test_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode)) + led_set_brightness(led_cdev, LED_OFF); + else { + if (test_bit(NETDEV_LED_LINK, &trigger_data->mode)) + led_set_brightness(led_cdev, + led_cdev->blink_brightness); + else + led_set_brightness(led_cdev, LED_OFF); + + /* If we are looking for RX/TX start periodically + * checking stats + */ + if (test_bit(NETDEV_LED_TX, &trigger_data->mode) || + test_bit(NETDEV_LED_RX, &trigger_data->mode)) + schedule_delayed_work(&trigger_data->work, 0); + } +} + +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; + ssize_t len; + + spin_lock_bh(&trigger_data->lock); + len = sprintf(buf, "%s\n", trigger_data->device_name); + spin_unlock_bh(&trigger_data->lock); + + return len; +} + +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; + + if (size >= IFNAMSIZ) + return -EINVAL; + + cancel_delayed_work_sync(&trigger_data->work); + + spin_lock_bh(&trigger_data->lock); + + if (trigger_data->net_dev) { + dev_put(trigger_data->net_dev); + trigger_data->net_dev = NULL; + } + + strncpy(trigger_data->device_name, buf, size); + if (size > 0 && trigger_data->device_name[size - 1] == '\n') + trigger_data->device_name[size - 1] = 0; + + if (trigger_data->device_name[0] != 0) + trigger_data->net_dev = + dev_get_by_name(&init_net, trigger_data->device_name); + + clear_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode); + if (trigger_data->net_dev != NULL) + if (netif_carrier_ok(trigger_data->net_dev)) + set_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode); + + trigger_data->last_activity = 0; + + set_baseline_state(trigger_data); + spin_unlock_bh(&trigger_data->lock); + + return size; +} + +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; + int bit; + + switch (attr) { + case NETDEV_ATTR_LINK: + bit = NETDEV_LED_LINK; + break; + case NETDEV_ATTR_TX: + bit = NETDEV_LED_TX; + break; + case NETDEV_ATTR_RX: + bit = NETDEV_LED_RX; + break; + default: + return -EINVAL; + } + + return sprintf(buf, "%u\n", test_bit(bit, &trigger_data->mode)); +} + +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; + unsigned long state; + int ret; + int bit; + + ret = kstrtoul(buf, 0, &state); + if (ret) + return ret; + + switch (attr) { + case NETDEV_ATTR_LINK: + bit = NETDEV_LED_LINK; + break; + case NETDEV_ATTR_TX: + bit = NETDEV_LED_TX; + break; + case NETDEV_ATTR_RX: + bit = NETDEV_LED_RX; + break; + default: + return -EINVAL; + } + + cancel_delayed_work_sync(&trigger_data->work); + + if (state) + set_bit(bit, &trigger_data->mode); + else + clear_bit(bit, &trigger_data->mode); + + set_baseline_state(trigger_data); + + return size; +} + +static ssize_t link_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return netdev_led_attr_show(dev, buf, NETDEV_ATTR_LINK); +} + +static ssize_t link_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + return netdev_led_attr_store(dev, buf, size, NETDEV_ATTR_LINK); +} + +static DEVICE_ATTR_RW(link); + +static ssize_t tx_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return netdev_led_attr_show(dev, buf, NETDEV_ATTR_TX); +} + +static ssize_t tx_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + return netdev_led_attr_store(dev, buf, size, NETDEV_ATTR_TX); +} + +static DEVICE_ATTR_RW(tx); + +static ssize_t rx_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return netdev_led_attr_show(dev, buf, NETDEV_ATTR_RX); +} + +static ssize_t rx_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + return netdev_led_attr_store(dev, buf, size, NETDEV_ATTR_RX); +} + +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; + + return sprintf(buf, "%u\n", + jiffies_to_msecs(atomic_read(&trigger_data->interval))); +} + +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; + unsigned long value; + int ret; + + ret = kstrtoul(buf, 0, &value); + if (ret) + return ret; + + /* impose some basic bounds on the timer interval */ + if (value >= 5 && value <= 10000) { + cancel_delayed_work_sync(&trigger_data->work); + + atomic_set(&trigger_data->interval, msecs_to_jiffies(value)); + set_baseline_state(trigger_data); /* resets timer */ + } + + return size; +} + +static DEVICE_ATTR_RW(interval); + +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); + + if (evt != NETDEV_UP && evt != NETDEV_DOWN && evt != NETDEV_CHANGE + && evt != NETDEV_REGISTER && evt != NETDEV_UNREGISTER + && evt != NETDEV_CHANGENAME) + return NOTIFY_DONE; + + if (strcmp(dev->name, trigger_data->device_name)) + return NOTIFY_DONE; + + cancel_delayed_work_sync(&trigger_data->work); + + spin_lock_bh(&trigger_data->lock); + + clear_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode); + switch (evt) { + case NETDEV_REGISTER: + if (trigger_data->net_dev) + dev_put(trigger_data->net_dev); + dev_hold(dev); + trigger_data->net_dev = dev; + break; + case NETDEV_CHANGENAME: + case NETDEV_UNREGISTER: + if (trigger_data->net_dev) { + dev_put(trigger_data->net_dev); + trigger_data->net_dev = NULL; + } + break; + case NETDEV_UP: + case NETDEV_CHANGE: + if (netif_carrier_ok(dev)) + set_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode); + break; + } + + set_baseline_state(trigger_data); + + spin_unlock_bh(&trigger_data->lock); + + return NOTIFY_DONE; +} + +/* 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 rtnl_link_stats64 *dev_stats; + unsigned int new_activity; + struct rtnl_link_stats64 temp; + unsigned long interval; + int invert; + + /* If we dont have a device, insure we are off */ + if (!trigger_data->net_dev) { + led_set_brightness(trigger_data->led_cdev, LED_OFF); + return; + } + + /* If we are not looking for RX/TX then return */ + if (!test_bit(NETDEV_LED_TX, &trigger_data->mode) && + !test_bit(NETDEV_LED_RX, &trigger_data->mode)) + return; + + dev_stats = dev_get_stats(trigger_data->net_dev, &temp); + new_activity = + (test_bit(NETDEV_LED_TX, &trigger_data->mode) ? + dev_stats->tx_packets : 0) + + (test_bit(NETDEV_LED_RX, &trigger_data->mode) ? + dev_stats->rx_packets : 0); + + if (trigger_data->last_activity != new_activity) { + led_stop_software_blink(trigger_data->led_cdev); + + invert = test_bit(NETDEV_LED_LINK, &trigger_data->mode); + interval = jiffies_to_msecs( + atomic_read(&trigger_data->interval)); + /* base state is ON (link present) */ + led_blink_set_oneshot(trigger_data->led_cdev, + &interval, + &interval, + invert); + trigger_data->last_activity = new_activity; + } + + schedule_delayed_work(&trigger_data->work, + (atomic_read(&trigger_data->interval)*2)); +} + +static void 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; + + spin_lock_init(&trigger_data->lock); + + trigger_data->notifier.notifier_call = netdev_trig_notify; + trigger_data->notifier.priority = 10; + + INIT_DELAYED_WORK(&trigger_data->work, netdev_trig_work); + + trigger_data->led_cdev = led_cdev; + trigger_data->net_dev = NULL; + trigger_data->device_name[0] = 0; + + trigger_data->mode = 0; + atomic_set(&trigger_data->interval, msecs_to_jiffies(50)); + trigger_data->last_activity = 0; + + led_cdev->trigger_data = 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; + +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); +} + +static void netdev_trig_deactivate(struct led_classdev *led_cdev) +{ + struct led_netdev_data *trigger_data = led_cdev->trigger_data; + + if (trigger_data) { + 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); + + if (trigger_data->net_dev) + dev_put(trigger_data->net_dev); + + kfree(trigger_data); + } +} + +static struct led_trigger netdev_led_trigger = { + .name = "netdev", + .activate = netdev_trig_activate, + .deactivate = netdev_trig_deactivate, +}; + +static int __init netdev_trig_init(void) +{ + return led_trigger_register(&netdev_led_trigger); +} + +static void __exit netdev_trig_exit(void) +{ + led_trigger_unregister(&netdev_led_trigger); +} + +module_init(netdev_trig_init); +module_exit(netdev_trig_exit); + +MODULE_AUTHOR("Ben Whitten "); +MODULE_AUTHOR("Oliver Jowett "); +MODULE_DESCRIPTION("Netdev LED trigger"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 9699cb6bbef273d7be25441bfc20a2db9ee0f509 Mon Sep 17 00:00:00 2001 From: Dan Murphy Date: Tue, 12 Dec 2017 12:15:50 -0600 Subject: leds: lm3692x: Introduce LM3692x dual string driver Introducing the LM3692x Dual-String white LED driver. Data sheet is located http://www.ti.com/lit/ds/snvsa29/snvsa29.pdf Signed-off-by: Dan Murphy Signed-off-by: Jacek Anaszewski --- drivers/leds/Kconfig | 7 + drivers/leds/Makefile | 1 + drivers/leds/leds-lm3692x.c | 393 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 401 insertions(+) create mode 100644 drivers/leds/leds-lm3692x.c (limited to 'drivers/leds') diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 318a28fd58fe..1d215b39cefd 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -137,6 +137,13 @@ config LEDS_LM3642 converter plus 1.5A constant current driver for a high-current white LED. +config LEDS_LM3692X + tristate "LED support for LM3692x Chips" + depends on LEDS_CLASS && I2C && OF + select REGMAP_I2C + help + This option enables support for the TI LM3692x family + of white LED string drivers used for backlighting. config LEDS_LOCOMO tristate "LED Support for Locomo device" diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index a2a6b5a4f86d..987884a5b9a5 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -74,6 +74,7 @@ obj-$(CONFIG_LEDS_PM8058) += leds-pm8058.o obj-$(CONFIG_LEDS_MLXCPLD) += leds-mlxcpld.o obj-$(CONFIG_LEDS_NIC78BX) += leds-nic78bx.o obj-$(CONFIG_LEDS_MT6323) += leds-mt6323.o +obj-$(CONFIG_LEDS_LM3692X) += leds-lm3692x.o # LED SPI Drivers obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o diff --git a/drivers/leds/leds-lm3692x.c b/drivers/leds/leds-lm3692x.c new file mode 100644 index 000000000000..437173d1712c --- /dev/null +++ b/drivers/leds/leds-lm3692x.c @@ -0,0 +1,393 @@ +/* + * TI lm3692x LED Driver + * + * Copyright (C) 2017 Texas Instruments + * + * Author: Dan Murphy + * + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LM3692X_REV 0x0 +#define LM3692X_RESET 0x1 +#define LM3692X_EN 0x10 +#define LM3692X_BRT_CTRL 0x11 +#define LM3692X_PWM_CTRL 0x12 +#define LM3692X_BOOST_CTRL 0x13 +#define LM3692X_AUTO_FREQ_HI 0x15 +#define LM3692X_AUTO_FREQ_LO 0x16 +#define LM3692X_BL_ADJ_THRESH 0x17 +#define LM3692X_BRT_LSB 0x18 +#define LM3692X_BRT_MSB 0x19 +#define LM3692X_FAULT_CTRL 0x1e +#define LM3692X_FAULT_FLAGS 0x1f + +#define LM3692X_SW_RESET BIT(0) +#define LM3692X_DEVICE_EN BIT(0) +#define LM3692X_LED1_EN BIT(1) +#define LM3692X_LED2_EN BIT(2) + +/* Brightness Control Bits */ +#define LM3692X_BL_ADJ_POL BIT(0) +#define LM3692X_RAMP_RATE_125us 0x00 +#define LM3692X_RAMP_RATE_250us BIT(1) +#define LM3692X_RAMP_RATE_500us BIT(2) +#define LM3692X_RAMP_RATE_1ms (BIT(1) | BIT(2)) +#define LM3692X_RAMP_RATE_2ms BIT(3) +#define LM3692X_RAMP_RATE_4ms (BIT(3) | BIT(1)) +#define LM3692X_RAMP_RATE_8ms (BIT(2) | BIT(3)) +#define LM3692X_RAMP_RATE_16ms (BIT(1) | BIT(2) | BIT(3)) +#define LM3692X_RAMP_EN BIT(4) +#define LM3692X_BRHT_MODE_REG 0x00 +#define LM3692X_BRHT_MODE_PWM BIT(5) +#define LM3692X_BRHT_MODE_MULTI_RAMP BIT(6) +#define LM3692X_BRHT_MODE_RAMP_MULTI (BIT(5) | BIT(6)) +#define LM3692X_MAP_MODE_EXP BIT(7) + +/* PWM Register Bits */ +#define LM3692X_PWM_FILTER_100 BIT(0) +#define LM3692X_PWM_FILTER_150 BIT(1) +#define LM3692X_PWM_FILTER_200 (BIT(0) | BIT(1)) +#define LM3692X_PWM_HYSTER_1LSB BIT(2) +#define LM3692X_PWM_HYSTER_2LSB BIT(3) +#define LM3692X_PWM_HYSTER_3LSB (BIT(3) | BIT(2)) +#define LM3692X_PWM_HYSTER_4LSB BIT(4) +#define LM3692X_PWM_HYSTER_5LSB (BIT(4) | BIT(2)) +#define LM3692X_PWM_HYSTER_6LSB (BIT(4) | BIT(3)) +#define LM3692X_PWM_POLARITY BIT(5) +#define LM3692X_PWM_SAMP_4MHZ BIT(6) +#define LM3692X_PWM_SAMP_24MHZ BIT(7) + +/* Boost Control Bits */ +#define LM3692X_OCP_PROT_1A BIT(0) +#define LM3692X_OCP_PROT_1_25A BIT(1) +#define LM3692X_OCP_PROT_1_5A (BIT(0) | BIT(1)) +#define LM3692X_OVP_21V BIT(2) +#define LM3692X_OVP_25V BIT(3) +#define LM3692X_OVP_29V (BIT(2) | BIT(3)) +#define LM3692X_MIN_IND_22UH BIT(4) +#define LM3692X_BOOST_SW_1MHZ BIT(5) +#define LM3692X_BOOST_SW_NO_SHIFT BIT(6) + +/* Fault Control Bits */ +#define LM3692X_FAULT_CTRL_OVP BIT(0) +#define LM3692X_FAULT_CTRL_OCP BIT(1) +#define LM3692X_FAULT_CTRL_TSD BIT(2) +#define LM3692X_FAULT_CTRL_OPEN BIT(3) + +/* Fault Flag Bits */ +#define LM3692X_FAULT_FLAG_OVP BIT(0) +#define LM3692X_FAULT_FLAG_OCP BIT(1) +#define LM3692X_FAULT_FLAG_TSD BIT(2) +#define LM3692X_FAULT_FLAG_SHRT BIT(3) +#define LM3692X_FAULT_FLAG_OPEN BIT(4) + +/** + * struct lm3692x_led - + * @lock - Lock for reading/writing the device + * @client - Pointer to the I2C client + * @led_dev - LED class device pointer + * @regmap - Devices register map + * @enable_gpio - VDDIO/EN gpio to enable communication interface + * @regulator - LED supply regulator pointer + * @label - LED label + */ +struct lm3692x_led { + struct mutex lock; + struct i2c_client *client; + struct led_classdev led_dev; + struct regmap *regmap; + struct gpio_desc *enable_gpio; + struct regulator *regulator; + char label[LED_MAX_NAME_SIZE]; +}; + +static const struct reg_default lm3692x_reg_defs[] = { + {LM3692X_EN, 0xf}, + {LM3692X_BRT_CTRL, 0x61}, + {LM3692X_PWM_CTRL, 0x73}, + {LM3692X_BOOST_CTRL, 0x6f}, + {LM3692X_AUTO_FREQ_HI, 0x0}, + {LM3692X_AUTO_FREQ_LO, 0x0}, + {LM3692X_BL_ADJ_THRESH, 0x0}, + {LM3692X_BRT_LSB, 0x7}, + {LM3692X_BRT_MSB, 0xff}, + {LM3692X_FAULT_CTRL, 0x7}, +}; + +static const struct regmap_config lm3692x_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = LM3692X_FAULT_FLAGS, + .reg_defaults = lm3692x_reg_defs, + .num_reg_defaults = ARRAY_SIZE(lm3692x_reg_defs), + .cache_type = REGCACHE_RBTREE, +}; + +static int lm3692x_fault_check(struct lm3692x_led *led) +{ + int ret; + unsigned int read_buf; + + ret = regmap_read(led->regmap, LM3692X_FAULT_FLAGS, &read_buf); + if (ret) + return ret; + + if (read_buf) + dev_err(&led->client->dev, "Detected a fault 0x%X\n", read_buf); + + /* The first read may clear the fault. Check again to see if the fault + * still exits and return that value. + */ + regmap_read(led->regmap, LM3692X_FAULT_FLAGS, &read_buf); + if (read_buf) + dev_err(&led->client->dev, "Second read of fault flags 0x%X\n", + read_buf); + + return read_buf; +} + +static int lm3692x_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brt_val) +{ + struct lm3692x_led *led = + container_of(led_cdev, struct lm3692x_led, led_dev); + int ret; + int led_brightness_lsb = (brt_val >> 5); + + mutex_lock(&led->lock); + + ret = lm3692x_fault_check(led); + if (ret) { + dev_err(&led->client->dev, "Cannot read/clear faults\n"); + goto out; + } + + ret = regmap_write(led->regmap, LM3692X_BRT_MSB, brt_val); + if (ret) { + dev_err(&led->client->dev, "Cannot write MSB\n"); + goto out; + } + + ret = regmap_write(led->regmap, LM3692X_BRT_LSB, led_brightness_lsb); + if (ret) { + dev_err(&led->client->dev, "Cannot write LSB\n"); + goto out; + } +out: + mutex_unlock(&led->lock); + return ret; +} + +static int lm3692x_init(struct lm3692x_led *led) +{ + int ret; + + if (led->regulator) { + ret = regulator_enable(led->regulator); + if (ret) { + dev_err(&led->client->dev, + "Failed to enable regulator\n"); + return ret; + } + } + + if (led->enable_gpio) + gpiod_direction_output(led->enable_gpio, 1); + + ret = lm3692x_fault_check(led); + if (ret) { + dev_err(&led->client->dev, "Cannot read/clear faults\n"); + goto out; + } + + ret = regmap_write(led->regmap, LM3692X_BRT_CTRL, 0x00); + if (ret) + goto out; + + /* + * For glitch free operation, the following data should + * only be written while device enable bit is 0 + * per Section 7.5.14 of the data sheet + */ + ret = regmap_write(led->regmap, LM3692X_PWM_CTRL, + LM3692X_PWM_FILTER_100 | LM3692X_PWM_SAMP_24MHZ); + if (ret) + goto out; + + ret = regmap_write(led->regmap, LM3692X_BOOST_CTRL, + LM3692X_BRHT_MODE_RAMP_MULTI | + LM3692X_BL_ADJ_POL | + LM3692X_RAMP_RATE_250us); + if (ret) + goto out; + + ret = regmap_write(led->regmap, LM3692X_AUTO_FREQ_HI, 0x00); + if (ret) + goto out; + + ret = regmap_write(led->regmap, LM3692X_AUTO_FREQ_LO, 0x00); + if (ret) + goto out; + + ret = regmap_write(led->regmap, LM3692X_BL_ADJ_THRESH, 0x00); + if (ret) + goto out; + + ret = regmap_write(led->regmap, LM3692X_BRT_CTRL, + LM3692X_BL_ADJ_POL | LM3692X_PWM_HYSTER_4LSB); + if (ret) + goto out; + + return ret; +out: + dev_err(&led->client->dev, "Fail writing initialization values\n"); + + if (led->enable_gpio) + gpiod_direction_output(led->enable_gpio, 0); + + if (led->regulator) { + ret = regulator_disable(led->regulator); + if (ret) + dev_err(&led->client->dev, + "Failed to disable regulator\n"); + } + + return ret; +} + +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; + + 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); + + i2c_set_clientdata(client, led); + + led->regmap = devm_regmap_init_i2c(client, &lm3692x_regmap_config); + if (IS_ERR(led->regmap)) { + ret = PTR_ERR(led->regmap); + dev_err(&client->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + ret = lm3692x_init(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); + return ret; + } + + return 0; +} + +static int lm3692x_remove(struct i2c_client *client) +{ + struct lm3692x_led *led = i2c_get_clientdata(client); + int ret; + + if (led->enable_gpio) + gpiod_direction_output(led->enable_gpio, 0); + + if (led->regulator) { + ret = regulator_disable(led->regulator); + if (ret) + dev_err(&led->client->dev, + "Failed to disable regulator\n"); + } + + mutex_destroy(&led->lock); + + return 0; +} + +static const struct i2c_device_id lm3692x_id[] = { + { "lm36922", 0 }, + { "lm36923", 1 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, lm3692x_id); + +static const struct of_device_id of_lm3692x_leds_match[] = { + { .compatible = "ti,lm36922", }, + { .compatible = "ti,lm36923", }, + {}, +}; +MODULE_DEVICE_TABLE(of, of_lm3692x_leds_match); + +static struct i2c_driver lm3692x_driver = { + .driver = { + .name = "lm3692x", + .of_match_table = of_lm3692x_leds_match, + }, + .probe = lm3692x_probe, + .remove = lm3692x_remove, + .id_table = lm3692x_id, +}; +module_i2c_driver(lm3692x_driver); + +MODULE_DESCRIPTION("Texas Instruments LM3692X LED driver"); +MODULE_AUTHOR("Dan Murphy "); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From faa91a7b5cb49375e2d786516c60d90278770a1e Mon Sep 17 00:00:00 2001 From: Dan Murphy Date: Thu, 14 Dec 2017 11:37:26 -0600 Subject: leds: as3645a: Fix quoted string split warning Fix a warning for a split quoted string across lines. WARNING: quoted string split across lines 459: FILE: drivers/leds/leds-as3645a.c:459: dev_err(dev, "AS3645A not detected " "(model %d rfu %d)\n", model, rfu); Signed-off-by: Dan Murphy Acked-by: Laurent Pinchart Acked-by: Sakari Ailus Signed-off-by: Jacek Anaszewski --- drivers/leds/leds-as3645a.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/leds') diff --git a/drivers/leds/leds-as3645a.c b/drivers/leds/leds-as3645a.c index 9a257f969300..49fdd7c0a6f6 100644 --- a/drivers/leds/leds-as3645a.c +++ b/drivers/leds/leds-as3645a.c @@ -455,8 +455,8 @@ static int as3645a_detect(struct as3645a *flash) /* Verify the chip model and version. */ if (model != 0x01 || rfu != 0x00) { - dev_err(dev, "AS3645A not detected " - "(model %d rfu %d)\n", model, rfu); + dev_err(dev, "AS3645A not detected (model %d rfu %d)\n", + model, rfu); return -ENODEV; } -- cgit v1.2.3 From 6b68441be1e83bd65507901e878f82030efedc4b Mon Sep 17 00:00:00 2001 From: Dan Murphy Date: Thu, 14 Dec 2017 11:37:27 -0600 Subject: leds: as3645a: Fix line over 80 characters Fix the warning for line over 80 characters. WARNING: line over 80 characters 363: FILE: drivers/leds/leds-as3645a.c:363: flash->flash_current = as3645a_current_to_reg(flash, true, brightness_ua); Signed-off-by: Dan Murphy Acked-by: Laurent Pinchart Acked-by: Sakari Ailus Signed-off-by: Jacek Anaszewski --- drivers/leds/leds-as3645a.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/leds') diff --git a/drivers/leds/leds-as3645a.c b/drivers/leds/leds-as3645a.c index 49fdd7c0a6f6..f883616d9e60 100644 --- a/drivers/leds/leds-as3645a.c +++ b/drivers/leds/leds-as3645a.c @@ -360,7 +360,8 @@ static int as3645a_set_flash_brightness(struct led_classdev_flash *fled, { struct as3645a *flash = fled_to_as3645a(fled); - flash->flash_current = as3645a_current_to_reg(flash, true, brightness_ua); + flash->flash_current = as3645a_current_to_reg(flash, true, + brightness_ua); return as3645a_set_current(flash); } -- cgit v1.2.3 From c6b218c9c0d686486dcc39a1d80aff90801ca6fc Mon Sep 17 00:00:00 2001 From: Dan Murphy Date: Mon, 18 Dec 2017 14:23:04 -0600 Subject: leds: lp8860: Update the dt parsing for LED labeling Update the DT parsing for the label node so that the label is retrieved from the device child as opposed to being part of the parent. This will align this driver with the LED binding documentation Documentation/devicetree/bindings/leds/common.txt Signed-off-by: Dan Murphy Signed-off-by: Jacek Anaszewski --- drivers/leds/leds-lp8860.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'drivers/leds') diff --git a/drivers/leds/leds-lp8860.c b/drivers/leds/leds-lp8860.c index f91a4fe25168..1ab5e19c3509 100644 --- a/drivers/leds/leds-lp8860.c +++ b/drivers/leds/leds-lp8860.c @@ -22,6 +22,7 @@ #include #include #include +#include #define LP8860_DISP_CL1_BRT_MSB 0x00 #define LP8860_DISP_CL1_BRT_LSB 0x01 @@ -86,8 +87,6 @@ #define LP8860_CLEAR_FAULTS 0x01 -#define LP8860_DISP_LED_NAME "display_cluster" - /** * struct lp8860_led - * @lock - Lock for reading/writing the device @@ -107,7 +106,7 @@ struct lp8860_led { struct regmap *eeprom_regmap; struct gpio_desc *enable_gpio; struct regulator *regulator; - const char *label; + char label[LED_MAX_NAME_SIZE]; }; struct lp8860_eeprom_reg { @@ -387,19 +386,21 @@ static int lp8860_probe(struct i2c_client *client, int ret; struct lp8860_led *led; struct device_node *np = client->dev.of_node; + struct device_node *child_node; + const char *name; led = devm_kzalloc(&client->dev, sizeof(*led), GFP_KERNEL); if (!led) return -ENOMEM; - led->label = LP8860_DISP_LED_NAME; - - if (client->dev.of_node) { - ret = of_property_read_string(np, "label", &led->label); - if (ret) { - dev_err(&client->dev, "Missing label in dt\n"); - return -EINVAL; - } + for_each_available_child_of_node(np, child_node) { + 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::display_cluster", id->name); } led->enable_gpio = devm_gpiod_get_optional(&client->dev, -- cgit v1.2.3 From 50aa46c4bd7b79a57766537dfa8e8c4d8b174a3a Mon Sep 17 00:00:00 2001 From: Dan Murphy Date: Mon, 18 Dec 2017 14:23:06 -0600 Subject: leds: lp8860: Add DT parsing to retrieve the trigger node Add the ability to parse the DT and set the default trigger mode for the LED. Signed-off-by: Dan Murphy Signed-off-by: Jacek Anaszewski --- drivers/leds/leds-lp8860.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/leds') diff --git a/drivers/leds/leds-lp8860.c b/drivers/leds/leds-lp8860.c index 1ab5e19c3509..94b996b343ce 100644 --- a/drivers/leds/leds-lp8860.c +++ b/drivers/leds/leds-lp8860.c @@ -394,6 +394,10 @@ static int lp8860_probe(struct i2c_client *client, 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", -- cgit v1.2.3 From a2169c9b762ac64899b2aefb170ea0e16178afd6 Mon Sep 17 00:00:00 2001 From: Dan Murphy Date: Mon, 18 Dec 2017 14:23:07 -0600 Subject: leds: lp8860: Various fixes to align with LED framework Update the driver to conform with the LED framework: - use devm_led_classdev_register - destroy mutex on exit - remove dependency on CONFIG_OF in the driver and move to the Kconfig - update the MODULE_LICENSE to GPL v2 - remove setting of MAX brightness as the LED framework does this. Signed-off-by: Dan Murphy Signed-off-by: Jacek Anaszewski --- drivers/leds/Kconfig | 2 +- drivers/leds/leds-lp8860.c | 13 +++++-------- 2 files changed, 6 insertions(+), 9 deletions(-) (limited to 'drivers/leds') diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 1d215b39cefd..3e763d2a0cb3 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -354,7 +354,7 @@ config LEDS_LP8788 config LEDS_LP8860 tristate "LED support for the TI LP8860 4 channel LED driver" - depends on LEDS_CLASS && I2C + depends on LEDS_CLASS && I2C && OF select REGMAP_I2C help If you say yes here you get support for the TI LP8860 4 channel diff --git a/drivers/leds/leds-lp8860.c b/drivers/leds/leds-lp8860.c index 94b996b343ce..39c72a908f3b 100644 --- a/drivers/leds/leds-lp8860.c +++ b/drivers/leds/leds-lp8860.c @@ -421,7 +421,6 @@ static int lp8860_probe(struct i2c_client *client, led->client = client; led->led_dev.name = led->label; - led->led_dev.max_brightness = LED_FULL; led->led_dev.brightness_set_blocking = lp8860_brightness_set; mutex_init(&led->lock); @@ -448,7 +447,7 @@ static int lp8860_probe(struct i2c_client *client, if (ret) return ret; - ret = led_classdev_register(&client->dev, &led->led_dev); + ret = devm_led_classdev_register(&client->dev, &led->led_dev); if (ret) { dev_err(&client->dev, "led register err: %d\n", ret); return ret; @@ -462,8 +461,6 @@ static int lp8860_remove(struct i2c_client *client) struct lp8860_led *led = i2c_get_clientdata(client); int ret; - led_classdev_unregister(&led->led_dev); - if (led->enable_gpio) gpiod_direction_output(led->enable_gpio, 0); @@ -474,6 +471,8 @@ static int lp8860_remove(struct i2c_client *client) "Failed to disable regulator\n"); } + mutex_destroy(&led->lock); + return 0; } @@ -483,18 +482,16 @@ static const struct i2c_device_id lp8860_id[] = { }; MODULE_DEVICE_TABLE(i2c, lp8860_id); -#ifdef CONFIG_OF static const struct of_device_id of_lp8860_leds_match[] = { { .compatible = "ti,lp8860", }, {}, }; MODULE_DEVICE_TABLE(of, of_lp8860_leds_match); -#endif static struct i2c_driver lp8860_driver = { .driver = { .name = "lp8860", - .of_match_table = of_match_ptr(of_lp8860_leds_match), + .of_match_table = of_lp8860_leds_match, }, .probe = lp8860_probe, .remove = lp8860_remove, @@ -504,4 +501,4 @@ module_i2c_driver(lp8860_driver); MODULE_DESCRIPTION("Texas Instruments LP8860 LED driver"); MODULE_AUTHOR("Dan Murphy "); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 6a836631e303cec7fd9469ae53a4d97d0360eb38 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Wed, 10 Jan 2018 15:42:05 -0700 Subject: leds: ledtrig-transient: Add SPDX license identifiers Replace GPL license statements with SPDX GPL-2.0 license identifiers and correct the module license to GPLv2. Signed-off-by: Shuah Khan Signed-off-by: Jacek Anaszewski --- drivers/leds/trigger/ledtrig-transient.c | 33 +++++++++++++------------------- 1 file changed, 13 insertions(+), 20 deletions(-) (limited to 'drivers/leds') diff --git a/drivers/leds/trigger/ledtrig-transient.c b/drivers/leds/trigger/ledtrig-transient.c index 7acce64b692a..9d1769073562 100644 --- a/drivers/leds/trigger/ledtrig-transient.c +++ b/drivers/leds/trigger/ledtrig-transient.c @@ -1,22 +1,15 @@ -/* - * LED Kernel Transient Trigger - * - * Copyright (C) 2012 Shuah Khan - * - * Based on Richard Purdie's ledtrig-timer.c and Atsushi Nemoto's - * ledtrig-heartbeat.c - * Design and use-case input from Jonas Bonn and - * Neil Brown - * - * 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. - * - */ -/* - * Transient trigger allows one shot timer activation. Please refer to - * Documentation/leds/ledtrig-transient.txt for details -*/ +// SPDX-License-Identifier: GPL-2.0 +// +// LED Kernel Transient Trigger +// +// Transient trigger allows one shot timer activation. Please refer to +// Documentation/leds/ledtrig-transient.txt for details +// Copyright (C) 2012 Shuah Khan +// +// Based on Richard Purdie's ledtrig-timer.c and Atsushi Nemoto's +// ledtrig-heartbeat.c +// Design and use-case input from Jonas Bonn and +// Neil Brown #include #include @@ -238,4 +231,4 @@ module_exit(transient_trig_exit); MODULE_AUTHOR("Shuah Khan "); MODULE_DESCRIPTION("Transient LED trigger"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3