xref: /openbmc/linux/drivers/leds/led-triggers.c (revision 0db00e5d86dc793aab9722ad3728d99166eb7d96)
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