xref: /linux/drivers/gpu/drm/drm_panel.c (revision 07fdad3a93756b872da7b53647715c48d0f4a2d0)
1 /*
2  * Copyright (C) 2013, NVIDIA Corporation.  All rights reserved.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sub license,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the
12  * next paragraph) shall be included in all copies or substantial portions
13  * of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23 
24 #include <linux/backlight.h>
25 #include <linux/err.h>
26 #include <linux/export.h>
27 #include <linux/module.h>
28 #include <linux/of.h>
29 
30 #include <drm/drm_crtc.h>
31 #include <drm/drm_panel.h>
32 #include <drm/drm_print.h>
33 
34 static DEFINE_MUTEX(panel_lock);
35 static LIST_HEAD(panel_list);
36 
37 /**
38  * DOC: drm panel
39  *
40  * The DRM panel helpers allow drivers to register panel objects with a
41  * central registry and provide functions to retrieve those panels in display
42  * drivers.
43  *
44  * For easy integration into drivers using the &drm_bridge infrastructure please
45  * take look at drm_panel_bridge_add() and devm_drm_panel_bridge_add().
46  */
47 
48 /**
49  * drm_panel_init - initialize a panel
50  * @panel: DRM panel
51  * @dev: parent device of the panel
52  * @funcs: panel operations
53  * @connector_type: the connector type (DRM_MODE_CONNECTOR_*) corresponding to
54  *	the panel interface (must NOT be DRM_MODE_CONNECTOR_Unknown)
55  *
56  * Initialize the panel structure for subsequent registration with
57  * drm_panel_add().
58  */
59 void drm_panel_init(struct drm_panel *panel, struct device *dev,
60 		    const struct drm_panel_funcs *funcs, int connector_type)
61 {
62 	if (connector_type == DRM_MODE_CONNECTOR_Unknown)
63 		DRM_WARN("%s: %s: a valid connector type is required!\n", __func__, dev_name(dev));
64 
65 	INIT_LIST_HEAD(&panel->list);
66 	INIT_LIST_HEAD(&panel->followers);
67 	mutex_init(&panel->follower_lock);
68 	panel->dev = dev;
69 	panel->funcs = funcs;
70 	panel->connector_type = connector_type;
71 }
72 EXPORT_SYMBOL(drm_panel_init);
73 
74 /**
75  * drm_panel_add - add a panel to the global registry
76  * @panel: panel to add
77  *
78  * Add a panel to the global registry so that it can be looked
79  * up by display drivers. The panel to be added must have been
80  * allocated by devm_drm_panel_alloc().
81  */
82 void drm_panel_add(struct drm_panel *panel)
83 {
84 	mutex_lock(&panel_lock);
85 	list_add_tail(&panel->list, &panel_list);
86 	mutex_unlock(&panel_lock);
87 }
88 EXPORT_SYMBOL(drm_panel_add);
89 
90 /**
91  * drm_panel_remove - remove a panel from the global registry
92  * @panel: DRM panel
93  *
94  * Removes a panel from the global registry.
95  */
96 void drm_panel_remove(struct drm_panel *panel)
97 {
98 	mutex_lock(&panel_lock);
99 	list_del_init(&panel->list);
100 	mutex_unlock(&panel_lock);
101 }
102 EXPORT_SYMBOL(drm_panel_remove);
103 
104 /**
105  * drm_panel_prepare - power on a panel
106  * @panel: DRM panel
107  *
108  * Calling this function will enable power and deassert any reset signals to
109  * the panel. After this has completed it is possible to communicate with any
110  * integrated circuitry via a command bus. This function cannot fail (as it is
111  * called from the pre_enable call chain). There will always be a call to
112  * drm_panel_disable() afterwards.
113  */
114 void drm_panel_prepare(struct drm_panel *panel)
115 {
116 	struct drm_panel_follower *follower;
117 	int ret;
118 
119 	if (!panel)
120 		return;
121 
122 	if (panel->prepared) {
123 		dev_warn(panel->dev, "Skipping prepare of already prepared panel\n");
124 		return;
125 	}
126 
127 	mutex_lock(&panel->follower_lock);
128 
129 	if (panel->funcs && panel->funcs->prepare) {
130 		ret = panel->funcs->prepare(panel);
131 		if (ret < 0)
132 			goto exit;
133 	}
134 	panel->prepared = true;
135 
136 	list_for_each_entry(follower, &panel->followers, list) {
137 		if (!follower->funcs->panel_prepared)
138 			continue;
139 
140 		ret = follower->funcs->panel_prepared(follower);
141 		if (ret < 0)
142 			dev_info(panel->dev, "%ps failed: %d\n",
143 				 follower->funcs->panel_prepared, ret);
144 	}
145 
146 exit:
147 	mutex_unlock(&panel->follower_lock);
148 }
149 EXPORT_SYMBOL(drm_panel_prepare);
150 
151 /**
152  * drm_panel_unprepare - power off a panel
153  * @panel: DRM panel
154  *
155  * Calling this function will completely power off a panel (assert the panel's
156  * reset, turn off power supplies, ...). After this function has completed, it
157  * is usually no longer possible to communicate with the panel until another
158  * call to drm_panel_prepare().
159  */
160 void drm_panel_unprepare(struct drm_panel *panel)
161 {
162 	struct drm_panel_follower *follower;
163 	int ret;
164 
165 	if (!panel)
166 		return;
167 
168 	/*
169 	 * If you are seeing the warning below it likely means one of two things:
170 	 * - Your panel driver incorrectly calls drm_panel_unprepare() in its
171 	 *   shutdown routine. You should delete this.
172 	 * - You are using panel-edp or panel-simple and your DRM modeset
173 	 *   driver's shutdown() callback happened after the panel's shutdown().
174 	 *   In this case the warning is harmless though ideally you should
175 	 *   figure out how to reverse the order of the shutdown() callbacks.
176 	 */
177 	if (!panel->prepared) {
178 		dev_warn(panel->dev, "Skipping unprepare of already unprepared panel\n");
179 		return;
180 	}
181 
182 	mutex_lock(&panel->follower_lock);
183 
184 	list_for_each_entry(follower, &panel->followers, list) {
185 		if (!follower->funcs->panel_unpreparing)
186 			continue;
187 
188 		ret = follower->funcs->panel_unpreparing(follower);
189 		if (ret < 0)
190 			dev_info(panel->dev, "%ps failed: %d\n",
191 				 follower->funcs->panel_unpreparing, ret);
192 	}
193 
194 	if (panel->funcs && panel->funcs->unprepare) {
195 		ret = panel->funcs->unprepare(panel);
196 		if (ret < 0)
197 			goto exit;
198 	}
199 	panel->prepared = false;
200 
201 exit:
202 	mutex_unlock(&panel->follower_lock);
203 }
204 EXPORT_SYMBOL(drm_panel_unprepare);
205 
206 /**
207  * drm_panel_enable - enable a panel
208  * @panel: DRM panel
209  *
210  * Calling this function will cause the panel display drivers to be turned on
211  * and the backlight to be enabled. Content will be visible on screen after
212  * this call completes. This function cannot fail (as it is called from the
213  * enable call chain). There will always be a call to drm_panel_disable()
214  * afterwards.
215  */
216 void drm_panel_enable(struct drm_panel *panel)
217 {
218 	struct drm_panel_follower *follower;
219 	int ret;
220 
221 	if (!panel)
222 		return;
223 
224 	if (panel->enabled) {
225 		dev_warn(panel->dev, "Skipping enable of already enabled panel\n");
226 		return;
227 	}
228 
229 	mutex_lock(&panel->follower_lock);
230 
231 	if (panel->funcs && panel->funcs->enable) {
232 		ret = panel->funcs->enable(panel);
233 		if (ret < 0)
234 			goto exit;
235 	}
236 	panel->enabled = true;
237 
238 	ret = backlight_enable(panel->backlight);
239 	if (ret < 0)
240 		DRM_DEV_INFO(panel->dev, "failed to enable backlight: %d\n",
241 			     ret);
242 
243 	list_for_each_entry(follower, &panel->followers, list) {
244 		if (!follower->funcs->panel_enabled)
245 			continue;
246 
247 		ret = follower->funcs->panel_enabled(follower);
248 		if (ret < 0)
249 			dev_info(panel->dev, "%ps failed: %d\n",
250 				 follower->funcs->panel_enabled, ret);
251 	}
252 
253 exit:
254 	mutex_unlock(&panel->follower_lock);
255 }
256 EXPORT_SYMBOL(drm_panel_enable);
257 
258 /**
259  * drm_panel_disable - disable a panel
260  * @panel: DRM panel
261  *
262  * This will typically turn off the panel's backlight or disable the display
263  * drivers. For smart panels it should still be possible to communicate with
264  * the integrated circuitry via any command bus after this call.
265  */
266 void drm_panel_disable(struct drm_panel *panel)
267 {
268 	struct drm_panel_follower *follower;
269 	int ret;
270 
271 	if (!panel)
272 		return;
273 
274 	/*
275 	 * If you are seeing the warning below it likely means one of two things:
276 	 * - Your panel driver incorrectly calls drm_panel_disable() in its
277 	 *   shutdown routine. You should delete this.
278 	 * - You are using panel-edp or panel-simple and your DRM modeset
279 	 *   driver's shutdown() callback happened after the panel's shutdown().
280 	 *   In this case the warning is harmless though ideally you should
281 	 *   figure out how to reverse the order of the shutdown() callbacks.
282 	 */
283 	if (!panel->enabled) {
284 		dev_warn(panel->dev, "Skipping disable of already disabled panel\n");
285 		return;
286 	}
287 
288 	mutex_lock(&panel->follower_lock);
289 
290 	list_for_each_entry(follower, &panel->followers, list) {
291 		if (!follower->funcs->panel_disabling)
292 			continue;
293 
294 		ret = follower->funcs->panel_disabling(follower);
295 		if (ret < 0)
296 			dev_info(panel->dev, "%ps failed: %d\n",
297 				 follower->funcs->panel_disabling, ret);
298 	}
299 
300 	ret = backlight_disable(panel->backlight);
301 	if (ret < 0)
302 		DRM_DEV_INFO(panel->dev, "failed to disable backlight: %d\n",
303 			     ret);
304 
305 	if (panel->funcs && panel->funcs->disable) {
306 		ret = panel->funcs->disable(panel);
307 		if (ret < 0)
308 			goto exit;
309 	}
310 	panel->enabled = false;
311 
312 exit:
313 	mutex_unlock(&panel->follower_lock);
314 }
315 EXPORT_SYMBOL(drm_panel_disable);
316 
317 /**
318  * drm_panel_get_modes - probe the available display modes of a panel
319  * @panel: DRM panel
320  * @connector: DRM connector
321  *
322  * The modes probed from the panel are automatically added to the connector
323  * that the panel is attached to.
324  *
325  * Return: The number of modes available from the panel on success, or 0 on
326  * failure (no modes).
327  */
328 int drm_panel_get_modes(struct drm_panel *panel,
329 			struct drm_connector *connector)
330 {
331 	if (!panel)
332 		return 0;
333 
334 	if (panel->funcs && panel->funcs->get_modes) {
335 		int num;
336 
337 		num = panel->funcs->get_modes(panel, connector);
338 		if (num > 0)
339 			return num;
340 	}
341 
342 	return 0;
343 }
344 EXPORT_SYMBOL(drm_panel_get_modes);
345 
346 static void __drm_panel_free(struct kref *kref)
347 {
348 	struct drm_panel *panel = container_of(kref, struct drm_panel, refcount);
349 
350 	kfree(panel->container);
351 }
352 
353 /**
354  * drm_panel_get - Acquire a panel reference
355  * @panel: DRM panel
356  *
357  * This function increments the panel's refcount.
358  * Returns:
359  * Pointer to @panel
360  */
361 struct drm_panel *drm_panel_get(struct drm_panel *panel)
362 {
363 	if (!panel)
364 		return panel;
365 
366 	kref_get(&panel->refcount);
367 
368 	return panel;
369 }
370 EXPORT_SYMBOL(drm_panel_get);
371 
372 /**
373  * drm_panel_put - Release a panel reference
374  * @panel: DRM panel
375  *
376  * This function decrements the panel's reference count and frees the
377  * object if the reference count drops to zero.
378  */
379 void drm_panel_put(struct drm_panel *panel)
380 {
381 	if (panel)
382 		kref_put(&panel->refcount, __drm_panel_free);
383 }
384 EXPORT_SYMBOL(drm_panel_put);
385 
386 /**
387  * drm_panel_put_void - wrapper to drm_panel_put() taking a void pointer
388  *
389  * @data: pointer to @struct drm_panel, cast to a void pointer
390  *
391  * Wrapper of drm_panel_put() to be used when a function taking a void
392  * pointer is needed, for example as a devm action.
393  */
394 static void drm_panel_put_void(void *data)
395 {
396 	struct drm_panel *panel = (struct drm_panel *)data;
397 
398 	drm_panel_put(panel);
399 }
400 
401 void *__devm_drm_panel_alloc(struct device *dev, size_t size, size_t offset,
402 			     const struct drm_panel_funcs *funcs,
403 			     int connector_type)
404 {
405 	void *container;
406 	struct drm_panel *panel;
407 	int err;
408 
409 	if (!funcs) {
410 		dev_warn(dev, "Missing funcs pointer\n");
411 		return ERR_PTR(-EINVAL);
412 	}
413 
414 	container = kzalloc(size, GFP_KERNEL);
415 	if (!container)
416 		return ERR_PTR(-ENOMEM);
417 
418 	panel = container + offset;
419 	panel->container = container;
420 	panel->funcs = funcs;
421 	kref_init(&panel->refcount);
422 
423 	err = devm_add_action_or_reset(dev, drm_panel_put_void, panel);
424 	if (err)
425 		return ERR_PTR(err);
426 
427 	drm_panel_init(panel, dev, funcs, connector_type);
428 
429 	return container;
430 }
431 EXPORT_SYMBOL(__devm_drm_panel_alloc);
432 
433 #ifdef CONFIG_OF
434 /**
435  * of_drm_find_panel - look up a panel using a device tree node
436  * @np: device tree node of the panel
437  *
438  * Searches the set of registered panels for one that matches the given device
439  * tree node. If a matching panel is found, return a pointer to it.
440  *
441  * Return: A pointer to the panel registered for the specified device tree
442  * node or an ERR_PTR() if no panel matching the device tree node can be found.
443  *
444  * Possible error codes returned by this function:
445  *
446  * - EPROBE_DEFER: the panel device has not been probed yet, and the caller
447  *   should retry later
448  * - ENODEV: the device is not available (status != "okay" or "ok")
449  */
450 struct drm_panel *of_drm_find_panel(const struct device_node *np)
451 {
452 	struct drm_panel *panel;
453 
454 	if (!of_device_is_available(np))
455 		return ERR_PTR(-ENODEV);
456 
457 	mutex_lock(&panel_lock);
458 
459 	list_for_each_entry(panel, &panel_list, list) {
460 		if (panel->dev->of_node == np) {
461 			mutex_unlock(&panel_lock);
462 			return panel;
463 		}
464 	}
465 
466 	mutex_unlock(&panel_lock);
467 	return ERR_PTR(-EPROBE_DEFER);
468 }
469 EXPORT_SYMBOL(of_drm_find_panel);
470 
471 /**
472  * of_drm_get_panel_orientation - look up the orientation of the panel through
473  * the "rotation" binding from a device tree node
474  * @np: device tree node of the panel
475  * @orientation: orientation enum to be filled in
476  *
477  * Looks up the rotation of a panel in the device tree. The orientation of the
478  * panel is expressed as a property name "rotation" in the device tree. The
479  * rotation in the device tree is counter clockwise.
480  *
481  * Return: 0 when a valid rotation value (0, 90, 180, or 270) is read or the
482  * rotation property doesn't exist. Return a negative error code on failure.
483  */
484 int of_drm_get_panel_orientation(const struct device_node *np,
485 				 enum drm_panel_orientation *orientation)
486 {
487 	int rotation, ret;
488 
489 	ret = of_property_read_u32(np, "rotation", &rotation);
490 	if (ret == -EINVAL) {
491 		/* Don't return an error if there's no rotation property. */
492 		*orientation = DRM_MODE_PANEL_ORIENTATION_UNKNOWN;
493 		return 0;
494 	}
495 
496 	if (ret < 0)
497 		return ret;
498 
499 	if (rotation == 0)
500 		*orientation = DRM_MODE_PANEL_ORIENTATION_NORMAL;
501 	else if (rotation == 90)
502 		*orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP;
503 	else if (rotation == 180)
504 		*orientation = DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP;
505 	else if (rotation == 270)
506 		*orientation = DRM_MODE_PANEL_ORIENTATION_LEFT_UP;
507 	else
508 		return -EINVAL;
509 
510 	return 0;
511 }
512 EXPORT_SYMBOL(of_drm_get_panel_orientation);
513 #endif
514 
515 /* Find panel by fwnode. This should be identical to of_drm_find_panel(). */
516 static struct drm_panel *find_panel_by_fwnode(const struct fwnode_handle *fwnode)
517 {
518 	struct drm_panel *panel;
519 
520 	if (!fwnode_device_is_available(fwnode))
521 		return ERR_PTR(-ENODEV);
522 
523 	mutex_lock(&panel_lock);
524 
525 	list_for_each_entry(panel, &panel_list, list) {
526 		if (dev_fwnode(panel->dev) == fwnode) {
527 			mutex_unlock(&panel_lock);
528 			return panel;
529 		}
530 	}
531 
532 	mutex_unlock(&panel_lock);
533 
534 	return ERR_PTR(-EPROBE_DEFER);
535 }
536 
537 /* Find panel by follower device */
538 static struct drm_panel *find_panel_by_dev(struct device *follower_dev)
539 {
540 	struct fwnode_handle *fwnode;
541 	struct drm_panel *panel;
542 
543 	fwnode = fwnode_find_reference(dev_fwnode(follower_dev), "panel", 0);
544 	if (IS_ERR(fwnode))
545 		return ERR_PTR(-ENODEV);
546 
547 	panel = find_panel_by_fwnode(fwnode);
548 	fwnode_handle_put(fwnode);
549 
550 	return panel;
551 }
552 
553 /**
554  * drm_is_panel_follower() - Check if the device is a panel follower
555  * @dev: The 'struct device' to check
556  *
557  * This checks to see if a device needs to be power sequenced together with
558  * a panel using the panel follower API.
559  *
560  * The "panel" property of the follower points to the panel to be followed.
561  *
562  * Return: true if we should be power sequenced with a panel; false otherwise.
563  */
564 bool drm_is_panel_follower(struct device *dev)
565 {
566 	/*
567 	 * The "panel" property is actually a phandle, but for simplicity we
568 	 * don't bother trying to parse it here. We just need to know if the
569 	 * property is there.
570 	 */
571 	return device_property_present(dev, "panel");
572 }
573 EXPORT_SYMBOL(drm_is_panel_follower);
574 
575 /**
576  * drm_panel_add_follower() - Register something to follow panel state.
577  * @follower_dev: The 'struct device' for the follower.
578  * @follower:     The panel follower descriptor for the follower.
579  *
580  * A panel follower is called right after preparing/enabling the panel and right
581  * before unpreparing/disabling the panel. It's primary intention is to power on
582  * an associated touchscreen, though it could be used for any similar devices.
583  * Multiple devices are allowed the follow the same panel.
584  *
585  * If a follower is added to a panel that's already been prepared/enabled, the
586  * follower's prepared/enabled callback is called right away.
587  *
588  * The "panel" property of the follower points to the panel to be followed.
589  *
590  * Return: 0 or an error code. Note that -ENODEV means that we detected that
591  *         follower_dev is not actually following a panel. The caller may
592  *         choose to ignore this return value if following a panel is optional.
593  */
594 int drm_panel_add_follower(struct device *follower_dev,
595 			   struct drm_panel_follower *follower)
596 {
597 	struct drm_panel *panel;
598 	int ret;
599 
600 	panel = find_panel_by_dev(follower_dev);
601 	if (IS_ERR(panel))
602 		return PTR_ERR(panel);
603 
604 	get_device(panel->dev);
605 	follower->panel = panel;
606 
607 	mutex_lock(&panel->follower_lock);
608 
609 	list_add_tail(&follower->list, &panel->followers);
610 	if (panel->prepared && follower->funcs->panel_prepared) {
611 		ret = follower->funcs->panel_prepared(follower);
612 		if (ret < 0)
613 			dev_info(panel->dev, "%ps failed: %d\n",
614 				 follower->funcs->panel_prepared, ret);
615 	}
616 	if (panel->enabled && follower->funcs->panel_enabled) {
617 		ret = follower->funcs->panel_enabled(follower);
618 		if (ret < 0)
619 			dev_info(panel->dev, "%ps failed: %d\n",
620 				 follower->funcs->panel_enabled, ret);
621 	}
622 
623 	mutex_unlock(&panel->follower_lock);
624 
625 	return 0;
626 }
627 EXPORT_SYMBOL(drm_panel_add_follower);
628 
629 /**
630  * drm_panel_remove_follower() - Reverse drm_panel_add_follower().
631  * @follower:     The panel follower descriptor for the follower.
632  *
633  * Undo drm_panel_add_follower(). This includes calling the follower's
634  * unpreparing/disabling function if we're removed from a panel that's currently
635  * prepared/enabled.
636  *
637  * Return: 0 or an error code.
638  */
639 void drm_panel_remove_follower(struct drm_panel_follower *follower)
640 {
641 	struct drm_panel *panel = follower->panel;
642 	int ret;
643 
644 	mutex_lock(&panel->follower_lock);
645 
646 	if (panel->enabled && follower->funcs->panel_disabling) {
647 		ret = follower->funcs->panel_disabling(follower);
648 		if (ret < 0)
649 			dev_info(panel->dev, "%ps failed: %d\n",
650 				 follower->funcs->panel_disabling, ret);
651 	}
652 	if (panel->prepared && follower->funcs->panel_unpreparing) {
653 		ret = follower->funcs->panel_unpreparing(follower);
654 		if (ret < 0)
655 			dev_info(panel->dev, "%ps failed: %d\n",
656 				 follower->funcs->panel_unpreparing, ret);
657 	}
658 	list_del_init(&follower->list);
659 
660 	mutex_unlock(&panel->follower_lock);
661 
662 	put_device(panel->dev);
663 }
664 EXPORT_SYMBOL(drm_panel_remove_follower);
665 
666 static void drm_panel_remove_follower_void(void *follower)
667 {
668 	drm_panel_remove_follower(follower);
669 }
670 
671 /**
672  * devm_drm_panel_add_follower() - devm version of drm_panel_add_follower()
673  * @follower_dev: The 'struct device' for the follower.
674  * @follower:     The panel follower descriptor for the follower.
675  *
676  * Handles calling drm_panel_remove_follower() using devm on the follower_dev.
677  *
678  * Return: 0 or an error code.
679  */
680 int devm_drm_panel_add_follower(struct device *follower_dev,
681 				struct drm_panel_follower *follower)
682 {
683 	int ret;
684 
685 	ret = drm_panel_add_follower(follower_dev, follower);
686 	if (ret)
687 		return ret;
688 
689 	return devm_add_action_or_reset(follower_dev,
690 					drm_panel_remove_follower_void, follower);
691 }
692 EXPORT_SYMBOL(devm_drm_panel_add_follower);
693 
694 #if IS_REACHABLE(CONFIG_BACKLIGHT_CLASS_DEVICE)
695 /**
696  * drm_panel_of_backlight - use backlight device node for backlight
697  * @panel: DRM panel
698  *
699  * Use this function to enable backlight handling if your panel
700  * uses device tree and has a backlight phandle.
701  *
702  * When the panel is enabled backlight will be enabled after a
703  * successful call to &drm_panel_funcs.enable()
704  *
705  * When the panel is disabled backlight will be disabled before the
706  * call to &drm_panel_funcs.disable().
707  *
708  * A typical implementation for a panel driver supporting device tree
709  * will call this function at probe time. Backlight will then be handled
710  * transparently without requiring any intervention from the driver.
711  * drm_panel_of_backlight() must be called after the call to drm_panel_init().
712  *
713  * Return: 0 on success or a negative error code on failure.
714  */
715 int drm_panel_of_backlight(struct drm_panel *panel)
716 {
717 	struct backlight_device *backlight;
718 
719 	if (!panel || !panel->dev)
720 		return -EINVAL;
721 
722 	backlight = devm_of_find_backlight(panel->dev);
723 
724 	if (IS_ERR(backlight))
725 		return PTR_ERR(backlight);
726 
727 	panel->backlight = backlight;
728 	return 0;
729 }
730 EXPORT_SYMBOL(drm_panel_of_backlight);
731 #endif
732 
733 MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>");
734 MODULE_DESCRIPTION("DRM panel infrastructure");
735 MODULE_LICENSE("GPL and additional rights");
736