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