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