blob: 79e30d2cb7a5cfdc5f96e36ae69b25dbc0a17050 [file] [log] [blame]
Thomas Gleixnerd2912cb2019-06-04 10:11:33 +02001// SPDX-License-Identifier: GPL-2.0-only
Richard Purdiec3bc9952006-03-31 02:31:05 -08002/*
3 * LED Triggers Core
4 *
Richard Purdief8a7c6f2007-07-08 23:19:31 +01005 * Copyright 2005-2007 Openedhand Ltd.
Richard Purdiec3bc9952006-03-31 02:31:05 -08006 *
7 * Author: Richard Purdie <rpurdie@openedhand.com>
Richard Purdiec3bc9952006-03-31 02:31:05 -08008 */
9
Paul Gortmaker50237862016-08-15 16:54:48 -040010#include <linux/export.h>
Richard Purdiec3bc9952006-03-31 02:31:05 -080011#include <linux/kernel.h>
Richard Purdiec3bc9952006-03-31 02:31:05 -080012#include <linux/list.h>
13#include <linux/spinlock.h>
14#include <linux/device.h>
Richard Purdiec3bc9952006-03-31 02:31:05 -080015#include <linux/timer.h>
Richard Purdiedc472062007-11-10 13:29:04 +000016#include <linux/rwsem.h>
Richard Purdiec3bc9952006-03-31 02:31:05 -080017#include <linux/leds.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090018#include <linux/slab.h>
Akinobu Mita11f70002019-09-29 23:18:49 +090019#include <linux/mm.h>
Richard Purdiec3bc9952006-03-31 02:31:05 -080020#include "leds.h"
21
22/*
23 * Nests outside led_cdev->trigger_lock
24 */
Richard Purdiedc472062007-11-10 13:29:04 +000025static DECLARE_RWSEM(triggers_list_lock);
Ezequiel Garciaba93cdc2016-04-28 19:03:38 -030026LIST_HEAD(trigger_list);
Richard Purdiec3bc9952006-03-31 02:31:05 -080027
Németh Márton4d404fd2008-03-09 20:59:57 +000028 /* Used by LED Class */
29
Akinobu Mita11f70002019-09-29 23:18:49 +090030ssize_t led_trigger_write(struct file *filp, struct kobject *kobj,
31 struct bin_attribute *bin_attr, char *buf,
32 loff_t pos, size_t count)
Richard Purdiec3bc9952006-03-31 02:31:05 -080033{
Akinobu Mita11f70002019-09-29 23:18:49 +090034 struct device *dev = kobj_to_dev(kobj);
Richard Purdief8a7c6f2007-07-08 23:19:31 +010035 struct led_classdev *led_cdev = dev_get_drvdata(dev);
Richard Purdiec3bc9952006-03-31 02:31:05 -080036 struct led_trigger *trig;
Jacek Anaszewskiacd899e2014-09-22 08:21:04 -070037 int ret = count;
38
39 mutex_lock(&led_cdev->led_access);
40
41 if (led_sysfs_is_disabled(led_cdev)) {
42 ret = -EBUSY;
43 goto unlock;
44 }
Richard Purdiec3bc9952006-03-31 02:31:05 -080045
Heiner Kallweit7296c332016-03-08 23:08:36 +010046 if (sysfs_streq(buf, "none")) {
Németh Márton0013b232008-03-09 20:54:37 +000047 led_trigger_remove(led_cdev);
Jacek Anaszewskiacd899e2014-09-22 08:21:04 -070048 goto unlock;
Richard Purdiec3bc9952006-03-31 02:31:05 -080049 }
50
Richard Purdiedc472062007-11-10 13:29:04 +000051 down_read(&triggers_list_lock);
Richard Purdiec3bc9952006-03-31 02:31:05 -080052 list_for_each_entry(trig, &trigger_list, next_trig) {
Heiner Kallweit7296c332016-03-08 23:08:36 +010053 if (sysfs_streq(buf, trig->name)) {
Richard Purdiedc472062007-11-10 13:29:04 +000054 down_write(&led_cdev->trigger_lock);
Richard Purdiec3bc9952006-03-31 02:31:05 -080055 led_trigger_set(led_cdev, trig);
Richard Purdiedc472062007-11-10 13:29:04 +000056 up_write(&led_cdev->trigger_lock);
Richard Purdiec3bc9952006-03-31 02:31:05 -080057
Richard Purdiedc472062007-11-10 13:29:04 +000058 up_read(&triggers_list_lock);
Jacek Anaszewskiacd899e2014-09-22 08:21:04 -070059 goto unlock;
Richard Purdiec3bc9952006-03-31 02:31:05 -080060 }
61 }
Heiner Kallweita3eac762016-07-01 23:08:54 +020062 /* we come here only if buf matches no trigger */
63 ret = -EINVAL;
Richard Purdiedc472062007-11-10 13:29:04 +000064 up_read(&triggers_list_lock);
Richard Purdiec3bc9952006-03-31 02:31:05 -080065
Jacek Anaszewskiacd899e2014-09-22 08:21:04 -070066unlock:
67 mutex_unlock(&led_cdev->led_access);
68 return ret;
Richard Purdiec3bc9952006-03-31 02:31:05 -080069}
Akinobu Mita11f70002019-09-29 23:18:49 +090070EXPORT_SYMBOL_GPL(led_trigger_write);
Richard Purdiec3bc9952006-03-31 02:31:05 -080071
Akinobu Mita11f70002019-09-29 23:18:49 +090072__printf(3, 4)
73static int led_trigger_snprintf(char *buf, ssize_t size, const char *fmt, ...)
Richard Purdiec3bc9952006-03-31 02:31:05 -080074{
Akinobu Mita11f70002019-09-29 23:18:49 +090075 va_list args;
76 int i;
77
78 va_start(args, fmt);
79 if (size <= 0)
80 i = vsnprintf(NULL, 0, fmt, args);
81 else
82 i = vscnprintf(buf, size, fmt, args);
83 va_end(args);
84
85 return i;
86}
87
88static int led_trigger_format(char *buf, size_t size,
89 struct led_classdev *led_cdev)
90{
Richard Purdiec3bc9952006-03-31 02:31:05 -080091 struct led_trigger *trig;
Akinobu Mita11f70002019-09-29 23:18:49 +090092 int len = led_trigger_snprintf(buf, size, "%s",
93 led_cdev->trigger ? "none" : "[none]");
94
95 list_for_each_entry(trig, &trigger_list, next_trig) {
96 bool hit = led_cdev->trigger &&
97 !strcmp(led_cdev->trigger->name, trig->name);
98
99 len += led_trigger_snprintf(buf + len, size - len,
100 " %s%s%s", hit ? "[" : "",
101 trig->name, hit ? "]" : "");
102 }
103
104 len += led_trigger_snprintf(buf + len, size - len, "\n");
105
106 return len;
107}
108
109/*
110 * It was stupid to create 10000 cpu triggers, but we are stuck with it now.
111 * Don't make that mistake again. We work around it here by creating binary
112 * attribute, which is not limited by length. This is _not_ good design, do not
113 * copy it.
114 */
115ssize_t led_trigger_read(struct file *filp, struct kobject *kobj,
116 struct bin_attribute *attr, char *buf,
117 loff_t pos, size_t count)
118{
119 struct device *dev = kobj_to_dev(kobj);
120 struct led_classdev *led_cdev = dev_get_drvdata(dev);
121 void *data;
122 int len;
Richard Purdiec3bc9952006-03-31 02:31:05 -0800123
Richard Purdiedc472062007-11-10 13:29:04 +0000124 down_read(&triggers_list_lock);
125 down_read(&led_cdev->trigger_lock);
Richard Purdiec3bc9952006-03-31 02:31:05 -0800126
Akinobu Mita11f70002019-09-29 23:18:49 +0900127 len = led_trigger_format(NULL, 0, led_cdev);
128 data = kvmalloc(len + 1, GFP_KERNEL);
129 if (!data) {
130 up_read(&led_cdev->trigger_lock);
131 up_read(&triggers_list_lock);
132 return -ENOMEM;
Richard Purdiec3bc9952006-03-31 02:31:05 -0800133 }
Akinobu Mita11f70002019-09-29 23:18:49 +0900134 len = led_trigger_format(data, len + 1, led_cdev);
135
Richard Purdiedc472062007-11-10 13:29:04 +0000136 up_read(&led_cdev->trigger_lock);
137 up_read(&triggers_list_lock);
Richard Purdiec3bc9952006-03-31 02:31:05 -0800138
Akinobu Mita11f70002019-09-29 23:18:49 +0900139 len = memory_read_from_buffer(buf, count, &pos, data, len);
140
141 kvfree(data);
142
Richard Purdiec3bc9952006-03-31 02:31:05 -0800143 return len;
144}
Akinobu Mita11f70002019-09-29 23:18:49 +0900145EXPORT_SYMBOL_GPL(led_trigger_read);
Richard Purdiec3bc9952006-03-31 02:31:05 -0800146
147/* Caller must ensure led_cdev->trigger_lock held */
Uwe Kleine-König2282e1252018-07-02 22:05:21 +0200148int led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig)
Richard Purdiec3bc9952006-03-31 02:31:05 -0800149{
150 unsigned long flags;
Colin Cross52c47742012-08-27 09:31:49 +0800151 char *event = NULL;
152 char *envp[2];
153 const char *name;
Uwe Kleine-König2282e1252018-07-02 22:05:21 +0200154 int ret;
Colin Cross52c47742012-08-27 09:31:49 +0800155
Jacek Anaszewskifbfa1972016-09-18 20:24:29 +0200156 if (!led_cdev->trigger && !trig)
Uwe Kleine-König2282e1252018-07-02 22:05:21 +0200157 return 0;
Jacek Anaszewskifbfa1972016-09-18 20:24:29 +0200158
Colin Cross52c47742012-08-27 09:31:49 +0800159 name = trig ? trig->name : "none";
160 event = kasprintf(GFP_KERNEL, "TRIGGER=%s", name);
Richard Purdiec3bc9952006-03-31 02:31:05 -0800161
162 /* Remove any existing trigger */
163 if (led_cdev->trigger) {
164 write_lock_irqsave(&led_cdev->trigger->leddev_list_lock, flags);
165 list_del(&led_cdev->trig_list);
Németh Márton4d404fd2008-03-09 20:59:57 +0000166 write_unlock_irqrestore(&led_cdev->trigger->leddev_list_lock,
167 flags);
Fabio Baltierid23a22a2012-08-15 21:44:34 +0800168 cancel_work_sync(&led_cdev->set_brightness_work);
169 led_stop_software_blink(led_cdev);
Richard Purdiec3bc9952006-03-31 02:31:05 -0800170 if (led_cdev->trigger->deactivate)
171 led_cdev->trigger->deactivate(led_cdev);
Uwe Kleine-Königa7e7a312018-07-02 22:05:22 +0200172 device_remove_groups(led_cdev->dev, led_cdev->trigger->groups);
Dmitry Baryshkovfe3025b2008-07-16 22:51:14 +0100173 led_cdev->trigger = NULL;
Uwe Kleine-Königa7d59042018-07-02 22:05:23 +0200174 led_cdev->trigger_data = NULL;
175 led_cdev->activated = false;
Shuah Khan19cd67e2012-06-14 04:34:30 +0800176 led_set_brightness(led_cdev, LED_OFF);
Richard Purdiec3bc9952006-03-31 02:31:05 -0800177 }
Bryan Wueb202622012-04-19 11:46:33 +0800178 if (trig) {
179 write_lock_irqsave(&trig->leddev_list_lock, flags);
180 list_add_tail(&led_cdev->trig_list, &trig->led_cdevs);
181 write_unlock_irqrestore(&trig->leddev_list_lock, flags);
182 led_cdev->trigger = trig;
Uwe Kleine-König2282e1252018-07-02 22:05:21 +0200183
Bryan Wueb202622012-04-19 11:46:33 +0800184 if (trig->activate)
Uwe Kleine-König2282e1252018-07-02 22:05:21 +0200185 ret = trig->activate(led_cdev);
186 else
187 ret = 0;
188
189 if (ret)
190 goto err_activate;
Uwe Kleine-Königa7e7a312018-07-02 22:05:22 +0200191
192 ret = device_add_groups(led_cdev->dev, trig->groups);
193 if (ret) {
194 dev_err(led_cdev->dev, "Failed to add trigger attributes\n");
195 goto err_add_groups;
196 }
Richard Purdiec3bc9952006-03-31 02:31:05 -0800197 }
Colin Cross52c47742012-08-27 09:31:49 +0800198
199 if (event) {
200 envp[0] = event;
201 envp[1] = NULL;
Jacek Anaszewski6f3bad92016-09-19 12:44:50 +0200202 if (kobject_uevent_env(&led_cdev->dev->kobj, KOBJ_CHANGE, envp))
203 dev_err(led_cdev->dev,
204 "%s: Error sending uevent\n", __func__);
Colin Cross52c47742012-08-27 09:31:49 +0800205 kfree(event);
206 }
Uwe Kleine-König2282e1252018-07-02 22:05:21 +0200207
208 return 0;
209
Uwe Kleine-Königa7e7a312018-07-02 22:05:22 +0200210err_add_groups:
211
212 if (trig->deactivate)
213 trig->deactivate(led_cdev);
Uwe Kleine-König2282e1252018-07-02 22:05:21 +0200214err_activate:
Uwe Kleine-Königa7e7a312018-07-02 22:05:22 +0200215
Uwe Kleine-König2282e1252018-07-02 22:05:21 +0200216 write_lock_irqsave(&led_cdev->trigger->leddev_list_lock, flags);
217 list_del(&led_cdev->trig_list);
218 write_unlock_irqrestore(&led_cdev->trigger->leddev_list_lock, flags);
Oleh Kravchenko4016ba82019-09-04 00:18:19 +0300219 led_cdev->trigger = NULL;
220 led_cdev->trigger_data = NULL;
Uwe Kleine-König2282e1252018-07-02 22:05:21 +0200221 led_set_brightness(led_cdev, LED_OFF);
Wenwen Wang60e2dde2019-08-19 15:41:42 -0500222 kfree(event);
Uwe Kleine-König2282e1252018-07-02 22:05:21 +0200223
224 return ret;
Richard Purdiec3bc9952006-03-31 02:31:05 -0800225}
Németh Márton4d404fd2008-03-09 20:59:57 +0000226EXPORT_SYMBOL_GPL(led_trigger_set);
Richard Purdiec3bc9952006-03-31 02:31:05 -0800227
Németh Márton0013b232008-03-09 20:54:37 +0000228void led_trigger_remove(struct led_classdev *led_cdev)
229{
230 down_write(&led_cdev->trigger_lock);
231 led_trigger_set(led_cdev, NULL);
232 up_write(&led_cdev->trigger_lock);
233}
Németh Márton4d404fd2008-03-09 20:59:57 +0000234EXPORT_SYMBOL_GPL(led_trigger_remove);
Németh Márton0013b232008-03-09 20:54:37 +0000235
Richard Purdiec3bc9952006-03-31 02:31:05 -0800236void led_trigger_set_default(struct led_classdev *led_cdev)
237{
238 struct led_trigger *trig;
239
240 if (!led_cdev->default_trigger)
241 return;
242
Richard Purdiedc472062007-11-10 13:29:04 +0000243 down_read(&triggers_list_lock);
244 down_write(&led_cdev->trigger_lock);
Richard Purdiec3bc9952006-03-31 02:31:05 -0800245 list_for_each_entry(trig, &trigger_list, next_trig) {
Jacek Anaszewskic4f7bd42018-12-10 10:29:57 +0100246 if (!strcmp(led_cdev->default_trigger, trig->name)) {
Jacek Anaszewski02d31762018-12-10 10:29:58 +0100247 led_cdev->flags |= LED_INIT_DEFAULT_TRIGGER;
Richard Purdiec3bc9952006-03-31 02:31:05 -0800248 led_trigger_set(led_cdev, trig);
Jacek Anaszewskic4f7bd42018-12-10 10:29:57 +0100249 break;
250 }
Richard Purdiec3bc9952006-03-31 02:31:05 -0800251 }
Richard Purdiedc472062007-11-10 13:29:04 +0000252 up_write(&led_cdev->trigger_lock);
253 up_read(&triggers_list_lock);
Richard Purdiec3bc9952006-03-31 02:31:05 -0800254}
Németh Márton4d404fd2008-03-09 20:59:57 +0000255EXPORT_SYMBOL_GPL(led_trigger_set_default);
256
Fabio Baltieria8df7b12012-11-04 01:54:34 -0800257void led_trigger_rename_static(const char *name, struct led_trigger *trig)
258{
259 /* new name must be on a temporary string to prevent races */
260 BUG_ON(name == trig->name);
261
262 down_write(&triggers_list_lock);
263 /* this assumes that trig->name was originaly allocated to
264 * non constant storage */
265 strcpy((char *)trig->name, name);
266 up_write(&triggers_list_lock);
267}
268EXPORT_SYMBOL_GPL(led_trigger_rename_static);
269
Németh Márton4d404fd2008-03-09 20:59:57 +0000270/* LED Trigger Interface */
Richard Purdiec3bc9952006-03-31 02:31:05 -0800271
Bryan Wueb202622012-04-19 11:46:33 +0800272int led_trigger_register(struct led_trigger *trig)
Richard Purdiec3bc9952006-03-31 02:31:05 -0800273{
274 struct led_classdev *led_cdev;
Bryan Wueb202622012-04-19 11:46:33 +0800275 struct led_trigger *_trig;
Richard Purdiec3bc9952006-03-31 02:31:05 -0800276
Bryan Wueb202622012-04-19 11:46:33 +0800277 rwlock_init(&trig->leddev_list_lock);
278 INIT_LIST_HEAD(&trig->led_cdevs);
Richard Purdiec3bc9952006-03-31 02:31:05 -0800279
Richard Purdiedc472062007-11-10 13:29:04 +0000280 down_write(&triggers_list_lock);
Adam Nielsen700c6ea2009-02-18 08:18:04 +1000281 /* Make sure the trigger's name isn't already in use */
Bryan Wueb202622012-04-19 11:46:33 +0800282 list_for_each_entry(_trig, &trigger_list, next_trig) {
283 if (!strcmp(_trig->name, trig->name)) {
Adam Nielsen700c6ea2009-02-18 08:18:04 +1000284 up_write(&triggers_list_lock);
285 return -EEXIST;
286 }
287 }
288 /* Add to the list of led triggers */
Bryan Wueb202622012-04-19 11:46:33 +0800289 list_add_tail(&trig->next_trig, &trigger_list);
Richard Purdiedc472062007-11-10 13:29:04 +0000290 up_write(&triggers_list_lock);
Richard Purdiec3bc9952006-03-31 02:31:05 -0800291
292 /* Register with any LEDs that have this as a default trigger */
Richard Purdie72f8da32007-12-31 23:09:44 +0000293 down_read(&leds_list_lock);
Richard Purdiec3bc9952006-03-31 02:31:05 -0800294 list_for_each_entry(led_cdev, &leds_list, node) {
Richard Purdiedc472062007-11-10 13:29:04 +0000295 down_write(&led_cdev->trigger_lock);
Richard Purdiec3bc9952006-03-31 02:31:05 -0800296 if (!led_cdev->trigger && led_cdev->default_trigger &&
Krzysztof Kozlowski8146aac2018-12-10 10:29:59 +0100297 !strcmp(led_cdev->default_trigger, trig->name)) {
298 led_cdev->flags |= LED_INIT_DEFAULT_TRIGGER;
Bryan Wueb202622012-04-19 11:46:33 +0800299 led_trigger_set(led_cdev, trig);
Krzysztof Kozlowski8146aac2018-12-10 10:29:59 +0100300 }
Richard Purdiedc472062007-11-10 13:29:04 +0000301 up_write(&led_cdev->trigger_lock);
Richard Purdiec3bc9952006-03-31 02:31:05 -0800302 }
Richard Purdie72f8da32007-12-31 23:09:44 +0000303 up_read(&leds_list_lock);
Richard Purdiec3bc9952006-03-31 02:31:05 -0800304
305 return 0;
306}
Németh Márton4d404fd2008-03-09 20:59:57 +0000307EXPORT_SYMBOL_GPL(led_trigger_register);
Richard Purdiec3bc9952006-03-31 02:31:05 -0800308
Bryan Wueb202622012-04-19 11:46:33 +0800309void led_trigger_unregister(struct led_trigger *trig)
Richard Purdiec3bc9952006-03-31 02:31:05 -0800310{
311 struct led_classdev *led_cdev;
312
Sasha Levin14f57162014-04-04 10:01:13 -0700313 if (list_empty_careful(&trig->next_trig))
314 return;
315
Richard Purdiec3bc9952006-03-31 02:31:05 -0800316 /* Remove from the list of led triggers */
Richard Purdiedc472062007-11-10 13:29:04 +0000317 down_write(&triggers_list_lock);
Sasha Levin14f57162014-04-04 10:01:13 -0700318 list_del_init(&trig->next_trig);
Richard Purdiedc472062007-11-10 13:29:04 +0000319 up_write(&triggers_list_lock);
Richard Purdiec3bc9952006-03-31 02:31:05 -0800320
321 /* Remove anyone actively using this trigger */
Richard Purdie72f8da32007-12-31 23:09:44 +0000322 down_read(&leds_list_lock);
Richard Purdiec3bc9952006-03-31 02:31:05 -0800323 list_for_each_entry(led_cdev, &leds_list, node) {
Richard Purdiedc472062007-11-10 13:29:04 +0000324 down_write(&led_cdev->trigger_lock);
Bryan Wueb202622012-04-19 11:46:33 +0800325 if (led_cdev->trigger == trig)
Richard Purdiec3bc9952006-03-31 02:31:05 -0800326 led_trigger_set(led_cdev, NULL);
Richard Purdiedc472062007-11-10 13:29:04 +0000327 up_write(&led_cdev->trigger_lock);
Richard Purdiec3bc9952006-03-31 02:31:05 -0800328 }
Richard Purdie72f8da32007-12-31 23:09:44 +0000329 up_read(&leds_list_lock);
Richard Purdiec3bc9952006-03-31 02:31:05 -0800330}
Németh Márton4d404fd2008-03-09 20:59:57 +0000331EXPORT_SYMBOL_GPL(led_trigger_unregister);
332
Heiner Kallweit9534cc32016-01-02 01:36:41 +0100333static void devm_led_trigger_release(struct device *dev, void *res)
334{
335 led_trigger_unregister(*(struct led_trigger **)res);
336}
337
338int devm_led_trigger_register(struct device *dev,
339 struct led_trigger *trig)
340{
341 struct led_trigger **dr;
342 int rc;
343
344 dr = devres_alloc(devm_led_trigger_release, sizeof(*dr),
345 GFP_KERNEL);
346 if (!dr)
347 return -ENOMEM;
348
349 *dr = trig;
350
351 rc = led_trigger_register(trig);
352 if (rc)
353 devres_free(dr);
354 else
355 devres_add(dev, dr);
356
357 return rc;
358}
359EXPORT_SYMBOL_GPL(devm_led_trigger_register);
360
Németh Márton4d404fd2008-03-09 20:59:57 +0000361/* Simple LED Tigger Interface */
362
Bryan Wueb202622012-04-19 11:46:33 +0800363void led_trigger_event(struct led_trigger *trig,
Németh Márton4d404fd2008-03-09 20:59:57 +0000364 enum led_brightness brightness)
365{
ZHAO Gang11e043b2013-12-28 07:00:26 -0800366 struct led_classdev *led_cdev;
Németh Márton4d404fd2008-03-09 20:59:57 +0000367
Bryan Wueb202622012-04-19 11:46:33 +0800368 if (!trig)
Németh Márton4d404fd2008-03-09 20:59:57 +0000369 return;
370
Bryan Wueb202622012-04-19 11:46:33 +0800371 read_lock(&trig->leddev_list_lock);
ZHAO Gang11e043b2013-12-28 07:00:26 -0800372 list_for_each_entry(led_cdev, &trig->led_cdevs, trig_list)
Fabio Baltierid23a22a2012-08-15 21:44:34 +0800373 led_set_brightness(led_cdev, brightness);
Bryan Wueb202622012-04-19 11:46:33 +0800374 read_unlock(&trig->leddev_list_lock);
Németh Márton4d404fd2008-03-09 20:59:57 +0000375}
376EXPORT_SYMBOL_GPL(led_trigger_event);
377
Bryan Wu20c0e6b2012-06-15 22:15:27 +0800378static void led_trigger_blink_setup(struct led_trigger *trig,
Fabio Baltieri5bb629c2012-05-27 07:19:22 +0800379 unsigned long *delay_on,
380 unsigned long *delay_off,
381 int oneshot,
382 int invert)
Vasily Khoruzhick0b9536c2011-01-07 16:28:16 +0000383{
ZHAO Gang11e043b2013-12-28 07:00:26 -0800384 struct led_classdev *led_cdev;
Vasily Khoruzhick0b9536c2011-01-07 16:28:16 +0000385
Bryan Wueb202622012-04-19 11:46:33 +0800386 if (!trig)
Vasily Khoruzhick0b9536c2011-01-07 16:28:16 +0000387 return;
388
Bryan Wueb202622012-04-19 11:46:33 +0800389 read_lock(&trig->leddev_list_lock);
ZHAO Gang11e043b2013-12-28 07:00:26 -0800390 list_for_each_entry(led_cdev, &trig->led_cdevs, trig_list) {
Fabio Baltieri5bb629c2012-05-27 07:19:22 +0800391 if (oneshot)
392 led_blink_set_oneshot(led_cdev, delay_on, delay_off,
393 invert);
394 else
395 led_blink_set(led_cdev, delay_on, delay_off);
Vasily Khoruzhick0b9536c2011-01-07 16:28:16 +0000396 }
Bryan Wueb202622012-04-19 11:46:33 +0800397 read_unlock(&trig->leddev_list_lock);
Vasily Khoruzhick0b9536c2011-01-07 16:28:16 +0000398}
Fabio Baltieri5bb629c2012-05-27 07:19:22 +0800399
400void led_trigger_blink(struct led_trigger *trig,
401 unsigned long *delay_on,
402 unsigned long *delay_off)
403{
404 led_trigger_blink_setup(trig, delay_on, delay_off, 0, 0);
405}
Vasily Khoruzhick0b9536c2011-01-07 16:28:16 +0000406EXPORT_SYMBOL_GPL(led_trigger_blink);
407
Fabio Baltieri5bb629c2012-05-27 07:19:22 +0800408void led_trigger_blink_oneshot(struct led_trigger *trig,
409 unsigned long *delay_on,
410 unsigned long *delay_off,
411 int invert)
412{
413 led_trigger_blink_setup(trig, delay_on, delay_off, 1, invert);
414}
415EXPORT_SYMBOL_GPL(led_trigger_blink_oneshot);
416
Németh Márton4d404fd2008-03-09 20:59:57 +0000417void led_trigger_register_simple(const char *name, struct led_trigger **tp)
418{
Bryan Wueb202622012-04-19 11:46:33 +0800419 struct led_trigger *trig;
Németh Márton4d404fd2008-03-09 20:59:57 +0000420 int err;
421
Bryan Wueb202622012-04-19 11:46:33 +0800422 trig = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
Németh Márton4d404fd2008-03-09 20:59:57 +0000423
Bryan Wueb202622012-04-19 11:46:33 +0800424 if (trig) {
425 trig->name = name;
426 err = led_trigger_register(trig);
Masakazu Mokunocba4c2a2011-10-31 17:11:59 -0700427 if (err < 0) {
Bryan Wueb202622012-04-19 11:46:33 +0800428 kfree(trig);
429 trig = NULL;
Sachin Kamat09f5fe72012-11-25 13:00:44 +0530430 pr_warn("LED trigger %s failed to register (%d)\n",
431 name, err);
Masakazu Mokunocba4c2a2011-10-31 17:11:59 -0700432 }
Sachin Kamat09f5fe72012-11-25 13:00:44 +0530433 } else {
434 pr_warn("LED trigger %s failed to register (no memory)\n",
435 name);
436 }
Bryan Wueb202622012-04-19 11:46:33 +0800437 *tp = trig;
Németh Márton4d404fd2008-03-09 20:59:57 +0000438}
439EXPORT_SYMBOL_GPL(led_trigger_register_simple);
Richard Purdiec3bc9952006-03-31 02:31:05 -0800440
Bryan Wueb202622012-04-19 11:46:33 +0800441void led_trigger_unregister_simple(struct led_trigger *trig)
Richard Purdiec3bc9952006-03-31 02:31:05 -0800442{
Bryan Wueb202622012-04-19 11:46:33 +0800443 if (trig)
444 led_trigger_unregister(trig);
445 kfree(trig);
Richard Purdiec3bc9952006-03-31 02:31:05 -0800446}
Richard Purdiec3bc9952006-03-31 02:31:05 -0800447EXPORT_SYMBOL_GPL(led_trigger_unregister_simple);