panel-simple.c revision 280921de7241ee63184c8baa89ec3fe0122dedb3
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/gpio.h> 26#include <linux/module.h> 27#include <linux/of_gpio.h> 28#include <linux/of_platform.h> 29#include <linux/platform_device.h> 30#include <linux/regulator/consumer.h> 31 32#include <drm/drmP.h> 33#include <drm/drm_crtc.h> 34#include <drm/drm_panel.h> 35 36struct panel_desc { 37 const struct drm_display_mode *modes; 38 unsigned int num_modes; 39 40 struct { 41 unsigned int width; 42 unsigned int height; 43 } size; 44}; 45 46/* TODO: convert to gpiod_*() API once it's been merged */ 47#define GPIO_ACTIVE_LOW (1 << 0) 48 49struct panel_simple { 50 struct drm_panel base; 51 bool enabled; 52 53 const struct panel_desc *desc; 54 55 struct backlight_device *backlight; 56 struct regulator *supply; 57 struct i2c_adapter *ddc; 58 59 unsigned long enable_gpio_flags; 60 int enable_gpio; 61}; 62 63static inline struct panel_simple *to_panel_simple(struct drm_panel *panel) 64{ 65 return container_of(panel, struct panel_simple, base); 66} 67 68static int panel_simple_get_fixed_modes(struct panel_simple *panel) 69{ 70 struct drm_connector *connector = panel->base.connector; 71 struct drm_device *drm = panel->base.drm; 72 struct drm_display_mode *mode; 73 unsigned int i, num = 0; 74 75 if (!panel->desc) 76 return 0; 77 78 for (i = 0; i < panel->desc->num_modes; i++) { 79 const struct drm_display_mode *m = &panel->desc->modes[i]; 80 81 mode = drm_mode_duplicate(drm, m); 82 if (!mode) { 83 dev_err(drm->dev, "failed to add mode %ux%u@%u\n", 84 m->hdisplay, m->vdisplay, m->vrefresh); 85 continue; 86 } 87 88 drm_mode_set_name(mode); 89 90 drm_mode_probed_add(connector, mode); 91 num++; 92 } 93 94 connector->display_info.width_mm = panel->desc->size.width; 95 connector->display_info.height_mm = panel->desc->size.height; 96 97 return num; 98} 99 100static int panel_simple_disable(struct drm_panel *panel) 101{ 102 struct panel_simple *p = to_panel_simple(panel); 103 104 if (!p->enabled) 105 return 0; 106 107 if (p->backlight) { 108 p->backlight->props.power = FB_BLANK_POWERDOWN; 109 backlight_update_status(p->backlight); 110 } 111 112 if (gpio_is_valid(p->enable_gpio)) { 113 if (p->enable_gpio_flags & GPIO_ACTIVE_LOW) 114 gpio_set_value(p->enable_gpio, 1); 115 else 116 gpio_set_value(p->enable_gpio, 0); 117 } 118 119 regulator_disable(p->supply); 120 p->enabled = false; 121 122 return 0; 123} 124 125static int panel_simple_enable(struct drm_panel *panel) 126{ 127 struct panel_simple *p = to_panel_simple(panel); 128 int err; 129 130 if (p->enabled) 131 return 0; 132 133 err = regulator_enable(p->supply); 134 if (err < 0) { 135 dev_err(panel->dev, "failed to enable supply: %d\n", err); 136 return err; 137 } 138 139 if (gpio_is_valid(p->enable_gpio)) { 140 if (p->enable_gpio_flags & GPIO_ACTIVE_LOW) 141 gpio_set_value(p->enable_gpio, 0); 142 else 143 gpio_set_value(p->enable_gpio, 1); 144 } 145 146 if (p->backlight) { 147 p->backlight->props.power = FB_BLANK_UNBLANK; 148 backlight_update_status(p->backlight); 149 } 150 151 p->enabled = true; 152 153 return 0; 154} 155 156static int panel_simple_get_modes(struct drm_panel *panel) 157{ 158 struct panel_simple *p = to_panel_simple(panel); 159 int num = 0; 160 161 /* probe EDID if a DDC bus is available */ 162 if (p->ddc) { 163 struct edid *edid = drm_get_edid(panel->connector, p->ddc); 164 if (edid) { 165 num += drm_add_edid_modes(panel->connector, edid); 166 kfree(edid); 167 } 168 } 169 170 /* add hard-coded panel modes */ 171 num += panel_simple_get_fixed_modes(p); 172 173 return num; 174} 175 176static const struct drm_panel_funcs panel_simple_funcs = { 177 .disable = panel_simple_disable, 178 .enable = panel_simple_enable, 179 .get_modes = panel_simple_get_modes, 180}; 181 182static int panel_simple_probe(struct device *dev, const struct panel_desc *desc) 183{ 184 struct device_node *backlight, *ddc; 185 struct panel_simple *panel; 186 enum of_gpio_flags flags; 187 int err; 188 189 panel = devm_kzalloc(dev, sizeof(*panel), GFP_KERNEL); 190 if (!panel) 191 return -ENOMEM; 192 193 panel->enabled = false; 194 panel->desc = desc; 195 196 panel->supply = devm_regulator_get(dev, "power"); 197 if (IS_ERR(panel->supply)) 198 return PTR_ERR(panel->supply); 199 200 panel->enable_gpio = of_get_named_gpio_flags(dev->of_node, 201 "enable-gpios", 0, 202 &flags); 203 if (gpio_is_valid(panel->enable_gpio)) { 204 unsigned int value; 205 206 if (flags & OF_GPIO_ACTIVE_LOW) 207 panel->enable_gpio_flags |= GPIO_ACTIVE_LOW; 208 209 err = gpio_request(panel->enable_gpio, "enable"); 210 if (err < 0) { 211 dev_err(dev, "failed to request GPIO#%u: %d\n", 212 panel->enable_gpio, err); 213 return err; 214 } 215 216 value = (panel->enable_gpio_flags & GPIO_ACTIVE_LOW) != 0; 217 218 err = gpio_direction_output(panel->enable_gpio, value); 219 if (err < 0) { 220 dev_err(dev, "failed to setup GPIO%u: %d\n", 221 panel->enable_gpio, err); 222 goto free_gpio; 223 } 224 } 225 226 backlight = of_parse_phandle(dev->of_node, "backlight", 0); 227 if (backlight) { 228 panel->backlight = of_find_backlight_by_node(backlight); 229 of_node_put(backlight); 230 231 if (!panel->backlight) { 232 err = -EPROBE_DEFER; 233 goto free_gpio; 234 } 235 } 236 237 ddc = of_parse_phandle(dev->of_node, "ddc-i2c-bus", 0); 238 if (ddc) { 239 panel->ddc = of_find_i2c_adapter_by_node(ddc); 240 of_node_put(ddc); 241 242 if (!panel->ddc) { 243 err = -EPROBE_DEFER; 244 goto free_backlight; 245 } 246 } 247 248 drm_panel_init(&panel->base); 249 panel->base.dev = dev; 250 panel->base.funcs = &panel_simple_funcs; 251 252 err = drm_panel_add(&panel->base); 253 if (err < 0) 254 goto free_ddc; 255 256 dev_set_drvdata(dev, panel); 257 258 return 0; 259 260free_ddc: 261 if (panel->ddc) 262 put_device(&panel->ddc->dev); 263free_backlight: 264 if (panel->backlight) 265 put_device(&panel->backlight->dev); 266free_gpio: 267 if (gpio_is_valid(panel->enable_gpio)) 268 gpio_free(panel->enable_gpio); 269 270 return err; 271} 272 273static int panel_simple_remove(struct device *dev) 274{ 275 struct panel_simple *panel = dev_get_drvdata(dev); 276 277 drm_panel_detach(&panel->base); 278 drm_panel_remove(&panel->base); 279 280 panel_simple_disable(&panel->base); 281 282 if (panel->ddc) 283 put_device(&panel->ddc->dev); 284 285 if (panel->backlight) 286 put_device(&panel->backlight->dev); 287 288 if (gpio_is_valid(panel->enable_gpio)) 289 gpio_free(panel->enable_gpio); 290 291 regulator_disable(panel->supply); 292 293 return 0; 294} 295 296static const struct drm_display_mode auo_b101aw03_mode = { 297 .clock = 51450, 298 .hdisplay = 1024, 299 .hsync_start = 1024 + 156, 300 .hsync_end = 1024 + 156 + 8, 301 .htotal = 1024 + 156 + 8 + 156, 302 .vdisplay = 600, 303 .vsync_start = 600 + 16, 304 .vsync_end = 600 + 16 + 6, 305 .vtotal = 600 + 16 + 6 + 16, 306 .vrefresh = 60, 307}; 308 309static const struct panel_desc auo_b101aw03 = { 310 .modes = &auo_b101aw03_mode, 311 .num_modes = 1, 312 .size = { 313 .width = 223, 314 .height = 125, 315 }, 316}; 317 318static const struct drm_display_mode chunghwa_claa101wb01_mode = { 319 .clock = 69300, 320 .hdisplay = 1366, 321 .hsync_start = 1366 + 48, 322 .hsync_end = 1366 + 48 + 32, 323 .htotal = 1366 + 48 + 32 + 20, 324 .vdisplay = 768, 325 .vsync_start = 768 + 16, 326 .vsync_end = 768 + 16 + 8, 327 .vtotal = 768 + 16 + 8 + 16, 328 .vrefresh = 60, 329}; 330 331static const struct panel_desc chunghwa_claa101wb01 = { 332 .modes = &chunghwa_claa101wb01_mode, 333 .num_modes = 1, 334 .size = { 335 .width = 223, 336 .height = 125, 337 }, 338}; 339 340static const struct of_device_id platform_of_match[] = { 341 { 342 .compatible = "auo,b101aw03", 343 .data = &auo_b101aw03, 344 }, { 345 .compatible = "chunghwa,claa101wb01", 346 .data = &chunghwa_claa101wb01 347 }, { 348 .compatible = "simple-panel", 349 }, { 350 /* sentinel */ 351 } 352}; 353MODULE_DEVICE_TABLE(of, platform_of_match); 354 355static int panel_simple_platform_probe(struct platform_device *pdev) 356{ 357 const struct of_device_id *id; 358 359 id = of_match_node(platform_of_match, pdev->dev.of_node); 360 if (!id) 361 return -ENODEV; 362 363 return panel_simple_probe(&pdev->dev, id->data); 364} 365 366static int panel_simple_platform_remove(struct platform_device *pdev) 367{ 368 return panel_simple_remove(&pdev->dev); 369} 370 371static struct platform_driver panel_simple_platform_driver = { 372 .driver = { 373 .name = "panel-simple", 374 .owner = THIS_MODULE, 375 .of_match_table = platform_of_match, 376 }, 377 .probe = panel_simple_platform_probe, 378 .remove = panel_simple_platform_remove, 379}; 380 381static const struct drm_display_mode panasonic_vvx10f004b00_mode = { 382 .clock = 157200, 383 .hdisplay = 1920, 384 .hsync_start = 1920 + 154, 385 .hsync_end = 1920 + 154 + 16, 386 .htotal = 1920 + 154 + 16 + 32, 387 .vdisplay = 1200, 388 .vsync_start = 1200 + 17, 389 .vsync_end = 1200 + 17 + 2, 390 .vtotal = 1200 + 17 + 2 + 16, 391 .vrefresh = 60, 392}; 393 394static const struct panel_desc panasonic_vvx10f004b00 = { 395 .modes = &panasonic_vvx10f004b00_mode, 396 .num_modes = 1, 397 .size = { 398 .width = 217, 399 .height = 136, 400 }, 401}; 402 403static int __init panel_simple_init(void) 404{ 405 return platform_driver_register(&panel_simple_platform_driver); 406} 407module_init(panel_simple_init); 408 409static void __exit panel_simple_exit(void) 410{ 411 platform_driver_unregister(&panel_simple_platform_driver); 412} 413module_exit(panel_simple_exit); 414 415MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>"); 416MODULE_DESCRIPTION("DRM Driver for Simple Panels"); 417MODULE_LICENSE("GPL and additional rights"); 418