projects/linux·blob master · refs

731 lines · 17.9 KiB

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