1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * LED Class Core
4 *
5 * Copyright (C) 2005 John Lenz <lenz@cs.wisc.edu>
6 * Copyright (C) 2005-2007 Richard Purdie <rpurdie@openedhand.com>
7 */
8
9 #include <linux/ctype.h>
10 #include <linux/device.h>
11 #include <linux/err.h>
12 #include <linux/init.h>
13 #include <linux/kernel.h>
14 #include <linux/leds.h>
15 #include <linux/list.h>
16 #include <linux/module.h>
17 #include <linux/property.h>
18 #include <linux/slab.h>
19 #include <linux/spinlock.h>
20 #include <linux/timer.h>
21 #include <uapi/linux/uleds.h>
22 #include <linux/of.h>
23 #include "leds.h"
24
25 static DEFINE_MUTEX(leds_lookup_lock);
26 static LIST_HEAD(leds_lookup_list);
27
brightness_show(struct device * dev,struct device_attribute * attr,char * buf)28 static ssize_t brightness_show(struct device *dev,
29 struct device_attribute *attr, char *buf)
30 {
31 struct led_classdev *led_cdev = dev_get_drvdata(dev);
32 unsigned int brightness;
33
34 mutex_lock(&led_cdev->led_access);
35 led_update_brightness(led_cdev);
36 brightness = led_cdev->brightness;
37 mutex_unlock(&led_cdev->led_access);
38
39 return sprintf(buf, "%u\n", brightness);
40 }
41
brightness_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t size)42 static ssize_t brightness_store(struct device *dev,
43 struct device_attribute *attr, const char *buf, size_t size)
44 {
45 struct led_classdev *led_cdev = dev_get_drvdata(dev);
46 unsigned long state;
47 ssize_t ret;
48
49 mutex_lock(&led_cdev->led_access);
50
51 if (led_sysfs_is_disabled(led_cdev)) {
52 ret = -EBUSY;
53 goto unlock;
54 }
55
56 ret = kstrtoul(buf, 10, &state);
57 if (ret)
58 goto unlock;
59
60 if (state == LED_OFF)
61 led_trigger_remove(led_cdev);
62 led_set_brightness(led_cdev, state);
63 flush_work(&led_cdev->set_brightness_work);
64
65 ret = size;
66 unlock:
67 mutex_unlock(&led_cdev->led_access);
68 return ret;
69 }
70 static DEVICE_ATTR_RW(brightness);
71
max_brightness_show(struct device * dev,struct device_attribute * attr,char * buf)72 static ssize_t max_brightness_show(struct device *dev,
73 struct device_attribute *attr, char *buf)
74 {
75 struct led_classdev *led_cdev = dev_get_drvdata(dev);
76 unsigned int max_brightness;
77
78 mutex_lock(&led_cdev->led_access);
79 max_brightness = led_cdev->max_brightness;
80 mutex_unlock(&led_cdev->led_access);
81
82 return sprintf(buf, "%u\n", max_brightness);
83 }
84 static DEVICE_ATTR_RO(max_brightness);
85
86 #ifdef CONFIG_LEDS_TRIGGERS
87 static BIN_ATTR(trigger, 0644, led_trigger_read, led_trigger_write, 0);
88 static struct bin_attribute *led_trigger_bin_attrs[] = {
89 &bin_attr_trigger,
90 NULL,
91 };
92 static const struct attribute_group led_trigger_group = {
93 .bin_attrs = led_trigger_bin_attrs,
94 };
95 #endif
96
97 static struct attribute *led_class_attrs[] = {
98 &dev_attr_brightness.attr,
99 &dev_attr_max_brightness.attr,
100 NULL,
101 };
102
103 static const struct attribute_group led_group = {
104 .attrs = led_class_attrs,
105 };
106
107 static const struct attribute_group *led_groups[] = {
108 &led_group,
109 #ifdef CONFIG_LEDS_TRIGGERS
110 &led_trigger_group,
111 #endif
112 NULL,
113 };
114
115 #ifdef CONFIG_LEDS_BRIGHTNESS_HW_CHANGED
brightness_hw_changed_show(struct device * dev,struct device_attribute * attr,char * buf)116 static ssize_t brightness_hw_changed_show(struct device *dev,
117 struct device_attribute *attr, char *buf)
118 {
119 struct led_classdev *led_cdev = dev_get_drvdata(dev);
120
121 if (led_cdev->brightness_hw_changed == -1)
122 return -ENODATA;
123
124 return sprintf(buf, "%u\n", led_cdev->brightness_hw_changed);
125 }
126
127 static DEVICE_ATTR_RO(brightness_hw_changed);
128
led_add_brightness_hw_changed(struct led_classdev * led_cdev)129 static int led_add_brightness_hw_changed(struct led_classdev *led_cdev)
130 {
131 struct device *dev = led_cdev->dev;
132 int ret;
133
134 ret = device_create_file(dev, &dev_attr_brightness_hw_changed);
135 if (ret) {
136 dev_err(dev, "Error creating brightness_hw_changed\n");
137 return ret;
138 }
139
140 led_cdev->brightness_hw_changed_kn =
141 sysfs_get_dirent(dev->kobj.sd, "brightness_hw_changed");
142 if (!led_cdev->brightness_hw_changed_kn) {
143 dev_err(dev, "Error getting brightness_hw_changed kn\n");
144 device_remove_file(dev, &dev_attr_brightness_hw_changed);
145 return -ENXIO;
146 }
147
148 return 0;
149 }
150
led_remove_brightness_hw_changed(struct led_classdev * led_cdev)151 static void led_remove_brightness_hw_changed(struct led_classdev *led_cdev)
152 {
153 sysfs_put(led_cdev->brightness_hw_changed_kn);
154 device_remove_file(led_cdev->dev, &dev_attr_brightness_hw_changed);
155 }
156
led_classdev_notify_brightness_hw_changed(struct led_classdev * led_cdev,unsigned int brightness)157 void led_classdev_notify_brightness_hw_changed(struct led_classdev *led_cdev, unsigned int brightness)
158 {
159 if (WARN_ON(!led_cdev->brightness_hw_changed_kn))
160 return;
161
162 led_cdev->brightness_hw_changed = brightness;
163 sysfs_notify_dirent(led_cdev->brightness_hw_changed_kn);
164 }
165 EXPORT_SYMBOL_GPL(led_classdev_notify_brightness_hw_changed);
166 #else
led_add_brightness_hw_changed(struct led_classdev * led_cdev)167 static int led_add_brightness_hw_changed(struct led_classdev *led_cdev)
168 {
169 return 0;
170 }
led_remove_brightness_hw_changed(struct led_classdev * led_cdev)171 static void led_remove_brightness_hw_changed(struct led_classdev *led_cdev)
172 {
173 }
174 #endif
175
176 /**
177 * led_classdev_suspend - suspend an led_classdev.
178 * @led_cdev: the led_classdev to suspend.
179 */
led_classdev_suspend(struct led_classdev * led_cdev)180 void led_classdev_suspend(struct led_classdev *led_cdev)
181 {
182 led_cdev->flags |= LED_SUSPENDED;
183 led_set_brightness_nopm(led_cdev, 0);
184 flush_work(&led_cdev->set_brightness_work);
185 }
186 EXPORT_SYMBOL_GPL(led_classdev_suspend);
187
188 /**
189 * led_classdev_resume - resume an led_classdev.
190 * @led_cdev: the led_classdev to resume.
191 */
led_classdev_resume(struct led_classdev * led_cdev)192 void led_classdev_resume(struct led_classdev *led_cdev)
193 {
194 led_set_brightness_nopm(led_cdev, led_cdev->brightness);
195
196 if (led_cdev->flash_resume)
197 led_cdev->flash_resume(led_cdev);
198
199 led_cdev->flags &= ~LED_SUSPENDED;
200 }
201 EXPORT_SYMBOL_GPL(led_classdev_resume);
202
203 #ifdef CONFIG_PM_SLEEP
led_suspend(struct device * dev)204 static int led_suspend(struct device *dev)
205 {
206 struct led_classdev *led_cdev = dev_get_drvdata(dev);
207
208 if (led_cdev->flags & LED_CORE_SUSPENDRESUME)
209 led_classdev_suspend(led_cdev);
210
211 return 0;
212 }
213
led_resume(struct device * dev)214 static int led_resume(struct device *dev)
215 {
216 struct led_classdev *led_cdev = dev_get_drvdata(dev);
217
218 if (led_cdev->flags & LED_CORE_SUSPENDRESUME)
219 led_classdev_resume(led_cdev);
220
221 return 0;
222 }
223 #endif
224
225 static SIMPLE_DEV_PM_OPS(leds_class_dev_pm_ops, led_suspend, led_resume);
226
led_module_get(struct device * led_dev)227 static struct led_classdev *led_module_get(struct device *led_dev)
228 {
229 struct led_classdev *led_cdev;
230
231 if (!led_dev)
232 return ERR_PTR(-EPROBE_DEFER);
233
234 led_cdev = dev_get_drvdata(led_dev);
235
236 if (!try_module_get(led_cdev->dev->parent->driver->owner)) {
237 put_device(led_cdev->dev);
238 return ERR_PTR(-ENODEV);
239 }
240
241 return led_cdev;
242 }
243
244 static const struct class leds_class = {
245 .name = "leds",
246 .dev_groups = led_groups,
247 .pm = &leds_class_dev_pm_ops,
248 };
249
250 /**
251 * of_led_get() - request a LED device via the LED framework
252 * @np: device node to get the LED device from
253 * @index: the index of the LED
254 *
255 * Returns the LED device parsed from the phandle specified in the "leds"
256 * property of a device tree node or a negative error-code on failure.
257 */
of_led_get(struct device_node * np,int index)258 struct led_classdev *of_led_get(struct device_node *np, int index)
259 {
260 struct device *led_dev;
261 struct device_node *led_node;
262
263 led_node = of_parse_phandle(np, "leds", index);
264 if (!led_node)
265 return ERR_PTR(-ENOENT);
266
267 led_dev = class_find_device_by_of_node(&leds_class, led_node);
268 of_node_put(led_node);
269
270 return led_module_get(led_dev);
271 }
272 EXPORT_SYMBOL_GPL(of_led_get);
273
274 /**
275 * led_put() - release a LED device
276 * @led_cdev: LED device
277 */
led_put(struct led_classdev * led_cdev)278 void led_put(struct led_classdev *led_cdev)
279 {
280 module_put(led_cdev->dev->parent->driver->owner);
281 put_device(led_cdev->dev);
282 }
283 EXPORT_SYMBOL_GPL(led_put);
284
devm_led_release(struct device * dev,void * res)285 static void devm_led_release(struct device *dev, void *res)
286 {
287 struct led_classdev **p = res;
288
289 led_put(*p);
290 }
291
__devm_led_get(struct device * dev,struct led_classdev * led)292 static struct led_classdev *__devm_led_get(struct device *dev, struct led_classdev *led)
293 {
294 struct led_classdev **dr;
295
296 dr = devres_alloc(devm_led_release, sizeof(struct led_classdev *), GFP_KERNEL);
297 if (!dr) {
298 led_put(led);
299 return ERR_PTR(-ENOMEM);
300 }
301
302 *dr = led;
303 devres_add(dev, dr);
304
305 return led;
306 }
307
308 /**
309 * devm_of_led_get - Resource-managed request of a LED device
310 * @dev: LED consumer
311 * @index: index of the LED to obtain in the consumer
312 *
313 * The device node of the device is parse to find the request LED device.
314 * The LED device returned from this function is automatically released
315 * on driver detach.
316 *
317 * @return a pointer to a LED device or ERR_PTR(errno) on failure.
318 */
devm_of_led_get(struct device * dev,int index)319 struct led_classdev *__must_check devm_of_led_get(struct device *dev,
320 int index)
321 {
322 struct led_classdev *led;
323
324 if (!dev)
325 return ERR_PTR(-EINVAL);
326
327 led = of_led_get(dev->of_node, index);
328 if (IS_ERR(led))
329 return led;
330
331 return __devm_led_get(dev, led);
332 }
333 EXPORT_SYMBOL_GPL(devm_of_led_get);
334
335 /**
336 * led_get() - request a LED device via the LED framework
337 * @dev: device for which to get the LED device
338 * @con_id: name of the LED from the device's point of view
339 *
340 * @return a pointer to a LED device or ERR_PTR(errno) on failure.
341 */
led_get(struct device * dev,char * con_id)342 struct led_classdev *led_get(struct device *dev, char *con_id)
343 {
344 struct led_lookup_data *lookup;
345 const char *provider = NULL;
346 struct device *led_dev;
347
348 mutex_lock(&leds_lookup_lock);
349 list_for_each_entry(lookup, &leds_lookup_list, list) {
350 if (!strcmp(lookup->dev_id, dev_name(dev)) &&
351 !strcmp(lookup->con_id, con_id)) {
352 provider = kstrdup_const(lookup->provider, GFP_KERNEL);
353 break;
354 }
355 }
356 mutex_unlock(&leds_lookup_lock);
357
358 if (!provider)
359 return ERR_PTR(-ENOENT);
360
361 led_dev = class_find_device_by_name(&leds_class, provider);
362 kfree_const(provider);
363
364 return led_module_get(led_dev);
365 }
366 EXPORT_SYMBOL_GPL(led_get);
367
368 /**
369 * devm_led_get() - request a LED device via the LED framework
370 * @dev: device for which to get the LED device
371 * @con_id: name of the LED from the device's point of view
372 *
373 * The LED device returned from this function is automatically released
374 * on driver detach.
375 *
376 * @return a pointer to a LED device or ERR_PTR(errno) on failure.
377 */
devm_led_get(struct device * dev,char * con_id)378 struct led_classdev *devm_led_get(struct device *dev, char *con_id)
379 {
380 struct led_classdev *led;
381
382 led = led_get(dev, con_id);
383 if (IS_ERR(led))
384 return led;
385
386 return __devm_led_get(dev, led);
387 }
388 EXPORT_SYMBOL_GPL(devm_led_get);
389
390 /**
391 * led_add_lookup() - Add a LED lookup table entry
392 * @led_lookup: the lookup table entry to add
393 *
394 * Add a LED lookup table entry. On systems without devicetree the lookup table
395 * is used by led_get() to find LEDs.
396 */
led_add_lookup(struct led_lookup_data * led_lookup)397 void led_add_lookup(struct led_lookup_data *led_lookup)
398 {
399 mutex_lock(&leds_lookup_lock);
400 list_add_tail(&led_lookup->list, &leds_lookup_list);
401 mutex_unlock(&leds_lookup_lock);
402 }
403 EXPORT_SYMBOL_GPL(led_add_lookup);
404
405 /**
406 * led_remove_lookup() - Remove a LED lookup table entry
407 * @led_lookup: the lookup table entry to remove
408 */
led_remove_lookup(struct led_lookup_data * led_lookup)409 void led_remove_lookup(struct led_lookup_data *led_lookup)
410 {
411 mutex_lock(&leds_lookup_lock);
412 list_del(&led_lookup->list);
413 mutex_unlock(&leds_lookup_lock);
414 }
415 EXPORT_SYMBOL_GPL(led_remove_lookup);
416
417 /**
418 * devm_of_led_get_optional - Resource-managed request of an optional LED device
419 * @dev: LED consumer
420 * @index: index of the LED to obtain in the consumer
421 *
422 * The device node of the device is parsed to find the requested LED device.
423 * The LED device returned from this function is automatically released
424 * on driver detach.
425 *
426 * @return a pointer to a LED device, ERR_PTR(errno) on failure and NULL if the
427 * led was not found.
428 */
devm_of_led_get_optional(struct device * dev,int index)429 struct led_classdev *__must_check devm_of_led_get_optional(struct device *dev,
430 int index)
431 {
432 struct led_classdev *led;
433
434 led = devm_of_led_get(dev, index);
435 if (IS_ERR(led) && PTR_ERR(led) == -ENOENT)
436 return NULL;
437
438 return led;
439 }
440 EXPORT_SYMBOL_GPL(devm_of_led_get_optional);
441
led_classdev_next_name(const char * init_name,char * name,size_t len)442 static int led_classdev_next_name(const char *init_name, char *name,
443 size_t len)
444 {
445 unsigned int i = 0;
446 int ret = 0;
447 struct device *dev;
448
449 strscpy(name, init_name, len);
450
451 while ((ret < len) &&
452 (dev = class_find_device_by_name(&leds_class, name))) {
453 put_device(dev);
454 ret = snprintf(name, len, "%s_%u", init_name, ++i);
455 }
456
457 if (ret >= len)
458 return -ENOMEM;
459
460 return i;
461 }
462
463 /**
464 * led_classdev_register_ext - register a new object of led_classdev class
465 * with init data.
466 *
467 * @parent: parent of LED device
468 * @led_cdev: the led_classdev structure for this device.
469 * @init_data: LED class device initialization data
470 */
led_classdev_register_ext(struct device * parent,struct led_classdev * led_cdev,struct led_init_data * init_data)471 int led_classdev_register_ext(struct device *parent,
472 struct led_classdev *led_cdev,
473 struct led_init_data *init_data)
474 {
475 char composed_name[LED_MAX_NAME_SIZE];
476 char final_name[LED_MAX_NAME_SIZE];
477 const char *proposed_name = composed_name;
478 int ret;
479
480 if (init_data) {
481 if (init_data->devname_mandatory && !init_data->devicename) {
482 dev_err(parent, "Mandatory device name is missing");
483 return -EINVAL;
484 }
485 ret = led_compose_name(parent, init_data, composed_name);
486 if (ret < 0)
487 return ret;
488
489 if (init_data->fwnode) {
490 fwnode_property_read_string(init_data->fwnode,
491 "linux,default-trigger",
492 &led_cdev->default_trigger);
493
494 if (fwnode_property_present(init_data->fwnode,
495 "retain-state-shutdown"))
496 led_cdev->flags |= LED_RETAIN_AT_SHUTDOWN;
497
498 fwnode_property_read_u32(init_data->fwnode,
499 "max-brightness",
500 &led_cdev->max_brightness);
501
502 if (fwnode_property_present(init_data->fwnode, "color"))
503 fwnode_property_read_u32(init_data->fwnode, "color",
504 &led_cdev->color);
505 }
506 } else {
507 proposed_name = led_cdev->name;
508 }
509
510 ret = led_classdev_next_name(proposed_name, final_name, sizeof(final_name));
511 if (ret < 0)
512 return ret;
513 else if (ret && led_cdev->flags & LED_REJECT_NAME_CONFLICT)
514 return -EEXIST;
515 else if (ret)
516 dev_warn(parent, "Led %s renamed to %s due to name collision\n",
517 proposed_name, final_name);
518
519 if (led_cdev->color >= LED_COLOR_ID_MAX)
520 dev_warn(parent, "LED %s color identifier out of range\n", final_name);
521
522 mutex_init(&led_cdev->led_access);
523 mutex_lock(&led_cdev->led_access);
524 led_cdev->dev = device_create_with_groups(&leds_class, parent, 0,
525 led_cdev, led_cdev->groups, "%s", final_name);
526 if (IS_ERR(led_cdev->dev)) {
527 mutex_unlock(&led_cdev->led_access);
528 return PTR_ERR(led_cdev->dev);
529 }
530 if (init_data && init_data->fwnode)
531 device_set_node(led_cdev->dev, init_data->fwnode);
532
533 if (led_cdev->flags & LED_BRIGHT_HW_CHANGED) {
534 ret = led_add_brightness_hw_changed(led_cdev);
535 if (ret) {
536 device_unregister(led_cdev->dev);
537 led_cdev->dev = NULL;
538 mutex_unlock(&led_cdev->led_access);
539 return ret;
540 }
541 }
542
543 led_cdev->work_flags = 0;
544 #ifdef CONFIG_LEDS_TRIGGERS
545 init_rwsem(&led_cdev->trigger_lock);
546 #endif
547 #ifdef CONFIG_LEDS_BRIGHTNESS_HW_CHANGED
548 led_cdev->brightness_hw_changed = -1;
549 #endif
550 /* add to the list of leds */
551 down_write(&leds_list_lock);
552 list_add_tail(&led_cdev->node, &leds_list);
553 up_write(&leds_list_lock);
554
555 if (!led_cdev->max_brightness)
556 led_cdev->max_brightness = LED_FULL;
557
558 led_update_brightness(led_cdev);
559
560 led_init_core(led_cdev);
561
562 #ifdef CONFIG_LEDS_TRIGGERS
563 led_trigger_set_default(led_cdev);
564 #endif
565
566 mutex_unlock(&led_cdev->led_access);
567
568 dev_dbg(parent, "Registered led device: %s\n",
569 led_cdev->name);
570
571 return 0;
572 }
573 EXPORT_SYMBOL_GPL(led_classdev_register_ext);
574
575 /**
576 * led_classdev_unregister - unregisters a object of led_properties class.
577 * @led_cdev: the led device to unregister
578 *
579 * Unregisters a previously registered via led_classdev_register object.
580 */
led_classdev_unregister(struct led_classdev * led_cdev)581 void led_classdev_unregister(struct led_classdev *led_cdev)
582 {
583 if (IS_ERR_OR_NULL(led_cdev->dev))
584 return;
585
586 #ifdef CONFIG_LEDS_TRIGGERS
587 down_write(&led_cdev->trigger_lock);
588 if (led_cdev->trigger)
589 led_trigger_set(led_cdev, NULL);
590 up_write(&led_cdev->trigger_lock);
591 #endif
592
593 led_cdev->flags |= LED_UNREGISTERING;
594
595 /* Stop blinking */
596 led_stop_software_blink(led_cdev);
597
598 if (!(led_cdev->flags & LED_RETAIN_AT_SHUTDOWN))
599 led_set_brightness(led_cdev, LED_OFF);
600
601 flush_work(&led_cdev->set_brightness_work);
602
603 if (led_cdev->flags & LED_BRIGHT_HW_CHANGED)
604 led_remove_brightness_hw_changed(led_cdev);
605
606 device_unregister(led_cdev->dev);
607
608 down_write(&leds_list_lock);
609 list_del(&led_cdev->node);
610 up_write(&leds_list_lock);
611
612 mutex_destroy(&led_cdev->led_access);
613 }
614 EXPORT_SYMBOL_GPL(led_classdev_unregister);
615
devm_led_classdev_release(struct device * dev,void * res)616 static void devm_led_classdev_release(struct device *dev, void *res)
617 {
618 led_classdev_unregister(*(struct led_classdev **)res);
619 }
620
621 /**
622 * devm_led_classdev_register_ext - resource managed led_classdev_register_ext()
623 *
624 * @parent: parent of LED device
625 * @led_cdev: the led_classdev structure for this device.
626 * @init_data: LED class device initialization data
627 */
devm_led_classdev_register_ext(struct device * parent,struct led_classdev * led_cdev,struct led_init_data * init_data)628 int devm_led_classdev_register_ext(struct device *parent,
629 struct led_classdev *led_cdev,
630 struct led_init_data *init_data)
631 {
632 struct led_classdev **dr;
633 int rc;
634
635 dr = devres_alloc(devm_led_classdev_release, sizeof(*dr), GFP_KERNEL);
636 if (!dr)
637 return -ENOMEM;
638
639 rc = led_classdev_register_ext(parent, led_cdev, init_data);
640 if (rc) {
641 devres_free(dr);
642 return rc;
643 }
644
645 *dr = led_cdev;
646 devres_add(parent, dr);
647
648 return 0;
649 }
650 EXPORT_SYMBOL_GPL(devm_led_classdev_register_ext);
651
devm_led_classdev_match(struct device * dev,void * res,void * data)652 static int devm_led_classdev_match(struct device *dev, void *res, void *data)
653 {
654 struct led_classdev **p = res;
655
656 if (WARN_ON(!p || !*p))
657 return 0;
658
659 return *p == data;
660 }
661
662 /**
663 * devm_led_classdev_unregister() - resource managed led_classdev_unregister()
664 * @dev: The device to unregister.
665 * @led_cdev: the led_classdev structure for this device.
666 */
devm_led_classdev_unregister(struct device * dev,struct led_classdev * led_cdev)667 void devm_led_classdev_unregister(struct device *dev,
668 struct led_classdev *led_cdev)
669 {
670 WARN_ON(devres_release(dev,
671 devm_led_classdev_release,
672 devm_led_classdev_match, led_cdev));
673 }
674 EXPORT_SYMBOL_GPL(devm_led_classdev_unregister);
675
leds_init(void)676 static int __init leds_init(void)
677 {
678 return class_register(&leds_class);
679 }
680
leds_exit(void)681 static void __exit leds_exit(void)
682 {
683 class_unregister(&leds_class);
684 }
685
686 subsys_initcall(leds_init);
687 module_exit(leds_exit);
688
689 MODULE_AUTHOR("John Lenz, Richard Purdie");
690 MODULE_LICENSE("GPL");
691 MODULE_DESCRIPTION("LED Class Interface");
692