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