panel-jdi-lt070me05000.c (11657B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Copyright (C) 2016 InforceComputing 4 * Author: Vinay Simha BN <simhavcs@gmail.com> 5 * 6 * Copyright (C) 2016 Linaro Ltd 7 * Author: Sumit Semwal <sumit.semwal@linaro.org> 8 * 9 * From internet archives, the panel for Nexus 7 2nd Gen, 2013 model is a 10 * JDI model LT070ME05000, and its data sheet is at: 11 * http://panelone.net/en/7-0-inch/JDI_LT070ME05000_7.0_inch-datasheet 12 */ 13 14#include <linux/backlight.h> 15#include <linux/delay.h> 16#include <linux/gpio/consumer.h> 17#include <linux/module.h> 18#include <linux/of.h> 19#include <linux/regulator/consumer.h> 20 21#include <video/mipi_display.h> 22 23#include <drm/drm_crtc.h> 24#include <drm/drm_mipi_dsi.h> 25#include <drm/drm_modes.h> 26#include <drm/drm_panel.h> 27 28static const char * const regulator_names[] = { 29 "vddp", 30 "iovcc" 31}; 32 33struct jdi_panel { 34 struct drm_panel base; 35 struct mipi_dsi_device *dsi; 36 37 struct regulator_bulk_data supplies[ARRAY_SIZE(regulator_names)]; 38 39 struct gpio_desc *enable_gpio; 40 struct gpio_desc *reset_gpio; 41 struct gpio_desc *dcdc_en_gpio; 42 struct backlight_device *backlight; 43 44 bool prepared; 45 bool enabled; 46 47 const struct drm_display_mode *mode; 48}; 49 50static inline struct jdi_panel *to_jdi_panel(struct drm_panel *panel) 51{ 52 return container_of(panel, struct jdi_panel, base); 53} 54 55static int jdi_panel_init(struct jdi_panel *jdi) 56{ 57 struct mipi_dsi_device *dsi = jdi->dsi; 58 struct device *dev = &jdi->dsi->dev; 59 int ret; 60 61 dsi->mode_flags |= MIPI_DSI_MODE_LPM; 62 63 ret = mipi_dsi_dcs_soft_reset(dsi); 64 if (ret < 0) 65 return ret; 66 67 usleep_range(10000, 20000); 68 69 ret = mipi_dsi_dcs_set_pixel_format(dsi, MIPI_DCS_PIXEL_FMT_24BIT << 4); 70 if (ret < 0) { 71 dev_err(dev, "failed to set pixel format: %d\n", ret); 72 return ret; 73 } 74 75 ret = mipi_dsi_dcs_set_column_address(dsi, 0, jdi->mode->hdisplay - 1); 76 if (ret < 0) { 77 dev_err(dev, "failed to set column address: %d\n", ret); 78 return ret; 79 } 80 81 ret = mipi_dsi_dcs_set_page_address(dsi, 0, jdi->mode->vdisplay - 1); 82 if (ret < 0) { 83 dev_err(dev, "failed to set page address: %d\n", ret); 84 return ret; 85 } 86 87 /* 88 * BIT(5) BCTRL = 1 Backlight Control Block On, Brightness registers 89 * are active 90 * BIT(3) BL = 1 Backlight Control On 91 * BIT(2) DD = 0 Display Dimming is Off 92 */ 93 ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, 94 (u8[]){ 0x24 }, 1); 95 if (ret < 0) { 96 dev_err(dev, "failed to write control display: %d\n", ret); 97 return ret; 98 } 99 100 /* CABC off */ 101 ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_WRITE_POWER_SAVE, 102 (u8[]){ 0x00 }, 1); 103 if (ret < 0) { 104 dev_err(dev, "failed to set cabc off: %d\n", ret); 105 return ret; 106 } 107 108 ret = mipi_dsi_dcs_exit_sleep_mode(dsi); 109 if (ret < 0) { 110 dev_err(dev, "failed to set exit sleep mode: %d\n", ret); 111 return ret; 112 } 113 114 msleep(120); 115 116 ret = mipi_dsi_generic_write(dsi, (u8[]){0xB0, 0x00}, 2); 117 if (ret < 0) { 118 dev_err(dev, "failed to set mcap: %d\n", ret); 119 return ret; 120 } 121 122 mdelay(10); 123 124 /* Interface setting, video mode */ 125 ret = mipi_dsi_generic_write(dsi, (u8[]) 126 {0xB3, 0x26, 0x08, 0x00, 0x20, 0x00}, 6); 127 if (ret < 0) { 128 dev_err(dev, "failed to set display interface setting: %d\n" 129 , ret); 130 return ret; 131 } 132 133 mdelay(20); 134 135 ret = mipi_dsi_generic_write(dsi, (u8[]){0xB0, 0x03}, 2); 136 if (ret < 0) { 137 dev_err(dev, "failed to set default values for mcap: %d\n" 138 , ret); 139 return ret; 140 } 141 142 return 0; 143} 144 145static int jdi_panel_on(struct jdi_panel *jdi) 146{ 147 struct mipi_dsi_device *dsi = jdi->dsi; 148 struct device *dev = &jdi->dsi->dev; 149 int ret; 150 151 dsi->mode_flags |= MIPI_DSI_MODE_LPM; 152 153 ret = mipi_dsi_dcs_set_display_on(dsi); 154 if (ret < 0) 155 dev_err(dev, "failed to set display on: %d\n", ret); 156 157 return ret; 158} 159 160static void jdi_panel_off(struct jdi_panel *jdi) 161{ 162 struct mipi_dsi_device *dsi = jdi->dsi; 163 struct device *dev = &jdi->dsi->dev; 164 int ret; 165 166 dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; 167 168 ret = mipi_dsi_dcs_set_display_off(dsi); 169 if (ret < 0) 170 dev_err(dev, "failed to set display off: %d\n", ret); 171 172 ret = mipi_dsi_dcs_enter_sleep_mode(dsi); 173 if (ret < 0) 174 dev_err(dev, "failed to enter sleep mode: %d\n", ret); 175 176 msleep(100); 177} 178 179static int jdi_panel_disable(struct drm_panel *panel) 180{ 181 struct jdi_panel *jdi = to_jdi_panel(panel); 182 183 if (!jdi->enabled) 184 return 0; 185 186 backlight_disable(jdi->backlight); 187 188 jdi->enabled = false; 189 190 return 0; 191} 192 193static int jdi_panel_unprepare(struct drm_panel *panel) 194{ 195 struct jdi_panel *jdi = to_jdi_panel(panel); 196 struct device *dev = &jdi->dsi->dev; 197 int ret; 198 199 if (!jdi->prepared) 200 return 0; 201 202 jdi_panel_off(jdi); 203 204 ret = regulator_bulk_disable(ARRAY_SIZE(jdi->supplies), jdi->supplies); 205 if (ret < 0) 206 dev_err(dev, "regulator disable failed, %d\n", ret); 207 208 gpiod_set_value(jdi->enable_gpio, 0); 209 210 gpiod_set_value(jdi->reset_gpio, 1); 211 212 gpiod_set_value(jdi->dcdc_en_gpio, 0); 213 214 jdi->prepared = false; 215 216 return 0; 217} 218 219static int jdi_panel_prepare(struct drm_panel *panel) 220{ 221 struct jdi_panel *jdi = to_jdi_panel(panel); 222 struct device *dev = &jdi->dsi->dev; 223 int ret; 224 225 if (jdi->prepared) 226 return 0; 227 228 ret = regulator_bulk_enable(ARRAY_SIZE(jdi->supplies), jdi->supplies); 229 if (ret < 0) { 230 dev_err(dev, "regulator enable failed, %d\n", ret); 231 return ret; 232 } 233 234 msleep(20); 235 236 gpiod_set_value(jdi->dcdc_en_gpio, 1); 237 usleep_range(10, 20); 238 239 gpiod_set_value(jdi->reset_gpio, 0); 240 usleep_range(10, 20); 241 242 gpiod_set_value(jdi->enable_gpio, 1); 243 usleep_range(10, 20); 244 245 ret = jdi_panel_init(jdi); 246 if (ret < 0) { 247 dev_err(dev, "failed to init panel: %d\n", ret); 248 goto poweroff; 249 } 250 251 ret = jdi_panel_on(jdi); 252 if (ret < 0) { 253 dev_err(dev, "failed to set panel on: %d\n", ret); 254 goto poweroff; 255 } 256 257 jdi->prepared = true; 258 259 return 0; 260 261poweroff: 262 ret = regulator_bulk_disable(ARRAY_SIZE(jdi->supplies), jdi->supplies); 263 if (ret < 0) 264 dev_err(dev, "regulator disable failed, %d\n", ret); 265 266 gpiod_set_value(jdi->enable_gpio, 0); 267 268 gpiod_set_value(jdi->reset_gpio, 1); 269 270 gpiod_set_value(jdi->dcdc_en_gpio, 0); 271 272 return ret; 273} 274 275static int jdi_panel_enable(struct drm_panel *panel) 276{ 277 struct jdi_panel *jdi = to_jdi_panel(panel); 278 279 if (jdi->enabled) 280 return 0; 281 282 backlight_enable(jdi->backlight); 283 284 jdi->enabled = true; 285 286 return 0; 287} 288 289static const struct drm_display_mode default_mode = { 290 .clock = 155493, 291 .hdisplay = 1200, 292 .hsync_start = 1200 + 48, 293 .hsync_end = 1200 + 48 + 32, 294 .htotal = 1200 + 48 + 32 + 60, 295 .vdisplay = 1920, 296 .vsync_start = 1920 + 3, 297 .vsync_end = 1920 + 3 + 5, 298 .vtotal = 1920 + 3 + 5 + 6, 299 .flags = 0, 300}; 301 302static int jdi_panel_get_modes(struct drm_panel *panel, 303 struct drm_connector *connector) 304{ 305 struct drm_display_mode *mode; 306 struct jdi_panel *jdi = to_jdi_panel(panel); 307 struct device *dev = &jdi->dsi->dev; 308 309 mode = drm_mode_duplicate(connector->dev, &default_mode); 310 if (!mode) { 311 dev_err(dev, "failed to add mode %ux%ux@%u\n", 312 default_mode.hdisplay, default_mode.vdisplay, 313 drm_mode_vrefresh(&default_mode)); 314 return -ENOMEM; 315 } 316 317 drm_mode_set_name(mode); 318 319 drm_mode_probed_add(connector, mode); 320 321 connector->display_info.width_mm = 95; 322 connector->display_info.height_mm = 151; 323 324 return 1; 325} 326 327static int dsi_dcs_bl_get_brightness(struct backlight_device *bl) 328{ 329 struct mipi_dsi_device *dsi = bl_get_data(bl); 330 int ret; 331 u16 brightness = bl->props.brightness; 332 333 dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; 334 335 ret = mipi_dsi_dcs_get_display_brightness(dsi, &brightness); 336 if (ret < 0) 337 return ret; 338 339 dsi->mode_flags |= MIPI_DSI_MODE_LPM; 340 341 return brightness & 0xff; 342} 343 344static int dsi_dcs_bl_update_status(struct backlight_device *bl) 345{ 346 struct mipi_dsi_device *dsi = bl_get_data(bl); 347 int ret; 348 349 dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; 350 351 ret = mipi_dsi_dcs_set_display_brightness(dsi, bl->props.brightness); 352 if (ret < 0) 353 return ret; 354 355 dsi->mode_flags |= MIPI_DSI_MODE_LPM; 356 357 return 0; 358} 359 360static const struct backlight_ops dsi_bl_ops = { 361 .update_status = dsi_dcs_bl_update_status, 362 .get_brightness = dsi_dcs_bl_get_brightness, 363}; 364 365static struct backlight_device * 366drm_panel_create_dsi_backlight(struct mipi_dsi_device *dsi) 367{ 368 struct device *dev = &dsi->dev; 369 struct backlight_properties props; 370 371 memset(&props, 0, sizeof(props)); 372 props.type = BACKLIGHT_RAW; 373 props.brightness = 255; 374 props.max_brightness = 255; 375 376 return devm_backlight_device_register(dev, dev_name(dev), dev, dsi, 377 &dsi_bl_ops, &props); 378} 379 380static const struct drm_panel_funcs jdi_panel_funcs = { 381 .disable = jdi_panel_disable, 382 .unprepare = jdi_panel_unprepare, 383 .prepare = jdi_panel_prepare, 384 .enable = jdi_panel_enable, 385 .get_modes = jdi_panel_get_modes, 386}; 387 388static const struct of_device_id jdi_of_match[] = { 389 { .compatible = "jdi,lt070me05000", }, 390 { } 391}; 392MODULE_DEVICE_TABLE(of, jdi_of_match); 393 394static int jdi_panel_add(struct jdi_panel *jdi) 395{ 396 struct device *dev = &jdi->dsi->dev; 397 int ret; 398 unsigned int i; 399 400 jdi->mode = &default_mode; 401 402 for (i = 0; i < ARRAY_SIZE(jdi->supplies); i++) 403 jdi->supplies[i].supply = regulator_names[i]; 404 405 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(jdi->supplies), 406 jdi->supplies); 407 if (ret < 0) { 408 dev_err(dev, "failed to init regulator, ret=%d\n", ret); 409 return ret; 410 } 411 412 jdi->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW); 413 if (IS_ERR(jdi->enable_gpio)) { 414 ret = PTR_ERR(jdi->enable_gpio); 415 dev_err(dev, "cannot get enable-gpio %d\n", ret); 416 return ret; 417 } 418 419 jdi->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); 420 if (IS_ERR(jdi->reset_gpio)) { 421 ret = PTR_ERR(jdi->reset_gpio); 422 dev_err(dev, "cannot get reset-gpios %d\n", ret); 423 return ret; 424 } 425 426 jdi->dcdc_en_gpio = devm_gpiod_get(dev, "dcdc-en", GPIOD_OUT_LOW); 427 if (IS_ERR(jdi->dcdc_en_gpio)) { 428 ret = PTR_ERR(jdi->dcdc_en_gpio); 429 dev_err(dev, "cannot get dcdc-en-gpio %d\n", ret); 430 return ret; 431 } 432 433 jdi->backlight = drm_panel_create_dsi_backlight(jdi->dsi); 434 if (IS_ERR(jdi->backlight)) { 435 ret = PTR_ERR(jdi->backlight); 436 dev_err(dev, "failed to register backlight %d\n", ret); 437 return ret; 438 } 439 440 drm_panel_init(&jdi->base, &jdi->dsi->dev, &jdi_panel_funcs, 441 DRM_MODE_CONNECTOR_DSI); 442 443 drm_panel_add(&jdi->base); 444 445 return 0; 446} 447 448static void jdi_panel_del(struct jdi_panel *jdi) 449{ 450 if (jdi->base.dev) 451 drm_panel_remove(&jdi->base); 452} 453 454static int jdi_panel_probe(struct mipi_dsi_device *dsi) 455{ 456 struct jdi_panel *jdi; 457 int ret; 458 459 dsi->lanes = 4; 460 dsi->format = MIPI_DSI_FMT_RGB888; 461 dsi->mode_flags = MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_VIDEO | 462 MIPI_DSI_CLOCK_NON_CONTINUOUS; 463 464 jdi = devm_kzalloc(&dsi->dev, sizeof(*jdi), GFP_KERNEL); 465 if (!jdi) 466 return -ENOMEM; 467 468 mipi_dsi_set_drvdata(dsi, jdi); 469 470 jdi->dsi = dsi; 471 472 ret = jdi_panel_add(jdi); 473 if (ret < 0) 474 return ret; 475 476 ret = mipi_dsi_attach(dsi); 477 if (ret < 0) { 478 jdi_panel_del(jdi); 479 return ret; 480 } 481 482 return 0; 483} 484 485static int jdi_panel_remove(struct mipi_dsi_device *dsi) 486{ 487 struct jdi_panel *jdi = mipi_dsi_get_drvdata(dsi); 488 int ret; 489 490 ret = jdi_panel_disable(&jdi->base); 491 if (ret < 0) 492 dev_err(&dsi->dev, "failed to disable panel: %d\n", ret); 493 494 ret = mipi_dsi_detach(dsi); 495 if (ret < 0) 496 dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", 497 ret); 498 499 jdi_panel_del(jdi); 500 501 return 0; 502} 503 504static void jdi_panel_shutdown(struct mipi_dsi_device *dsi) 505{ 506 struct jdi_panel *jdi = mipi_dsi_get_drvdata(dsi); 507 508 jdi_panel_disable(&jdi->base); 509} 510 511static struct mipi_dsi_driver jdi_panel_driver = { 512 .driver = { 513 .name = "panel-jdi-lt070me05000", 514 .of_match_table = jdi_of_match, 515 }, 516 .probe = jdi_panel_probe, 517 .remove = jdi_panel_remove, 518 .shutdown = jdi_panel_shutdown, 519}; 520module_mipi_dsi_driver(jdi_panel_driver); 521 522MODULE_AUTHOR("Sumit Semwal <sumit.semwal@linaro.org>"); 523MODULE_AUTHOR("Vinay Simha BN <simhavcs@gmail.com>"); 524MODULE_DESCRIPTION("JDI LT070ME05000 WUXGA"); 525MODULE_LICENSE("GPL v2");