1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * S6E63M0 AMOLED LCD drm_panel driver. 4 * 5 * Copyright (C) 2019 Paweł Chmiel <pawel.mikolaj.chmiel@gmail.com> 6 * Derived from drivers/gpu/drm/panel-samsung-ld9040.c 7 * 8 * Andrzej Hajda <a.hajda@samsung.com> 9 */ 10 11 #include <drm/drm_modes.h> 12 #include <drm/drm_panel.h> 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/regulator/consumer.h> 19 20 #include <video/mipi_display.h> 21 22 #include "panel-samsung-s6e63m0.h" 23 24 /* Manufacturer Command Set */ 25 #define MCS_ELVSS_ON 0xb1 26 #define MCS_MIECTL1 0xc0 27 #define MCS_BCMODE 0xc1 28 #define MCS_ERROR_CHECK 0xd5 29 #define MCS_READ_ID1 0xda 30 #define MCS_READ_ID2 0xdb 31 #define MCS_READ_ID3 0xdc 32 #define MCS_LEVEL_2_KEY 0xf0 33 #define MCS_MTP_KEY 0xf1 34 #define MCS_DISCTL 0xf2 35 #define MCS_SRCCTL 0xf6 36 #define MCS_IFCTL 0xf7 37 #define MCS_PANELCTL 0xF8 38 #define MCS_PGAMMACTL 0xfa 39 40 #define S6E63M0_LCD_ID_VALUE_M2 0xA4 41 #define S6E63M0_LCD_ID_VALUE_SM2 0xB4 42 #define S6E63M0_LCD_ID_VALUE_SM2_1 0xB6 43 44 #define NUM_GAMMA_LEVELS 11 45 #define GAMMA_TABLE_COUNT 23 46 47 #define MAX_BRIGHTNESS (NUM_GAMMA_LEVELS - 1) 48 49 /* array of gamma tables for gamma value 2.2 */ 50 static u8 const s6e63m0_gamma_22[NUM_GAMMA_LEVELS][GAMMA_TABLE_COUNT] = { 51 { MCS_PGAMMACTL, 0x00, 52 0x18, 0x08, 0x24, 0x78, 0xEC, 0x3D, 0xC8, 53 0xC2, 0xB6, 0xC4, 0xC7, 0xB6, 0xD5, 0xD7, 54 0xCC, 0x00, 0x39, 0x00, 0x36, 0x00, 0x51 }, 55 { MCS_PGAMMACTL, 0x00, 56 0x18, 0x08, 0x24, 0x73, 0x4A, 0x3D, 0xC0, 57 0xC2, 0xB1, 0xBB, 0xBE, 0xAC, 0xCE, 0xCF, 58 0xC5, 0x00, 0x5D, 0x00, 0x5E, 0x00, 0x82 }, 59 { MCS_PGAMMACTL, 0x00, 60 0x18, 0x08, 0x24, 0x70, 0x51, 0x3E, 0xBF, 61 0xC1, 0xAF, 0xB9, 0xBC, 0xAB, 0xCC, 0xCC, 62 0xC2, 0x00, 0x65, 0x00, 0x67, 0x00, 0x8D }, 63 { MCS_PGAMMACTL, 0x00, 64 0x18, 0x08, 0x24, 0x6C, 0x54, 0x3A, 0xBC, 65 0xBF, 0xAC, 0xB7, 0xBB, 0xA9, 0xC9, 0xC9, 66 0xBE, 0x00, 0x71, 0x00, 0x73, 0x00, 0x9E }, 67 { MCS_PGAMMACTL, 0x00, 68 0x18, 0x08, 0x24, 0x69, 0x54, 0x37, 0xBB, 69 0xBE, 0xAC, 0xB4, 0xB7, 0xA6, 0xC7, 0xC8, 70 0xBC, 0x00, 0x7B, 0x00, 0x7E, 0x00, 0xAB }, 71 { MCS_PGAMMACTL, 0x00, 72 0x18, 0x08, 0x24, 0x66, 0x55, 0x34, 0xBA, 73 0xBD, 0xAB, 0xB1, 0xB5, 0xA3, 0xC5, 0xC6, 74 0xB9, 0x00, 0x85, 0x00, 0x88, 0x00, 0xBA }, 75 { MCS_PGAMMACTL, 0x00, 76 0x18, 0x08, 0x24, 0x63, 0x53, 0x31, 0xB8, 77 0xBC, 0xA9, 0xB0, 0xB5, 0xA2, 0xC4, 0xC4, 78 0xB8, 0x00, 0x8B, 0x00, 0x8E, 0x00, 0xC2 }, 79 { MCS_PGAMMACTL, 0x00, 80 0x18, 0x08, 0x24, 0x62, 0x54, 0x30, 0xB9, 81 0xBB, 0xA9, 0xB0, 0xB3, 0xA1, 0xC1, 0xC3, 82 0xB7, 0x00, 0x91, 0x00, 0x95, 0x00, 0xDA }, 83 { MCS_PGAMMACTL, 0x00, 84 0x18, 0x08, 0x24, 0x66, 0x58, 0x34, 0xB6, 85 0xBA, 0xA7, 0xAF, 0xB3, 0xA0, 0xC1, 0xC2, 86 0xB7, 0x00, 0x97, 0x00, 0x9A, 0x00, 0xD1 }, 87 { MCS_PGAMMACTL, 0x00, 88 0x18, 0x08, 0x24, 0x64, 0x56, 0x33, 0xB6, 89 0xBA, 0xA8, 0xAC, 0xB1, 0x9D, 0xC1, 0xC1, 90 0xB7, 0x00, 0x9C, 0x00, 0x9F, 0x00, 0xD6 }, 91 { MCS_PGAMMACTL, 0x00, 92 0x18, 0x08, 0x24, 0x5f, 0x50, 0x2d, 0xB6, 93 0xB9, 0xA7, 0xAd, 0xB1, 0x9f, 0xbe, 0xC0, 94 0xB5, 0x00, 0xa0, 0x00, 0xa4, 0x00, 0xdb }, 95 }; 96 97 struct s6e63m0 { 98 struct device *dev; 99 int (*dcs_read)(struct device *dev, const u8 cmd, u8 *val); 100 int (*dcs_write)(struct device *dev, const u8 *data, size_t len); 101 struct drm_panel panel; 102 struct backlight_device *bl_dev; 103 u8 lcd_type; 104 105 struct regulator_bulk_data supplies[2]; 106 struct gpio_desc *reset_gpio; 107 108 bool prepared; 109 bool enabled; 110 111 /* 112 * This field is tested by functions directly accessing bus before 113 * transfer, transfer is skipped if it is set. In case of transfer 114 * failure or unexpected response the field is set to error value. 115 * Such construct allows to eliminate many checks in higher level 116 * functions. 117 */ 118 int error; 119 }; 120 121 static const struct drm_display_mode default_mode = { 122 .clock = 25628, 123 .hdisplay = 480, 124 .hsync_start = 480 + 16, 125 .hsync_end = 480 + 16 + 2, 126 .htotal = 480 + 16 + 2 + 16, 127 .vdisplay = 800, 128 .vsync_start = 800 + 28, 129 .vsync_end = 800 + 28 + 2, 130 .vtotal = 800 + 28 + 2 + 1, 131 .width_mm = 53, 132 .height_mm = 89, 133 .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC, 134 }; 135 136 static inline struct s6e63m0 *panel_to_s6e63m0(struct drm_panel *panel) 137 { 138 return container_of(panel, struct s6e63m0, panel); 139 } 140 141 static int s6e63m0_clear_error(struct s6e63m0 *ctx) 142 { 143 int ret = ctx->error; 144 145 ctx->error = 0; 146 return ret; 147 } 148 149 static void s6e63m0_dcs_read(struct s6e63m0 *ctx, const u8 cmd, u8 *data) 150 { 151 if (ctx->error < 0) 152 return; 153 154 ctx->error = ctx->dcs_read(ctx->dev, cmd, data); 155 } 156 157 static void s6e63m0_dcs_write(struct s6e63m0 *ctx, const u8 *data, size_t len) 158 { 159 if (ctx->error < 0 || len == 0) 160 return; 161 162 ctx->error = ctx->dcs_write(ctx->dev, data, len); 163 } 164 165 #define s6e63m0_dcs_write_seq_static(ctx, seq ...) \ 166 ({ \ 167 static const u8 d[] = { seq }; \ 168 s6e63m0_dcs_write(ctx, d, ARRAY_SIZE(d)); \ 169 }) 170 171 static int s6e63m0_check_lcd_type(struct s6e63m0 *ctx) 172 { 173 u8 id1, id2, id3; 174 int ret; 175 176 s6e63m0_dcs_read(ctx, MCS_READ_ID1, &id1); 177 s6e63m0_dcs_read(ctx, MCS_READ_ID2, &id2); 178 s6e63m0_dcs_read(ctx, MCS_READ_ID3, &id3); 179 180 ret = s6e63m0_clear_error(ctx); 181 if (ret) { 182 dev_err(ctx->dev, "error checking LCD type (%d)\n", ret); 183 ctx->lcd_type = 0x00; 184 return ret; 185 } 186 187 dev_info(ctx->dev, "MTP ID: %02x %02x %02x\n", id1, id2, id3); 188 189 /* We attempt to detect what panel is mounted on the controller */ 190 switch (id2) { 191 case S6E63M0_LCD_ID_VALUE_M2: 192 dev_info(ctx->dev, "detected LCD panel AMS397GE MIPI M2\n"); 193 break; 194 case S6E63M0_LCD_ID_VALUE_SM2: 195 case S6E63M0_LCD_ID_VALUE_SM2_1: 196 dev_info(ctx->dev, "detected LCD panel AMS397GE MIPI SM2\n"); 197 break; 198 default: 199 dev_info(ctx->dev, "unknown LCD panel type %02x\n", id2); 200 break; 201 } 202 203 ctx->lcd_type = id2; 204 205 return 0; 206 } 207 208 static void s6e63m0_init(struct s6e63m0 *ctx) 209 { 210 s6e63m0_dcs_write_seq_static(ctx, MCS_PANELCTL, 211 0x01, 0x27, 0x27, 0x07, 0x07, 0x54, 0x9f, 212 0x63, 0x86, 0x1a, 0x33, 0x0d, 0x00, 0x00); 213 214 s6e63m0_dcs_write_seq_static(ctx, MCS_DISCTL, 215 0x02, 0x03, 0x1c, 0x10, 0x10); 216 s6e63m0_dcs_write_seq_static(ctx, MCS_IFCTL, 217 0x03, 0x00, 0x00); 218 219 s6e63m0_dcs_write_seq_static(ctx, MCS_PGAMMACTL, 220 0x00, 0x18, 0x08, 0x24, 0x64, 0x56, 0x33, 221 0xb6, 0xba, 0xa8, 0xac, 0xb1, 0x9d, 0xc1, 222 0xc1, 0xb7, 0x00, 0x9c, 0x00, 0x9f, 0x00, 223 0xd6); 224 s6e63m0_dcs_write_seq_static(ctx, MCS_PGAMMACTL, 225 0x01); 226 227 s6e63m0_dcs_write_seq_static(ctx, MCS_SRCCTL, 228 0x00, 0x8c, 0x07); 229 s6e63m0_dcs_write_seq_static(ctx, 0xb3, 230 0xc); 231 232 s6e63m0_dcs_write_seq_static(ctx, 0xb5, 233 0x2c, 0x12, 0x0c, 0x0a, 0x10, 0x0e, 0x17, 234 0x13, 0x1f, 0x1a, 0x2a, 0x24, 0x1f, 0x1b, 235 0x1a, 0x17, 0x2b, 0x26, 0x22, 0x20, 0x3a, 236 0x34, 0x30, 0x2c, 0x29, 0x26, 0x25, 0x23, 237 0x21, 0x20, 0x1e, 0x1e); 238 239 s6e63m0_dcs_write_seq_static(ctx, 0xb6, 240 0x00, 0x00, 0x11, 0x22, 0x33, 0x44, 0x44, 241 0x44, 0x55, 0x55, 0x66, 0x66, 0x66, 0x66, 242 0x66, 0x66); 243 244 s6e63m0_dcs_write_seq_static(ctx, 0xb7, 245 0x2c, 0x12, 0x0c, 0x0a, 0x10, 0x0e, 0x17, 246 0x13, 0x1f, 0x1a, 0x2a, 0x24, 0x1f, 0x1b, 247 0x1a, 0x17, 0x2b, 0x26, 0x22, 0x20, 0x3a, 248 0x34, 0x30, 0x2c, 0x29, 0x26, 0x25, 0x23, 249 0x21, 0x20, 0x1e, 0x1e, 0x00, 0x00, 0x11, 250 0x22, 0x33, 0x44, 0x44, 0x44, 0x55, 0x55, 251 0x66, 0x66, 0x66, 0x66, 0x66, 0x66); 252 253 s6e63m0_dcs_write_seq_static(ctx, 0xb9, 254 0x2c, 0x12, 0x0c, 0x0a, 0x10, 0x0e, 0x17, 255 0x13, 0x1f, 0x1a, 0x2a, 0x24, 0x1f, 0x1b, 256 0x1a, 0x17, 0x2b, 0x26, 0x22, 0x20, 0x3a, 257 0x34, 0x30, 0x2c, 0x29, 0x26, 0x25, 0x23, 258 0x21, 0x20, 0x1e, 0x1e); 259 260 s6e63m0_dcs_write_seq_static(ctx, 0xba, 261 0x00, 0x00, 0x11, 0x22, 0x33, 0x44, 0x44, 262 0x44, 0x55, 0x55, 0x66, 0x66, 0x66, 0x66, 263 0x66, 0x66); 264 265 s6e63m0_dcs_write_seq_static(ctx, MCS_BCMODE, 266 0x4d, 0x96, 0x1d, 0x00, 0x00, 0x01, 0xdf, 267 0x00, 0x00, 0x03, 0x1f, 0x00, 0x00, 0x00, 268 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x06, 269 0x09, 0x0d, 0x0f, 0x12, 0x15, 0x18); 270 271 s6e63m0_dcs_write_seq_static(ctx, 0xb2, 272 0x10, 0x10, 0x0b, 0x05); 273 274 s6e63m0_dcs_write_seq_static(ctx, MCS_MIECTL1, 275 0x01); 276 277 s6e63m0_dcs_write_seq_static(ctx, MCS_ELVSS_ON, 278 0x0b); 279 } 280 281 static int s6e63m0_power_on(struct s6e63m0 *ctx) 282 { 283 int ret; 284 285 ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies); 286 if (ret < 0) 287 return ret; 288 289 msleep(25); 290 291 /* Be sure to send a reset pulse */ 292 gpiod_set_value(ctx->reset_gpio, 1); 293 msleep(5); 294 gpiod_set_value(ctx->reset_gpio, 0); 295 msleep(120); 296 297 return 0; 298 } 299 300 static int s6e63m0_power_off(struct s6e63m0 *ctx) 301 { 302 int ret; 303 304 gpiod_set_value(ctx->reset_gpio, 1); 305 msleep(120); 306 307 ret = regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); 308 if (ret < 0) 309 return ret; 310 311 return 0; 312 } 313 314 static int s6e63m0_disable(struct drm_panel *panel) 315 { 316 struct s6e63m0 *ctx = panel_to_s6e63m0(panel); 317 318 if (!ctx->enabled) 319 return 0; 320 321 backlight_disable(ctx->bl_dev); 322 323 s6e63m0_dcs_write_seq_static(ctx, MIPI_DCS_SET_DISPLAY_OFF); 324 msleep(10); 325 s6e63m0_dcs_write_seq_static(ctx, MIPI_DCS_ENTER_SLEEP_MODE); 326 msleep(120); 327 328 ctx->enabled = false; 329 330 return 0; 331 } 332 333 static int s6e63m0_unprepare(struct drm_panel *panel) 334 { 335 struct s6e63m0 *ctx = panel_to_s6e63m0(panel); 336 int ret; 337 338 if (!ctx->prepared) 339 return 0; 340 341 s6e63m0_clear_error(ctx); 342 343 ret = s6e63m0_power_off(ctx); 344 if (ret < 0) 345 return ret; 346 347 ctx->prepared = false; 348 349 return 0; 350 } 351 352 static int s6e63m0_prepare(struct drm_panel *panel) 353 { 354 struct s6e63m0 *ctx = panel_to_s6e63m0(panel); 355 int ret; 356 357 if (ctx->prepared) 358 return 0; 359 360 ret = s6e63m0_power_on(ctx); 361 if (ret < 0) 362 return ret; 363 364 /* Magic to unlock level 2 control of the display */ 365 s6e63m0_dcs_write_seq_static(ctx, MCS_LEVEL_2_KEY, 0x5a, 0x5a); 366 /* Magic to unlock MTP reading */ 367 s6e63m0_dcs_write_seq_static(ctx, MCS_MTP_KEY, 0x5a, 0x5a); 368 369 ret = s6e63m0_check_lcd_type(ctx); 370 if (ret < 0) 371 return ret; 372 373 s6e63m0_init(ctx); 374 375 ret = s6e63m0_clear_error(ctx); 376 377 if (ret < 0) 378 s6e63m0_unprepare(panel); 379 380 ctx->prepared = true; 381 382 return ret; 383 } 384 385 static int s6e63m0_enable(struct drm_panel *panel) 386 { 387 struct s6e63m0 *ctx = panel_to_s6e63m0(panel); 388 389 if (ctx->enabled) 390 return 0; 391 392 s6e63m0_dcs_write_seq_static(ctx, MIPI_DCS_EXIT_SLEEP_MODE); 393 msleep(120); 394 s6e63m0_dcs_write_seq_static(ctx, MIPI_DCS_SET_DISPLAY_ON); 395 msleep(10); 396 397 s6e63m0_dcs_write_seq_static(ctx, MCS_ERROR_CHECK, 398 0xE7, 0x14, 0x60, 0x17, 0x0A, 0x49, 0xC3, 399 0x8F, 0x19, 0x64, 0x91, 0x84, 0x76, 0x20, 400 0x0F, 0x00); 401 402 backlight_enable(ctx->bl_dev); 403 404 ctx->enabled = true; 405 406 return 0; 407 } 408 409 static int s6e63m0_get_modes(struct drm_panel *panel, 410 struct drm_connector *connector) 411 { 412 struct drm_display_mode *mode; 413 414 mode = drm_mode_duplicate(connector->dev, &default_mode); 415 if (!mode) { 416 dev_err(panel->dev, "failed to add mode %ux%u@%u\n", 417 default_mode.hdisplay, default_mode.vdisplay, 418 drm_mode_vrefresh(&default_mode)); 419 return -ENOMEM; 420 } 421 422 drm_mode_set_name(mode); 423 424 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; 425 drm_mode_probed_add(connector, mode); 426 427 return 1; 428 } 429 430 static const struct drm_panel_funcs s6e63m0_drm_funcs = { 431 .disable = s6e63m0_disable, 432 .unprepare = s6e63m0_unprepare, 433 .prepare = s6e63m0_prepare, 434 .enable = s6e63m0_enable, 435 .get_modes = s6e63m0_get_modes, 436 }; 437 438 static int s6e63m0_set_brightness(struct backlight_device *bd) 439 { 440 struct s6e63m0 *ctx = bl_get_data(bd); 441 442 int brightness = bd->props.brightness; 443 444 /* disable and set new gamma */ 445 s6e63m0_dcs_write(ctx, s6e63m0_gamma_22[brightness], 446 ARRAY_SIZE(s6e63m0_gamma_22[brightness])); 447 448 /* update gamma table. */ 449 s6e63m0_dcs_write_seq_static(ctx, MCS_PGAMMACTL, 0x01); 450 451 return s6e63m0_clear_error(ctx); 452 } 453 454 static const struct backlight_ops s6e63m0_backlight_ops = { 455 .update_status = s6e63m0_set_brightness, 456 }; 457 458 static int s6e63m0_backlight_register(struct s6e63m0 *ctx) 459 { 460 struct backlight_properties props = { 461 .type = BACKLIGHT_RAW, 462 .brightness = MAX_BRIGHTNESS, 463 .max_brightness = MAX_BRIGHTNESS 464 }; 465 struct device *dev = ctx->dev; 466 int ret = 0; 467 468 ctx->bl_dev = devm_backlight_device_register(dev, "panel", dev, ctx, 469 &s6e63m0_backlight_ops, 470 &props); 471 if (IS_ERR(ctx->bl_dev)) { 472 ret = PTR_ERR(ctx->bl_dev); 473 dev_err(dev, "error registering backlight device (%d)\n", ret); 474 } 475 476 return ret; 477 } 478 479 int s6e63m0_probe(struct device *dev, 480 int (*dcs_read)(struct device *dev, const u8 cmd, u8 *val), 481 int (*dcs_write)(struct device *dev, const u8 *data, size_t len), 482 bool dsi_mode) 483 { 484 struct s6e63m0 *ctx; 485 int ret; 486 487 ctx = devm_kzalloc(dev, sizeof(struct s6e63m0), GFP_KERNEL); 488 if (!ctx) 489 return -ENOMEM; 490 491 ctx->dcs_read = dcs_read; 492 ctx->dcs_write = dcs_write; 493 dev_set_drvdata(dev, ctx); 494 495 ctx->dev = dev; 496 ctx->enabled = false; 497 ctx->prepared = false; 498 499 ctx->supplies[0].supply = "vdd3"; 500 ctx->supplies[1].supply = "vci"; 501 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies), 502 ctx->supplies); 503 if (ret < 0) { 504 dev_err(dev, "failed to get regulators: %d\n", ret); 505 return ret; 506 } 507 508 ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); 509 if (IS_ERR(ctx->reset_gpio)) { 510 dev_err(dev, "cannot get reset-gpios %ld\n", PTR_ERR(ctx->reset_gpio)); 511 return PTR_ERR(ctx->reset_gpio); 512 } 513 514 drm_panel_init(&ctx->panel, dev, &s6e63m0_drm_funcs, 515 dsi_mode ? DRM_MODE_CONNECTOR_DSI : 516 DRM_MODE_CONNECTOR_DPI); 517 518 ret = s6e63m0_backlight_register(ctx); 519 if (ret < 0) 520 return ret; 521 522 drm_panel_add(&ctx->panel); 523 524 return 0; 525 } 526 EXPORT_SYMBOL_GPL(s6e63m0_probe); 527 528 int s6e63m0_remove(struct device *dev) 529 { 530 struct s6e63m0 *ctx = dev_get_drvdata(dev); 531 532 drm_panel_remove(&ctx->panel); 533 534 return 0; 535 } 536 EXPORT_SYMBOL_GPL(s6e63m0_remove); 537 538 MODULE_AUTHOR("Paweł Chmiel <pawel.mikolaj.chmiel@gmail.com>"); 539 MODULE_DESCRIPTION("s6e63m0 LCD Driver"); 540 MODULE_LICENSE("GPL v2"); 541