1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2c3bc9956SRichard Purdie /*
3c3bc9956SRichard Purdie * LED Triggers Core
4c3bc9956SRichard Purdie *
5f8a7c6feSRichard Purdie * Copyright 2005-2007 Openedhand Ltd.
6c3bc9956SRichard Purdie *
7c3bc9956SRichard Purdie * Author: Richard Purdie <rpurdie@openedhand.com>
8c3bc9956SRichard Purdie */
9c3bc9956SRichard Purdie
1050237863SPaul Gortmaker #include <linux/export.h>
11c3bc9956SRichard Purdie #include <linux/kernel.h>
12c3bc9956SRichard Purdie #include <linux/list.h>
13c3bc9956SRichard Purdie #include <linux/spinlock.h>
14c3bc9956SRichard Purdie #include <linux/device.h>
15c3bc9956SRichard Purdie #include <linux/timer.h>
16dc47206eSRichard Purdie #include <linux/rwsem.h>
17c3bc9956SRichard Purdie #include <linux/leds.h>
185a0e3ad6STejun Heo #include <linux/slab.h>
1911f70002SAkinobu Mita #include <linux/mm.h>
20c3bc9956SRichard Purdie #include "leds.h"
21c3bc9956SRichard Purdie
22c3bc9956SRichard Purdie /*
23c3bc9956SRichard Purdie * Nests outside led_cdev->trigger_lock
24c3bc9956SRichard Purdie */
25dc47206eSRichard Purdie static DECLARE_RWSEM(triggers_list_lock);
26ba93cdceSEzequiel Garcia LIST_HEAD(trigger_list);
27c3bc9956SRichard Purdie
284d404fd5SNémeth Márton /* Used by LED Class */
294d404fd5SNémeth Márton
3093690cdfSMarek Behún static inline bool
trigger_relevant(struct led_classdev * led_cdev,struct led_trigger * trig)3193690cdfSMarek Behún trigger_relevant(struct led_classdev *led_cdev, struct led_trigger *trig)
3293690cdfSMarek Behún {
3393690cdfSMarek Behún return !trig->trigger_type || trig->trigger_type == led_cdev->trigger_type;
3493690cdfSMarek Behún }
3593690cdfSMarek Behún
led_trigger_write(struct file * filp,struct kobject * kobj,struct bin_attribute * bin_attr,char * buf,loff_t pos,size_t count)3611f70002SAkinobu Mita ssize_t led_trigger_write(struct file *filp, struct kobject *kobj,
3711f70002SAkinobu Mita struct bin_attribute *bin_attr, char *buf,
3811f70002SAkinobu Mita loff_t pos, size_t count)
39c3bc9956SRichard Purdie {
4011f70002SAkinobu Mita struct device *dev = kobj_to_dev(kobj);
41f8a7c6feSRichard Purdie struct led_classdev *led_cdev = dev_get_drvdata(dev);
42c3bc9956SRichard Purdie struct led_trigger *trig;
43acd899e4SJacek Anaszewski int ret = count;
44acd899e4SJacek Anaszewski
45acd899e4SJacek Anaszewski mutex_lock(&led_cdev->led_access);
46acd899e4SJacek Anaszewski
47acd899e4SJacek Anaszewski if (led_sysfs_is_disabled(led_cdev)) {
48acd899e4SJacek Anaszewski ret = -EBUSY;
49acd899e4SJacek Anaszewski goto unlock;
50acd899e4SJacek Anaszewski }
51c3bc9956SRichard Purdie
527296c33eSHeiner Kallweit if (sysfs_streq(buf, "none")) {
530013b23dSNémeth Márton led_trigger_remove(led_cdev);
54acd899e4SJacek Anaszewski goto unlock;
55c3bc9956SRichard Purdie }
56c3bc9956SRichard Purdie
57dc47206eSRichard Purdie down_read(&triggers_list_lock);
58c3bc9956SRichard Purdie list_for_each_entry(trig, &trigger_list, next_trig) {
5993690cdfSMarek Behún if (sysfs_streq(buf, trig->name) && trigger_relevant(led_cdev, trig)) {
60dc47206eSRichard Purdie down_write(&led_cdev->trigger_lock);
61c3bc9956SRichard Purdie led_trigger_set(led_cdev, trig);
62dc47206eSRichard Purdie up_write(&led_cdev->trigger_lock);
63c3bc9956SRichard Purdie
64dc47206eSRichard Purdie up_read(&triggers_list_lock);
65acd899e4SJacek Anaszewski goto unlock;
66c3bc9956SRichard Purdie }
67c3bc9956SRichard Purdie }
68a3eac76cSHeiner Kallweit /* we come here only if buf matches no trigger */
69a3eac76cSHeiner Kallweit ret = -EINVAL;
70dc47206eSRichard Purdie up_read(&triggers_list_lock);
71c3bc9956SRichard Purdie
72acd899e4SJacek Anaszewski unlock:
73acd899e4SJacek Anaszewski mutex_unlock(&led_cdev->led_access);
74acd899e4SJacek Anaszewski return ret;
75c3bc9956SRichard Purdie }
7611f70002SAkinobu Mita EXPORT_SYMBOL_GPL(led_trigger_write);
77c3bc9956SRichard Purdie
7811f70002SAkinobu Mita __printf(3, 4)
led_trigger_snprintf(char * buf,ssize_t size,const char * fmt,...)7911f70002SAkinobu Mita static int led_trigger_snprintf(char *buf, ssize_t size, const char *fmt, ...)
80c3bc9956SRichard Purdie {
8111f70002SAkinobu Mita va_list args;
8211f70002SAkinobu Mita int i;
8311f70002SAkinobu Mita
8411f70002SAkinobu Mita va_start(args, fmt);
8511f70002SAkinobu Mita if (size <= 0)
8611f70002SAkinobu Mita i = vsnprintf(NULL, 0, fmt, args);
8711f70002SAkinobu Mita else
8811f70002SAkinobu Mita i = vscnprintf(buf, size, fmt, args);
8911f70002SAkinobu Mita va_end(args);
9011f70002SAkinobu Mita
9111f70002SAkinobu Mita return i;
9211f70002SAkinobu Mita }
9311f70002SAkinobu Mita
led_trigger_format(char * buf,size_t size,struct led_classdev * led_cdev)9411f70002SAkinobu Mita static int led_trigger_format(char *buf, size_t size,
9511f70002SAkinobu Mita struct led_classdev *led_cdev)
9611f70002SAkinobu Mita {
97c3bc9956SRichard Purdie struct led_trigger *trig;
9811f70002SAkinobu Mita int len = led_trigger_snprintf(buf, size, "%s",
9911f70002SAkinobu Mita led_cdev->trigger ? "none" : "[none]");
10011f70002SAkinobu Mita
10111f70002SAkinobu Mita list_for_each_entry(trig, &trigger_list, next_trig) {
10293690cdfSMarek Behún bool hit;
10393690cdfSMarek Behún
10493690cdfSMarek Behún if (!trigger_relevant(led_cdev, trig))
10593690cdfSMarek Behún continue;
10693690cdfSMarek Behún
10793690cdfSMarek Behún hit = led_cdev->trigger && !strcmp(led_cdev->trigger->name, trig->name);
10811f70002SAkinobu Mita
10911f70002SAkinobu Mita len += led_trigger_snprintf(buf + len, size - len,
11011f70002SAkinobu Mita " %s%s%s", hit ? "[" : "",
11111f70002SAkinobu Mita trig->name, hit ? "]" : "");
11211f70002SAkinobu Mita }
11311f70002SAkinobu Mita
11411f70002SAkinobu Mita len += led_trigger_snprintf(buf + len, size - len, "\n");
11511f70002SAkinobu Mita
11611f70002SAkinobu Mita return len;
11711f70002SAkinobu Mita }
11811f70002SAkinobu Mita
11911f70002SAkinobu Mita /*
12011f70002SAkinobu Mita * It was stupid to create 10000 cpu triggers, but we are stuck with it now.
12111f70002SAkinobu Mita * Don't make that mistake again. We work around it here by creating binary
12211f70002SAkinobu Mita * attribute, which is not limited by length. This is _not_ good design, do not
12311f70002SAkinobu Mita * copy it.
12411f70002SAkinobu Mita */
led_trigger_read(struct file * filp,struct kobject * kobj,struct bin_attribute * attr,char * buf,loff_t pos,size_t count)12511f70002SAkinobu Mita ssize_t led_trigger_read(struct file *filp, struct kobject *kobj,
12611f70002SAkinobu Mita struct bin_attribute *attr, char *buf,
12711f70002SAkinobu Mita loff_t pos, size_t count)
12811f70002SAkinobu Mita {
12911f70002SAkinobu Mita struct device *dev = kobj_to_dev(kobj);
13011f70002SAkinobu Mita struct led_classdev *led_cdev = dev_get_drvdata(dev);
13111f70002SAkinobu Mita void *data;
13211f70002SAkinobu Mita int len;
133c3bc9956SRichard Purdie
134dc47206eSRichard Purdie down_read(&triggers_list_lock);
135dc47206eSRichard Purdie down_read(&led_cdev->trigger_lock);
136c3bc9956SRichard Purdie
13711f70002SAkinobu Mita len = led_trigger_format(NULL, 0, led_cdev);
13811f70002SAkinobu Mita data = kvmalloc(len + 1, GFP_KERNEL);
13911f70002SAkinobu Mita if (!data) {
14011f70002SAkinobu Mita up_read(&led_cdev->trigger_lock);
14111f70002SAkinobu Mita up_read(&triggers_list_lock);
14211f70002SAkinobu Mita return -ENOMEM;
143c3bc9956SRichard Purdie }
14411f70002SAkinobu Mita len = led_trigger_format(data, len + 1, led_cdev);
14511f70002SAkinobu Mita
146dc47206eSRichard Purdie up_read(&led_cdev->trigger_lock);
147dc47206eSRichard Purdie up_read(&triggers_list_lock);
148c3bc9956SRichard Purdie
14911f70002SAkinobu Mita len = memory_read_from_buffer(buf, count, &pos, data, len);
15011f70002SAkinobu Mita
15111f70002SAkinobu Mita kvfree(data);
15211f70002SAkinobu Mita
153c3bc9956SRichard Purdie return len;
154c3bc9956SRichard Purdie }
15511f70002SAkinobu Mita EXPORT_SYMBOL_GPL(led_trigger_read);
156c3bc9956SRichard Purdie
157c3bc9956SRichard Purdie /* Caller must ensure led_cdev->trigger_lock held */
led_trigger_set(struct led_classdev * led_cdev,struct led_trigger * trig)1582282e125SUwe Kleine-König int led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig)
159c3bc9956SRichard Purdie {
16052c47742SColin Cross char *event = NULL;
16152c47742SColin Cross char *envp[2];
16252c47742SColin Cross const char *name;
1632282e125SUwe Kleine-König int ret;
16452c47742SColin Cross
165fbfa197aSJacek Anaszewski if (!led_cdev->trigger && !trig)
1662282e125SUwe Kleine-König return 0;
167fbfa197aSJacek Anaszewski
16852c47742SColin Cross name = trig ? trig->name : "none";
16952c47742SColin Cross event = kasprintf(GFP_KERNEL, "TRIGGER=%s", name);
170c3bc9956SRichard Purdie
171c3bc9956SRichard Purdie /* Remove any existing trigger */
172c3bc9956SRichard Purdie if (led_cdev->trigger) {
1732a5a8fa8SJohannes Berg spin_lock(&led_cdev->trigger->leddev_list_lock);
1742a5a8fa8SJohannes Berg list_del_rcu(&led_cdev->trig_list);
1752a5a8fa8SJohannes Berg spin_unlock(&led_cdev->trigger->leddev_list_lock);
1762a5a8fa8SJohannes Berg
1772a5a8fa8SJohannes Berg /* ensure it's no longer visible on the led_cdevs list */
1782a5a8fa8SJohannes Berg synchronize_rcu();
1792a5a8fa8SJohannes Berg
180d23a22a7SFabio Baltieri cancel_work_sync(&led_cdev->set_brightness_work);
181d23a22a7SFabio Baltieri led_stop_software_blink(led_cdev);
182cb8aa9d2SHans de Goede device_remove_groups(led_cdev->dev, led_cdev->trigger->groups);
183c3bc9956SRichard Purdie if (led_cdev->trigger->deactivate)
184c3bc9956SRichard Purdie led_cdev->trigger->deactivate(led_cdev);
185fe3025b5SDmitry Baryshkov led_cdev->trigger = NULL;
186a7d5904aSUwe Kleine-König led_cdev->trigger_data = NULL;
187a7d5904aSUwe Kleine-König led_cdev->activated = false;
18882f80ef5SHans de Goede led_cdev->flags &= ~LED_INIT_DEFAULT_TRIGGER;
18919cd67e2SShuah Khan led_set_brightness(led_cdev, LED_OFF);
190c3bc9956SRichard Purdie }
191eb202621SBryan Wu if (trig) {
1922a5a8fa8SJohannes Berg spin_lock(&trig->leddev_list_lock);
1932a5a8fa8SJohannes Berg list_add_tail_rcu(&led_cdev->trig_list, &trig->led_cdevs);
1942a5a8fa8SJohannes Berg spin_unlock(&trig->leddev_list_lock);
195eb202621SBryan Wu led_cdev->trigger = trig;
1962282e125SUwe Kleine-König
1979ce3c14fSHans de Goede /*
1989ce3c14fSHans de Goede * Some activate() calls use led_trigger_event() to initialize
1999ce3c14fSHans de Goede * the brightness of the LED for which the trigger is being set.
2009ce3c14fSHans de Goede * Ensure the led_cdev is visible on trig->led_cdevs for this.
2019ce3c14fSHans de Goede */
2029ce3c14fSHans de Goede synchronize_rcu();
2039ce3c14fSHans de Goede
204*93ac74cdSThomas Weißschuh /*
205*93ac74cdSThomas Weißschuh * If "set brightness to 0" is pending in workqueue,
206*93ac74cdSThomas Weißschuh * we don't want that to be reordered after ->activate()
207*93ac74cdSThomas Weißschuh */
208*93ac74cdSThomas Weißschuh flush_work(&led_cdev->set_brightness_work);
209*93ac74cdSThomas Weißschuh
210587cf9c0SHeiner Kallweit ret = 0;
211eb202621SBryan Wu if (trig->activate)
2122282e125SUwe Kleine-König ret = trig->activate(led_cdev);
2132282e125SUwe Kleine-König else
214587cf9c0SHeiner Kallweit led_set_brightness(led_cdev, trig->brightness);
2152282e125SUwe Kleine-König if (ret)
2162282e125SUwe Kleine-König goto err_activate;
217a7e7a315SUwe Kleine-König
218a7e7a315SUwe Kleine-König ret = device_add_groups(led_cdev->dev, trig->groups);
219a7e7a315SUwe Kleine-König if (ret) {
220a7e7a315SUwe Kleine-König dev_err(led_cdev->dev, "Failed to add trigger attributes\n");
221a7e7a315SUwe Kleine-König goto err_add_groups;
222a7e7a315SUwe Kleine-König }
223c3bc9956SRichard Purdie }
22452c47742SColin Cross
22552c47742SColin Cross if (event) {
22652c47742SColin Cross envp[0] = event;
22752c47742SColin Cross envp[1] = NULL;
2286f3bad96SJacek Anaszewski if (kobject_uevent_env(&led_cdev->dev->kobj, KOBJ_CHANGE, envp))
2296f3bad96SJacek Anaszewski dev_err(led_cdev->dev,
2306f3bad96SJacek Anaszewski "%s: Error sending uevent\n", __func__);
23152c47742SColin Cross kfree(event);
23252c47742SColin Cross }
2332282e125SUwe Kleine-König
2342282e125SUwe Kleine-König return 0;
2352282e125SUwe Kleine-König
236a7e7a315SUwe Kleine-König err_add_groups:
237a7e7a315SUwe Kleine-König
238a7e7a315SUwe Kleine-König if (trig->deactivate)
239a7e7a315SUwe Kleine-König trig->deactivate(led_cdev);
2402282e125SUwe Kleine-König err_activate:
241a7e7a315SUwe Kleine-König
2422a5a8fa8SJohannes Berg spin_lock(&led_cdev->trigger->leddev_list_lock);
2432a5a8fa8SJohannes Berg list_del_rcu(&led_cdev->trig_list);
2442a5a8fa8SJohannes Berg spin_unlock(&led_cdev->trigger->leddev_list_lock);
2452a5a8fa8SJohannes Berg synchronize_rcu();
2464016ba85SOleh Kravchenko led_cdev->trigger = NULL;
2474016ba85SOleh Kravchenko led_cdev->trigger_data = NULL;
2482282e125SUwe Kleine-König led_set_brightness(led_cdev, LED_OFF);
24960e2dde1SWenwen Wang kfree(event);
2502282e125SUwe Kleine-König
2512282e125SUwe Kleine-König return ret;
252c3bc9956SRichard Purdie }
2534d404fd5SNémeth Márton EXPORT_SYMBOL_GPL(led_trigger_set);
254c3bc9956SRichard Purdie
led_trigger_remove(struct led_classdev * led_cdev)2550013b23dSNémeth Márton void led_trigger_remove(struct led_classdev *led_cdev)
2560013b23dSNémeth Márton {
2570013b23dSNémeth Márton down_write(&led_cdev->trigger_lock);
2580013b23dSNémeth Márton led_trigger_set(led_cdev, NULL);
2590013b23dSNémeth Márton up_write(&led_cdev->trigger_lock);
2600013b23dSNémeth Márton }
2614d404fd5SNémeth Márton EXPORT_SYMBOL_GPL(led_trigger_remove);
2620013b23dSNémeth Márton
led_trigger_set_default(struct led_classdev * led_cdev)263c3bc9956SRichard Purdie void led_trigger_set_default(struct led_classdev *led_cdev)
264c3bc9956SRichard Purdie {
265c3bc9956SRichard Purdie struct led_trigger *trig;
266c3bc9956SRichard Purdie
267c3bc9956SRichard Purdie if (!led_cdev->default_trigger)
268c3bc9956SRichard Purdie return;
269c3bc9956SRichard Purdie
270dc47206eSRichard Purdie down_read(&triggers_list_lock);
271dc47206eSRichard Purdie down_write(&led_cdev->trigger_lock);
272c3bc9956SRichard Purdie list_for_each_entry(trig, &trigger_list, next_trig) {
27393690cdfSMarek Behún if (!strcmp(led_cdev->default_trigger, trig->name) &&
27493690cdfSMarek Behún trigger_relevant(led_cdev, trig)) {
27502d31765SJacek Anaszewski led_cdev->flags |= LED_INIT_DEFAULT_TRIGGER;
276c3bc9956SRichard Purdie led_trigger_set(led_cdev, trig);
277c4f7bd4aSJacek Anaszewski break;
278c4f7bd4aSJacek Anaszewski }
279c3bc9956SRichard Purdie }
280dc47206eSRichard Purdie up_write(&led_cdev->trigger_lock);
281dc47206eSRichard Purdie up_read(&triggers_list_lock);
282c3bc9956SRichard Purdie }
2834d404fd5SNémeth Márton EXPORT_SYMBOL_GPL(led_trigger_set_default);
2844d404fd5SNémeth Márton
2854d404fd5SNémeth Márton /* LED Trigger Interface */
286c3bc9956SRichard Purdie
led_trigger_register(struct led_trigger * trig)287eb202621SBryan Wu int led_trigger_register(struct led_trigger *trig)
288c3bc9956SRichard Purdie {
289c3bc9956SRichard Purdie struct led_classdev *led_cdev;
290eb202621SBryan Wu struct led_trigger *_trig;
291c3bc9956SRichard Purdie
2922a5a8fa8SJohannes Berg spin_lock_init(&trig->leddev_list_lock);
293eb202621SBryan Wu INIT_LIST_HEAD(&trig->led_cdevs);
294c3bc9956SRichard Purdie
295dc47206eSRichard Purdie down_write(&triggers_list_lock);
296700c6ea2SAdam Nielsen /* Make sure the trigger's name isn't already in use */
297eb202621SBryan Wu list_for_each_entry(_trig, &trigger_list, next_trig) {
29893690cdfSMarek Behún if (!strcmp(_trig->name, trig->name) &&
29993690cdfSMarek Behún (trig->trigger_type == _trig->trigger_type ||
30093690cdfSMarek Behún !trig->trigger_type || !_trig->trigger_type)) {
301700c6ea2SAdam Nielsen up_write(&triggers_list_lock);
302700c6ea2SAdam Nielsen return -EEXIST;
303700c6ea2SAdam Nielsen }
304700c6ea2SAdam Nielsen }
305700c6ea2SAdam Nielsen /* Add to the list of led triggers */
306eb202621SBryan Wu list_add_tail(&trig->next_trig, &trigger_list);
307dc47206eSRichard Purdie up_write(&triggers_list_lock);
308c3bc9956SRichard Purdie
309c3bc9956SRichard Purdie /* Register with any LEDs that have this as a default trigger */
31072f8da32SRichard Purdie down_read(&leds_list_lock);
311c3bc9956SRichard Purdie list_for_each_entry(led_cdev, &leds_list, node) {
312dc47206eSRichard Purdie down_write(&led_cdev->trigger_lock);
313c3bc9956SRichard Purdie if (!led_cdev->trigger && led_cdev->default_trigger &&
31493690cdfSMarek Behún !strcmp(led_cdev->default_trigger, trig->name) &&
31593690cdfSMarek Behún trigger_relevant(led_cdev, trig)) {
3168146aaceSKrzysztof Kozlowski led_cdev->flags |= LED_INIT_DEFAULT_TRIGGER;
317eb202621SBryan Wu led_trigger_set(led_cdev, trig);
3188146aaceSKrzysztof Kozlowski }
319dc47206eSRichard Purdie up_write(&led_cdev->trigger_lock);
320c3bc9956SRichard Purdie }
32172f8da32SRichard Purdie up_read(&leds_list_lock);
322c3bc9956SRichard Purdie
323c3bc9956SRichard Purdie return 0;
324c3bc9956SRichard Purdie }
3254d404fd5SNémeth Márton EXPORT_SYMBOL_GPL(led_trigger_register);
326c3bc9956SRichard Purdie
led_trigger_unregister(struct led_trigger * trig)327eb202621SBryan Wu void led_trigger_unregister(struct led_trigger *trig)
328c3bc9956SRichard Purdie {
329c3bc9956SRichard Purdie struct led_classdev *led_cdev;
330c3bc9956SRichard Purdie
33114f5716bSSasha Levin if (list_empty_careful(&trig->next_trig))
33214f5716bSSasha Levin return;
33314f5716bSSasha Levin
334c3bc9956SRichard Purdie /* Remove from the list of led triggers */
335dc47206eSRichard Purdie down_write(&triggers_list_lock);
33614f5716bSSasha Levin list_del_init(&trig->next_trig);
337dc47206eSRichard Purdie up_write(&triggers_list_lock);
338c3bc9956SRichard Purdie
339c3bc9956SRichard Purdie /* Remove anyone actively using this trigger */
34072f8da32SRichard Purdie down_read(&leds_list_lock);
341c3bc9956SRichard Purdie list_for_each_entry(led_cdev, &leds_list, node) {
342dc47206eSRichard Purdie down_write(&led_cdev->trigger_lock);
343eb202621SBryan Wu if (led_cdev->trigger == trig)
344c3bc9956SRichard Purdie led_trigger_set(led_cdev, NULL);
345dc47206eSRichard Purdie up_write(&led_cdev->trigger_lock);
346c3bc9956SRichard Purdie }
34772f8da32SRichard Purdie up_read(&leds_list_lock);
348c3bc9956SRichard Purdie }
3494d404fd5SNémeth Márton EXPORT_SYMBOL_GPL(led_trigger_unregister);
3504d404fd5SNémeth Márton
devm_led_trigger_release(struct device * dev,void * res)3519534cc31SHeiner Kallweit static void devm_led_trigger_release(struct device *dev, void *res)
3529534cc31SHeiner Kallweit {
3539534cc31SHeiner Kallweit led_trigger_unregister(*(struct led_trigger **)res);
3549534cc31SHeiner Kallweit }
3559534cc31SHeiner Kallweit
devm_led_trigger_register(struct device * dev,struct led_trigger * trig)3569534cc31SHeiner Kallweit int devm_led_trigger_register(struct device *dev,
3579534cc31SHeiner Kallweit struct led_trigger *trig)
3589534cc31SHeiner Kallweit {
3599534cc31SHeiner Kallweit struct led_trigger **dr;
3609534cc31SHeiner Kallweit int rc;
3619534cc31SHeiner Kallweit
3629534cc31SHeiner Kallweit dr = devres_alloc(devm_led_trigger_release, sizeof(*dr),
3639534cc31SHeiner Kallweit GFP_KERNEL);
3649534cc31SHeiner Kallweit if (!dr)
3659534cc31SHeiner Kallweit return -ENOMEM;
3669534cc31SHeiner Kallweit
3679534cc31SHeiner Kallweit *dr = trig;
3689534cc31SHeiner Kallweit
3699534cc31SHeiner Kallweit rc = led_trigger_register(trig);
3709534cc31SHeiner Kallweit if (rc)
3719534cc31SHeiner Kallweit devres_free(dr);
3729534cc31SHeiner Kallweit else
3739534cc31SHeiner Kallweit devres_add(dev, dr);
3749534cc31SHeiner Kallweit
3759534cc31SHeiner Kallweit return rc;
3769534cc31SHeiner Kallweit }
3779534cc31SHeiner Kallweit EXPORT_SYMBOL_GPL(devm_led_trigger_register);
3789534cc31SHeiner Kallweit
37914d3e74fSFlavio Suligoi /* Simple LED Trigger Interface */
3804d404fd5SNémeth Márton
led_trigger_event(struct led_trigger * trig,enum led_brightness brightness)381eb202621SBryan Wu void led_trigger_event(struct led_trigger *trig,
3824d404fd5SNémeth Márton enum led_brightness brightness)
3834d404fd5SNémeth Márton {
38411e043b5SZHAO Gang struct led_classdev *led_cdev;
3854d404fd5SNémeth Márton
386eb202621SBryan Wu if (!trig)
3874d404fd5SNémeth Márton return;
3884d404fd5SNémeth Márton
389587cf9c0SHeiner Kallweit trig->brightness = brightness;
390587cf9c0SHeiner Kallweit
3912a5a8fa8SJohannes Berg rcu_read_lock();
3922a5a8fa8SJohannes Berg list_for_each_entry_rcu(led_cdev, &trig->led_cdevs, trig_list)
393d23a22a7SFabio Baltieri led_set_brightness(led_cdev, brightness);
3942a5a8fa8SJohannes Berg rcu_read_unlock();
3954d404fd5SNémeth Márton }
3964d404fd5SNémeth Márton EXPORT_SYMBOL_GPL(led_trigger_event);
3974d404fd5SNémeth Márton
led_trigger_blink_setup(struct led_trigger * trig,unsigned long delay_on,unsigned long delay_off,int oneshot,int invert)39820c0e6b8SBryan Wu static void led_trigger_blink_setup(struct led_trigger *trig,
399e298d8a3SHans de Goede unsigned long delay_on,
400e298d8a3SHans de Goede unsigned long delay_off,
4015bb629c5SFabio Baltieri int oneshot,
4025bb629c5SFabio Baltieri int invert)
4030b9536c9SVasily Khoruzhick {
40411e043b5SZHAO Gang struct led_classdev *led_cdev;
4050b9536c9SVasily Khoruzhick
406eb202621SBryan Wu if (!trig)
4070b9536c9SVasily Khoruzhick return;
4080b9536c9SVasily Khoruzhick
4092a5a8fa8SJohannes Berg rcu_read_lock();
4102a5a8fa8SJohannes Berg list_for_each_entry_rcu(led_cdev, &trig->led_cdevs, trig_list) {
4115bb629c5SFabio Baltieri if (oneshot)
412e298d8a3SHans de Goede led_blink_set_oneshot(led_cdev, &delay_on, &delay_off,
4135bb629c5SFabio Baltieri invert);
4145bb629c5SFabio Baltieri else
41522720a87SHans de Goede led_blink_set_nosleep(led_cdev, delay_on, delay_off);
4160b9536c9SVasily Khoruzhick }
4172a5a8fa8SJohannes Berg rcu_read_unlock();
4180b9536c9SVasily Khoruzhick }
4195bb629c5SFabio Baltieri
led_trigger_blink(struct led_trigger * trig,unsigned long delay_on,unsigned long delay_off)4205bb629c5SFabio Baltieri void led_trigger_blink(struct led_trigger *trig,
421e298d8a3SHans de Goede unsigned long delay_on,
422e298d8a3SHans de Goede unsigned long delay_off)
4235bb629c5SFabio Baltieri {
4245bb629c5SFabio Baltieri led_trigger_blink_setup(trig, delay_on, delay_off, 0, 0);
4255bb629c5SFabio Baltieri }
4260b9536c9SVasily Khoruzhick EXPORT_SYMBOL_GPL(led_trigger_blink);
4270b9536c9SVasily Khoruzhick
led_trigger_blink_oneshot(struct led_trigger * trig,unsigned long delay_on,unsigned long delay_off,int invert)4285bb629c5SFabio Baltieri void led_trigger_blink_oneshot(struct led_trigger *trig,
429e298d8a3SHans de Goede unsigned long delay_on,
430e298d8a3SHans de Goede unsigned long delay_off,
4315bb629c5SFabio Baltieri int invert)
4325bb629c5SFabio Baltieri {
4335bb629c5SFabio Baltieri led_trigger_blink_setup(trig, delay_on, delay_off, 1, invert);
4345bb629c5SFabio Baltieri }
4355bb629c5SFabio Baltieri EXPORT_SYMBOL_GPL(led_trigger_blink_oneshot);
4365bb629c5SFabio Baltieri
led_trigger_register_simple(const char * name,struct led_trigger ** tp)4374d404fd5SNémeth Márton void led_trigger_register_simple(const char *name, struct led_trigger **tp)
4384d404fd5SNémeth Márton {
439eb202621SBryan Wu struct led_trigger *trig;
4404d404fd5SNémeth Márton int err;
4414d404fd5SNémeth Márton
442eb202621SBryan Wu trig = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
4434d404fd5SNémeth Márton
444eb202621SBryan Wu if (trig) {
445eb202621SBryan Wu trig->name = name;
446eb202621SBryan Wu err = led_trigger_register(trig);
447cba4c2acSMasakazu Mokuno if (err < 0) {
448eb202621SBryan Wu kfree(trig);
449eb202621SBryan Wu trig = NULL;
45009f5fe75SSachin Kamat pr_warn("LED trigger %s failed to register (%d)\n",
45109f5fe75SSachin Kamat name, err);
452cba4c2acSMasakazu Mokuno }
45309f5fe75SSachin Kamat } else {
45409f5fe75SSachin Kamat pr_warn("LED trigger %s failed to register (no memory)\n",
45509f5fe75SSachin Kamat name);
45609f5fe75SSachin Kamat }
457eb202621SBryan Wu *tp = trig;
4584d404fd5SNémeth Márton }
4594d404fd5SNémeth Márton EXPORT_SYMBOL_GPL(led_trigger_register_simple);
460c3bc9956SRichard Purdie
led_trigger_unregister_simple(struct led_trigger * trig)461eb202621SBryan Wu void led_trigger_unregister_simple(struct led_trigger *trig)
462c3bc9956SRichard Purdie {
463eb202621SBryan Wu if (trig)
464eb202621SBryan Wu led_trigger_unregister(trig);
465eb202621SBryan Wu kfree(trig);
466c3bc9956SRichard Purdie }
467c3bc9956SRichard Purdie EXPORT_SYMBOL_GPL(led_trigger_unregister_simple);
468