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