File Index
Files and directories
Sign in
FILE

drm_panel.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/drm_panel.c C
  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
 34static DEFINE_MUTEX(panel_lock);
 35static 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 */
 59void 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}
 72EXPORT_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 */
 82void 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}
 88EXPORT_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 */
 96void 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}
102EXPORT_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 */
114void 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
146exit:
147	mutex_unlock(&panel->follower_lock);
148}
149EXPORT_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 */
160void 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
201exit:
202	mutex_unlock(&panel->follower_lock);
203}
204EXPORT_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 */
216void 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
253exit:
254	mutex_unlock(&panel->follower_lock);
255}
256EXPORT_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 */
266void 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
312exit:
313	mutex_unlock(&panel->follower_lock);
314}
315EXPORT_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 */
328int 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}
344EXPORT_SYMBOL(drm_panel_get_modes);
345
346static 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 */
361struct 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}
370EXPORT_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 */
379void drm_panel_put(struct drm_panel *panel)
380{
381	if (panel)
382		kref_put(&panel->refcount, __drm_panel_free);
383}
384EXPORT_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 */
394static 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
401void *__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}
431EXPORT_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 */
450struct 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}
469EXPORT_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 */
484int 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}
512EXPORT_SYMBOL(of_drm_get_panel_orientation);
513#endif
514
515/* Find panel by fwnode. This should be identical to of_drm_find_panel(). */
516static 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 */
538static 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 */
564bool 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}
573EXPORT_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 */
594int 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}
627EXPORT_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 */
639void 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}
664EXPORT_SYMBOL(drm_panel_remove_follower);
665
666static 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 */
680int 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}
692EXPORT_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 */
715int 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}
730EXPORT_SYMBOL(drm_panel_of_backlight);
731#endif
732
733MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>");
734MODULE_DESCRIPTION("DRM panel infrastructure");
735MODULE_LICENSE("GPL and additional rights");
~/ Read-only file preview.