18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (C) 2013, NVIDIA Corporation. All rights reserved. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 58c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 68c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation 78c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sub license, 88c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 98c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice (including the 128c2ecf20Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions 138c2ecf20Sopenharmony_ci * of the Software. 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 168c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 178c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 188c2ecf20Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 198c2ecf20Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 208c2ecf20Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 218c2ecf20Sopenharmony_ci * DEALINGS IN THE SOFTWARE. 228c2ecf20Sopenharmony_ci */ 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include <linux/backlight.h> 258c2ecf20Sopenharmony_ci#include <linux/err.h> 268c2ecf20Sopenharmony_ci#include <linux/module.h> 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#include <drm/drm_crtc.h> 298c2ecf20Sopenharmony_ci#include <drm/drm_panel.h> 308c2ecf20Sopenharmony_ci#include <drm/drm_print.h> 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(panel_lock); 338c2ecf20Sopenharmony_cistatic LIST_HEAD(panel_list); 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/** 368c2ecf20Sopenharmony_ci * DOC: drm panel 378c2ecf20Sopenharmony_ci * 388c2ecf20Sopenharmony_ci * The DRM panel helpers allow drivers to register panel objects with a 398c2ecf20Sopenharmony_ci * central registry and provide functions to retrieve those panels in display 408c2ecf20Sopenharmony_ci * drivers. 418c2ecf20Sopenharmony_ci * 428c2ecf20Sopenharmony_ci * For easy integration into drivers using the &drm_bridge infrastructure please 438c2ecf20Sopenharmony_ci * take look at drm_panel_bridge_add() and devm_drm_panel_bridge_add(). 448c2ecf20Sopenharmony_ci */ 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci/** 478c2ecf20Sopenharmony_ci * drm_panel_init - initialize a panel 488c2ecf20Sopenharmony_ci * @panel: DRM panel 498c2ecf20Sopenharmony_ci * @dev: parent device of the panel 508c2ecf20Sopenharmony_ci * @funcs: panel operations 518c2ecf20Sopenharmony_ci * @connector_type: the connector type (DRM_MODE_CONNECTOR_*) corresponding to 528c2ecf20Sopenharmony_ci * the panel interface 538c2ecf20Sopenharmony_ci * 548c2ecf20Sopenharmony_ci * Initialize the panel structure for subsequent registration with 558c2ecf20Sopenharmony_ci * drm_panel_add(). 568c2ecf20Sopenharmony_ci */ 578c2ecf20Sopenharmony_civoid drm_panel_init(struct drm_panel *panel, struct device *dev, 588c2ecf20Sopenharmony_ci const struct drm_panel_funcs *funcs, int connector_type) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&panel->list); 618c2ecf20Sopenharmony_ci panel->dev = dev; 628c2ecf20Sopenharmony_ci panel->funcs = funcs; 638c2ecf20Sopenharmony_ci panel->connector_type = connector_type; 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_panel_init); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci/** 688c2ecf20Sopenharmony_ci * drm_panel_add - add a panel to the global registry 698c2ecf20Sopenharmony_ci * @panel: panel to add 708c2ecf20Sopenharmony_ci * 718c2ecf20Sopenharmony_ci * Add a panel to the global registry so that it can be looked up by display 728c2ecf20Sopenharmony_ci * drivers. 738c2ecf20Sopenharmony_ci */ 748c2ecf20Sopenharmony_civoid drm_panel_add(struct drm_panel *panel) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci mutex_lock(&panel_lock); 778c2ecf20Sopenharmony_ci list_add_tail(&panel->list, &panel_list); 788c2ecf20Sopenharmony_ci mutex_unlock(&panel_lock); 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_panel_add); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci/** 838c2ecf20Sopenharmony_ci * drm_panel_remove - remove a panel from the global registry 848c2ecf20Sopenharmony_ci * @panel: DRM panel 858c2ecf20Sopenharmony_ci * 868c2ecf20Sopenharmony_ci * Removes a panel from the global registry. 878c2ecf20Sopenharmony_ci */ 888c2ecf20Sopenharmony_civoid drm_panel_remove(struct drm_panel *panel) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci mutex_lock(&panel_lock); 918c2ecf20Sopenharmony_ci list_del_init(&panel->list); 928c2ecf20Sopenharmony_ci mutex_unlock(&panel_lock); 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_panel_remove); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci/** 978c2ecf20Sopenharmony_ci * drm_panel_prepare - power on a panel 988c2ecf20Sopenharmony_ci * @panel: DRM panel 998c2ecf20Sopenharmony_ci * 1008c2ecf20Sopenharmony_ci * Calling this function will enable power and deassert any reset signals to 1018c2ecf20Sopenharmony_ci * the panel. After this has completed it is possible to communicate with any 1028c2ecf20Sopenharmony_ci * integrated circuitry via a command bus. 1038c2ecf20Sopenharmony_ci * 1048c2ecf20Sopenharmony_ci * Return: 0 on success or a negative error code on failure. 1058c2ecf20Sopenharmony_ci */ 1068c2ecf20Sopenharmony_ciint drm_panel_prepare(struct drm_panel *panel) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci if (!panel) 1098c2ecf20Sopenharmony_ci return -EINVAL; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci if (panel->funcs && panel->funcs->prepare) 1128c2ecf20Sopenharmony_ci return panel->funcs->prepare(panel); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci return 0; 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_panel_prepare); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci/** 1198c2ecf20Sopenharmony_ci * drm_panel_unprepare - power off a panel 1208c2ecf20Sopenharmony_ci * @panel: DRM panel 1218c2ecf20Sopenharmony_ci * 1228c2ecf20Sopenharmony_ci * Calling this function will completely power off a panel (assert the panel's 1238c2ecf20Sopenharmony_ci * reset, turn off power supplies, ...). After this function has completed, it 1248c2ecf20Sopenharmony_ci * is usually no longer possible to communicate with the panel until another 1258c2ecf20Sopenharmony_ci * call to drm_panel_prepare(). 1268c2ecf20Sopenharmony_ci * 1278c2ecf20Sopenharmony_ci * Return: 0 on success or a negative error code on failure. 1288c2ecf20Sopenharmony_ci */ 1298c2ecf20Sopenharmony_ciint drm_panel_unprepare(struct drm_panel *panel) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci if (!panel) 1328c2ecf20Sopenharmony_ci return -EINVAL; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci if (panel->funcs && panel->funcs->unprepare) 1358c2ecf20Sopenharmony_ci return panel->funcs->unprepare(panel); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci return 0; 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_panel_unprepare); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci/** 1428c2ecf20Sopenharmony_ci * drm_panel_enable - enable a panel 1438c2ecf20Sopenharmony_ci * @panel: DRM panel 1448c2ecf20Sopenharmony_ci * 1458c2ecf20Sopenharmony_ci * Calling this function will cause the panel display drivers to be turned on 1468c2ecf20Sopenharmony_ci * and the backlight to be enabled. Content will be visible on screen after 1478c2ecf20Sopenharmony_ci * this call completes. 1488c2ecf20Sopenharmony_ci * 1498c2ecf20Sopenharmony_ci * Return: 0 on success or a negative error code on failure. 1508c2ecf20Sopenharmony_ci */ 1518c2ecf20Sopenharmony_ciint drm_panel_enable(struct drm_panel *panel) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci int ret; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci if (!panel) 1568c2ecf20Sopenharmony_ci return -EINVAL; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci if (panel->funcs && panel->funcs->enable) { 1598c2ecf20Sopenharmony_ci ret = panel->funcs->enable(panel); 1608c2ecf20Sopenharmony_ci if (ret < 0) 1618c2ecf20Sopenharmony_ci return ret; 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci ret = backlight_enable(panel->backlight); 1658c2ecf20Sopenharmony_ci if (ret < 0) 1668c2ecf20Sopenharmony_ci DRM_DEV_INFO(panel->dev, "failed to enable backlight: %d\n", 1678c2ecf20Sopenharmony_ci ret); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci return 0; 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_panel_enable); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci/** 1748c2ecf20Sopenharmony_ci * drm_panel_disable - disable a panel 1758c2ecf20Sopenharmony_ci * @panel: DRM panel 1768c2ecf20Sopenharmony_ci * 1778c2ecf20Sopenharmony_ci * This will typically turn off the panel's backlight or disable the display 1788c2ecf20Sopenharmony_ci * drivers. For smart panels it should still be possible to communicate with 1798c2ecf20Sopenharmony_ci * the integrated circuitry via any command bus after this call. 1808c2ecf20Sopenharmony_ci * 1818c2ecf20Sopenharmony_ci * Return: 0 on success or a negative error code on failure. 1828c2ecf20Sopenharmony_ci */ 1838c2ecf20Sopenharmony_ciint drm_panel_disable(struct drm_panel *panel) 1848c2ecf20Sopenharmony_ci{ 1858c2ecf20Sopenharmony_ci int ret; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci if (!panel) 1888c2ecf20Sopenharmony_ci return -EINVAL; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci ret = backlight_disable(panel->backlight); 1918c2ecf20Sopenharmony_ci if (ret < 0) 1928c2ecf20Sopenharmony_ci DRM_DEV_INFO(panel->dev, "failed to disable backlight: %d\n", 1938c2ecf20Sopenharmony_ci ret); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci if (panel->funcs && panel->funcs->disable) 1968c2ecf20Sopenharmony_ci return panel->funcs->disable(panel); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci return 0; 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_panel_disable); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci/** 2038c2ecf20Sopenharmony_ci * drm_panel_get_modes - probe the available display modes of a panel 2048c2ecf20Sopenharmony_ci * @panel: DRM panel 2058c2ecf20Sopenharmony_ci * @connector: DRM connector 2068c2ecf20Sopenharmony_ci * 2078c2ecf20Sopenharmony_ci * The modes probed from the panel are automatically added to the connector 2088c2ecf20Sopenharmony_ci * that the panel is attached to. 2098c2ecf20Sopenharmony_ci * 2108c2ecf20Sopenharmony_ci * Return: The number of modes available from the panel on success or a 2118c2ecf20Sopenharmony_ci * negative error code on failure. 2128c2ecf20Sopenharmony_ci */ 2138c2ecf20Sopenharmony_ciint drm_panel_get_modes(struct drm_panel *panel, 2148c2ecf20Sopenharmony_ci struct drm_connector *connector) 2158c2ecf20Sopenharmony_ci{ 2168c2ecf20Sopenharmony_ci if (!panel) 2178c2ecf20Sopenharmony_ci return -EINVAL; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci if (panel->funcs && panel->funcs->get_modes) 2208c2ecf20Sopenharmony_ci return panel->funcs->get_modes(panel, connector); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 2238c2ecf20Sopenharmony_ci} 2248c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_panel_get_modes); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci#ifdef CONFIG_OF 2278c2ecf20Sopenharmony_ci/** 2288c2ecf20Sopenharmony_ci * of_drm_find_panel - look up a panel using a device tree node 2298c2ecf20Sopenharmony_ci * @np: device tree node of the panel 2308c2ecf20Sopenharmony_ci * 2318c2ecf20Sopenharmony_ci * Searches the set of registered panels for one that matches the given device 2328c2ecf20Sopenharmony_ci * tree node. If a matching panel is found, return a pointer to it. 2338c2ecf20Sopenharmony_ci * 2348c2ecf20Sopenharmony_ci * Return: A pointer to the panel registered for the specified device tree 2358c2ecf20Sopenharmony_ci * node or an ERR_PTR() if no panel matching the device tree node can be found. 2368c2ecf20Sopenharmony_ci * 2378c2ecf20Sopenharmony_ci * Possible error codes returned by this function: 2388c2ecf20Sopenharmony_ci * 2398c2ecf20Sopenharmony_ci * - EPROBE_DEFER: the panel device has not been probed yet, and the caller 2408c2ecf20Sopenharmony_ci * should retry later 2418c2ecf20Sopenharmony_ci * - ENODEV: the device is not available (status != "okay" or "ok") 2428c2ecf20Sopenharmony_ci */ 2438c2ecf20Sopenharmony_cistruct drm_panel *of_drm_find_panel(const struct device_node *np) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci struct drm_panel *panel; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci if (!of_device_is_available(np)) 2488c2ecf20Sopenharmony_ci return ERR_PTR(-ENODEV); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci mutex_lock(&panel_lock); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci list_for_each_entry(panel, &panel_list, list) { 2538c2ecf20Sopenharmony_ci if (panel->dev->of_node == np) { 2548c2ecf20Sopenharmony_ci mutex_unlock(&panel_lock); 2558c2ecf20Sopenharmony_ci return panel; 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci mutex_unlock(&panel_lock); 2608c2ecf20Sopenharmony_ci return ERR_PTR(-EPROBE_DEFER); 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ciEXPORT_SYMBOL(of_drm_find_panel); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci/** 2658c2ecf20Sopenharmony_ci * of_drm_get_panel_orientation - look up the orientation of the panel through 2668c2ecf20Sopenharmony_ci * the "rotation" binding from a device tree node 2678c2ecf20Sopenharmony_ci * @np: device tree node of the panel 2688c2ecf20Sopenharmony_ci * @orientation: orientation enum to be filled in 2698c2ecf20Sopenharmony_ci * 2708c2ecf20Sopenharmony_ci * Looks up the rotation of a panel in the device tree. The orientation of the 2718c2ecf20Sopenharmony_ci * panel is expressed as a property name "rotation" in the device tree. The 2728c2ecf20Sopenharmony_ci * rotation in the device tree is counter clockwise. 2738c2ecf20Sopenharmony_ci * 2748c2ecf20Sopenharmony_ci * Return: 0 when a valid rotation value (0, 90, 180, or 270) is read or the 2758c2ecf20Sopenharmony_ci * rotation property doesn't exist. Return a negative error code on failure. 2768c2ecf20Sopenharmony_ci */ 2778c2ecf20Sopenharmony_ciint of_drm_get_panel_orientation(const struct device_node *np, 2788c2ecf20Sopenharmony_ci enum drm_panel_orientation *orientation) 2798c2ecf20Sopenharmony_ci{ 2808c2ecf20Sopenharmony_ci int rotation, ret; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci ret = of_property_read_u32(np, "rotation", &rotation); 2838c2ecf20Sopenharmony_ci if (ret == -EINVAL) { 2848c2ecf20Sopenharmony_ci /* Don't return an error if there's no rotation property. */ 2858c2ecf20Sopenharmony_ci *orientation = DRM_MODE_PANEL_ORIENTATION_UNKNOWN; 2868c2ecf20Sopenharmony_ci return 0; 2878c2ecf20Sopenharmony_ci } 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci if (ret < 0) 2908c2ecf20Sopenharmony_ci return ret; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci if (rotation == 0) 2938c2ecf20Sopenharmony_ci *orientation = DRM_MODE_PANEL_ORIENTATION_NORMAL; 2948c2ecf20Sopenharmony_ci else if (rotation == 90) 2958c2ecf20Sopenharmony_ci *orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP; 2968c2ecf20Sopenharmony_ci else if (rotation == 180) 2978c2ecf20Sopenharmony_ci *orientation = DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP; 2988c2ecf20Sopenharmony_ci else if (rotation == 270) 2998c2ecf20Sopenharmony_ci *orientation = DRM_MODE_PANEL_ORIENTATION_LEFT_UP; 3008c2ecf20Sopenharmony_ci else 3018c2ecf20Sopenharmony_ci return -EINVAL; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci return 0; 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ciEXPORT_SYMBOL(of_drm_get_panel_orientation); 3068c2ecf20Sopenharmony_ci#endif 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci#if IS_REACHABLE(CONFIG_BACKLIGHT_CLASS_DEVICE) 3098c2ecf20Sopenharmony_ci/** 3108c2ecf20Sopenharmony_ci * drm_panel_of_backlight - use backlight device node for backlight 3118c2ecf20Sopenharmony_ci * @panel: DRM panel 3128c2ecf20Sopenharmony_ci * 3138c2ecf20Sopenharmony_ci * Use this function to enable backlight handling if your panel 3148c2ecf20Sopenharmony_ci * uses device tree and has a backlight phandle. 3158c2ecf20Sopenharmony_ci * 3168c2ecf20Sopenharmony_ci * When the panel is enabled backlight will be enabled after a 3178c2ecf20Sopenharmony_ci * successful call to &drm_panel_funcs.enable() 3188c2ecf20Sopenharmony_ci * 3198c2ecf20Sopenharmony_ci * When the panel is disabled backlight will be disabled before the 3208c2ecf20Sopenharmony_ci * call to &drm_panel_funcs.disable(). 3218c2ecf20Sopenharmony_ci * 3228c2ecf20Sopenharmony_ci * A typical implementation for a panel driver supporting device tree 3238c2ecf20Sopenharmony_ci * will call this function at probe time. Backlight will then be handled 3248c2ecf20Sopenharmony_ci * transparently without requiring any intervention from the driver. 3258c2ecf20Sopenharmony_ci * drm_panel_of_backlight() must be called after the call to drm_panel_init(). 3268c2ecf20Sopenharmony_ci * 3278c2ecf20Sopenharmony_ci * Return: 0 on success or a negative error code on failure. 3288c2ecf20Sopenharmony_ci */ 3298c2ecf20Sopenharmony_ciint drm_panel_of_backlight(struct drm_panel *panel) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci struct backlight_device *backlight; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci if (!panel || !panel->dev) 3348c2ecf20Sopenharmony_ci return -EINVAL; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci backlight = devm_of_find_backlight(panel->dev); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci if (IS_ERR(backlight)) 3398c2ecf20Sopenharmony_ci return PTR_ERR(backlight); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci panel->backlight = backlight; 3428c2ecf20Sopenharmony_ci return 0; 3438c2ecf20Sopenharmony_ci} 3448c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drm_panel_of_backlight); 3458c2ecf20Sopenharmony_ci#endif 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ciMODULE_AUTHOR("Thierry Reding <treding@nvidia.com>"); 3488c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("DRM panel infrastructure"); 3498c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL and additional rights"); 350