|
12 | 12 | #include <linux/bitfield.h> |
13 | 13 | #include <linux/gpio/consumer.h> |
14 | 14 | #include <linux/delay.h> |
| 15 | +#include <linux/media-bus-format.h> |
15 | 16 | #include <linux/module.h> |
16 | 17 | #include <linux/of.h> |
17 | 18 | #include <linux/regulator/consumer.h> |
@@ -106,6 +107,7 @@ struct st7701_panel_desc { |
106 | 107 | const struct drm_display_mode *mode; |
107 | 108 | unsigned int lanes; |
108 | 109 | enum mipi_dsi_pixel_format format; |
| 110 | + u32 mediabus_format; |
109 | 111 | unsigned int panel_sleep_delay; |
110 | 112 |
|
111 | 113 | /* TFT matrix driver configuration, panel specific. */ |
@@ -520,6 +522,94 @@ static void rg28xx_gip_sequence(struct st7701 *st7701) |
520 | 522 | st7701_switch_cmd_bkx(st7701, false, 0); |
521 | 523 | } |
522 | 524 |
|
| 525 | +static void txw210001b0_gip_sequence(struct st7701 *st7701) |
| 526 | +{ |
| 527 | + ST7701_WRITE(st7701, MIPI_DCS_SOFT_RESET); |
| 528 | + |
| 529 | + usleep_range(5000, 7000); |
| 530 | + |
| 531 | + st7701_switch_cmd_bkx(st7701, true, 0); |
| 532 | + |
| 533 | + ST7701_WRITE(st7701, ST7701_CMD2_BK0_LNESET, 0x3B, 0x0); |
| 534 | + |
| 535 | + ST7701_WRITE(st7701, ST7701_CMD2_BK0_PORCTRL, 0xB, 0x2); |
| 536 | + |
| 537 | + ST7701_WRITE(st7701, ST7701_CMD2_BK0_INVSEL, 0x0, 0x2); |
| 538 | + |
| 539 | + ST7701_WRITE(st7701, 0xCC, 0x10); |
| 540 | + |
| 541 | + st7701_switch_cmd_bkx(st7701, true, 1); |
| 542 | + |
| 543 | + ST7701_WRITE(st7701, ST7701_CMD2_BK1_VRHS, 0x5D); |
| 544 | + |
| 545 | + ST7701_WRITE(st7701, ST7701_CMD2_BK1_VCOM, 0x43); |
| 546 | + |
| 547 | + ST7701_WRITE(st7701, ST7701_CMD2_BK1_VGHSS, 0x81); |
| 548 | + |
| 549 | + ST7701_WRITE(st7701, ST7701_CMD2_BK1_TESTCMD, 0x80); |
| 550 | + |
| 551 | + ST7701_WRITE(st7701, ST7701_CMD2_BK1_VGLS, 0x43); |
| 552 | + |
| 553 | + ST7701_WRITE(st7701, ST7701_CMD2_BK1_PWCTLR1, 0x85); |
| 554 | + |
| 555 | + ST7701_WRITE(st7701, ST7701_CMD2_BK1_PWCTLR2, 0x20); |
| 556 | + |
| 557 | + ST7701_WRITE(st7701, ST7701_CMD2_BK1_SPD1, 0x78); |
| 558 | + |
| 559 | + ST7701_WRITE(st7701, ST7701_CMD2_BK1_SPD2, 0x78); |
| 560 | + |
| 561 | + ST7701_WRITE(st7701, ST7701_CMD2_BK1_MIPISET1, 0x88); |
| 562 | + |
| 563 | + ST7701_WRITE(st7701, 0xE0, 0x0, 0x0, 0x2); |
| 564 | + |
| 565 | + ST7701_WRITE(st7701, 0xE1, |
| 566 | + 0x3, 0xA0, 0x0, 0x0, 0x4, 0xA0, 0x0, 0x0, |
| 567 | + 0x0, 0x20, 0x20); |
| 568 | + |
| 569 | + ST7701_WRITE(st7701, 0xE2, |
| 570 | + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, |
| 571 | + 0x0, 0x0, 0x0, 0x0, 0x0); |
| 572 | + |
| 573 | + ST7701_WRITE(st7701, 0xE3, 0x0, 0x0, 0x11, 0x0); |
| 574 | + |
| 575 | + ST7701_WRITE(st7701, 0xE4, 0x22, 0x0); |
| 576 | + |
| 577 | + ST7701_WRITE(st7701, 0xE5, |
| 578 | + 0x5, 0xEC, 0xA0, 0xA0, 0x7, 0xEE, 0xA0, 0xA0, |
| 579 | + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0); |
| 580 | + |
| 581 | + ST7701_WRITE(st7701, 0xE6, 0x0, 0x0, 0x11, 0x0); |
| 582 | + |
| 583 | + ST7701_WRITE(st7701, 0xE7, 0x22, 0x0); |
| 584 | + |
| 585 | + ST7701_WRITE(st7701, 0xE8, |
| 586 | + 0x6, 0xED, 0xA0, 0xA0, 0x8, 0xEF, 0xA0, 0xA0, |
| 587 | + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0); |
| 588 | + |
| 589 | + ST7701_WRITE(st7701, 0xEB, |
| 590 | + 0x0, 0x0, 0x40, 0x40, 0x0, 0x0, 0x0); |
| 591 | + |
| 592 | + ST7701_WRITE(st7701, 0xED, |
| 593 | + 0xFF, 0xFF, 0xFF, 0xBA, 0xA, 0xBF, 0x45, 0xFF, |
| 594 | + 0xFF, 0x54, 0xFB, 0xA0, 0xAB, 0xFF, 0xFF, 0xFF); |
| 595 | + |
| 596 | + ST7701_WRITE(st7701, 0xEF, 0x10, 0xD, 0x4, 0x8, 0x3F, 0x1F); |
| 597 | + |
| 598 | + st7701_switch_cmd_bkx(st7701, true, 3); |
| 599 | + |
| 600 | + ST7701_WRITE(st7701, 0xEF, 0x8); |
| 601 | + |
| 602 | + st7701_switch_cmd_bkx(st7701, false, 0); |
| 603 | + |
| 604 | + ST7701_WRITE(st7701, 0xCD, 0x8); /* RGB format COLCTRL */ |
| 605 | + |
| 606 | + ST7701_WRITE(st7701, 0x36, 0x8); /* MadCtl */ |
| 607 | + |
| 608 | + ST7701_WRITE(st7701, 0x3A, 0x66); /* Colmod */ |
| 609 | + |
| 610 | + ST7701_WRITE(st7701, MIPI_DCS_EXIT_SLEEP_MODE); |
| 611 | +} |
| 612 | + |
523 | 613 | static int st7701_prepare(struct drm_panel *panel) |
524 | 614 | { |
525 | 615 | struct st7701 *st7701 = panel_to_st7701(panel); |
@@ -609,6 +699,11 @@ static int st7701_get_modes(struct drm_panel *panel, |
609 | 699 | drm_mode_set_name(mode); |
610 | 700 | drm_mode_probed_add(connector, mode); |
611 | 701 |
|
| 702 | + if (st7701->desc->mediabus_format) |
| 703 | + drm_display_info_set_bus_formats(&connector->display_info, |
| 704 | + &st7701->desc->mediabus_format, |
| 705 | + 1); |
| 706 | + |
612 | 707 | connector->display_info.width_mm = desc_mode->width_mm; |
613 | 708 | connector->display_info.height_mm = desc_mode->height_mm; |
614 | 709 |
|
@@ -1135,6 +1230,154 @@ static const struct st7701_panel_desc rg28xx_desc = { |
1135 | 1230 | .gip_sequence = rg28xx_gip_sequence, |
1136 | 1231 | }; |
1137 | 1232 |
|
| 1233 | +static const struct drm_display_mode txw210001b0_mode = { |
| 1234 | + .clock = 19200, |
| 1235 | + |
| 1236 | + .hdisplay = 480, |
| 1237 | + .hsync_start = 480 + 10, |
| 1238 | + .hsync_end = 480 + 10 + 16, |
| 1239 | + .htotal = 480 + 10 + 16 + 56, |
| 1240 | + |
| 1241 | + .vdisplay = 480, |
| 1242 | + .vsync_start = 480 + 15, |
| 1243 | + .vsync_end = 480 + 15 + 60, |
| 1244 | + .vtotal = 480 + 15 + 60 + 15, |
| 1245 | + |
| 1246 | + .width_mm = 53, |
| 1247 | + .height_mm = 53, |
| 1248 | + .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, |
| 1249 | + |
| 1250 | + .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, |
| 1251 | +}; |
| 1252 | + |
| 1253 | +static const struct st7701_panel_desc txw210001b0_desc = { |
| 1254 | + .mode = &txw210001b0_mode, |
| 1255 | + .mediabus_format = MEDIA_BUS_FMT_RGB888_1X24, |
| 1256 | + .pv_gamma = { |
| 1257 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | |
| 1258 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC0_MASK, 0x2), |
| 1259 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | |
| 1260 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC4_MASK, 0x13), |
| 1261 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | |
| 1262 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC8_MASK, 0x1b), |
| 1263 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC16_MASK, 0xd), |
| 1264 | + |
| 1265 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | |
| 1266 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC24_MASK, 0x10), |
| 1267 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC52_MASK, 0x5), |
| 1268 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC80_MASK, 0x8), |
| 1269 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC108_MASK, 0x7), |
| 1270 | + |
| 1271 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC147_MASK, 0x7), |
| 1272 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC175_MASK, 0x24), |
| 1273 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC203_MASK, 0x4), |
| 1274 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | |
| 1275 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC231_MASK, 0x11), |
| 1276 | + |
| 1277 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC239_MASK, 0xe), |
| 1278 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | |
| 1279 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC247_MASK, 0x2c), |
| 1280 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | |
| 1281 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC251_MASK, 0x33), |
| 1282 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | |
| 1283 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC255_MASK, 0x1d) |
| 1284 | + }, |
| 1285 | + .nv_gamma = { |
| 1286 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | |
| 1287 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC0_MASK, 0x5), |
| 1288 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | |
| 1289 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC4_MASK, 0x13), |
| 1290 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0x0) | |
| 1291 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC8_MASK, 0x1b), |
| 1292 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC16_MASK, 0xd), |
| 1293 | + |
| 1294 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | |
| 1295 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC24_MASK, 0x11), |
| 1296 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC52_MASK, 0x5), |
| 1297 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC80_MASK, 0x8), |
| 1298 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC108_MASK, 0x7), |
| 1299 | + |
| 1300 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC147_MASK, 0x7), |
| 1301 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC175_MASK, 0x24), |
| 1302 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC203_MASK, 0x4), |
| 1303 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | |
| 1304 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC231_MASK, 0x11), |
| 1305 | + |
| 1306 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC239_MASK, 0xe), |
| 1307 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | |
| 1308 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC247_MASK, 0x2c), |
| 1309 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | |
| 1310 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC251_MASK, 0x33), |
| 1311 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | |
| 1312 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC255_MASK, 0x1d) |
| 1313 | + }, |
| 1314 | + .gip_sequence = txw210001b0_gip_sequence, |
| 1315 | +}; |
| 1316 | + |
| 1317 | +static const struct st7701_panel_desc hyperpixel2r_desc = { |
| 1318 | + .mode = &txw210001b0_mode, |
| 1319 | + .mediabus_format = MEDIA_BUS_FMT_RGB666_1X24_CPADHI, |
| 1320 | + .pv_gamma = { |
| 1321 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | |
| 1322 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC0_MASK, 0x2), |
| 1323 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | |
| 1324 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC4_MASK, 0x13), |
| 1325 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | |
| 1326 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC8_MASK, 0x1b), |
| 1327 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC16_MASK, 0xd), |
| 1328 | + |
| 1329 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | |
| 1330 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC24_MASK, 0x10), |
| 1331 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC52_MASK, 0x5), |
| 1332 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC80_MASK, 0x8), |
| 1333 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC108_MASK, 0x7), |
| 1334 | + |
| 1335 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC147_MASK, 0x7), |
| 1336 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC175_MASK, 0x24), |
| 1337 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC203_MASK, 0x4), |
| 1338 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | |
| 1339 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC231_MASK, 0x11), |
| 1340 | + |
| 1341 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC239_MASK, 0xe), |
| 1342 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | |
| 1343 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC247_MASK, 0x2c), |
| 1344 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | |
| 1345 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC251_MASK, 0x33), |
| 1346 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | |
| 1347 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC255_MASK, 0x1d) |
| 1348 | + }, |
| 1349 | + .nv_gamma = { |
| 1350 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | |
| 1351 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC0_MASK, 0x5), |
| 1352 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | |
| 1353 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC4_MASK, 0x13), |
| 1354 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0x0) | |
| 1355 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC8_MASK, 0x1b), |
| 1356 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC16_MASK, 0xd), |
| 1357 | + |
| 1358 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | |
| 1359 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC24_MASK, 0x11), |
| 1360 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC52_MASK, 0x5), |
| 1361 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC80_MASK, 0x8), |
| 1362 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC108_MASK, 0x7), |
| 1363 | + |
| 1364 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC147_MASK, 0x7), |
| 1365 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC175_MASK, 0x24), |
| 1366 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC203_MASK, 0x4), |
| 1367 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | |
| 1368 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC231_MASK, 0x11), |
| 1369 | + |
| 1370 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC239_MASK, 0xe), |
| 1371 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | |
| 1372 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC247_MASK, 0x2c), |
| 1373 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | |
| 1374 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC251_MASK, 0x33), |
| 1375 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_AJ_MASK, 0) | |
| 1376 | + CFIELD_PREP(ST7701_CMD2_BK0_GAMCTRL_VC255_MASK, 0x1d) |
| 1377 | + }, |
| 1378 | + .gip_sequence = txw210001b0_gip_sequence, |
| 1379 | +}; |
| 1380 | + |
1138 | 1381 | static void st7701_cleanup(void *data) |
1139 | 1382 | { |
1140 | 1383 | struct st7701 *st7701 = (struct st7701 *)data; |
@@ -1166,7 +1409,7 @@ static int st7701_probe(struct device *dev, int connector_type) |
1166 | 1409 | if (ret < 0) |
1167 | 1410 | return ret; |
1168 | 1411 |
|
1169 | | - st7701->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); |
| 1412 | + st7701->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); |
1170 | 1413 | if (IS_ERR(st7701->reset)) { |
1171 | 1414 | dev_err(dev, "Couldn't get our reset GPIO\n"); |
1172 | 1415 | return PTR_ERR(st7701->reset); |
@@ -1271,12 +1514,16 @@ MODULE_DEVICE_TABLE(of, st7701_dsi_of_match); |
1271 | 1514 |
|
1272 | 1515 | static const struct of_device_id st7701_spi_of_match[] = { |
1273 | 1516 | { .compatible = "anbernic,rg28xx-panel", .data = &rg28xx_desc }, |
| 1517 | + { .compatible = "txw,txw210001b0", .data = &txw210001b0_desc }, |
| 1518 | + { .compatible = "pimoroni,hyperpixel2round", .data = &hyperpixel2r_desc }, |
1274 | 1519 | { /* sentinel */ } |
1275 | 1520 | }; |
1276 | 1521 | MODULE_DEVICE_TABLE(of, st7701_spi_of_match); |
1277 | 1522 |
|
1278 | 1523 | static const struct spi_device_id st7701_spi_ids[] = { |
1279 | 1524 | { "rg28xx-panel" }, |
| 1525 | + { "txw210001b0" }, |
| 1526 | + { "hyperpixel2round" }, |
1280 | 1527 | { /* sentinel */ } |
1281 | 1528 | }; |
1282 | 1529 | MODULE_DEVICE_TABLE(spi, st7701_spi_ids); |
|
0 commit comments