917 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (c) 2019, Huaqin Telecom Technology Co., Ltd4 *5 * Author: Jerry Han <jerry.han.hq@gmail.com>6 *7 */8 9#include <linux/delay.h>10#include <linux/kernel.h>11#include <linux/module.h>12#include <linux/of.h>13 14#include <linux/gpio/consumer.h>15#include <linux/regulator/consumer.h>16 17#include <drm/drm_device.h>18#include <drm/drm_mipi_dsi.h>19#include <drm/drm_modes.h>20#include <drm/drm_panel.h>21 22#include <video/mipi_display.h>23 24struct panel_cmd {25 char cmd;26 char data;27};28 29struct panel_desc {30 const struct drm_display_mode *display_mode;31 unsigned int bpc;32 unsigned int width_mm;33 unsigned int height_mm;34 35 unsigned long mode_flags;36 enum mipi_dsi_pixel_format format;37 unsigned int lanes;38 const struct panel_cmd *on_cmds;39 unsigned int on_cmds_num;40};41 42struct panel_info {43 struct drm_panel base;44 struct mipi_dsi_device *link;45 const struct panel_desc *desc;46 47 struct gpio_desc *enable_gpio;48 struct gpio_desc *pp33_gpio;49 struct gpio_desc *pp18_gpio;50};51 52static inline struct panel_info *to_panel_info(struct drm_panel *panel)53{54 return container_of(panel, struct panel_info, base);55}56 57static void disable_gpios(struct panel_info *pinfo)58{59 gpiod_set_value(pinfo->enable_gpio, 0);60 gpiod_set_value(pinfo->pp33_gpio, 0);61 gpiod_set_value(pinfo->pp18_gpio, 0);62}63 64static int send_mipi_cmds(struct drm_panel *panel, const struct panel_cmd *cmds)65{66 struct panel_info *pinfo = to_panel_info(panel);67 unsigned int i = 0;68 int err;69 70 for (i = 0; i < pinfo->desc->on_cmds_num; i++) {71 err = mipi_dsi_dcs_write_buffer(pinfo->link, &cmds[i],72 sizeof(struct panel_cmd));73 74 if (err < 0)75 return err;76 }77 78 return 0;79}80 81static int boe_panel_disable(struct drm_panel *panel)82{83 struct panel_info *pinfo = to_panel_info(panel);84 int err;85 86 err = mipi_dsi_dcs_set_display_off(pinfo->link);87 if (err < 0) {88 dev_err(panel->dev, "failed to set display off: %d\n", err);89 return err;90 }91 92 return 0;93}94 95static int boe_panel_unprepare(struct drm_panel *panel)96{97 struct panel_info *pinfo = to_panel_info(panel);98 int err;99 100 err = mipi_dsi_dcs_set_display_off(pinfo->link);101 if (err < 0)102 dev_err(panel->dev, "failed to set display off: %d\n", err);103 104 err = mipi_dsi_dcs_enter_sleep_mode(pinfo->link);105 if (err < 0)106 dev_err(panel->dev, "failed to enter sleep mode: %d\n", err);107 108 /* sleep_mode_delay: 1ms - 2ms */109 usleep_range(1000, 2000);110 111 disable_gpios(pinfo);112 113 return 0;114}115 116static int boe_panel_prepare(struct drm_panel *panel)117{118 struct panel_info *pinfo = to_panel_info(panel);119 int err;120 121 gpiod_set_value(pinfo->pp18_gpio, 1);122 /* T1: 5ms - 6ms */123 usleep_range(5000, 6000);124 gpiod_set_value(pinfo->pp33_gpio, 1);125 126 /* reset sequence */127 /* T2: 14ms - 15ms */128 usleep_range(14000, 15000);129 gpiod_set_value(pinfo->enable_gpio, 1);130 131 /* T3: 1ms - 2ms */132 usleep_range(1000, 2000);133 gpiod_set_value(pinfo->enable_gpio, 0);134 135 /* T4: 1ms - 2ms */136 usleep_range(1000, 2000);137 gpiod_set_value(pinfo->enable_gpio, 1);138 139 /* T5: 5ms - 6ms */140 usleep_range(5000, 6000);141 142 /* send init code */143 err = send_mipi_cmds(panel, pinfo->desc->on_cmds);144 if (err < 0) {145 dev_err(panel->dev, "failed to send DCS Init Code: %d\n", err);146 goto poweroff;147 }148 149 err = mipi_dsi_dcs_exit_sleep_mode(pinfo->link);150 if (err < 0) {151 dev_err(panel->dev, "failed to exit sleep mode: %d\n", err);152 goto poweroff;153 }154 155 /* T6: 120ms - 121ms */156 usleep_range(120000, 121000);157 158 err = mipi_dsi_dcs_set_display_on(pinfo->link);159 if (err < 0) {160 dev_err(panel->dev, "failed to set display on: %d\n", err);161 goto poweroff;162 }163 164 /* T7: 20ms - 21ms */165 usleep_range(20000, 21000);166 167 return 0;168 169poweroff:170 disable_gpios(pinfo);171 return err;172}173 174static int boe_panel_enable(struct drm_panel *panel)175{176 struct panel_info *pinfo = to_panel_info(panel);177 int ret;178 179 usleep_range(120000, 121000);180 181 ret = mipi_dsi_dcs_set_display_on(pinfo->link);182 if (ret < 0) {183 dev_err(panel->dev, "failed to set display on: %d\n", ret);184 return ret;185 }186 187 return 0;188}189 190static int boe_panel_get_modes(struct drm_panel *panel,191 struct drm_connector *connector)192{193 struct panel_info *pinfo = to_panel_info(panel);194 const struct drm_display_mode *m = pinfo->desc->display_mode;195 struct drm_display_mode *mode;196 197 mode = drm_mode_duplicate(connector->dev, m);198 if (!mode) {199 dev_err(pinfo->base.dev, "failed to add mode %ux%u@%u\n",200 m->hdisplay, m->vdisplay, drm_mode_vrefresh(m));201 return -ENOMEM;202 }203 204 drm_mode_set_name(mode);205 206 drm_mode_probed_add(connector, mode);207 208 connector->display_info.width_mm = pinfo->desc->width_mm;209 connector->display_info.height_mm = pinfo->desc->height_mm;210 connector->display_info.bpc = pinfo->desc->bpc;211 212 return 1;213}214 215static const struct drm_panel_funcs panel_funcs = {216 .disable = boe_panel_disable,217 .unprepare = boe_panel_unprepare,218 .prepare = boe_panel_prepare,219 .enable = boe_panel_enable,220 .get_modes = boe_panel_get_modes,221};222 223static const struct drm_display_mode default_display_mode = {224 .clock = 159420,225 .hdisplay = 1200,226 .hsync_start = 1200 + 80,227 .hsync_end = 1200 + 80 + 60,228 .htotal = 1200 + 80 + 60 + 24,229 .vdisplay = 1920,230 .vsync_start = 1920 + 10,231 .vsync_end = 1920 + 10 + 14,232 .vtotal = 1920 + 10 + 14 + 4,233};234 235/* 8 inch */236static const struct panel_cmd boe_himax8279d8p_on_cmds[] = {237 { 0xB0, 0x05 },238 { 0xB1, 0xE5 },239 { 0xB3, 0x52 },240 { 0xC0, 0x00 },241 { 0xC2, 0x57 },242 { 0xD9, 0x85 },243 { 0xB0, 0x01 },244 { 0xC8, 0x00 },245 { 0xC9, 0x00 },246 { 0xCC, 0x26 },247 { 0xCD, 0x26 },248 { 0xDC, 0x00 },249 { 0xDD, 0x00 },250 { 0xE0, 0x26 },251 { 0xE1, 0x26 },252 { 0xB0, 0x03 },253 { 0xC3, 0x2A },254 { 0xE7, 0x2A },255 { 0xC5, 0x2A },256 { 0xDE, 0x2A },257 { 0xBC, 0x02 },258 { 0xCB, 0x02 },259 { 0xB0, 0x00 },260 { 0xB6, 0x03 },261 { 0xBA, 0x8B },262 { 0xBF, 0x15 },263 { 0xC0, 0x18 },264 { 0xC2, 0x14 },265 { 0xC3, 0x02 },266 { 0xC4, 0x14 },267 { 0xC5, 0x02 },268 { 0xCC, 0x0A },269 { 0xB0, 0x06 },270 { 0xC0, 0xA5 },271 { 0xD5, 0x20 },272 { 0xC0, 0x00 },273 { 0xB0, 0x02 },274 { 0xC0, 0x00 },275 { 0xC1, 0x02 },276 { 0xC2, 0x06 },277 { 0xC3, 0x16 },278 { 0xC4, 0x0E },279 { 0xC5, 0x18 },280 { 0xC6, 0x26 },281 { 0xC7, 0x32 },282 { 0xC8, 0x3F },283 { 0xC9, 0x3F },284 { 0xCA, 0x3F },285 { 0xCB, 0x3F },286 { 0xCC, 0x3D },287 { 0xCD, 0x2F },288 { 0xCE, 0x2F },289 { 0xCF, 0x2F },290 { 0xD0, 0x07 },291 { 0xD2, 0x00 },292 { 0xD3, 0x02 },293 { 0xD4, 0x06 },294 { 0xD5, 0x12 },295 { 0xD6, 0x0A },296 { 0xD7, 0x14 },297 { 0xD8, 0x22 },298 { 0xD9, 0x2E },299 { 0xDA, 0x3D },300 { 0xDB, 0x3F },301 { 0xDC, 0x3F },302 { 0xDD, 0x3F },303 { 0xDE, 0x3D },304 { 0xDF, 0x2F },305 { 0xE0, 0x2F },306 { 0xE1, 0x2F },307 { 0xE2, 0x07 },308 { 0xB0, 0x07 },309 { 0xB1, 0x18 },310 { 0xB2, 0x19 },311 { 0xB3, 0x2E },312 { 0xB4, 0x52 },313 { 0xB5, 0x72 },314 { 0xB6, 0x8C },315 { 0xB7, 0xBD },316 { 0xB8, 0xEB },317 { 0xB9, 0x47 },318 { 0xBA, 0x96 },319 { 0xBB, 0x1E },320 { 0xBC, 0x90 },321 { 0xBD, 0x93 },322 { 0xBE, 0xFA },323 { 0xBF, 0x56 },324 { 0xC0, 0x8C },325 { 0xC1, 0xB7 },326 { 0xC2, 0xCC },327 { 0xC3, 0xDF },328 { 0xC4, 0xE8 },329 { 0xC5, 0xF0 },330 { 0xC6, 0xF8 },331 { 0xC7, 0xFA },332 { 0xC8, 0xFC },333 { 0xC9, 0x00 },334 { 0xCA, 0x00 },335 { 0xCB, 0x5A },336 { 0xCC, 0xAF },337 { 0xCD, 0xFF },338 { 0xCE, 0xFF },339 { 0xB0, 0x08 },340 { 0xB1, 0x04 },341 { 0xB2, 0x15 },342 { 0xB3, 0x2D },343 { 0xB4, 0x51 },344 { 0xB5, 0x72 },345 { 0xB6, 0x8D },346 { 0xB7, 0xBE },347 { 0xB8, 0xED },348 { 0xB9, 0x4A },349 { 0xBA, 0x9A },350 { 0xBB, 0x23 },351 { 0xBC, 0x95 },352 { 0xBD, 0x98 },353 { 0xBE, 0xFF },354 { 0xBF, 0x59 },355 { 0xC0, 0x8E },356 { 0xC1, 0xB9 },357 { 0xC2, 0xCD },358 { 0xC3, 0xDF },359 { 0xC4, 0xE8 },360 { 0xC5, 0xF0 },361 { 0xC6, 0xF8 },362 { 0xC7, 0xFA },363 { 0xC8, 0xFC },364 { 0xC9, 0x00 },365 { 0xCA, 0x00 },366 { 0xCB, 0x5A },367 { 0xCC, 0xAF },368 { 0xCD, 0xFF },369 { 0xCE, 0xFF },370 { 0xB0, 0x09 },371 { 0xB1, 0x04 },372 { 0xB2, 0x2C },373 { 0xB3, 0x36 },374 { 0xB4, 0x53 },375 { 0xB5, 0x73 },376 { 0xB6, 0x8E },377 { 0xB7, 0xC0 },378 { 0xB8, 0xEF },379 { 0xB9, 0x4C },380 { 0xBA, 0x9D },381 { 0xBB, 0x25 },382 { 0xBC, 0x96 },383 { 0xBD, 0x9A },384 { 0xBE, 0x01 },385 { 0xBF, 0x59 },386 { 0xC0, 0x8E },387 { 0xC1, 0xB9 },388 { 0xC2, 0xCD },389 { 0xC3, 0xDF },390 { 0xC4, 0xE8 },391 { 0xC5, 0xF0 },392 { 0xC6, 0xF8 },393 { 0xC7, 0xFA },394 { 0xC8, 0xFC },395 { 0xC9, 0x00 },396 { 0xCA, 0x00 },397 { 0xCB, 0x5A },398 { 0xCC, 0xBF },399 { 0xCD, 0xFF },400 { 0xCE, 0xFF },401 { 0xB0, 0x0A },402 { 0xB1, 0x18 },403 { 0xB2, 0x19 },404 { 0xB3, 0x2E },405 { 0xB4, 0x52 },406 { 0xB5, 0x72 },407 { 0xB6, 0x8C },408 { 0xB7, 0xBD },409 { 0xB8, 0xEB },410 { 0xB9, 0x47 },411 { 0xBA, 0x96 },412 { 0xBB, 0x1E },413 { 0xBC, 0x90 },414 { 0xBD, 0x93 },415 { 0xBE, 0xFA },416 { 0xBF, 0x56 },417 { 0xC0, 0x8C },418 { 0xC1, 0xB7 },419 { 0xC2, 0xCC },420 { 0xC3, 0xDF },421 { 0xC4, 0xE8 },422 { 0xC5, 0xF0 },423 { 0xC6, 0xF8 },424 { 0xC7, 0xFA },425 { 0xC8, 0xFC },426 { 0xC9, 0x00 },427 { 0xCA, 0x00 },428 { 0xCB, 0x5A },429 { 0xCC, 0xAF },430 { 0xCD, 0xFF },431 { 0xCE, 0xFF },432 { 0xB0, 0x0B },433 { 0xB1, 0x04 },434 { 0xB2, 0x15 },435 { 0xB3, 0x2D },436 { 0xB4, 0x51 },437 { 0xB5, 0x72 },438 { 0xB6, 0x8D },439 { 0xB7, 0xBE },440 { 0xB8, 0xED },441 { 0xB9, 0x4A },442 { 0xBA, 0x9A },443 { 0xBB, 0x23 },444 { 0xBC, 0x95 },445 { 0xBD, 0x98 },446 { 0xBE, 0xFF },447 { 0xBF, 0x59 },448 { 0xC0, 0x8E },449 { 0xC1, 0xB9 },450 { 0xC2, 0xCD },451 { 0xC3, 0xDF },452 { 0xC4, 0xE8 },453 { 0xC5, 0xF0 },454 { 0xC6, 0xF8 },455 { 0xC7, 0xFA },456 { 0xC8, 0xFC },457 { 0xC9, 0x00 },458 { 0xCA, 0x00 },459 { 0xCB, 0x5A },460 { 0xCC, 0xAF },461 { 0xCD, 0xFF },462 { 0xCE, 0xFF },463 { 0xB0, 0x0C },464 { 0xB1, 0x04 },465 { 0xB2, 0x2C },466 { 0xB3, 0x36 },467 { 0xB4, 0x53 },468 { 0xB5, 0x73 },469 { 0xB6, 0x8E },470 { 0xB7, 0xC0 },471 { 0xB8, 0xEF },472 { 0xB9, 0x4C },473 { 0xBA, 0x9D },474 { 0xBB, 0x25 },475 { 0xBC, 0x96 },476 { 0xBD, 0x9A },477 { 0xBE, 0x01 },478 { 0xBF, 0x59 },479 { 0xC0, 0x8E },480 { 0xC1, 0xB9 },481 { 0xC2, 0xCD },482 { 0xC3, 0xDF },483 { 0xC4, 0xE8 },484 { 0xC5, 0xF0 },485 { 0xC6, 0xF8 },486 { 0xC7, 0xFA },487 { 0xC8, 0xFC },488 { 0xC9, 0x00 },489 { 0xCA, 0x00 },490 { 0xCB, 0x5A },491 { 0xCC, 0xBF },492 { 0xCD, 0xFF },493 { 0xCE, 0xFF },494 { 0xB0, 0x04 },495 { 0xB5, 0x02 },496 { 0xB6, 0x01 },497};498 499static const struct panel_desc boe_himax8279d8p_panel_desc = {500 .display_mode = &default_display_mode,501 .bpc = 8,502 .width_mm = 107,503 .height_mm = 172,504 .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |505 MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM,506 .format = MIPI_DSI_FMT_RGB888,507 .lanes = 4,508 .on_cmds = boe_himax8279d8p_on_cmds,509 .on_cmds_num = 260,510};511 512/* 10 inch */513static const struct panel_cmd boe_himax8279d10p_on_cmds[] = {514 { 0xB0, 0x05 },515 { 0xB1, 0xE5 },516 { 0xB3, 0x52 },517 { 0xB0, 0x00 },518 { 0xB6, 0x03 },519 { 0xBA, 0x8B },520 { 0xBF, 0x1A },521 { 0xC0, 0x0F },522 { 0xC2, 0x0C },523 { 0xC3, 0x02 },524 { 0xC4, 0x0C },525 { 0xC5, 0x02 },526 { 0xB0, 0x01 },527 { 0xE0, 0x26 },528 { 0xE1, 0x26 },529 { 0xDC, 0x00 },530 { 0xDD, 0x00 },531 { 0xCC, 0x26 },532 { 0xCD, 0x26 },533 { 0xC8, 0x00 },534 { 0xC9, 0x00 },535 { 0xD2, 0x03 },536 { 0xD3, 0x03 },537 { 0xE6, 0x04 },538 { 0xE7, 0x04 },539 { 0xC4, 0x09 },540 { 0xC5, 0x09 },541 { 0xD8, 0x0A },542 { 0xD9, 0x0A },543 { 0xC2, 0x0B },544 { 0xC3, 0x0B },545 { 0xD6, 0x0C },546 { 0xD7, 0x0C },547 { 0xC0, 0x05 },548 { 0xC1, 0x05 },549 { 0xD4, 0x06 },550 { 0xD5, 0x06 },551 { 0xCA, 0x07 },552 { 0xCB, 0x07 },553 { 0xDE, 0x08 },554 { 0xDF, 0x08 },555 { 0xB0, 0x02 },556 { 0xC0, 0x00 },557 { 0xC1, 0x0D },558 { 0xC2, 0x17 },559 { 0xC3, 0x26 },560 { 0xC4, 0x31 },561 { 0xC5, 0x1C },562 { 0xC6, 0x2C },563 { 0xC7, 0x33 },564 { 0xC8, 0x31 },565 { 0xC9, 0x37 },566 { 0xCA, 0x37 },567 { 0xCB, 0x37 },568 { 0xCC, 0x39 },569 { 0xCD, 0x2E },570 { 0xCE, 0x2F },571 { 0xCF, 0x2F },572 { 0xD0, 0x07 },573 { 0xD2, 0x00 },574 { 0xD3, 0x0D },575 { 0xD4, 0x17 },576 { 0xD5, 0x26 },577 { 0xD6, 0x31 },578 { 0xD7, 0x3F },579 { 0xD8, 0x3F },580 { 0xD9, 0x3F },581 { 0xDA, 0x3F },582 { 0xDB, 0x37 },583 { 0xDC, 0x37 },584 { 0xDD, 0x37 },585 { 0xDE, 0x39 },586 { 0xDF, 0x2E },587 { 0xE0, 0x2F },588 { 0xE1, 0x2F },589 { 0xE2, 0x07 },590 { 0xB0, 0x03 },591 { 0xC8, 0x0B },592 { 0xC9, 0x07 },593 { 0xC3, 0x00 },594 { 0xE7, 0x00 },595 { 0xC5, 0x2A },596 { 0xDE, 0x2A },597 { 0xCA, 0x43 },598 { 0xC9, 0x07 },599 { 0xE4, 0xC0 },600 { 0xE5, 0x0D },601 { 0xCB, 0x01 },602 { 0xBC, 0x01 },603 { 0xB0, 0x06 },604 { 0xB8, 0xA5 },605 { 0xC0, 0xA5 },606 { 0xC7, 0x0F },607 { 0xD5, 0x32 },608 { 0xB8, 0x00 },609 { 0xC0, 0x00 },610 { 0xBC, 0x00 },611 { 0xB0, 0x07 },612 { 0xB1, 0x00 },613 { 0xB2, 0x05 },614 { 0xB3, 0x10 },615 { 0xB4, 0x22 },616 { 0xB5, 0x36 },617 { 0xB6, 0x4A },618 { 0xB7, 0x6C },619 { 0xB8, 0x9A },620 { 0xB9, 0xD7 },621 { 0xBA, 0x17 },622 { 0xBB, 0x92 },623 { 0xBC, 0x15 },624 { 0xBD, 0x18 },625 { 0xBE, 0x8C },626 { 0xBF, 0x00 },627 { 0xC0, 0x3A },628 { 0xC1, 0x72 },629 { 0xC2, 0x8C },630 { 0xC3, 0xA5 },631 { 0xC4, 0xB1 },632 { 0xC5, 0xBE },633 { 0xC6, 0xCA },634 { 0xC7, 0xD1 },635 { 0xC8, 0xD4 },636 { 0xC9, 0x00 },637 { 0xCA, 0x00 },638 { 0xCB, 0x16 },639 { 0xCC, 0xAF },640 { 0xCD, 0xFF },641 { 0xCE, 0xFF },642 { 0xB0, 0x08 },643 { 0xB1, 0x04 },644 { 0xB2, 0x05 },645 { 0xB3, 0x11 },646 { 0xB4, 0x24 },647 { 0xB5, 0x39 },648 { 0xB6, 0x4E },649 { 0xB7, 0x72 },650 { 0xB8, 0xA3 },651 { 0xB9, 0xE1 },652 { 0xBA, 0x25 },653 { 0xBB, 0xA8 },654 { 0xBC, 0x2E },655 { 0xBD, 0x32 },656 { 0xBE, 0xAD },657 { 0xBF, 0x28 },658 { 0xC0, 0x63 },659 { 0xC1, 0x9B },660 { 0xC2, 0xB5 },661 { 0xC3, 0xCF },662 { 0xC4, 0xDB },663 { 0xC5, 0xE8 },664 { 0xC6, 0xF5 },665 { 0xC7, 0xFA },666 { 0xC8, 0xFC },667 { 0xC9, 0x00 },668 { 0xCA, 0x00 },669 { 0xCB, 0x16 },670 { 0xCC, 0xAF },671 { 0xCD, 0xFF },672 { 0xCE, 0xFF },673 { 0xB0, 0x09 },674 { 0xB1, 0x04 },675 { 0xB2, 0x04 },676 { 0xB3, 0x0F },677 { 0xB4, 0x22 },678 { 0xB5, 0x37 },679 { 0xB6, 0x4D },680 { 0xB7, 0x71 },681 { 0xB8, 0xA2 },682 { 0xB9, 0xE1 },683 { 0xBA, 0x26 },684 { 0xBB, 0xA9 },685 { 0xBC, 0x2F },686 { 0xBD, 0x33 },687 { 0xBE, 0xAC },688 { 0xBF, 0x24 },689 { 0xC0, 0x5D },690 { 0xC1, 0x94 },691 { 0xC2, 0xAC },692 { 0xC3, 0xC5 },693 { 0xC4, 0xD1 },694 { 0xC5, 0xDC },695 { 0xC6, 0xE8 },696 { 0xC7, 0xED },697 { 0xC8, 0xF0 },698 { 0xC9, 0x00 },699 { 0xCA, 0x00 },700 { 0xCB, 0x16 },701 { 0xCC, 0xAF },702 { 0xCD, 0xFF },703 { 0xCE, 0xFF },704 { 0xB0, 0x0A },705 { 0xB1, 0x00 },706 { 0xB2, 0x05 },707 { 0xB3, 0x10 },708 { 0xB4, 0x22 },709 { 0xB5, 0x36 },710 { 0xB6, 0x4A },711 { 0xB7, 0x6C },712 { 0xB8, 0x9A },713 { 0xB9, 0xD7 },714 { 0xBA, 0x17 },715 { 0xBB, 0x92 },716 { 0xBC, 0x15 },717 { 0xBD, 0x18 },718 { 0xBE, 0x8C },719 { 0xBF, 0x00 },720 { 0xC0, 0x3A },721 { 0xC1, 0x72 },722 { 0xC2, 0x8C },723 { 0xC3, 0xA5 },724 { 0xC4, 0xB1 },725 { 0xC5, 0xBE },726 { 0xC6, 0xCA },727 { 0xC7, 0xD1 },728 { 0xC8, 0xD4 },729 { 0xC9, 0x00 },730 { 0xCA, 0x00 },731 { 0xCB, 0x16 },732 { 0xCC, 0xAF },733 { 0xCD, 0xFF },734 { 0xCE, 0xFF },735 { 0xB0, 0x0B },736 { 0xB1, 0x04 },737 { 0xB2, 0x05 },738 { 0xB3, 0x11 },739 { 0xB4, 0x24 },740 { 0xB5, 0x39 },741 { 0xB6, 0x4E },742 { 0xB7, 0x72 },743 { 0xB8, 0xA3 },744 { 0xB9, 0xE1 },745 { 0xBA, 0x25 },746 { 0xBB, 0xA8 },747 { 0xBC, 0x2E },748 { 0xBD, 0x32 },749 { 0xBE, 0xAD },750 { 0xBF, 0x28 },751 { 0xC0, 0x63 },752 { 0xC1, 0x9B },753 { 0xC2, 0xB5 },754 { 0xC3, 0xCF },755 { 0xC4, 0xDB },756 { 0xC5, 0xE8 },757 { 0xC6, 0xF5 },758 { 0xC7, 0xFA },759 { 0xC8, 0xFC },760 { 0xC9, 0x00 },761 { 0xCA, 0x00 },762 { 0xCB, 0x16 },763 { 0xCC, 0xAF },764 { 0xCD, 0xFF },765 { 0xCE, 0xFF },766 { 0xB0, 0x0C },767 { 0xB1, 0x04 },768 { 0xB2, 0x04 },769 { 0xB3, 0x0F },770 { 0xB4, 0x22 },771 { 0xB5, 0x37 },772 { 0xB6, 0x4D },773 { 0xB7, 0x71 },774 { 0xB8, 0xA2 },775 { 0xB9, 0xE1 },776 { 0xBA, 0x26 },777 { 0xBB, 0xA9 },778 { 0xBC, 0x2F },779 { 0xBD, 0x33 },780 { 0xBE, 0xAC },781 { 0xBF, 0x24 },782 { 0xC0, 0x5D },783 { 0xC1, 0x94 },784 { 0xC2, 0xAC },785 { 0xC3, 0xC5 },786 { 0xC4, 0xD1 },787 { 0xC5, 0xDC },788 { 0xC6, 0xE8 },789 { 0xC7, 0xED },790 { 0xC8, 0xF0 },791 { 0xC9, 0x00 },792 { 0xCA, 0x00 },793 { 0xCB, 0x16 },794 { 0xCC, 0xAF },795 { 0xCD, 0xFF },796 { 0xCE, 0xFF },797};798 799static const struct panel_desc boe_himax8279d10p_panel_desc = {800 .display_mode = &default_display_mode,801 .bpc = 8,802 .width_mm = 135,803 .height_mm = 216,804 .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |805 MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM,806 .format = MIPI_DSI_FMT_RGB888,807 .lanes = 4,808 .on_cmds = boe_himax8279d10p_on_cmds,809 .on_cmds_num = 283,810};811 812static const struct of_device_id panel_of_match[] = {813 {814 .compatible = "boe,himax8279d8p",815 .data = &boe_himax8279d8p_panel_desc,816 },817 {818 .compatible = "boe,himax8279d10p",819 .data = &boe_himax8279d10p_panel_desc,820 },821 {822 /* sentinel */823 }824};825MODULE_DEVICE_TABLE(of, panel_of_match);826 827static int panel_add(struct panel_info *pinfo)828{829 struct device *dev = &pinfo->link->dev;830 int ret;831 832 pinfo->pp18_gpio = devm_gpiod_get(dev, "pp18", GPIOD_OUT_HIGH);833 if (IS_ERR(pinfo->pp18_gpio)) {834 return dev_err_probe(dev, PTR_ERR(pinfo->pp18_gpio),835 "failed to get pp18 gpio\n");836 }837 838 pinfo->pp33_gpio = devm_gpiod_get(dev, "pp33", GPIOD_OUT_HIGH);839 if (IS_ERR(pinfo->pp33_gpio)) {840 return dev_err_probe(dev, PTR_ERR(pinfo->pp33_gpio),841 "failed to get pp33 gpio\n");842 }843 844 pinfo->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_HIGH);845 if (IS_ERR(pinfo->enable_gpio)) {846 return dev_err_probe(dev, PTR_ERR(pinfo->enable_gpio),847 "failed to get enable gpio\n");848 }849 850 drm_panel_init(&pinfo->base, dev, &panel_funcs,851 DRM_MODE_CONNECTOR_DSI);852 853 ret = drm_panel_of_backlight(&pinfo->base);854 if (ret)855 return ret;856 857 drm_panel_add(&pinfo->base);858 859 return 0;860}861 862static int panel_probe(struct mipi_dsi_device *dsi)863{864 struct panel_info *pinfo;865 const struct panel_desc *desc;866 int err;867 868 pinfo = devm_kzalloc(&dsi->dev, sizeof(*pinfo), GFP_KERNEL);869 if (!pinfo)870 return -ENOMEM;871 872 desc = of_device_get_match_data(&dsi->dev);873 dsi->mode_flags = desc->mode_flags;874 dsi->format = desc->format;875 dsi->lanes = desc->lanes;876 pinfo->desc = desc;877 878 pinfo->link = dsi;879 mipi_dsi_set_drvdata(dsi, pinfo);880 881 err = panel_add(pinfo);882 if (err < 0)883 return err;884 885 err = mipi_dsi_attach(dsi);886 if (err < 0)887 drm_panel_remove(&pinfo->base);888 889 return err;890}891 892static void panel_remove(struct mipi_dsi_device *dsi)893{894 struct panel_info *pinfo = mipi_dsi_get_drvdata(dsi);895 int err;896 897 err = mipi_dsi_detach(dsi);898 if (err < 0)899 dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err);900 901 drm_panel_remove(&pinfo->base);902}903 904static struct mipi_dsi_driver panel_driver = {905 .driver = {906 .name = "panel-boe-himax8279d",907 .of_match_table = panel_of_match,908 },909 .probe = panel_probe,910 .remove = panel_remove,911};912module_mipi_dsi_driver(panel_driver);913 914MODULE_AUTHOR("Jerry Han <jerry.han.hq@gmail.com>");915MODULE_DESCRIPTION("Boe Himax8279d driver");916MODULE_LICENSE("GPL v2");917