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