From 93690cdf3060c61dfce813121d0bfc055e7fa30d Mon Sep 17 00:00:00 2001 From: Marek Behún Date: Thu, 16 Jul 2020 19:17:28 +0200 Subject: leds: trigger: add support for LED-private device triggers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some LED controllers may come with an internal HW triggering mechanism for the LED and the ability to switch between SW control and the internal HW control. This includes most PHYs, various ethernet switches, the Turris Omnia LED controller or AXP20X PMIC. This adds support for registering such triggers. This code is based on work by Pavel Machek and Ondřej Jirman . Signed-off-by: Marek Behún Acked-by: Jacek Anaszewski Signed-off-by: Pavel Machek --- drivers/leds/led-triggers.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) (limited to 'drivers/leds/led-triggers.c') diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c index 0836bf7631ea..91da90cfb11d 100644 --- a/drivers/leds/led-triggers.c +++ b/drivers/leds/led-triggers.c @@ -27,6 +27,12 @@ LIST_HEAD(trigger_list); /* Used by LED Class */ +static inline bool +trigger_relevant(struct led_classdev *led_cdev, struct led_trigger *trig) +{ + return !trig->trigger_type || trig->trigger_type == led_cdev->trigger_type; +} + ssize_t led_trigger_write(struct file *filp, struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t pos, size_t count) @@ -50,7 +56,7 @@ ssize_t led_trigger_write(struct file *filp, struct kobject *kobj, down_read(&triggers_list_lock); list_for_each_entry(trig, &trigger_list, next_trig) { - if (sysfs_streq(buf, trig->name)) { + if (sysfs_streq(buf, trig->name) && trigger_relevant(led_cdev, trig)) { down_write(&led_cdev->trigger_lock); led_trigger_set(led_cdev, trig); up_write(&led_cdev->trigger_lock); @@ -93,8 +99,12 @@ static int led_trigger_format(char *buf, size_t size, led_cdev->trigger ? "none" : "[none]"); list_for_each_entry(trig, &trigger_list, next_trig) { - bool hit = led_cdev->trigger && - !strcmp(led_cdev->trigger->name, trig->name); + bool hit; + + if (!trigger_relevant(led_cdev, trig)) + continue; + + hit = led_cdev->trigger && !strcmp(led_cdev->trigger->name, trig->name); len += led_trigger_snprintf(buf + len, size - len, " %s%s%s", hit ? "[" : "", @@ -243,7 +253,8 @@ void led_trigger_set_default(struct led_classdev *led_cdev) down_read(&triggers_list_lock); down_write(&led_cdev->trigger_lock); list_for_each_entry(trig, &trigger_list, next_trig) { - if (!strcmp(led_cdev->default_trigger, trig->name)) { + if (!strcmp(led_cdev->default_trigger, trig->name) && + trigger_relevant(led_cdev, trig)) { led_cdev->flags |= LED_INIT_DEFAULT_TRIGGER; led_trigger_set(led_cdev, trig); break; @@ -280,7 +291,9 @@ int led_trigger_register(struct led_trigger *trig) down_write(&triggers_list_lock); /* Make sure the trigger's name isn't already in use */ list_for_each_entry(_trig, &trigger_list, next_trig) { - if (!strcmp(_trig->name, trig->name)) { + if (!strcmp(_trig->name, trig->name) && + (trig->trigger_type == _trig->trigger_type || + !trig->trigger_type || !_trig->trigger_type)) { up_write(&triggers_list_lock); return -EEXIST; } @@ -294,7 +307,8 @@ int led_trigger_register(struct led_trigger *trig) list_for_each_entry(led_cdev, &leds_list, node) { down_write(&led_cdev->trigger_lock); if (!led_cdev->trigger && led_cdev->default_trigger && - !strcmp(led_cdev->default_trigger, trig->name)) { + !strcmp(led_cdev->default_trigger, trig->name) && + trigger_relevant(led_cdev, trig)) { led_cdev->flags |= LED_INIT_DEFAULT_TRIGGER; led_trigger_set(led_cdev, trig); } -- cgit v1.2.3-59-g8ed1b