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