^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * Copyright (C) 2013, NVIDIA Corporation. All rights reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Permission is hereby granted, free of charge, to any person obtaining a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * copy of this software and associated documentation files (the "Software"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * to deal in the Software without restriction, including without limitation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * the rights to use, copy, modify, merge, publish, distribute, sub license,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * and/or sell copies of the Software, and to permit persons to whom the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Software is furnished to do so, subject to the following conditions:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * The above copyright notice and this permission notice (including the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * next paragraph) shall be included in all copies or substantial portions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * of the Software.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * DEALINGS IN THE SOFTWARE.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/backlight.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <drm/drm_crtc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <drm/drm_panel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <drm/drm_print.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) static DEFINE_MUTEX(panel_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) static LIST_HEAD(panel_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) * DOC: drm panel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) * The DRM panel helpers allow drivers to register panel objects with a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) * central registry and provide functions to retrieve those panels in display
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) * drivers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) * For easy integration into drivers using the &drm_bridge infrastructure please
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) * take look at drm_panel_bridge_add() and devm_drm_panel_bridge_add().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * drm_panel_init - initialize a panel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) * @panel: DRM panel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) * @dev: parent device of the panel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) * @funcs: panel operations
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) * @connector_type: the connector type (DRM_MODE_CONNECTOR_*) corresponding to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) * the panel interface
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) * Initialize the panel structure for subsequent registration with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) * drm_panel_add().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) void drm_panel_init(struct drm_panel *panel, struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) const struct drm_panel_funcs *funcs, int connector_type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) INIT_LIST_HEAD(&panel->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) panel->dev = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) panel->funcs = funcs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) panel->connector_type = connector_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) EXPORT_SYMBOL(drm_panel_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) * drm_panel_add - add a panel to the global registry
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) * @panel: panel to add
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) * Add a panel to the global registry so that it can be looked up by display
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) * drivers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) void drm_panel_add(struct drm_panel *panel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) mutex_lock(&panel_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) list_add_tail(&panel->list, &panel_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) mutex_unlock(&panel_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) EXPORT_SYMBOL(drm_panel_add);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) * drm_panel_remove - remove a panel from the global registry
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) * @panel: DRM panel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) * Removes a panel from the global registry.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) void drm_panel_remove(struct drm_panel *panel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) mutex_lock(&panel_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) list_del_init(&panel->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) mutex_unlock(&panel_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) EXPORT_SYMBOL(drm_panel_remove);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) * drm_panel_prepare - power on a panel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) * @panel: DRM panel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) * Calling this function will enable power and deassert any reset signals to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) * the panel. After this has completed it is possible to communicate with any
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) * integrated circuitry via a command bus.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) * Return: 0 on success or a negative error code on failure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) int drm_panel_prepare(struct drm_panel *panel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) if (!panel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) if (panel->funcs && panel->funcs->prepare)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) return panel->funcs->prepare(panel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) EXPORT_SYMBOL(drm_panel_prepare);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) * drm_panel_unprepare - power off a panel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) * @panel: DRM panel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) * Calling this function will completely power off a panel (assert the panel's
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) * reset, turn off power supplies, ...). After this function has completed, it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) * is usually no longer possible to communicate with the panel until another
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) * call to drm_panel_prepare().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) * Return: 0 on success or a negative error code on failure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) int drm_panel_unprepare(struct drm_panel *panel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) if (!panel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) if (panel->funcs && panel->funcs->unprepare)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) return panel->funcs->unprepare(panel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) EXPORT_SYMBOL(drm_panel_unprepare);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) * drm_panel_enable - enable a panel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) * @panel: DRM panel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) * Calling this function will cause the panel display drivers to be turned on
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) * and the backlight to be enabled. Content will be visible on screen after
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) * this call completes.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) * Return: 0 on success or a negative error code on failure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) int drm_panel_enable(struct drm_panel *panel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) if (!panel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) if (panel->funcs && panel->funcs->enable) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) ret = panel->funcs->enable(panel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) ret = backlight_enable(panel->backlight);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) DRM_DEV_INFO(panel->dev, "failed to enable backlight: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) EXPORT_SYMBOL(drm_panel_enable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) * drm_panel_disable - disable a panel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) * @panel: DRM panel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) * This will typically turn off the panel's backlight or disable the display
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) * drivers. For smart panels it should still be possible to communicate with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) * the integrated circuitry via any command bus after this call.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) * Return: 0 on success or a negative error code on failure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) int drm_panel_disable(struct drm_panel *panel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) if (!panel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) ret = backlight_disable(panel->backlight);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) DRM_DEV_INFO(panel->dev, "failed to disable backlight: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) if (panel->funcs && panel->funcs->disable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) return panel->funcs->disable(panel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) EXPORT_SYMBOL(drm_panel_disable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) * drm_panel_get_modes - probe the available display modes of a panel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) * @panel: DRM panel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) * @connector: DRM connector
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) * The modes probed from the panel are automatically added to the connector
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) * that the panel is attached to.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) * Return: The number of modes available from the panel on success or a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) * negative error code on failure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) int drm_panel_get_modes(struct drm_panel *panel,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) struct drm_connector *connector)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) if (!panel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) if (panel->funcs && panel->funcs->get_modes)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) return panel->funcs->get_modes(panel, connector);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) EXPORT_SYMBOL(drm_panel_get_modes);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) #ifdef CONFIG_OF
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) * of_drm_find_panel - look up a panel using a device tree node
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) * @np: device tree node of the panel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) * Searches the set of registered panels for one that matches the given device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) * tree node. If a matching panel is found, return a pointer to it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) * Return: A pointer to the panel registered for the specified device tree
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) * node or an ERR_PTR() if no panel matching the device tree node can be found.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) * Possible error codes returned by this function:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) * - EPROBE_DEFER: the panel device has not been probed yet, and the caller
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) * should retry later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) * - ENODEV: the device is not available (status != "okay" or "ok")
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) struct drm_panel *of_drm_find_panel(const struct device_node *np)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) struct drm_panel *panel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) if (!of_device_is_available(np))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) return ERR_PTR(-ENODEV);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) mutex_lock(&panel_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) list_for_each_entry(panel, &panel_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) if (panel->dev->of_node == np) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) mutex_unlock(&panel_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) return panel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) mutex_unlock(&panel_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) return ERR_PTR(-EPROBE_DEFER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) EXPORT_SYMBOL(of_drm_find_panel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) * of_drm_get_panel_orientation - look up the orientation of the panel through
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) * the "rotation" binding from a device tree node
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) * @np: device tree node of the panel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) * @orientation: orientation enum to be filled in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) * Looks up the rotation of a panel in the device tree. The orientation of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) * panel is expressed as a property name "rotation" in the device tree. The
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) * rotation in the device tree is counter clockwise.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) * Return: 0 when a valid rotation value (0, 90, 180, or 270) is read or the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) * rotation property doesn't exist. Return a negative error code on failure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) int of_drm_get_panel_orientation(const struct device_node *np,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) enum drm_panel_orientation *orientation)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) int rotation, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) ret = of_property_read_u32(np, "rotation", &rotation);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) if (ret == -EINVAL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) /* Don't return an error if there's no rotation property. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) *orientation = DRM_MODE_PANEL_ORIENTATION_UNKNOWN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) if (rotation == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) *orientation = DRM_MODE_PANEL_ORIENTATION_NORMAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) else if (rotation == 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) *orientation = DRM_MODE_PANEL_ORIENTATION_RIGHT_UP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) else if (rotation == 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) *orientation = DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) else if (rotation == 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) *orientation = DRM_MODE_PANEL_ORIENTATION_LEFT_UP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) EXPORT_SYMBOL(of_drm_get_panel_orientation);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) #if IS_REACHABLE(CONFIG_BACKLIGHT_CLASS_DEVICE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) * drm_panel_of_backlight - use backlight device node for backlight
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) * @panel: DRM panel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) * Use this function to enable backlight handling if your panel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) * uses device tree and has a backlight phandle.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) * When the panel is enabled backlight will be enabled after a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) * successful call to &drm_panel_funcs.enable()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) * When the panel is disabled backlight will be disabled before the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) * call to &drm_panel_funcs.disable().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) * A typical implementation for a panel driver supporting device tree
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) * will call this function at probe time. Backlight will then be handled
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) * transparently without requiring any intervention from the driver.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) * drm_panel_of_backlight() must be called after the call to drm_panel_init().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) * Return: 0 on success or a negative error code on failure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) int drm_panel_of_backlight(struct drm_panel *panel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) struct backlight_device *backlight;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) if (!panel || !panel->dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) backlight = devm_of_find_backlight(panel->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) if (IS_ERR(backlight))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) return PTR_ERR(backlight);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) panel->backlight = backlight;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) EXPORT_SYMBOL(drm_panel_of_backlight);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) MODULE_DESCRIPTION("DRM panel infrastructure");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) MODULE_LICENSE("GPL and additional rights");