0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/delay.h>
0010 #include <linux/kernel.h>
0011 #include <linux/module.h>
0012 #include <linux/of.h>
0013 #include <linux/of_device.h>
0014
0015 #include <linux/gpio/consumer.h>
0016 #include <linux/regulator/consumer.h>
0017
0018 #include <drm/drm_device.h>
0019 #include <drm/drm_mipi_dsi.h>
0020 #include <drm/drm_modes.h>
0021 #include <drm/drm_panel.h>
0022
0023 #include <video/mipi_display.h>
0024
0025 struct panel_cmd {
0026 char cmd;
0027 char data;
0028 };
0029
0030 struct panel_desc {
0031 const struct drm_display_mode *display_mode;
0032 unsigned int bpc;
0033 unsigned int width_mm;
0034 unsigned int height_mm;
0035
0036 unsigned long mode_flags;
0037 enum mipi_dsi_pixel_format format;
0038 unsigned int lanes;
0039 const struct panel_cmd *on_cmds;
0040 unsigned int on_cmds_num;
0041 };
0042
0043 struct panel_info {
0044 struct drm_panel base;
0045 struct mipi_dsi_device *link;
0046 const struct panel_desc *desc;
0047
0048 struct gpio_desc *enable_gpio;
0049 struct gpio_desc *pp33_gpio;
0050 struct gpio_desc *pp18_gpio;
0051
0052 bool prepared;
0053 bool enabled;
0054 };
0055
0056 static inline struct panel_info *to_panel_info(struct drm_panel *panel)
0057 {
0058 return container_of(panel, struct panel_info, base);
0059 }
0060
0061 static void disable_gpios(struct panel_info *pinfo)
0062 {
0063 gpiod_set_value(pinfo->enable_gpio, 0);
0064 gpiod_set_value(pinfo->pp33_gpio, 0);
0065 gpiod_set_value(pinfo->pp18_gpio, 0);
0066 }
0067
0068 static int send_mipi_cmds(struct drm_panel *panel, const struct panel_cmd *cmds)
0069 {
0070 struct panel_info *pinfo = to_panel_info(panel);
0071 unsigned int i = 0;
0072 int err;
0073
0074 for (i = 0; i < pinfo->desc->on_cmds_num; i++) {
0075 err = mipi_dsi_dcs_write_buffer(pinfo->link, &cmds[i],
0076 sizeof(struct panel_cmd));
0077
0078 if (err < 0)
0079 return err;
0080 }
0081
0082 return 0;
0083 }
0084
0085 static int boe_panel_disable(struct drm_panel *panel)
0086 {
0087 struct panel_info *pinfo = to_panel_info(panel);
0088 int err;
0089
0090 if (!pinfo->enabled)
0091 return 0;
0092
0093 err = mipi_dsi_dcs_set_display_off(pinfo->link);
0094 if (err < 0) {
0095 dev_err(panel->dev, "failed to set display off: %d\n", err);
0096 return err;
0097 }
0098
0099 pinfo->enabled = false;
0100
0101 return 0;
0102 }
0103
0104 static int boe_panel_unprepare(struct drm_panel *panel)
0105 {
0106 struct panel_info *pinfo = to_panel_info(panel);
0107 int err;
0108
0109 if (!pinfo->prepared)
0110 return 0;
0111
0112 err = mipi_dsi_dcs_set_display_off(pinfo->link);
0113 if (err < 0)
0114 dev_err(panel->dev, "failed to set display off: %d\n", err);
0115
0116 err = mipi_dsi_dcs_enter_sleep_mode(pinfo->link);
0117 if (err < 0)
0118 dev_err(panel->dev, "failed to enter sleep mode: %d\n", err);
0119
0120
0121 usleep_range(1000, 2000);
0122
0123 disable_gpios(pinfo);
0124
0125 pinfo->prepared = false;
0126
0127 return 0;
0128 }
0129
0130 static int boe_panel_prepare(struct drm_panel *panel)
0131 {
0132 struct panel_info *pinfo = to_panel_info(panel);
0133 int err;
0134
0135 if (pinfo->prepared)
0136 return 0;
0137
0138 gpiod_set_value(pinfo->pp18_gpio, 1);
0139
0140 usleep_range(5000, 6000);
0141 gpiod_set_value(pinfo->pp33_gpio, 1);
0142
0143
0144
0145 usleep_range(14000, 15000);
0146 gpiod_set_value(pinfo->enable_gpio, 1);
0147
0148
0149 usleep_range(1000, 2000);
0150 gpiod_set_value(pinfo->enable_gpio, 0);
0151
0152
0153 usleep_range(1000, 2000);
0154 gpiod_set_value(pinfo->enable_gpio, 1);
0155
0156
0157 usleep_range(5000, 6000);
0158
0159
0160 err = send_mipi_cmds(panel, pinfo->desc->on_cmds);
0161 if (err < 0) {
0162 dev_err(panel->dev, "failed to send DCS Init Code: %d\n", err);
0163 goto poweroff;
0164 }
0165
0166 err = mipi_dsi_dcs_exit_sleep_mode(pinfo->link);
0167 if (err < 0) {
0168 dev_err(panel->dev, "failed to exit sleep mode: %d\n", err);
0169 goto poweroff;
0170 }
0171
0172
0173 usleep_range(120000, 121000);
0174
0175 err = mipi_dsi_dcs_set_display_on(pinfo->link);
0176 if (err < 0) {
0177 dev_err(panel->dev, "failed to set display on: %d\n", err);
0178 goto poweroff;
0179 }
0180
0181
0182 usleep_range(20000, 21000);
0183
0184 pinfo->prepared = true;
0185
0186 return 0;
0187
0188 poweroff:
0189 disable_gpios(pinfo);
0190 return err;
0191 }
0192
0193 static int boe_panel_enable(struct drm_panel *panel)
0194 {
0195 struct panel_info *pinfo = to_panel_info(panel);
0196 int ret;
0197
0198 if (pinfo->enabled)
0199 return 0;
0200
0201 usleep_range(120000, 121000);
0202
0203 ret = mipi_dsi_dcs_set_display_on(pinfo->link);
0204 if (ret < 0) {
0205 dev_err(panel->dev, "failed to set display on: %d\n", ret);
0206 return ret;
0207 }
0208
0209 pinfo->enabled = true;
0210
0211 return 0;
0212 }
0213
0214 static int boe_panel_get_modes(struct drm_panel *panel,
0215 struct drm_connector *connector)
0216 {
0217 struct panel_info *pinfo = to_panel_info(panel);
0218 const struct drm_display_mode *m = pinfo->desc->display_mode;
0219 struct drm_display_mode *mode;
0220
0221 mode = drm_mode_duplicate(connector->dev, m);
0222 if (!mode) {
0223 dev_err(pinfo->base.dev, "failed to add mode %ux%u@%u\n",
0224 m->hdisplay, m->vdisplay, drm_mode_vrefresh(m));
0225 return -ENOMEM;
0226 }
0227
0228 drm_mode_set_name(mode);
0229
0230 drm_mode_probed_add(connector, mode);
0231
0232 connector->display_info.width_mm = pinfo->desc->width_mm;
0233 connector->display_info.height_mm = pinfo->desc->height_mm;
0234 connector->display_info.bpc = pinfo->desc->bpc;
0235
0236 return 1;
0237 }
0238
0239 static const struct drm_panel_funcs panel_funcs = {
0240 .disable = boe_panel_disable,
0241 .unprepare = boe_panel_unprepare,
0242 .prepare = boe_panel_prepare,
0243 .enable = boe_panel_enable,
0244 .get_modes = boe_panel_get_modes,
0245 };
0246
0247 static const struct drm_display_mode default_display_mode = {
0248 .clock = 159420,
0249 .hdisplay = 1200,
0250 .hsync_start = 1200 + 80,
0251 .hsync_end = 1200 + 80 + 60,
0252 .htotal = 1200 + 80 + 60 + 24,
0253 .vdisplay = 1920,
0254 .vsync_start = 1920 + 10,
0255 .vsync_end = 1920 + 10 + 14,
0256 .vtotal = 1920 + 10 + 14 + 4,
0257 };
0258
0259
0260 static const struct panel_cmd boe_himax8279d8p_on_cmds[] = {
0261 { 0xB0, 0x05 },
0262 { 0xB1, 0xE5 },
0263 { 0xB3, 0x52 },
0264 { 0xC0, 0x00 },
0265 { 0xC2, 0x57 },
0266 { 0xD9, 0x85 },
0267 { 0xB0, 0x01 },
0268 { 0xC8, 0x00 },
0269 { 0xC9, 0x00 },
0270 { 0xCC, 0x26 },
0271 { 0xCD, 0x26 },
0272 { 0xDC, 0x00 },
0273 { 0xDD, 0x00 },
0274 { 0xE0, 0x26 },
0275 { 0xE1, 0x26 },
0276 { 0xB0, 0x03 },
0277 { 0xC3, 0x2A },
0278 { 0xE7, 0x2A },
0279 { 0xC5, 0x2A },
0280 { 0xDE, 0x2A },
0281 { 0xBC, 0x02 },
0282 { 0xCB, 0x02 },
0283 { 0xB0, 0x00 },
0284 { 0xB6, 0x03 },
0285 { 0xBA, 0x8B },
0286 { 0xBF, 0x15 },
0287 { 0xC0, 0x18 },
0288 { 0xC2, 0x14 },
0289 { 0xC3, 0x02 },
0290 { 0xC4, 0x14 },
0291 { 0xC5, 0x02 },
0292 { 0xCC, 0x0A },
0293 { 0xB0, 0x06 },
0294 { 0xC0, 0xA5 },
0295 { 0xD5, 0x20 },
0296 { 0xC0, 0x00 },
0297 { 0xB0, 0x02 },
0298 { 0xC0, 0x00 },
0299 { 0xC1, 0x02 },
0300 { 0xC2, 0x06 },
0301 { 0xC3, 0x16 },
0302 { 0xC4, 0x0E },
0303 { 0xC5, 0x18 },
0304 { 0xC6, 0x26 },
0305 { 0xC7, 0x32 },
0306 { 0xC8, 0x3F },
0307 { 0xC9, 0x3F },
0308 { 0xCA, 0x3F },
0309 { 0xCB, 0x3F },
0310 { 0xCC, 0x3D },
0311 { 0xCD, 0x2F },
0312 { 0xCE, 0x2F },
0313 { 0xCF, 0x2F },
0314 { 0xD0, 0x07 },
0315 { 0xD2, 0x00 },
0316 { 0xD3, 0x02 },
0317 { 0xD4, 0x06 },
0318 { 0xD5, 0x12 },
0319 { 0xD6, 0x0A },
0320 { 0xD7, 0x14 },
0321 { 0xD8, 0x22 },
0322 { 0xD9, 0x2E },
0323 { 0xDA, 0x3D },
0324 { 0xDB, 0x3F },
0325 { 0xDC, 0x3F },
0326 { 0xDD, 0x3F },
0327 { 0xDE, 0x3D },
0328 { 0xDF, 0x2F },
0329 { 0xE0, 0x2F },
0330 { 0xE1, 0x2F },
0331 { 0xE2, 0x07 },
0332 { 0xB0, 0x07 },
0333 { 0xB1, 0x18 },
0334 { 0xB2, 0x19 },
0335 { 0xB3, 0x2E },
0336 { 0xB4, 0x52 },
0337 { 0xB5, 0x72 },
0338 { 0xB6, 0x8C },
0339 { 0xB7, 0xBD },
0340 { 0xB8, 0xEB },
0341 { 0xB9, 0x47 },
0342 { 0xBA, 0x96 },
0343 { 0xBB, 0x1E },
0344 { 0xBC, 0x90 },
0345 { 0xBD, 0x93 },
0346 { 0xBE, 0xFA },
0347 { 0xBF, 0x56 },
0348 { 0xC0, 0x8C },
0349 { 0xC1, 0xB7 },
0350 { 0xC2, 0xCC },
0351 { 0xC3, 0xDF },
0352 { 0xC4, 0xE8 },
0353 { 0xC5, 0xF0 },
0354 { 0xC6, 0xF8 },
0355 { 0xC7, 0xFA },
0356 { 0xC8, 0xFC },
0357 { 0xC9, 0x00 },
0358 { 0xCA, 0x00 },
0359 { 0xCB, 0x5A },
0360 { 0xCC, 0xAF },
0361 { 0xCD, 0xFF },
0362 { 0xCE, 0xFF },
0363 { 0xB0, 0x08 },
0364 { 0xB1, 0x04 },
0365 { 0xB2, 0x15 },
0366 { 0xB3, 0x2D },
0367 { 0xB4, 0x51 },
0368 { 0xB5, 0x72 },
0369 { 0xB6, 0x8D },
0370 { 0xB7, 0xBE },
0371 { 0xB8, 0xED },
0372 { 0xB9, 0x4A },
0373 { 0xBA, 0x9A },
0374 { 0xBB, 0x23 },
0375 { 0xBC, 0x95 },
0376 { 0xBD, 0x98 },
0377 { 0xBE, 0xFF },
0378 { 0xBF, 0x59 },
0379 { 0xC0, 0x8E },
0380 { 0xC1, 0xB9 },
0381 { 0xC2, 0xCD },
0382 { 0xC3, 0xDF },
0383 { 0xC4, 0xE8 },
0384 { 0xC5, 0xF0 },
0385 { 0xC6, 0xF8 },
0386 { 0xC7, 0xFA },
0387 { 0xC8, 0xFC },
0388 { 0xC9, 0x00 },
0389 { 0xCA, 0x00 },
0390 { 0xCB, 0x5A },
0391 { 0xCC, 0xAF },
0392 { 0xCD, 0xFF },
0393 { 0xCE, 0xFF },
0394 { 0xB0, 0x09 },
0395 { 0xB1, 0x04 },
0396 { 0xB2, 0x2C },
0397 { 0xB3, 0x36 },
0398 { 0xB4, 0x53 },
0399 { 0xB5, 0x73 },
0400 { 0xB6, 0x8E },
0401 { 0xB7, 0xC0 },
0402 { 0xB8, 0xEF },
0403 { 0xB9, 0x4C },
0404 { 0xBA, 0x9D },
0405 { 0xBB, 0x25 },
0406 { 0xBC, 0x96 },
0407 { 0xBD, 0x9A },
0408 { 0xBE, 0x01 },
0409 { 0xBF, 0x59 },
0410 { 0xC0, 0x8E },
0411 { 0xC1, 0xB9 },
0412 { 0xC2, 0xCD },
0413 { 0xC3, 0xDF },
0414 { 0xC4, 0xE8 },
0415 { 0xC5, 0xF0 },
0416 { 0xC6, 0xF8 },
0417 { 0xC7, 0xFA },
0418 { 0xC8, 0xFC },
0419 { 0xC9, 0x00 },
0420 { 0xCA, 0x00 },
0421 { 0xCB, 0x5A },
0422 { 0xCC, 0xBF },
0423 { 0xCD, 0xFF },
0424 { 0xCE, 0xFF },
0425 { 0xB0, 0x0A },
0426 { 0xB1, 0x18 },
0427 { 0xB2, 0x19 },
0428 { 0xB3, 0x2E },
0429 { 0xB4, 0x52 },
0430 { 0xB5, 0x72 },
0431 { 0xB6, 0x8C },
0432 { 0xB7, 0xBD },
0433 { 0xB8, 0xEB },
0434 { 0xB9, 0x47 },
0435 { 0xBA, 0x96 },
0436 { 0xBB, 0x1E },
0437 { 0xBC, 0x90 },
0438 { 0xBD, 0x93 },
0439 { 0xBE, 0xFA },
0440 { 0xBF, 0x56 },
0441 { 0xC0, 0x8C },
0442 { 0xC1, 0xB7 },
0443 { 0xC2, 0xCC },
0444 { 0xC3, 0xDF },
0445 { 0xC4, 0xE8 },
0446 { 0xC5, 0xF0 },
0447 { 0xC6, 0xF8 },
0448 { 0xC7, 0xFA },
0449 { 0xC8, 0xFC },
0450 { 0xC9, 0x00 },
0451 { 0xCA, 0x00 },
0452 { 0xCB, 0x5A },
0453 { 0xCC, 0xAF },
0454 { 0xCD, 0xFF },
0455 { 0xCE, 0xFF },
0456 { 0xB0, 0x0B },
0457 { 0xB1, 0x04 },
0458 { 0xB2, 0x15 },
0459 { 0xB3, 0x2D },
0460 { 0xB4, 0x51 },
0461 { 0xB5, 0x72 },
0462 { 0xB6, 0x8D },
0463 { 0xB7, 0xBE },
0464 { 0xB8, 0xED },
0465 { 0xB9, 0x4A },
0466 { 0xBA, 0x9A },
0467 { 0xBB, 0x23 },
0468 { 0xBC, 0x95 },
0469 { 0xBD, 0x98 },
0470 { 0xBE, 0xFF },
0471 { 0xBF, 0x59 },
0472 { 0xC0, 0x8E },
0473 { 0xC1, 0xB9 },
0474 { 0xC2, 0xCD },
0475 { 0xC3, 0xDF },
0476 { 0xC4, 0xE8 },
0477 { 0xC5, 0xF0 },
0478 { 0xC6, 0xF8 },
0479 { 0xC7, 0xFA },
0480 { 0xC8, 0xFC },
0481 { 0xC9, 0x00 },
0482 { 0xCA, 0x00 },
0483 { 0xCB, 0x5A },
0484 { 0xCC, 0xAF },
0485 { 0xCD, 0xFF },
0486 { 0xCE, 0xFF },
0487 { 0xB0, 0x0C },
0488 { 0xB1, 0x04 },
0489 { 0xB2, 0x2C },
0490 { 0xB3, 0x36 },
0491 { 0xB4, 0x53 },
0492 { 0xB5, 0x73 },
0493 { 0xB6, 0x8E },
0494 { 0xB7, 0xC0 },
0495 { 0xB8, 0xEF },
0496 { 0xB9, 0x4C },
0497 { 0xBA, 0x9D },
0498 { 0xBB, 0x25 },
0499 { 0xBC, 0x96 },
0500 { 0xBD, 0x9A },
0501 { 0xBE, 0x01 },
0502 { 0xBF, 0x59 },
0503 { 0xC0, 0x8E },
0504 { 0xC1, 0xB9 },
0505 { 0xC2, 0xCD },
0506 { 0xC3, 0xDF },
0507 { 0xC4, 0xE8 },
0508 { 0xC5, 0xF0 },
0509 { 0xC6, 0xF8 },
0510 { 0xC7, 0xFA },
0511 { 0xC8, 0xFC },
0512 { 0xC9, 0x00 },
0513 { 0xCA, 0x00 },
0514 { 0xCB, 0x5A },
0515 { 0xCC, 0xBF },
0516 { 0xCD, 0xFF },
0517 { 0xCE, 0xFF },
0518 { 0xB0, 0x04 },
0519 { 0xB5, 0x02 },
0520 { 0xB6, 0x01 },
0521 };
0522
0523 static const struct panel_desc boe_himax8279d8p_panel_desc = {
0524 .display_mode = &default_display_mode,
0525 .bpc = 8,
0526 .width_mm = 107,
0527 .height_mm = 172,
0528 .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
0529 MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM,
0530 .format = MIPI_DSI_FMT_RGB888,
0531 .lanes = 4,
0532 .on_cmds = boe_himax8279d8p_on_cmds,
0533 .on_cmds_num = 260,
0534 };
0535
0536
0537 static const struct panel_cmd boe_himax8279d10p_on_cmds[] = {
0538 { 0xB0, 0x05 },
0539 { 0xB1, 0xE5 },
0540 { 0xB3, 0x52 },
0541 { 0xB0, 0x00 },
0542 { 0xB6, 0x03 },
0543 { 0xBA, 0x8B },
0544 { 0xBF, 0x1A },
0545 { 0xC0, 0x0F },
0546 { 0xC2, 0x0C },
0547 { 0xC3, 0x02 },
0548 { 0xC4, 0x0C },
0549 { 0xC5, 0x02 },
0550 { 0xB0, 0x01 },
0551 { 0xE0, 0x26 },
0552 { 0xE1, 0x26 },
0553 { 0xDC, 0x00 },
0554 { 0xDD, 0x00 },
0555 { 0xCC, 0x26 },
0556 { 0xCD, 0x26 },
0557 { 0xC8, 0x00 },
0558 { 0xC9, 0x00 },
0559 { 0xD2, 0x03 },
0560 { 0xD3, 0x03 },
0561 { 0xE6, 0x04 },
0562 { 0xE7, 0x04 },
0563 { 0xC4, 0x09 },
0564 { 0xC5, 0x09 },
0565 { 0xD8, 0x0A },
0566 { 0xD9, 0x0A },
0567 { 0xC2, 0x0B },
0568 { 0xC3, 0x0B },
0569 { 0xD6, 0x0C },
0570 { 0xD7, 0x0C },
0571 { 0xC0, 0x05 },
0572 { 0xC1, 0x05 },
0573 { 0xD4, 0x06 },
0574 { 0xD5, 0x06 },
0575 { 0xCA, 0x07 },
0576 { 0xCB, 0x07 },
0577 { 0xDE, 0x08 },
0578 { 0xDF, 0x08 },
0579 { 0xB0, 0x02 },
0580 { 0xC0, 0x00 },
0581 { 0xC1, 0x0D },
0582 { 0xC2, 0x17 },
0583 { 0xC3, 0x26 },
0584 { 0xC4, 0x31 },
0585 { 0xC5, 0x1C },
0586 { 0xC6, 0x2C },
0587 { 0xC7, 0x33 },
0588 { 0xC8, 0x31 },
0589 { 0xC9, 0x37 },
0590 { 0xCA, 0x37 },
0591 { 0xCB, 0x37 },
0592 { 0xCC, 0x39 },
0593 { 0xCD, 0x2E },
0594 { 0xCE, 0x2F },
0595 { 0xCF, 0x2F },
0596 { 0xD0, 0x07 },
0597 { 0xD2, 0x00 },
0598 { 0xD3, 0x0D },
0599 { 0xD4, 0x17 },
0600 { 0xD5, 0x26 },
0601 { 0xD6, 0x31 },
0602 { 0xD7, 0x3F },
0603 { 0xD8, 0x3F },
0604 { 0xD9, 0x3F },
0605 { 0xDA, 0x3F },
0606 { 0xDB, 0x37 },
0607 { 0xDC, 0x37 },
0608 { 0xDD, 0x37 },
0609 { 0xDE, 0x39 },
0610 { 0xDF, 0x2E },
0611 { 0xE0, 0x2F },
0612 { 0xE1, 0x2F },
0613 { 0xE2, 0x07 },
0614 { 0xB0, 0x03 },
0615 { 0xC8, 0x0B },
0616 { 0xC9, 0x07 },
0617 { 0xC3, 0x00 },
0618 { 0xE7, 0x00 },
0619 { 0xC5, 0x2A },
0620 { 0xDE, 0x2A },
0621 { 0xCA, 0x43 },
0622 { 0xC9, 0x07 },
0623 { 0xE4, 0xC0 },
0624 { 0xE5, 0x0D },
0625 { 0xCB, 0x01 },
0626 { 0xBC, 0x01 },
0627 { 0xB0, 0x06 },
0628 { 0xB8, 0xA5 },
0629 { 0xC0, 0xA5 },
0630 { 0xC7, 0x0F },
0631 { 0xD5, 0x32 },
0632 { 0xB8, 0x00 },
0633 { 0xC0, 0x00 },
0634 { 0xBC, 0x00 },
0635 { 0xB0, 0x07 },
0636 { 0xB1, 0x00 },
0637 { 0xB2, 0x05 },
0638 { 0xB3, 0x10 },
0639 { 0xB4, 0x22 },
0640 { 0xB5, 0x36 },
0641 { 0xB6, 0x4A },
0642 { 0xB7, 0x6C },
0643 { 0xB8, 0x9A },
0644 { 0xB9, 0xD7 },
0645 { 0xBA, 0x17 },
0646 { 0xBB, 0x92 },
0647 { 0xBC, 0x15 },
0648 { 0xBD, 0x18 },
0649 { 0xBE, 0x8C },
0650 { 0xBF, 0x00 },
0651 { 0xC0, 0x3A },
0652 { 0xC1, 0x72 },
0653 { 0xC2, 0x8C },
0654 { 0xC3, 0xA5 },
0655 { 0xC4, 0xB1 },
0656 { 0xC5, 0xBE },
0657 { 0xC6, 0xCA },
0658 { 0xC7, 0xD1 },
0659 { 0xC8, 0xD4 },
0660 { 0xC9, 0x00 },
0661 { 0xCA, 0x00 },
0662 { 0xCB, 0x16 },
0663 { 0xCC, 0xAF },
0664 { 0xCD, 0xFF },
0665 { 0xCE, 0xFF },
0666 { 0xB0, 0x08 },
0667 { 0xB1, 0x04 },
0668 { 0xB2, 0x05 },
0669 { 0xB3, 0x11 },
0670 { 0xB4, 0x24 },
0671 { 0xB5, 0x39 },
0672 { 0xB6, 0x4E },
0673 { 0xB7, 0x72 },
0674 { 0xB8, 0xA3 },
0675 { 0xB9, 0xE1 },
0676 { 0xBA, 0x25 },
0677 { 0xBB, 0xA8 },
0678 { 0xBC, 0x2E },
0679 { 0xBD, 0x32 },
0680 { 0xBE, 0xAD },
0681 { 0xBF, 0x28 },
0682 { 0xC0, 0x63 },
0683 { 0xC1, 0x9B },
0684 { 0xC2, 0xB5 },
0685 { 0xC3, 0xCF },
0686 { 0xC4, 0xDB },
0687 { 0xC5, 0xE8 },
0688 { 0xC6, 0xF5 },
0689 { 0xC7, 0xFA },
0690 { 0xC8, 0xFC },
0691 { 0xC9, 0x00 },
0692 { 0xCA, 0x00 },
0693 { 0xCB, 0x16 },
0694 { 0xCC, 0xAF },
0695 { 0xCD, 0xFF },
0696 { 0xCE, 0xFF },
0697 { 0xB0, 0x09 },
0698 { 0xB1, 0x04 },
0699 { 0xB2, 0x04 },
0700 { 0xB3, 0x0F },
0701 { 0xB4, 0x22 },
0702 { 0xB5, 0x37 },
0703 { 0xB6, 0x4D },
0704 { 0xB7, 0x71 },
0705 { 0xB8, 0xA2 },
0706 { 0xB9, 0xE1 },
0707 { 0xBA, 0x26 },
0708 { 0xBB, 0xA9 },
0709 { 0xBC, 0x2F },
0710 { 0xBD, 0x33 },
0711 { 0xBE, 0xAC },
0712 { 0xBF, 0x24 },
0713 { 0xC0, 0x5D },
0714 { 0xC1, 0x94 },
0715 { 0xC2, 0xAC },
0716 { 0xC3, 0xC5 },
0717 { 0xC4, 0xD1 },
0718 { 0xC5, 0xDC },
0719 { 0xC6, 0xE8 },
0720 { 0xC7, 0xED },
0721 { 0xC8, 0xF0 },
0722 { 0xC9, 0x00 },
0723 { 0xCA, 0x00 },
0724 { 0xCB, 0x16 },
0725 { 0xCC, 0xAF },
0726 { 0xCD, 0xFF },
0727 { 0xCE, 0xFF },
0728 { 0xB0, 0x0A },
0729 { 0xB1, 0x00 },
0730 { 0xB2, 0x05 },
0731 { 0xB3, 0x10 },
0732 { 0xB4, 0x22 },
0733 { 0xB5, 0x36 },
0734 { 0xB6, 0x4A },
0735 { 0xB7, 0x6C },
0736 { 0xB8, 0x9A },
0737 { 0xB9, 0xD7 },
0738 { 0xBA, 0x17 },
0739 { 0xBB, 0x92 },
0740 { 0xBC, 0x15 },
0741 { 0xBD, 0x18 },
0742 { 0xBE, 0x8C },
0743 { 0xBF, 0x00 },
0744 { 0xC0, 0x3A },
0745 { 0xC1, 0x72 },
0746 { 0xC2, 0x8C },
0747 { 0xC3, 0xA5 },
0748 { 0xC4, 0xB1 },
0749 { 0xC5, 0xBE },
0750 { 0xC6, 0xCA },
0751 { 0xC7, 0xD1 },
0752 { 0xC8, 0xD4 },
0753 { 0xC9, 0x00 },
0754 { 0xCA, 0x00 },
0755 { 0xCB, 0x16 },
0756 { 0xCC, 0xAF },
0757 { 0xCD, 0xFF },
0758 { 0xCE, 0xFF },
0759 { 0xB0, 0x0B },
0760 { 0xB1, 0x04 },
0761 { 0xB2, 0x05 },
0762 { 0xB3, 0x11 },
0763 { 0xB4, 0x24 },
0764 { 0xB5, 0x39 },
0765 { 0xB6, 0x4E },
0766 { 0xB7, 0x72 },
0767 { 0xB8, 0xA3 },
0768 { 0xB9, 0xE1 },
0769 { 0xBA, 0x25 },
0770 { 0xBB, 0xA8 },
0771 { 0xBC, 0x2E },
0772 { 0xBD, 0x32 },
0773 { 0xBE, 0xAD },
0774 { 0xBF, 0x28 },
0775 { 0xC0, 0x63 },
0776 { 0xC1, 0x9B },
0777 { 0xC2, 0xB5 },
0778 { 0xC3, 0xCF },
0779 { 0xC4, 0xDB },
0780 { 0xC5, 0xE8 },
0781 { 0xC6, 0xF5 },
0782 { 0xC7, 0xFA },
0783 { 0xC8, 0xFC },
0784 { 0xC9, 0x00 },
0785 { 0xCA, 0x00 },
0786 { 0xCB, 0x16 },
0787 { 0xCC, 0xAF },
0788 { 0xCD, 0xFF },
0789 { 0xCE, 0xFF },
0790 { 0xB0, 0x0C },
0791 { 0xB1, 0x04 },
0792 { 0xB2, 0x04 },
0793 { 0xB3, 0x0F },
0794 { 0xB4, 0x22 },
0795 { 0xB5, 0x37 },
0796 { 0xB6, 0x4D },
0797 { 0xB7, 0x71 },
0798 { 0xB8, 0xA2 },
0799 { 0xB9, 0xE1 },
0800 { 0xBA, 0x26 },
0801 { 0xBB, 0xA9 },
0802 { 0xBC, 0x2F },
0803 { 0xBD, 0x33 },
0804 { 0xBE, 0xAC },
0805 { 0xBF, 0x24 },
0806 { 0xC0, 0x5D },
0807 { 0xC1, 0x94 },
0808 { 0xC2, 0xAC },
0809 { 0xC3, 0xC5 },
0810 { 0xC4, 0xD1 },
0811 { 0xC5, 0xDC },
0812 { 0xC6, 0xE8 },
0813 { 0xC7, 0xED },
0814 { 0xC8, 0xF0 },
0815 { 0xC9, 0x00 },
0816 { 0xCA, 0x00 },
0817 { 0xCB, 0x16 },
0818 { 0xCC, 0xAF },
0819 { 0xCD, 0xFF },
0820 { 0xCE, 0xFF },
0821 };
0822
0823 static const struct panel_desc boe_himax8279d10p_panel_desc = {
0824 .display_mode = &default_display_mode,
0825 .bpc = 8,
0826 .width_mm = 135,
0827 .height_mm = 216,
0828 .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
0829 MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM,
0830 .format = MIPI_DSI_FMT_RGB888,
0831 .lanes = 4,
0832 .on_cmds = boe_himax8279d10p_on_cmds,
0833 .on_cmds_num = 283,
0834 };
0835
0836 static const struct of_device_id panel_of_match[] = {
0837 {
0838 .compatible = "boe,himax8279d8p",
0839 .data = &boe_himax8279d8p_panel_desc,
0840 },
0841 {
0842 .compatible = "boe,himax8279d10p",
0843 .data = &boe_himax8279d10p_panel_desc,
0844 },
0845 {
0846
0847 }
0848 };
0849 MODULE_DEVICE_TABLE(of, panel_of_match);
0850
0851 static int panel_add(struct panel_info *pinfo)
0852 {
0853 struct device *dev = &pinfo->link->dev;
0854 int ret;
0855
0856 pinfo->pp18_gpio = devm_gpiod_get(dev, "pp18", GPIOD_OUT_HIGH);
0857 if (IS_ERR(pinfo->pp18_gpio)) {
0858 ret = PTR_ERR(pinfo->pp18_gpio);
0859 if (ret != -EPROBE_DEFER)
0860 dev_err(dev, "failed to get pp18 gpio: %d\n", ret);
0861 return ret;
0862 }
0863
0864 pinfo->pp33_gpio = devm_gpiod_get(dev, "pp33", GPIOD_OUT_HIGH);
0865 if (IS_ERR(pinfo->pp33_gpio)) {
0866 ret = PTR_ERR(pinfo->pp33_gpio);
0867 if (ret != -EPROBE_DEFER)
0868 dev_err(dev, "failed to get pp33 gpio: %d\n", ret);
0869 return ret;
0870 }
0871
0872 pinfo->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_HIGH);
0873 if (IS_ERR(pinfo->enable_gpio)) {
0874 ret = PTR_ERR(pinfo->enable_gpio);
0875 if (ret != -EPROBE_DEFER)
0876 dev_err(dev, "failed to get enable gpio: %d\n", ret);
0877 return ret;
0878 }
0879
0880 drm_panel_init(&pinfo->base, dev, &panel_funcs,
0881 DRM_MODE_CONNECTOR_DSI);
0882
0883 ret = drm_panel_of_backlight(&pinfo->base);
0884 if (ret)
0885 return ret;
0886
0887 drm_panel_add(&pinfo->base);
0888
0889 return 0;
0890 }
0891
0892 static int panel_probe(struct mipi_dsi_device *dsi)
0893 {
0894 struct panel_info *pinfo;
0895 const struct panel_desc *desc;
0896 int err;
0897
0898 pinfo = devm_kzalloc(&dsi->dev, sizeof(*pinfo), GFP_KERNEL);
0899 if (!pinfo)
0900 return -ENOMEM;
0901
0902 desc = of_device_get_match_data(&dsi->dev);
0903 dsi->mode_flags = desc->mode_flags;
0904 dsi->format = desc->format;
0905 dsi->lanes = desc->lanes;
0906 pinfo->desc = desc;
0907
0908 pinfo->link = dsi;
0909 mipi_dsi_set_drvdata(dsi, pinfo);
0910
0911 err = panel_add(pinfo);
0912 if (err < 0)
0913 return err;
0914
0915 err = mipi_dsi_attach(dsi);
0916 if (err < 0)
0917 drm_panel_remove(&pinfo->base);
0918
0919 return err;
0920 }
0921
0922 static int panel_remove(struct mipi_dsi_device *dsi)
0923 {
0924 struct panel_info *pinfo = mipi_dsi_get_drvdata(dsi);
0925 int err;
0926
0927 err = boe_panel_disable(&pinfo->base);
0928 if (err < 0)
0929 dev_err(&dsi->dev, "failed to disable panel: %d\n", err);
0930
0931 err = boe_panel_unprepare(&pinfo->base);
0932 if (err < 0)
0933 dev_err(&dsi->dev, "failed to unprepare panel: %d\n", err);
0934
0935 err = mipi_dsi_detach(dsi);
0936 if (err < 0)
0937 dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err);
0938
0939 drm_panel_remove(&pinfo->base);
0940
0941 return 0;
0942 }
0943
0944 static void panel_shutdown(struct mipi_dsi_device *dsi)
0945 {
0946 struct panel_info *pinfo = mipi_dsi_get_drvdata(dsi);
0947
0948 boe_panel_disable(&pinfo->base);
0949 boe_panel_unprepare(&pinfo->base);
0950 }
0951
0952 static struct mipi_dsi_driver panel_driver = {
0953 .driver = {
0954 .name = "panel-boe-himax8279d",
0955 .of_match_table = panel_of_match,
0956 },
0957 .probe = panel_probe,
0958 .remove = panel_remove,
0959 .shutdown = panel_shutdown,
0960 };
0961 module_mipi_dsi_driver(panel_driver);
0962
0963 MODULE_AUTHOR("Jerry Han <jerry.han.hq@gmail.com>");
0964 MODULE_DESCRIPTION("Boe Himax8279d driver");
0965 MODULE_LICENSE("GPL v2");