xref: /linux/drivers/video/backlight/backlight.c (revision ab93e0dd72c37d378dd936f031ffb83ff2bd87ce)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Backlight Lowlevel Control Abstraction
4  *
5  * Copyright (C) 2003,2004 Hewlett-Packard Company
6  *
7  */
8 
9 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
10 
11 #include <linux/module.h>
12 #include <linux/init.h>
13 #include <linux/device.h>
14 #include <linux/backlight.h>
15 #include <linux/notifier.h>
16 #include <linux/ctype.h>
17 #include <linux/err.h>
18 #include <linux/slab.h>
19 
20 #ifdef CONFIG_PMAC_BACKLIGHT
21 #include <asm/backlight.h>
22 #endif
23 
24 /**
25  * DOC: overview
26  *
27  * The backlight core supports implementing backlight drivers.
28  *
29  * A backlight driver registers a driver using
30  * devm_backlight_device_register(). The properties of the backlight
31  * driver such as type and max_brightness must be specified.
32  * When the core detect changes in for example brightness or power state
33  * the update_status() operation is called. The backlight driver shall
34  * implement this operation and use it to adjust backlight.
35  *
36  * Several sysfs attributes are provided by the backlight core::
37  *
38  * - brightness         R/W, set the requested brightness level
39  * - actual_brightness  RO, the brightness level used by the HW
40  * - max_brightness     RO, the maximum  brightness level supported
41  *
42  * See Documentation/ABI/stable/sysfs-class-backlight for the full list.
43  *
44  * The backlight can be adjusted using the sysfs interface, and
45  * the backlight driver may also support adjusting backlight using
46  * a hot-key or some other platform or firmware specific way.
47  *
48  * The driver must implement the get_brightness() operation if
49  * the HW do not support all the levels that can be specified in
50  * brightness, thus providing user-space access to the actual level
51  * via the actual_brightness attribute.
52  *
53  * When the backlight changes this is reported to user-space using
54  * an uevent connected to the actual_brightness attribute.
55  * When brightness is set by platform specific means, for example
56  * a hot-key to adjust backlight, the driver must notify the backlight
57  * core that brightness has changed using backlight_force_update().
58  *
59  * Display drives can control the backlight device's status using
60  * backlight_notify_blank() and backlight_notify_blank_all(). If this
61  * results in a change in the backlight state the functions call the
62  * update_status() operation.
63  */
64 
65 static struct list_head backlight_dev_list;
66 static struct mutex backlight_dev_list_mutex;
67 
68 static const char *const backlight_types[] = {
69 	[BACKLIGHT_RAW] = "raw",
70 	[BACKLIGHT_PLATFORM] = "platform",
71 	[BACKLIGHT_FIRMWARE] = "firmware",
72 };
73 
74 static const char *const backlight_scale_types[] = {
75 	[BACKLIGHT_SCALE_UNKNOWN]	= "unknown",
76 	[BACKLIGHT_SCALE_LINEAR]	= "linear",
77 	[BACKLIGHT_SCALE_NON_LINEAR]	= "non-linear",
78 };
79 
backlight_notify_blank(struct backlight_device * bd,struct device * display_dev,bool fb_on,bool prev_fb_on)80 void backlight_notify_blank(struct backlight_device *bd, struct device *display_dev,
81 			    bool fb_on, bool prev_fb_on)
82 {
83 	guard(mutex)(&bd->ops_lock);
84 
85 	if (!bd->ops)
86 		return;
87 	if (bd->ops->controls_device && !bd->ops->controls_device(bd, display_dev))
88 		return;
89 
90 	if (fb_on && (!prev_fb_on || !bd->use_count)) {
91 		if (!bd->use_count++) {
92 			bd->props.state &= ~BL_CORE_FBBLANK;
93 			backlight_update_status(bd);
94 		}
95 	} else if (!fb_on && prev_fb_on && bd->use_count) {
96 		if (!(--bd->use_count)) {
97 			bd->props.state |= BL_CORE_FBBLANK;
98 			backlight_update_status(bd);
99 		}
100 	}
101 }
102 EXPORT_SYMBOL(backlight_notify_blank);
103 
backlight_notify_blank_all(struct device * display_dev,bool fb_on,bool prev_fb_on)104 void backlight_notify_blank_all(struct device *display_dev, bool fb_on, bool prev_fb_on)
105 {
106 	struct backlight_device *bd;
107 
108 	guard(mutex)(&backlight_dev_list_mutex);
109 
110 	list_for_each_entry(bd, &backlight_dev_list, entry)
111 		backlight_notify_blank(bd, display_dev, fb_on, prev_fb_on);
112 }
113 EXPORT_SYMBOL(backlight_notify_blank_all);
114 
backlight_generate_event(struct backlight_device * bd,enum backlight_update_reason reason)115 static void backlight_generate_event(struct backlight_device *bd,
116 				     enum backlight_update_reason reason)
117 {
118 	char *envp[2];
119 
120 	switch (reason) {
121 	case BACKLIGHT_UPDATE_SYSFS:
122 		envp[0] = "SOURCE=sysfs";
123 		break;
124 	case BACKLIGHT_UPDATE_HOTKEY:
125 		envp[0] = "SOURCE=hotkey";
126 		break;
127 	default:
128 		envp[0] = "SOURCE=unknown";
129 		break;
130 	}
131 	envp[1] = NULL;
132 	kobject_uevent_env(&bd->dev.kobj, KOBJ_CHANGE, envp);
133 	sysfs_notify(&bd->dev.kobj, NULL, "actual_brightness");
134 }
135 
bl_power_show(struct device * dev,struct device_attribute * attr,char * buf)136 static ssize_t bl_power_show(struct device *dev, struct device_attribute *attr,
137 		char *buf)
138 {
139 	struct backlight_device *bd = to_backlight_device(dev);
140 
141 	return sprintf(buf, "%d\n", bd->props.power);
142 }
143 
bl_power_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)144 static ssize_t bl_power_store(struct device *dev, struct device_attribute *attr,
145 		const char *buf, size_t count)
146 {
147 	int rc;
148 	struct backlight_device *bd = to_backlight_device(dev);
149 	unsigned long power, old_power;
150 
151 	rc = kstrtoul(buf, 0, &power);
152 	if (rc)
153 		return rc;
154 
155 	rc = -ENXIO;
156 	mutex_lock(&bd->ops_lock);
157 	if (bd->ops) {
158 		pr_debug("set power to %lu\n", power);
159 		if (bd->props.power != power) {
160 			old_power = bd->props.power;
161 			bd->props.power = power;
162 			rc = backlight_update_status(bd);
163 			if (rc)
164 				bd->props.power = old_power;
165 			else
166 				rc = count;
167 		} else {
168 			rc = count;
169 		}
170 	}
171 	mutex_unlock(&bd->ops_lock);
172 
173 	return rc;
174 }
175 static DEVICE_ATTR_RW(bl_power);
176 
brightness_show(struct device * dev,struct device_attribute * attr,char * buf)177 static ssize_t brightness_show(struct device *dev,
178 		struct device_attribute *attr, char *buf)
179 {
180 	struct backlight_device *bd = to_backlight_device(dev);
181 
182 	return sprintf(buf, "%d\n", bd->props.brightness);
183 }
184 
backlight_device_set_brightness(struct backlight_device * bd,unsigned long brightness)185 int backlight_device_set_brightness(struct backlight_device *bd,
186 				    unsigned long brightness)
187 {
188 	int rc = -ENXIO;
189 
190 	mutex_lock(&bd->ops_lock);
191 	if (bd->ops) {
192 		if (brightness > bd->props.max_brightness)
193 			rc = -EINVAL;
194 		else {
195 			pr_debug("set brightness to %lu\n", brightness);
196 			bd->props.brightness = brightness;
197 			rc = backlight_update_status(bd);
198 		}
199 	}
200 	mutex_unlock(&bd->ops_lock);
201 
202 	backlight_generate_event(bd, BACKLIGHT_UPDATE_SYSFS);
203 
204 	return rc;
205 }
206 EXPORT_SYMBOL(backlight_device_set_brightness);
207 
brightness_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)208 static ssize_t brightness_store(struct device *dev,
209 		struct device_attribute *attr, const char *buf, size_t count)
210 {
211 	int rc;
212 	struct backlight_device *bd = to_backlight_device(dev);
213 	unsigned long brightness;
214 
215 	rc = kstrtoul(buf, 0, &brightness);
216 	if (rc)
217 		return rc;
218 
219 	rc = backlight_device_set_brightness(bd, brightness);
220 
221 	return rc ? rc : count;
222 }
223 static DEVICE_ATTR_RW(brightness);
224 
type_show(struct device * dev,struct device_attribute * attr,char * buf)225 static ssize_t type_show(struct device *dev, struct device_attribute *attr,
226 		char *buf)
227 {
228 	struct backlight_device *bd = to_backlight_device(dev);
229 
230 	return sprintf(buf, "%s\n", backlight_types[bd->props.type]);
231 }
232 static DEVICE_ATTR_RO(type);
233 
max_brightness_show(struct device * dev,struct device_attribute * attr,char * buf)234 static ssize_t max_brightness_show(struct device *dev,
235 		struct device_attribute *attr, char *buf)
236 {
237 	struct backlight_device *bd = to_backlight_device(dev);
238 
239 	return sprintf(buf, "%d\n", bd->props.max_brightness);
240 }
241 static DEVICE_ATTR_RO(max_brightness);
242 
actual_brightness_show(struct device * dev,struct device_attribute * attr,char * buf)243 static ssize_t actual_brightness_show(struct device *dev,
244 		struct device_attribute *attr, char *buf)
245 {
246 	int rc = -ENXIO;
247 	struct backlight_device *bd = to_backlight_device(dev);
248 
249 	mutex_lock(&bd->ops_lock);
250 	if (bd->ops && bd->ops->get_brightness) {
251 		rc = bd->ops->get_brightness(bd);
252 		if (rc >= 0)
253 			rc = sprintf(buf, "%d\n", rc);
254 	} else {
255 		rc = sprintf(buf, "%d\n", bd->props.brightness);
256 	}
257 	mutex_unlock(&bd->ops_lock);
258 
259 	return rc;
260 }
261 static DEVICE_ATTR_RO(actual_brightness);
262 
scale_show(struct device * dev,struct device_attribute * attr,char * buf)263 static ssize_t scale_show(struct device *dev,
264 		struct device_attribute *attr, char *buf)
265 {
266 	struct backlight_device *bd = to_backlight_device(dev);
267 
268 	if (WARN_ON(bd->props.scale > BACKLIGHT_SCALE_NON_LINEAR))
269 		return sprintf(buf, "unknown\n");
270 
271 	return sprintf(buf, "%s\n", backlight_scale_types[bd->props.scale]);
272 }
273 static DEVICE_ATTR_RO(scale);
274 
275 #ifdef CONFIG_PM_SLEEP
backlight_suspend(struct device * dev)276 static int backlight_suspend(struct device *dev)
277 {
278 	struct backlight_device *bd = to_backlight_device(dev);
279 
280 	mutex_lock(&bd->ops_lock);
281 	if (bd->ops && bd->ops->options & BL_CORE_SUSPENDRESUME) {
282 		bd->props.state |= BL_CORE_SUSPENDED;
283 		backlight_update_status(bd);
284 	}
285 	mutex_unlock(&bd->ops_lock);
286 
287 	return 0;
288 }
289 
backlight_resume(struct device * dev)290 static int backlight_resume(struct device *dev)
291 {
292 	struct backlight_device *bd = to_backlight_device(dev);
293 
294 	mutex_lock(&bd->ops_lock);
295 	if (bd->ops && bd->ops->options & BL_CORE_SUSPENDRESUME) {
296 		bd->props.state &= ~BL_CORE_SUSPENDED;
297 		backlight_update_status(bd);
298 	}
299 	mutex_unlock(&bd->ops_lock);
300 
301 	return 0;
302 }
303 #endif
304 
305 static SIMPLE_DEV_PM_OPS(backlight_class_dev_pm_ops, backlight_suspend,
306 			 backlight_resume);
307 
bl_device_release(struct device * dev)308 static void bl_device_release(struct device *dev)
309 {
310 	struct backlight_device *bd = to_backlight_device(dev);
311 	kfree(bd);
312 }
313 
314 static struct attribute *bl_device_attrs[] = {
315 	&dev_attr_bl_power.attr,
316 	&dev_attr_brightness.attr,
317 	&dev_attr_actual_brightness.attr,
318 	&dev_attr_max_brightness.attr,
319 	&dev_attr_scale.attr,
320 	&dev_attr_type.attr,
321 	NULL,
322 };
323 ATTRIBUTE_GROUPS(bl_device);
324 
325 static const struct class backlight_class = {
326 	.name = "backlight",
327 	.dev_groups = bl_device_groups,
328 	.pm = &backlight_class_dev_pm_ops,
329 };
330 
331 /**
332  * backlight_force_update - tell the backlight subsystem that hardware state
333  *   has changed
334  * @bd: the backlight device to update
335  * @reason: reason for update
336  *
337  * Updates the internal state of the backlight in response to a hardware event,
338  * and generates an uevent to notify userspace. A backlight driver shall call
339  * backlight_force_update() when the backlight is changed using, for example,
340  * a hot-key. The updated brightness is read using get_brightness() and the
341  * brightness value is reported using an uevent.
342  */
backlight_force_update(struct backlight_device * bd,enum backlight_update_reason reason)343 void backlight_force_update(struct backlight_device *bd,
344 			    enum backlight_update_reason reason)
345 {
346 	int brightness;
347 
348 	mutex_lock(&bd->ops_lock);
349 	if (bd->ops && bd->ops->get_brightness) {
350 		brightness = bd->ops->get_brightness(bd);
351 		if (brightness >= 0)
352 			bd->props.brightness = brightness;
353 		else
354 			dev_err(&bd->dev,
355 				"Could not update brightness from device: %pe\n",
356 				ERR_PTR(brightness));
357 	}
358 	mutex_unlock(&bd->ops_lock);
359 	backlight_generate_event(bd, reason);
360 }
361 EXPORT_SYMBOL(backlight_force_update);
362 
363 /* deprecated - use devm_backlight_device_register() */
backlight_device_register(const char * name,struct device * parent,void * devdata,const struct backlight_ops * ops,const struct backlight_properties * props)364 struct backlight_device *backlight_device_register(const char *name,
365 	struct device *parent, void *devdata, const struct backlight_ops *ops,
366 	const struct backlight_properties *props)
367 {
368 	struct backlight_device *new_bd;
369 	int rc;
370 
371 	pr_debug("backlight_device_register: name=%s\n", name);
372 
373 	new_bd = kzalloc(sizeof(struct backlight_device), GFP_KERNEL);
374 	if (!new_bd)
375 		return ERR_PTR(-ENOMEM);
376 
377 	mutex_init(&new_bd->update_lock);
378 	mutex_init(&new_bd->ops_lock);
379 
380 	new_bd->dev.class = &backlight_class;
381 	new_bd->dev.parent = parent;
382 	new_bd->dev.release = bl_device_release;
383 	dev_set_name(&new_bd->dev, "%s", name);
384 	dev_set_drvdata(&new_bd->dev, devdata);
385 
386 	/* Set default properties */
387 	if (props) {
388 		memcpy(&new_bd->props, props,
389 		       sizeof(struct backlight_properties));
390 		if (props->type <= 0 || props->type >= BACKLIGHT_TYPE_MAX) {
391 			WARN(1, "%s: invalid backlight type", name);
392 			new_bd->props.type = BACKLIGHT_RAW;
393 		}
394 	} else {
395 		new_bd->props.type = BACKLIGHT_RAW;
396 	}
397 
398 	rc = device_register(&new_bd->dev);
399 	if (rc) {
400 		put_device(&new_bd->dev);
401 		return ERR_PTR(rc);
402 	}
403 
404 	new_bd->ops = ops;
405 
406 #ifdef CONFIG_PMAC_BACKLIGHT
407 	mutex_lock(&pmac_backlight_mutex);
408 	if (!pmac_backlight)
409 		pmac_backlight = new_bd;
410 	mutex_unlock(&pmac_backlight_mutex);
411 #endif
412 
413 	mutex_lock(&backlight_dev_list_mutex);
414 	list_add(&new_bd->entry, &backlight_dev_list);
415 	mutex_unlock(&backlight_dev_list_mutex);
416 
417 	return new_bd;
418 }
419 EXPORT_SYMBOL(backlight_device_register);
420 
421 /** backlight_device_get_by_type - find first backlight device of a type
422  * @type: the type of backlight device
423  *
424  * Look up the first backlight device of the specified type
425  *
426  * RETURNS:
427  *
428  * Pointer to backlight device if any was found. Otherwise NULL.
429  */
backlight_device_get_by_type(enum backlight_type type)430 struct backlight_device *backlight_device_get_by_type(enum backlight_type type)
431 {
432 	bool found = false;
433 	struct backlight_device *bd;
434 
435 	mutex_lock(&backlight_dev_list_mutex);
436 	list_for_each_entry(bd, &backlight_dev_list, entry) {
437 		if (bd->props.type == type) {
438 			found = true;
439 			break;
440 		}
441 	}
442 	mutex_unlock(&backlight_dev_list_mutex);
443 
444 	return found ? bd : NULL;
445 }
446 EXPORT_SYMBOL(backlight_device_get_by_type);
447 
448 /**
449  * backlight_device_get_by_name - Get backlight device by name
450  * @name: Device name
451  *
452  * This function looks up a backlight device by its name. It obtains a reference
453  * on the backlight device and it is the caller's responsibility to drop the
454  * reference by calling put_device().
455  *
456  * Returns:
457  * A pointer to the backlight device if found, otherwise NULL.
458  */
backlight_device_get_by_name(const char * name)459 struct backlight_device *backlight_device_get_by_name(const char *name)
460 {
461 	struct device *dev;
462 
463 	dev = class_find_device_by_name(&backlight_class, name);
464 
465 	return dev ? to_backlight_device(dev) : NULL;
466 }
467 EXPORT_SYMBOL(backlight_device_get_by_name);
468 
469 /* deprecated - use devm_backlight_device_unregister() */
backlight_device_unregister(struct backlight_device * bd)470 void backlight_device_unregister(struct backlight_device *bd)
471 {
472 	if (!bd)
473 		return;
474 
475 	mutex_lock(&backlight_dev_list_mutex);
476 	list_del(&bd->entry);
477 	mutex_unlock(&backlight_dev_list_mutex);
478 
479 #ifdef CONFIG_PMAC_BACKLIGHT
480 	mutex_lock(&pmac_backlight_mutex);
481 	if (pmac_backlight == bd)
482 		pmac_backlight = NULL;
483 	mutex_unlock(&pmac_backlight_mutex);
484 #endif
485 
486 	mutex_lock(&bd->ops_lock);
487 	bd->ops = NULL;
488 	mutex_unlock(&bd->ops_lock);
489 
490 	device_unregister(&bd->dev);
491 }
492 EXPORT_SYMBOL(backlight_device_unregister);
493 
devm_backlight_device_release(struct device * dev,void * res)494 static void devm_backlight_device_release(struct device *dev, void *res)
495 {
496 	struct backlight_device *backlight = *(struct backlight_device **)res;
497 
498 	backlight_device_unregister(backlight);
499 }
500 
devm_backlight_device_match(struct device * dev,void * res,void * data)501 static int devm_backlight_device_match(struct device *dev, void *res,
502 					void *data)
503 {
504 	struct backlight_device **r = res;
505 
506 	return *r == data;
507 }
508 
509 /**
510  * devm_backlight_device_register - register a new backlight device
511  * @dev: the device to register
512  * @name: the name of the device
513  * @parent: a pointer to the parent device (often the same as @dev)
514  * @devdata: an optional pointer to be stored for private driver use
515  * @ops: the backlight operations structure
516  * @props: the backlight properties
517  *
518  * Creates and registers new backlight device. When a backlight device
519  * is registered the configuration must be specified in the @props
520  * parameter. See description of &backlight_properties.
521  *
522  * RETURNS:
523  *
524  * struct backlight on success, or an ERR_PTR on error
525  */
devm_backlight_device_register(struct device * dev,const char * name,struct device * parent,void * devdata,const struct backlight_ops * ops,const struct backlight_properties * props)526 struct backlight_device *devm_backlight_device_register(struct device *dev,
527 	const char *name, struct device *parent, void *devdata,
528 	const struct backlight_ops *ops,
529 	const struct backlight_properties *props)
530 {
531 	struct backlight_device **ptr, *backlight;
532 
533 	ptr = devres_alloc(devm_backlight_device_release, sizeof(*ptr),
534 			GFP_KERNEL);
535 	if (!ptr)
536 		return ERR_PTR(-ENOMEM);
537 
538 	backlight = backlight_device_register(name, parent, devdata, ops,
539 						props);
540 	if (!IS_ERR(backlight)) {
541 		*ptr = backlight;
542 		devres_add(dev, ptr);
543 	} else {
544 		devres_free(ptr);
545 	}
546 
547 	return backlight;
548 }
549 EXPORT_SYMBOL(devm_backlight_device_register);
550 
551 /**
552  * devm_backlight_device_unregister - unregister backlight device
553  * @dev: the device to unregister
554  * @bd: the backlight device to unregister
555  *
556  * Deallocates a backlight allocated with devm_backlight_device_register().
557  * Normally this function will not need to be called and the resource management
558  * code will ensure that the resources are freed.
559  */
devm_backlight_device_unregister(struct device * dev,struct backlight_device * bd)560 void devm_backlight_device_unregister(struct device *dev,
561 				struct backlight_device *bd)
562 {
563 	int rc;
564 
565 	rc = devres_release(dev, devm_backlight_device_release,
566 				devm_backlight_device_match, bd);
567 	WARN_ON(rc);
568 }
569 EXPORT_SYMBOL(devm_backlight_device_unregister);
570 
571 #ifdef CONFIG_OF
of_parent_match(struct device * dev,const void * data)572 static int of_parent_match(struct device *dev, const void *data)
573 {
574 	return dev->parent && dev->parent->of_node == data;
575 }
576 
577 /**
578  * of_find_backlight_by_node() - find backlight device by device-tree node
579  * @node: device-tree node of the backlight device
580  *
581  * Returns a pointer to the backlight device corresponding to the given DT
582  * node or NULL if no such backlight device exists or if the device hasn't
583  * been probed yet.
584  *
585  * This function obtains a reference on the backlight device and it is the
586  * caller's responsibility to drop the reference by calling put_device() on
587  * the backlight device's .dev field.
588  */
of_find_backlight_by_node(struct device_node * node)589 struct backlight_device *of_find_backlight_by_node(struct device_node *node)
590 {
591 	struct device *dev;
592 
593 	dev = class_find_device(&backlight_class, NULL, node, of_parent_match);
594 
595 	return dev ? to_backlight_device(dev) : NULL;
596 }
597 EXPORT_SYMBOL(of_find_backlight_by_node);
598 #endif
599 
of_find_backlight(struct device * dev)600 static struct backlight_device *of_find_backlight(struct device *dev)
601 {
602 	struct backlight_device *bd = NULL;
603 	struct device_node *np;
604 
605 	if (!dev)
606 		return NULL;
607 
608 	if (IS_ENABLED(CONFIG_OF) && dev->of_node) {
609 		np = of_parse_phandle(dev->of_node, "backlight", 0);
610 		if (np) {
611 			bd = of_find_backlight_by_node(np);
612 			of_node_put(np);
613 			if (!bd)
614 				return ERR_PTR(-EPROBE_DEFER);
615 		}
616 	}
617 
618 	return bd;
619 }
620 
devm_backlight_release(void * data)621 static void devm_backlight_release(void *data)
622 {
623 	struct backlight_device *bd = data;
624 
625 	put_device(&bd->dev);
626 }
627 
628 /**
629  * devm_of_find_backlight - find backlight for a device
630  * @dev: the device
631  *
632  * This function looks for a property named 'backlight' on the DT node
633  * connected to @dev and looks up the backlight device. The lookup is
634  * device managed so the reference to the backlight device is automatically
635  * dropped on driver detach.
636  *
637  * RETURNS:
638  *
639  * A pointer to the backlight device if found.
640  * Error pointer -EPROBE_DEFER if the DT property is set, but no backlight
641  * device is found. NULL if there's no backlight property.
642  */
devm_of_find_backlight(struct device * dev)643 struct backlight_device *devm_of_find_backlight(struct device *dev)
644 {
645 	struct backlight_device *bd;
646 	int ret;
647 
648 	bd = of_find_backlight(dev);
649 	if (IS_ERR_OR_NULL(bd))
650 		return bd;
651 	ret = devm_add_action_or_reset(dev, devm_backlight_release, bd);
652 	if (ret)
653 		return ERR_PTR(ret);
654 
655 	return bd;
656 }
657 EXPORT_SYMBOL(devm_of_find_backlight);
658 
backlight_class_exit(void)659 static void __exit backlight_class_exit(void)
660 {
661 	class_unregister(&backlight_class);
662 }
663 
backlight_class_init(void)664 static int __init backlight_class_init(void)
665 {
666 	int ret;
667 
668 	ret = class_register(&backlight_class);
669 	if (ret) {
670 		pr_warn("Unable to create backlight class; errno = %d\n", ret);
671 		return ret;
672 	}
673 
674 	INIT_LIST_HEAD(&backlight_dev_list);
675 	mutex_init(&backlight_dev_list_mutex);
676 
677 	return 0;
678 }
679 
680 /*
681  * if this is compiled into the kernel, we need to ensure that the
682  * class is registered before users of the class try to register lcd's
683  */
684 postcore_initcall(backlight_class_init);
685 module_exit(backlight_class_exit);
686 
687 MODULE_LICENSE("GPL");
688 MODULE_AUTHOR("Jamey Hicks <jamey.hicks@hp.com>, Andrew Zabolotny <zap@homelink.ru>");
689 MODULE_DESCRIPTION("Backlight Lowlevel Control Abstraction");
690