xref: /OK3568_Linux_fs/kernel/drivers/leds/led-triggers.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * LED Triggers Core
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright 2005-2007 Openedhand Ltd.
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Author: Richard Purdie <rpurdie@openedhand.com>
8*4882a593Smuzhiyun  */
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include <linux/export.h>
11*4882a593Smuzhiyun #include <linux/kernel.h>
12*4882a593Smuzhiyun #include <linux/list.h>
13*4882a593Smuzhiyun #include <linux/spinlock.h>
14*4882a593Smuzhiyun #include <linux/device.h>
15*4882a593Smuzhiyun #include <linux/timer.h>
16*4882a593Smuzhiyun #include <linux/rwsem.h>
17*4882a593Smuzhiyun #include <linux/leds.h>
18*4882a593Smuzhiyun #include <linux/slab.h>
19*4882a593Smuzhiyun #include <linux/mm.h>
20*4882a593Smuzhiyun #include "leds.h"
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun /*
23*4882a593Smuzhiyun  * Nests outside led_cdev->trigger_lock
24*4882a593Smuzhiyun  */
25*4882a593Smuzhiyun static DECLARE_RWSEM(triggers_list_lock);
26*4882a593Smuzhiyun LIST_HEAD(trigger_list);
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun  /* Used by LED Class */
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun static inline bool
trigger_relevant(struct led_classdev * led_cdev,struct led_trigger * trig)31*4882a593Smuzhiyun trigger_relevant(struct led_classdev *led_cdev, struct led_trigger *trig)
32*4882a593Smuzhiyun {
33*4882a593Smuzhiyun 	return !trig->trigger_type || trig->trigger_type == led_cdev->trigger_type;
34*4882a593Smuzhiyun }
35*4882a593Smuzhiyun 
led_trigger_write(struct file * filp,struct kobject * kobj,struct bin_attribute * bin_attr,char * buf,loff_t pos,size_t count)36*4882a593Smuzhiyun ssize_t led_trigger_write(struct file *filp, struct kobject *kobj,
37*4882a593Smuzhiyun 			  struct bin_attribute *bin_attr, char *buf,
38*4882a593Smuzhiyun 			  loff_t pos, size_t count)
39*4882a593Smuzhiyun {
40*4882a593Smuzhiyun 	struct device *dev = kobj_to_dev(kobj);
41*4882a593Smuzhiyun 	struct led_classdev *led_cdev = dev_get_drvdata(dev);
42*4882a593Smuzhiyun 	struct led_trigger *trig;
43*4882a593Smuzhiyun 	int ret = count;
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun 	mutex_lock(&led_cdev->led_access);
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun 	if (led_sysfs_is_disabled(led_cdev)) {
48*4882a593Smuzhiyun 		ret = -EBUSY;
49*4882a593Smuzhiyun 		goto unlock;
50*4882a593Smuzhiyun 	}
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun 	if (sysfs_streq(buf, "none")) {
53*4882a593Smuzhiyun 		led_trigger_remove(led_cdev);
54*4882a593Smuzhiyun 		goto unlock;
55*4882a593Smuzhiyun 	}
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun 	down_read(&triggers_list_lock);
58*4882a593Smuzhiyun 	list_for_each_entry(trig, &trigger_list, next_trig) {
59*4882a593Smuzhiyun 		if (sysfs_streq(buf, trig->name) && trigger_relevant(led_cdev, trig)) {
60*4882a593Smuzhiyun 			down_write(&led_cdev->trigger_lock);
61*4882a593Smuzhiyun 			led_trigger_set(led_cdev, trig);
62*4882a593Smuzhiyun 			up_write(&led_cdev->trigger_lock);
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun 			up_read(&triggers_list_lock);
65*4882a593Smuzhiyun 			goto unlock;
66*4882a593Smuzhiyun 		}
67*4882a593Smuzhiyun 	}
68*4882a593Smuzhiyun 	/* we come here only if buf matches no trigger */
69*4882a593Smuzhiyun 	ret = -EINVAL;
70*4882a593Smuzhiyun 	up_read(&triggers_list_lock);
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun unlock:
73*4882a593Smuzhiyun 	mutex_unlock(&led_cdev->led_access);
74*4882a593Smuzhiyun 	return ret;
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(led_trigger_write);
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun __printf(3, 4)
led_trigger_snprintf(char * buf,ssize_t size,const char * fmt,...)79*4882a593Smuzhiyun static int led_trigger_snprintf(char *buf, ssize_t size, const char *fmt, ...)
80*4882a593Smuzhiyun {
81*4882a593Smuzhiyun 	va_list args;
82*4882a593Smuzhiyun 	int i;
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 	va_start(args, fmt);
85*4882a593Smuzhiyun 	if (size <= 0)
86*4882a593Smuzhiyun 		i = vsnprintf(NULL, 0, fmt, args);
87*4882a593Smuzhiyun 	else
88*4882a593Smuzhiyun 		i = vscnprintf(buf, size, fmt, args);
89*4882a593Smuzhiyun 	va_end(args);
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun 	return i;
92*4882a593Smuzhiyun }
93*4882a593Smuzhiyun 
led_trigger_format(char * buf,size_t size,struct led_classdev * led_cdev)94*4882a593Smuzhiyun static int led_trigger_format(char *buf, size_t size,
95*4882a593Smuzhiyun 			      struct led_classdev *led_cdev)
96*4882a593Smuzhiyun {
97*4882a593Smuzhiyun 	struct led_trigger *trig;
98*4882a593Smuzhiyun 	int len = led_trigger_snprintf(buf, size, "%s",
99*4882a593Smuzhiyun 				       led_cdev->trigger ? "none" : "[none]");
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun 	list_for_each_entry(trig, &trigger_list, next_trig) {
102*4882a593Smuzhiyun 		bool hit;
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun 		if (!trigger_relevant(led_cdev, trig))
105*4882a593Smuzhiyun 			continue;
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun 		hit = led_cdev->trigger && !strcmp(led_cdev->trigger->name, trig->name);
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 		len += led_trigger_snprintf(buf + len, size - len,
110*4882a593Smuzhiyun 					    " %s%s%s", hit ? "[" : "",
111*4882a593Smuzhiyun 					    trig->name, hit ? "]" : "");
112*4882a593Smuzhiyun 	}
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	len += led_trigger_snprintf(buf + len, size - len, "\n");
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun 	return len;
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun /*
120*4882a593Smuzhiyun  * It was stupid to create 10000 cpu triggers, but we are stuck with it now.
121*4882a593Smuzhiyun  * Don't make that mistake again. We work around it here by creating binary
122*4882a593Smuzhiyun  * attribute, which is not limited by length. This is _not_ good design, do not
123*4882a593Smuzhiyun  * copy it.
124*4882a593Smuzhiyun  */
led_trigger_read(struct file * filp,struct kobject * kobj,struct bin_attribute * attr,char * buf,loff_t pos,size_t count)125*4882a593Smuzhiyun ssize_t led_trigger_read(struct file *filp, struct kobject *kobj,
126*4882a593Smuzhiyun 			struct bin_attribute *attr, char *buf,
127*4882a593Smuzhiyun 			loff_t pos, size_t count)
128*4882a593Smuzhiyun {
129*4882a593Smuzhiyun 	struct device *dev = kobj_to_dev(kobj);
130*4882a593Smuzhiyun 	struct led_classdev *led_cdev = dev_get_drvdata(dev);
131*4882a593Smuzhiyun 	void *data;
132*4882a593Smuzhiyun 	int len;
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun 	down_read(&triggers_list_lock);
135*4882a593Smuzhiyun 	down_read(&led_cdev->trigger_lock);
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun 	len = led_trigger_format(NULL, 0, led_cdev);
138*4882a593Smuzhiyun 	data = kvmalloc(len + 1, GFP_KERNEL);
139*4882a593Smuzhiyun 	if (!data) {
140*4882a593Smuzhiyun 		up_read(&led_cdev->trigger_lock);
141*4882a593Smuzhiyun 		up_read(&triggers_list_lock);
142*4882a593Smuzhiyun 		return -ENOMEM;
143*4882a593Smuzhiyun 	}
144*4882a593Smuzhiyun 	len = led_trigger_format(data, len + 1, led_cdev);
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun 	up_read(&led_cdev->trigger_lock);
147*4882a593Smuzhiyun 	up_read(&triggers_list_lock);
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 	len = memory_read_from_buffer(buf, count, &pos, data, len);
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 	kvfree(data);
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 	return len;
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(led_trigger_read);
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun /* Caller must ensure led_cdev->trigger_lock held */
led_trigger_set(struct led_classdev * led_cdev,struct led_trigger * trig)158*4882a593Smuzhiyun int led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig)
159*4882a593Smuzhiyun {
160*4882a593Smuzhiyun 	unsigned long flags;
161*4882a593Smuzhiyun 	char *event = NULL;
162*4882a593Smuzhiyun 	char *envp[2];
163*4882a593Smuzhiyun 	const char *name;
164*4882a593Smuzhiyun 	int ret;
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun 	if (!led_cdev->trigger && !trig)
167*4882a593Smuzhiyun 		return 0;
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	name = trig ? trig->name : "none";
170*4882a593Smuzhiyun 	event = kasprintf(GFP_KERNEL, "TRIGGER=%s", name);
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 	/* Remove any existing trigger */
173*4882a593Smuzhiyun 	if (led_cdev->trigger) {
174*4882a593Smuzhiyun 		write_lock_irqsave(&led_cdev->trigger->leddev_list_lock, flags);
175*4882a593Smuzhiyun 		list_del(&led_cdev->trig_list);
176*4882a593Smuzhiyun 		write_unlock_irqrestore(&led_cdev->trigger->leddev_list_lock,
177*4882a593Smuzhiyun 			flags);
178*4882a593Smuzhiyun 		cancel_work_sync(&led_cdev->set_brightness_work);
179*4882a593Smuzhiyun 		led_stop_software_blink(led_cdev);
180*4882a593Smuzhiyun 		if (led_cdev->trigger->deactivate)
181*4882a593Smuzhiyun 			led_cdev->trigger->deactivate(led_cdev);
182*4882a593Smuzhiyun 		device_remove_groups(led_cdev->dev, led_cdev->trigger->groups);
183*4882a593Smuzhiyun 		led_cdev->trigger = NULL;
184*4882a593Smuzhiyun 		led_cdev->trigger_data = NULL;
185*4882a593Smuzhiyun 		led_cdev->activated = false;
186*4882a593Smuzhiyun 		led_set_brightness(led_cdev, LED_OFF);
187*4882a593Smuzhiyun 	}
188*4882a593Smuzhiyun 	if (trig) {
189*4882a593Smuzhiyun 		write_lock_irqsave(&trig->leddev_list_lock, flags);
190*4882a593Smuzhiyun 		list_add_tail(&led_cdev->trig_list, &trig->led_cdevs);
191*4882a593Smuzhiyun 		write_unlock_irqrestore(&trig->leddev_list_lock, flags);
192*4882a593Smuzhiyun 		led_cdev->trigger = trig;
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 		if (trig->activate)
195*4882a593Smuzhiyun 			ret = trig->activate(led_cdev);
196*4882a593Smuzhiyun 		else
197*4882a593Smuzhiyun 			ret = 0;
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 		if (ret)
200*4882a593Smuzhiyun 			goto err_activate;
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun 		ret = device_add_groups(led_cdev->dev, trig->groups);
203*4882a593Smuzhiyun 		if (ret) {
204*4882a593Smuzhiyun 			dev_err(led_cdev->dev, "Failed to add trigger attributes\n");
205*4882a593Smuzhiyun 			goto err_add_groups;
206*4882a593Smuzhiyun 		}
207*4882a593Smuzhiyun 	}
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun 	if (event) {
210*4882a593Smuzhiyun 		envp[0] = event;
211*4882a593Smuzhiyun 		envp[1] = NULL;
212*4882a593Smuzhiyun 		if (kobject_uevent_env(&led_cdev->dev->kobj, KOBJ_CHANGE, envp))
213*4882a593Smuzhiyun 			dev_err(led_cdev->dev,
214*4882a593Smuzhiyun 				"%s: Error sending uevent\n", __func__);
215*4882a593Smuzhiyun 		kfree(event);
216*4882a593Smuzhiyun 	}
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun 	return 0;
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun err_add_groups:
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 	if (trig->deactivate)
223*4882a593Smuzhiyun 		trig->deactivate(led_cdev);
224*4882a593Smuzhiyun err_activate:
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun 	write_lock_irqsave(&led_cdev->trigger->leddev_list_lock, flags);
227*4882a593Smuzhiyun 	list_del(&led_cdev->trig_list);
228*4882a593Smuzhiyun 	write_unlock_irqrestore(&led_cdev->trigger->leddev_list_lock, flags);
229*4882a593Smuzhiyun 	led_cdev->trigger = NULL;
230*4882a593Smuzhiyun 	led_cdev->trigger_data = NULL;
231*4882a593Smuzhiyun 	led_set_brightness(led_cdev, LED_OFF);
232*4882a593Smuzhiyun 	kfree(event);
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun 	return ret;
235*4882a593Smuzhiyun }
236*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(led_trigger_set);
237*4882a593Smuzhiyun 
led_trigger_remove(struct led_classdev * led_cdev)238*4882a593Smuzhiyun void led_trigger_remove(struct led_classdev *led_cdev)
239*4882a593Smuzhiyun {
240*4882a593Smuzhiyun 	down_write(&led_cdev->trigger_lock);
241*4882a593Smuzhiyun 	led_trigger_set(led_cdev, NULL);
242*4882a593Smuzhiyun 	up_write(&led_cdev->trigger_lock);
243*4882a593Smuzhiyun }
244*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(led_trigger_remove);
245*4882a593Smuzhiyun 
led_trigger_set_default(struct led_classdev * led_cdev)246*4882a593Smuzhiyun void led_trigger_set_default(struct led_classdev *led_cdev)
247*4882a593Smuzhiyun {
248*4882a593Smuzhiyun 	struct led_trigger *trig;
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun 	if (!led_cdev->default_trigger)
251*4882a593Smuzhiyun 		return;
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	down_read(&triggers_list_lock);
254*4882a593Smuzhiyun 	down_write(&led_cdev->trigger_lock);
255*4882a593Smuzhiyun 	list_for_each_entry(trig, &trigger_list, next_trig) {
256*4882a593Smuzhiyun 		if (!strcmp(led_cdev->default_trigger, trig->name) &&
257*4882a593Smuzhiyun 		    trigger_relevant(led_cdev, trig)) {
258*4882a593Smuzhiyun 			led_cdev->flags |= LED_INIT_DEFAULT_TRIGGER;
259*4882a593Smuzhiyun 			led_trigger_set(led_cdev, trig);
260*4882a593Smuzhiyun 			break;
261*4882a593Smuzhiyun 		}
262*4882a593Smuzhiyun 	}
263*4882a593Smuzhiyun 	up_write(&led_cdev->trigger_lock);
264*4882a593Smuzhiyun 	up_read(&triggers_list_lock);
265*4882a593Smuzhiyun }
266*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(led_trigger_set_default);
267*4882a593Smuzhiyun 
led_trigger_rename_static(const char * name,struct led_trigger * trig)268*4882a593Smuzhiyun void led_trigger_rename_static(const char *name, struct led_trigger *trig)
269*4882a593Smuzhiyun {
270*4882a593Smuzhiyun 	/* new name must be on a temporary string to prevent races */
271*4882a593Smuzhiyun 	BUG_ON(name == trig->name);
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun 	down_write(&triggers_list_lock);
274*4882a593Smuzhiyun 	/* this assumes that trig->name was originaly allocated to
275*4882a593Smuzhiyun 	 * non constant storage */
276*4882a593Smuzhiyun 	strcpy((char *)trig->name, name);
277*4882a593Smuzhiyun 	up_write(&triggers_list_lock);
278*4882a593Smuzhiyun }
279*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(led_trigger_rename_static);
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun /* LED Trigger Interface */
282*4882a593Smuzhiyun 
led_trigger_register(struct led_trigger * trig)283*4882a593Smuzhiyun int led_trigger_register(struct led_trigger *trig)
284*4882a593Smuzhiyun {
285*4882a593Smuzhiyun 	struct led_classdev *led_cdev;
286*4882a593Smuzhiyun 	struct led_trigger *_trig;
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun 	rwlock_init(&trig->leddev_list_lock);
289*4882a593Smuzhiyun 	INIT_LIST_HEAD(&trig->led_cdevs);
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 	down_write(&triggers_list_lock);
292*4882a593Smuzhiyun 	/* Make sure the trigger's name isn't already in use */
293*4882a593Smuzhiyun 	list_for_each_entry(_trig, &trigger_list, next_trig) {
294*4882a593Smuzhiyun 		if (!strcmp(_trig->name, trig->name) &&
295*4882a593Smuzhiyun 		    (trig->trigger_type == _trig->trigger_type ||
296*4882a593Smuzhiyun 		     !trig->trigger_type || !_trig->trigger_type)) {
297*4882a593Smuzhiyun 			up_write(&triggers_list_lock);
298*4882a593Smuzhiyun 			return -EEXIST;
299*4882a593Smuzhiyun 		}
300*4882a593Smuzhiyun 	}
301*4882a593Smuzhiyun 	/* Add to the list of led triggers */
302*4882a593Smuzhiyun 	list_add_tail(&trig->next_trig, &trigger_list);
303*4882a593Smuzhiyun 	up_write(&triggers_list_lock);
304*4882a593Smuzhiyun 
305*4882a593Smuzhiyun 	/* Register with any LEDs that have this as a default trigger */
306*4882a593Smuzhiyun 	down_read(&leds_list_lock);
307*4882a593Smuzhiyun 	list_for_each_entry(led_cdev, &leds_list, node) {
308*4882a593Smuzhiyun 		down_write(&led_cdev->trigger_lock);
309*4882a593Smuzhiyun 		if (!led_cdev->trigger && led_cdev->default_trigger &&
310*4882a593Smuzhiyun 		    !strcmp(led_cdev->default_trigger, trig->name) &&
311*4882a593Smuzhiyun 		    trigger_relevant(led_cdev, trig)) {
312*4882a593Smuzhiyun 			led_cdev->flags |= LED_INIT_DEFAULT_TRIGGER;
313*4882a593Smuzhiyun 			led_trigger_set(led_cdev, trig);
314*4882a593Smuzhiyun 		}
315*4882a593Smuzhiyun 		up_write(&led_cdev->trigger_lock);
316*4882a593Smuzhiyun 	}
317*4882a593Smuzhiyun 	up_read(&leds_list_lock);
318*4882a593Smuzhiyun 
319*4882a593Smuzhiyun 	return 0;
320*4882a593Smuzhiyun }
321*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(led_trigger_register);
322*4882a593Smuzhiyun 
led_trigger_unregister(struct led_trigger * trig)323*4882a593Smuzhiyun void led_trigger_unregister(struct led_trigger *trig)
324*4882a593Smuzhiyun {
325*4882a593Smuzhiyun 	struct led_classdev *led_cdev;
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 	if (list_empty_careful(&trig->next_trig))
328*4882a593Smuzhiyun 		return;
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 	/* Remove from the list of led triggers */
331*4882a593Smuzhiyun 	down_write(&triggers_list_lock);
332*4882a593Smuzhiyun 	list_del_init(&trig->next_trig);
333*4882a593Smuzhiyun 	up_write(&triggers_list_lock);
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	/* Remove anyone actively using this trigger */
336*4882a593Smuzhiyun 	down_read(&leds_list_lock);
337*4882a593Smuzhiyun 	list_for_each_entry(led_cdev, &leds_list, node) {
338*4882a593Smuzhiyun 		down_write(&led_cdev->trigger_lock);
339*4882a593Smuzhiyun 		if (led_cdev->trigger == trig)
340*4882a593Smuzhiyun 			led_trigger_set(led_cdev, NULL);
341*4882a593Smuzhiyun 		up_write(&led_cdev->trigger_lock);
342*4882a593Smuzhiyun 	}
343*4882a593Smuzhiyun 	up_read(&leds_list_lock);
344*4882a593Smuzhiyun }
345*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(led_trigger_unregister);
346*4882a593Smuzhiyun 
devm_led_trigger_release(struct device * dev,void * res)347*4882a593Smuzhiyun static void devm_led_trigger_release(struct device *dev, void *res)
348*4882a593Smuzhiyun {
349*4882a593Smuzhiyun 	led_trigger_unregister(*(struct led_trigger **)res);
350*4882a593Smuzhiyun }
351*4882a593Smuzhiyun 
devm_led_trigger_register(struct device * dev,struct led_trigger * trig)352*4882a593Smuzhiyun int devm_led_trigger_register(struct device *dev,
353*4882a593Smuzhiyun 			      struct led_trigger *trig)
354*4882a593Smuzhiyun {
355*4882a593Smuzhiyun 	struct led_trigger **dr;
356*4882a593Smuzhiyun 	int rc;
357*4882a593Smuzhiyun 
358*4882a593Smuzhiyun 	dr = devres_alloc(devm_led_trigger_release, sizeof(*dr),
359*4882a593Smuzhiyun 			  GFP_KERNEL);
360*4882a593Smuzhiyun 	if (!dr)
361*4882a593Smuzhiyun 		return -ENOMEM;
362*4882a593Smuzhiyun 
363*4882a593Smuzhiyun 	*dr = trig;
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun 	rc = led_trigger_register(trig);
366*4882a593Smuzhiyun 	if (rc)
367*4882a593Smuzhiyun 		devres_free(dr);
368*4882a593Smuzhiyun 	else
369*4882a593Smuzhiyun 		devres_add(dev, dr);
370*4882a593Smuzhiyun 
371*4882a593Smuzhiyun 	return rc;
372*4882a593Smuzhiyun }
373*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(devm_led_trigger_register);
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun /* Simple LED Trigger Interface */
376*4882a593Smuzhiyun 
led_trigger_event(struct led_trigger * trig,enum led_brightness brightness)377*4882a593Smuzhiyun void led_trigger_event(struct led_trigger *trig,
378*4882a593Smuzhiyun 			enum led_brightness brightness)
379*4882a593Smuzhiyun {
380*4882a593Smuzhiyun 	struct led_classdev *led_cdev;
381*4882a593Smuzhiyun 	unsigned long flags;
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun 	if (!trig)
384*4882a593Smuzhiyun 		return;
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun 	read_lock_irqsave(&trig->leddev_list_lock, flags);
387*4882a593Smuzhiyun 	list_for_each_entry(led_cdev, &trig->led_cdevs, trig_list)
388*4882a593Smuzhiyun 		led_set_brightness(led_cdev, brightness);
389*4882a593Smuzhiyun 	read_unlock_irqrestore(&trig->leddev_list_lock, flags);
390*4882a593Smuzhiyun }
391*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(led_trigger_event);
392*4882a593Smuzhiyun 
led_trigger_blink_setup(struct led_trigger * trig,unsigned long * delay_on,unsigned long * delay_off,int oneshot,int invert)393*4882a593Smuzhiyun static void led_trigger_blink_setup(struct led_trigger *trig,
394*4882a593Smuzhiyun 			     unsigned long *delay_on,
395*4882a593Smuzhiyun 			     unsigned long *delay_off,
396*4882a593Smuzhiyun 			     int oneshot,
397*4882a593Smuzhiyun 			     int invert)
398*4882a593Smuzhiyun {
399*4882a593Smuzhiyun 	struct led_classdev *led_cdev;
400*4882a593Smuzhiyun 	unsigned long flags;
401*4882a593Smuzhiyun 
402*4882a593Smuzhiyun 	if (!trig)
403*4882a593Smuzhiyun 		return;
404*4882a593Smuzhiyun 
405*4882a593Smuzhiyun 	read_lock_irqsave(&trig->leddev_list_lock, flags);
406*4882a593Smuzhiyun 	list_for_each_entry(led_cdev, &trig->led_cdevs, trig_list) {
407*4882a593Smuzhiyun 		if (oneshot)
408*4882a593Smuzhiyun 			led_blink_set_oneshot(led_cdev, delay_on, delay_off,
409*4882a593Smuzhiyun 					      invert);
410*4882a593Smuzhiyun 		else
411*4882a593Smuzhiyun 			led_blink_set(led_cdev, delay_on, delay_off);
412*4882a593Smuzhiyun 	}
413*4882a593Smuzhiyun 	read_unlock_irqrestore(&trig->leddev_list_lock, flags);
414*4882a593Smuzhiyun }
415*4882a593Smuzhiyun 
led_trigger_blink(struct led_trigger * trig,unsigned long * delay_on,unsigned long * delay_off)416*4882a593Smuzhiyun void led_trigger_blink(struct led_trigger *trig,
417*4882a593Smuzhiyun 		       unsigned long *delay_on,
418*4882a593Smuzhiyun 		       unsigned long *delay_off)
419*4882a593Smuzhiyun {
420*4882a593Smuzhiyun 	led_trigger_blink_setup(trig, delay_on, delay_off, 0, 0);
421*4882a593Smuzhiyun }
422*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(led_trigger_blink);
423*4882a593Smuzhiyun 
led_trigger_blink_oneshot(struct led_trigger * trig,unsigned long * delay_on,unsigned long * delay_off,int invert)424*4882a593Smuzhiyun void led_trigger_blink_oneshot(struct led_trigger *trig,
425*4882a593Smuzhiyun 			       unsigned long *delay_on,
426*4882a593Smuzhiyun 			       unsigned long *delay_off,
427*4882a593Smuzhiyun 			       int invert)
428*4882a593Smuzhiyun {
429*4882a593Smuzhiyun 	led_trigger_blink_setup(trig, delay_on, delay_off, 1, invert);
430*4882a593Smuzhiyun }
431*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(led_trigger_blink_oneshot);
432*4882a593Smuzhiyun 
led_trigger_register_simple(const char * name,struct led_trigger ** tp)433*4882a593Smuzhiyun void led_trigger_register_simple(const char *name, struct led_trigger **tp)
434*4882a593Smuzhiyun {
435*4882a593Smuzhiyun 	struct led_trigger *trig;
436*4882a593Smuzhiyun 	int err;
437*4882a593Smuzhiyun 
438*4882a593Smuzhiyun 	trig = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun 	if (trig) {
441*4882a593Smuzhiyun 		trig->name = name;
442*4882a593Smuzhiyun 		err = led_trigger_register(trig);
443*4882a593Smuzhiyun 		if (err < 0) {
444*4882a593Smuzhiyun 			kfree(trig);
445*4882a593Smuzhiyun 			trig = NULL;
446*4882a593Smuzhiyun 			pr_warn("LED trigger %s failed to register (%d)\n",
447*4882a593Smuzhiyun 				name, err);
448*4882a593Smuzhiyun 		}
449*4882a593Smuzhiyun 	} else {
450*4882a593Smuzhiyun 		pr_warn("LED trigger %s failed to register (no memory)\n",
451*4882a593Smuzhiyun 			name);
452*4882a593Smuzhiyun 	}
453*4882a593Smuzhiyun 	*tp = trig;
454*4882a593Smuzhiyun }
455*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(led_trigger_register_simple);
456*4882a593Smuzhiyun 
led_trigger_unregister_simple(struct led_trigger * trig)457*4882a593Smuzhiyun void led_trigger_unregister_simple(struct led_trigger *trig)
458*4882a593Smuzhiyun {
459*4882a593Smuzhiyun 	if (trig)
460*4882a593Smuzhiyun 		led_trigger_unregister(trig);
461*4882a593Smuzhiyun 	kfree(trig);
462*4882a593Smuzhiyun }
463*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(led_trigger_unregister_simple);
464