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(list: &panel->list);
66 INIT_LIST_HEAD(list: &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(lock: &panel_lock);
85 list_add_tail(new: &panel->list, head: &panel_list);
86 mutex_unlock(lock: &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(lock: &panel_lock);
99 list_del_init(entry: &panel->list);
100 mutex_unlock(lock: &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(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(lock: &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(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(lock: &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(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(bd: 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(lock: &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(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(bd: 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(lock: &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(objp: 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(kref: &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(kref: &panel->refcount, release: __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(error: -EINVAL);
412 }
413
414 container = kzalloc(size, GFP_KERNEL);
415 if (!container)
416 return ERR_PTR(error: -ENOMEM);
417
418 panel = container + offset;
419 panel->container = container;
420 panel->funcs = funcs;
421 kref_init(kref: &panel->refcount);
422
423 err = devm_add_action_or_reset(dev, drm_panel_put_void, panel);
424 if (err)
425 return ERR_PTR(error: 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(error: -ENODEV);
522
523 mutex_lock(lock: &panel_lock);
524
525 list_for_each_entry(panel, &panel_list, list) {
526 if (dev_fwnode(panel->dev) == fwnode) {
527 mutex_unlock(lock: &panel_lock);
528 return panel;
529 }
530 }
531
532 mutex_unlock(lock: &panel_lock);
533
534 return ERR_PTR(error: -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), name: "panel", index: 0);
544 if (IS_ERR(ptr: fwnode))
545 return ERR_PTR(error: -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, propname: "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(ptr: panel))
602 return PTR_ERR(ptr: panel);
603
604 get_device(dev: panel->dev);
605 follower->panel = panel;
606
607 mutex_lock(lock: &panel->follower_lock);
608
609 list_add_tail(new: &follower->list, head: &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(lock: &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(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(entry: &follower->list);
659
660 mutex_unlock(lock: &panel->follower_lock);
661
662 put_device(dev: 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(dev: panel->dev);
723
724 if (IS_ERR(ptr: backlight))
725 return PTR_ERR(ptr: 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");
736