0001
0002
0003
0004
0005
0006 #include <linux/delay.h>
0007 #include <linux/gpio/consumer.h>
0008 #include <linux/module.h>
0009 #include <linux/of.h>
0010 #include <linux/of_device.h>
0011 #include <linux/regulator/consumer.h>
0012
0013 #include <video/mipi_display.h>
0014
0015 #include <drm/drm_crtc.h>
0016 #include <drm/drm_device.h>
0017 #include <drm/drm_mipi_dsi.h>
0018 #include <drm/drm_modes.h>
0019 #include <drm/drm_panel.h>
0020
0021 struct panel_init_cmd {
0022 size_t len;
0023 const char *data;
0024 };
0025
0026 #define _INIT_CMD(...) { \
0027 .len = sizeof((char[]){__VA_ARGS__}), \
0028 .data = (char[]){__VA_ARGS__} }
0029
0030 struct panel_desc {
0031 const struct drm_display_mode *mode;
0032 unsigned int bpc;
0033 struct {
0034 unsigned int width;
0035 unsigned int height;
0036 } size;
0037
0038 unsigned long flags;
0039 enum mipi_dsi_pixel_format format;
0040 const struct panel_init_cmd *init_cmds;
0041 unsigned int lanes;
0042 const char * const *supply_names;
0043 unsigned int num_supplies;
0044 unsigned int sleep_mode_delay;
0045 unsigned int power_down_delay;
0046 };
0047
0048 struct innolux_panel {
0049 struct drm_panel base;
0050 struct mipi_dsi_device *link;
0051 const struct panel_desc *desc;
0052
0053 struct regulator_bulk_data *supplies;
0054 struct gpio_desc *enable_gpio;
0055
0056 bool prepared;
0057 bool enabled;
0058 };
0059
0060 static inline struct innolux_panel *to_innolux_panel(struct drm_panel *panel)
0061 {
0062 return container_of(panel, struct innolux_panel, base);
0063 }
0064
0065 static int innolux_panel_disable(struct drm_panel *panel)
0066 {
0067 struct innolux_panel *innolux = to_innolux_panel(panel);
0068
0069 if (!innolux->enabled)
0070 return 0;
0071
0072 innolux->enabled = false;
0073
0074 return 0;
0075 }
0076
0077 static int innolux_panel_unprepare(struct drm_panel *panel)
0078 {
0079 struct innolux_panel *innolux = to_innolux_panel(panel);
0080 int err;
0081
0082 if (!innolux->prepared)
0083 return 0;
0084
0085 err = mipi_dsi_dcs_set_display_off(innolux->link);
0086 if (err < 0)
0087 dev_err(panel->dev, "failed to set display off: %d\n", err);
0088
0089 err = mipi_dsi_dcs_enter_sleep_mode(innolux->link);
0090 if (err < 0) {
0091 dev_err(panel->dev, "failed to enter sleep mode: %d\n", err);
0092 return err;
0093 }
0094
0095 if (innolux->desc->sleep_mode_delay)
0096 msleep(innolux->desc->sleep_mode_delay);
0097
0098 gpiod_set_value_cansleep(innolux->enable_gpio, 0);
0099
0100 if (innolux->desc->power_down_delay)
0101 msleep(innolux->desc->power_down_delay);
0102
0103 err = regulator_bulk_disable(innolux->desc->num_supplies,
0104 innolux->supplies);
0105 if (err < 0)
0106 return err;
0107
0108 innolux->prepared = false;
0109
0110 return 0;
0111 }
0112
0113 static int innolux_panel_prepare(struct drm_panel *panel)
0114 {
0115 struct innolux_panel *innolux = to_innolux_panel(panel);
0116 int err;
0117
0118 if (innolux->prepared)
0119 return 0;
0120
0121 gpiod_set_value_cansleep(innolux->enable_gpio, 0);
0122
0123 err = regulator_bulk_enable(innolux->desc->num_supplies,
0124 innolux->supplies);
0125 if (err < 0)
0126 return err;
0127
0128
0129 usleep_range(20000, 21000);
0130
0131 gpiod_set_value_cansleep(innolux->enable_gpio, 1);
0132
0133
0134 usleep_range(20000, 21000);
0135
0136 if (innolux->desc->init_cmds) {
0137 const struct panel_init_cmd *cmds =
0138 innolux->desc->init_cmds;
0139 unsigned int i;
0140
0141 for (i = 0; cmds[i].len != 0; i++) {
0142 const struct panel_init_cmd *cmd = &cmds[i];
0143
0144 err = mipi_dsi_generic_write(innolux->link, cmd->data,
0145 cmd->len);
0146 if (err < 0) {
0147 dev_err(panel->dev, "failed to write command %u\n", i);
0148 goto poweroff;
0149 }
0150
0151
0152
0153
0154
0155
0156 err = mipi_dsi_dcs_nop(innolux->link);
0157 if (err < 0) {
0158 dev_err(panel->dev, "failed to send DCS nop: %d\n", err);
0159 goto poweroff;
0160 }
0161 }
0162 }
0163
0164 err = mipi_dsi_dcs_exit_sleep_mode(innolux->link);
0165 if (err < 0) {
0166 dev_err(panel->dev, "failed to exit sleep mode: %d\n", err);
0167 goto poweroff;
0168 }
0169
0170
0171 msleep(120);
0172
0173 err = mipi_dsi_dcs_set_display_on(innolux->link);
0174 if (err < 0) {
0175 dev_err(panel->dev, "failed to set display on: %d\n", err);
0176 goto poweroff;
0177 }
0178
0179
0180 usleep_range(5000, 6000);
0181
0182 innolux->prepared = true;
0183
0184 return 0;
0185
0186 poweroff:
0187 gpiod_set_value_cansleep(innolux->enable_gpio, 0);
0188 regulator_bulk_disable(innolux->desc->num_supplies, innolux->supplies);
0189
0190 return err;
0191 }
0192
0193 static int innolux_panel_enable(struct drm_panel *panel)
0194 {
0195 struct innolux_panel *innolux = to_innolux_panel(panel);
0196
0197 if (innolux->enabled)
0198 return 0;
0199
0200 innolux->enabled = true;
0201
0202 return 0;
0203 }
0204
0205 static const char * const innolux_p079zca_supply_names[] = {
0206 "power",
0207 };
0208
0209 static const struct drm_display_mode innolux_p079zca_mode = {
0210 .clock = 56900,
0211 .hdisplay = 768,
0212 .hsync_start = 768 + 40,
0213 .hsync_end = 768 + 40 + 40,
0214 .htotal = 768 + 40 + 40 + 40,
0215 .vdisplay = 1024,
0216 .vsync_start = 1024 + 20,
0217 .vsync_end = 1024 + 20 + 4,
0218 .vtotal = 1024 + 20 + 4 + 20,
0219 };
0220
0221 static const struct panel_desc innolux_p079zca_panel_desc = {
0222 .mode = &innolux_p079zca_mode,
0223 .bpc = 8,
0224 .size = {
0225 .width = 120,
0226 .height = 160,
0227 },
0228 .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
0229 MIPI_DSI_MODE_LPM,
0230 .format = MIPI_DSI_FMT_RGB888,
0231 .lanes = 4,
0232 .supply_names = innolux_p079zca_supply_names,
0233 .num_supplies = ARRAY_SIZE(innolux_p079zca_supply_names),
0234 .power_down_delay = 80,
0235 };
0236
0237 static const char * const innolux_p097pfg_supply_names[] = {
0238 "avdd",
0239 "avee",
0240 };
0241
0242 static const struct drm_display_mode innolux_p097pfg_mode = {
0243 .clock = 229000,
0244 .hdisplay = 1536,
0245 .hsync_start = 1536 + 100,
0246 .hsync_end = 1536 + 100 + 24,
0247 .htotal = 1536 + 100 + 24 + 100,
0248 .vdisplay = 2048,
0249 .vsync_start = 2048 + 100,
0250 .vsync_end = 2048 + 100 + 2,
0251 .vtotal = 2048 + 100 + 2 + 18,
0252 };
0253
0254
0255
0256
0257
0258
0259 static const struct panel_init_cmd innolux_p097pfg_init_cmds[] = {
0260
0261 _INIT_CMD(0xF0, 0x55, 0xAA, 0x52, 0x08, 0x00),
0262 _INIT_CMD(0xB1, 0xE8, 0x11),
0263 _INIT_CMD(0xB2, 0x25, 0x02),
0264 _INIT_CMD(0xB5, 0x08, 0x00),
0265 _INIT_CMD(0xBC, 0x0F, 0x00),
0266 _INIT_CMD(0xB8, 0x03, 0x06, 0x00, 0x00),
0267 _INIT_CMD(0xBD, 0x01, 0x90, 0x14, 0x14),
0268 _INIT_CMD(0x6F, 0x01),
0269 _INIT_CMD(0xC0, 0x03),
0270 _INIT_CMD(0x6F, 0x02),
0271 _INIT_CMD(0xC1, 0x0D),
0272 _INIT_CMD(0xD9, 0x01, 0x09, 0x70),
0273 _INIT_CMD(0xC5, 0x12, 0x21, 0x00),
0274 _INIT_CMD(0xBB, 0x93, 0x93),
0275
0276
0277 _INIT_CMD(0xF0, 0x55, 0xAA, 0x52, 0x08, 0x01),
0278 _INIT_CMD(0xB3, 0x3C, 0x3C),
0279 _INIT_CMD(0xB4, 0x0F, 0x0F),
0280 _INIT_CMD(0xB9, 0x45, 0x45),
0281 _INIT_CMD(0xBA, 0x14, 0x14),
0282 _INIT_CMD(0xCA, 0x02),
0283 _INIT_CMD(0xCE, 0x04),
0284 _INIT_CMD(0xC3, 0x9B, 0x9B),
0285 _INIT_CMD(0xD8, 0xC0, 0x03),
0286 _INIT_CMD(0xBC, 0x82, 0x01),
0287 _INIT_CMD(0xBD, 0x9E, 0x01),
0288
0289
0290 _INIT_CMD(0xF0, 0x55, 0xAA, 0x52, 0x08, 0x02),
0291 _INIT_CMD(0xB0, 0x82),
0292 _INIT_CMD(0xD1, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x82, 0x00, 0xA5,
0293 0x00, 0xC1, 0x00, 0xEA, 0x01, 0x0D, 0x01, 0x40),
0294 _INIT_CMD(0xD2, 0x01, 0x6A, 0x01, 0xA8, 0x01, 0xDC, 0x02, 0x29,
0295 0x02, 0x67, 0x02, 0x68, 0x02, 0xA8, 0x02, 0xF0),
0296 _INIT_CMD(0xD3, 0x03, 0x19, 0x03, 0x49, 0x03, 0x67, 0x03, 0x8C,
0297 0x03, 0xA6, 0x03, 0xC7, 0x03, 0xDE, 0x03, 0xEC),
0298 _INIT_CMD(0xD4, 0x03, 0xFF, 0x03, 0xFF),
0299 _INIT_CMD(0xE0, 0x00, 0x00, 0x00, 0x86, 0x00, 0xC5, 0x00, 0xE5,
0300 0x00, 0xFF, 0x01, 0x26, 0x01, 0x45, 0x01, 0x75),
0301 _INIT_CMD(0xE1, 0x01, 0x9C, 0x01, 0xD5, 0x02, 0x05, 0x02, 0x4D,
0302 0x02, 0x86, 0x02, 0x87, 0x02, 0xC3, 0x03, 0x03),
0303 _INIT_CMD(0xE2, 0x03, 0x2A, 0x03, 0x56, 0x03, 0x72, 0x03, 0x94,
0304 0x03, 0xAC, 0x03, 0xCB, 0x03, 0xE0, 0x03, 0xED),
0305 _INIT_CMD(0xE3, 0x03, 0xFF, 0x03, 0xFF),
0306
0307
0308 _INIT_CMD(0xF0, 0x55, 0xAA, 0x52, 0x08, 0x03),
0309 _INIT_CMD(0xB0, 0x00, 0x00, 0x00, 0x00),
0310 _INIT_CMD(0xB1, 0x00, 0x00, 0x00, 0x00),
0311 _INIT_CMD(0xB2, 0x00, 0x00, 0x06, 0x04, 0x01, 0x40, 0x85),
0312 _INIT_CMD(0xB3, 0x10, 0x07, 0xFC, 0x04, 0x01, 0x40, 0x80),
0313 _INIT_CMD(0xB6, 0xF0, 0x08, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01,
0314 0x40, 0x80),
0315 _INIT_CMD(0xBA, 0xC5, 0x07, 0x00, 0x04, 0x11, 0x25, 0x8C),
0316 _INIT_CMD(0xBB, 0xC5, 0x07, 0x00, 0x03, 0x11, 0x25, 0x8C),
0317 _INIT_CMD(0xC0, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x80, 0x80),
0318 _INIT_CMD(0xC1, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x80, 0x80),
0319 _INIT_CMD(0xC4, 0x00, 0x00),
0320 _INIT_CMD(0xEF, 0x41),
0321
0322
0323 _INIT_CMD(0xF0, 0x55, 0xAA, 0x52, 0x08, 0x04),
0324 _INIT_CMD(0xEC, 0x4C),
0325
0326
0327 _INIT_CMD(0xF0, 0x55, 0xAA, 0x52, 0x08, 0x05),
0328 _INIT_CMD(0xB0, 0x13, 0x03, 0x03, 0x01),
0329 _INIT_CMD(0xB1, 0x30, 0x00),
0330 _INIT_CMD(0xB2, 0x02, 0x02, 0x00),
0331 _INIT_CMD(0xB3, 0x82, 0x23, 0x82, 0x9D),
0332 _INIT_CMD(0xB4, 0xC5, 0x75, 0x24, 0x57),
0333 _INIT_CMD(0xB5, 0x00, 0xD4, 0x72, 0x11, 0x11, 0xAB, 0x0A),
0334 _INIT_CMD(0xB6, 0x00, 0x00, 0xD5, 0x72, 0x24, 0x56),
0335 _INIT_CMD(0xB7, 0x5C, 0xDC, 0x5C, 0x5C),
0336 _INIT_CMD(0xB9, 0x0C, 0x00, 0x00, 0x01, 0x00),
0337 _INIT_CMD(0xC0, 0x75, 0x11, 0x11, 0x54, 0x05),
0338 _INIT_CMD(0xC6, 0x00, 0x00, 0x00, 0x00),
0339 _INIT_CMD(0xD0, 0x00, 0x48, 0x08, 0x00, 0x00),
0340 _INIT_CMD(0xD1, 0x00, 0x48, 0x09, 0x00, 0x00),
0341
0342
0343 _INIT_CMD(0xF0, 0x55, 0xAA, 0x52, 0x08, 0x06),
0344 _INIT_CMD(0xB0, 0x02, 0x32, 0x32, 0x08, 0x2F),
0345 _INIT_CMD(0xB1, 0x2E, 0x15, 0x14, 0x13, 0x12),
0346 _INIT_CMD(0xB2, 0x11, 0x10, 0x00, 0x3D, 0x3D),
0347 _INIT_CMD(0xB3, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D),
0348 _INIT_CMD(0xB4, 0x3D, 0x32),
0349 _INIT_CMD(0xB5, 0x03, 0x32, 0x32, 0x09, 0x2F),
0350 _INIT_CMD(0xB6, 0x2E, 0x1B, 0x1A, 0x19, 0x18),
0351 _INIT_CMD(0xB7, 0x17, 0x16, 0x01, 0x3D, 0x3D),
0352 _INIT_CMD(0xB8, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D),
0353 _INIT_CMD(0xB9, 0x3D, 0x32),
0354 _INIT_CMD(0xC0, 0x01, 0x32, 0x32, 0x09, 0x2F),
0355 _INIT_CMD(0xC1, 0x2E, 0x1A, 0x1B, 0x16, 0x17),
0356 _INIT_CMD(0xC2, 0x18, 0x19, 0x03, 0x3D, 0x3D),
0357 _INIT_CMD(0xC3, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D),
0358 _INIT_CMD(0xC4, 0x3D, 0x32),
0359 _INIT_CMD(0xC5, 0x00, 0x32, 0x32, 0x08, 0x2F),
0360 _INIT_CMD(0xC6, 0x2E, 0x14, 0x15, 0x10, 0x11),
0361 _INIT_CMD(0xC7, 0x12, 0x13, 0x02, 0x3D, 0x3D),
0362 _INIT_CMD(0xC8, 0x3D, 0x3D, 0x3D, 0x3D, 0x3D),
0363 _INIT_CMD(0xC9, 0x3D, 0x32),
0364
0365 {},
0366 };
0367
0368 static const struct panel_desc innolux_p097pfg_panel_desc = {
0369 .mode = &innolux_p097pfg_mode,
0370 .bpc = 8,
0371 .size = {
0372 .width = 147,
0373 .height = 196,
0374 },
0375 .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
0376 MIPI_DSI_MODE_LPM,
0377 .format = MIPI_DSI_FMT_RGB888,
0378 .init_cmds = innolux_p097pfg_init_cmds,
0379 .lanes = 4,
0380 .supply_names = innolux_p097pfg_supply_names,
0381 .num_supplies = ARRAY_SIZE(innolux_p097pfg_supply_names),
0382 .sleep_mode_delay = 100,
0383 };
0384
0385 static int innolux_panel_get_modes(struct drm_panel *panel,
0386 struct drm_connector *connector)
0387 {
0388 struct innolux_panel *innolux = to_innolux_panel(panel);
0389 const struct drm_display_mode *m = innolux->desc->mode;
0390 struct drm_display_mode *mode;
0391
0392 mode = drm_mode_duplicate(connector->dev, m);
0393 if (!mode) {
0394 dev_err(panel->dev, "failed to add mode %ux%u@%u\n",
0395 m->hdisplay, m->vdisplay, drm_mode_vrefresh(m));
0396 return -ENOMEM;
0397 }
0398
0399 drm_mode_set_name(mode);
0400
0401 drm_mode_probed_add(connector, mode);
0402
0403 connector->display_info.width_mm = innolux->desc->size.width;
0404 connector->display_info.height_mm = innolux->desc->size.height;
0405 connector->display_info.bpc = innolux->desc->bpc;
0406
0407 return 1;
0408 }
0409
0410 static const struct drm_panel_funcs innolux_panel_funcs = {
0411 .disable = innolux_panel_disable,
0412 .unprepare = innolux_panel_unprepare,
0413 .prepare = innolux_panel_prepare,
0414 .enable = innolux_panel_enable,
0415 .get_modes = innolux_panel_get_modes,
0416 };
0417
0418 static const struct of_device_id innolux_of_match[] = {
0419 { .compatible = "innolux,p079zca",
0420 .data = &innolux_p079zca_panel_desc
0421 },
0422 { .compatible = "innolux,p097pfg",
0423 .data = &innolux_p097pfg_panel_desc
0424 },
0425 { }
0426 };
0427 MODULE_DEVICE_TABLE(of, innolux_of_match);
0428
0429 static int innolux_panel_add(struct mipi_dsi_device *dsi,
0430 const struct panel_desc *desc)
0431 {
0432 struct innolux_panel *innolux;
0433 struct device *dev = &dsi->dev;
0434 int err, i;
0435
0436 innolux = devm_kzalloc(dev, sizeof(*innolux), GFP_KERNEL);
0437 if (!innolux)
0438 return -ENOMEM;
0439
0440 innolux->desc = desc;
0441
0442 innolux->supplies = devm_kcalloc(dev, desc->num_supplies,
0443 sizeof(*innolux->supplies),
0444 GFP_KERNEL);
0445 if (!innolux->supplies)
0446 return -ENOMEM;
0447
0448 for (i = 0; i < desc->num_supplies; i++)
0449 innolux->supplies[i].supply = desc->supply_names[i];
0450
0451 err = devm_regulator_bulk_get(dev, desc->num_supplies,
0452 innolux->supplies);
0453 if (err < 0)
0454 return err;
0455
0456 innolux->enable_gpio = devm_gpiod_get_optional(dev, "enable",
0457 GPIOD_OUT_HIGH);
0458 if (IS_ERR(innolux->enable_gpio)) {
0459 err = PTR_ERR(innolux->enable_gpio);
0460 dev_dbg(dev, "failed to get enable gpio: %d\n", err);
0461 innolux->enable_gpio = NULL;
0462 }
0463
0464 drm_panel_init(&innolux->base, dev, &innolux_panel_funcs,
0465 DRM_MODE_CONNECTOR_DSI);
0466
0467 err = drm_panel_of_backlight(&innolux->base);
0468 if (err)
0469 return err;
0470
0471 drm_panel_add(&innolux->base);
0472
0473 mipi_dsi_set_drvdata(dsi, innolux);
0474 innolux->link = dsi;
0475
0476 return 0;
0477 }
0478
0479 static void innolux_panel_del(struct innolux_panel *innolux)
0480 {
0481 drm_panel_remove(&innolux->base);
0482 }
0483
0484 static int innolux_panel_probe(struct mipi_dsi_device *dsi)
0485 {
0486 const struct panel_desc *desc;
0487 struct innolux_panel *innolux;
0488 int err;
0489
0490 desc = of_device_get_match_data(&dsi->dev);
0491 dsi->mode_flags = desc->flags;
0492 dsi->format = desc->format;
0493 dsi->lanes = desc->lanes;
0494
0495 err = innolux_panel_add(dsi, desc);
0496 if (err < 0)
0497 return err;
0498
0499 err = mipi_dsi_attach(dsi);
0500 if (err < 0) {
0501 innolux = mipi_dsi_get_drvdata(dsi);
0502 innolux_panel_del(innolux);
0503 return err;
0504 }
0505
0506 return 0;
0507 }
0508
0509 static int innolux_panel_remove(struct mipi_dsi_device *dsi)
0510 {
0511 struct innolux_panel *innolux = mipi_dsi_get_drvdata(dsi);
0512 int err;
0513
0514 err = drm_panel_unprepare(&innolux->base);
0515 if (err < 0)
0516 dev_err(&dsi->dev, "failed to unprepare panel: %d\n", err);
0517
0518 err = drm_panel_disable(&innolux->base);
0519 if (err < 0)
0520 dev_err(&dsi->dev, "failed to disable panel: %d\n", err);
0521
0522 err = mipi_dsi_detach(dsi);
0523 if (err < 0)
0524 dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err);
0525
0526 innolux_panel_del(innolux);
0527
0528 return 0;
0529 }
0530
0531 static void innolux_panel_shutdown(struct mipi_dsi_device *dsi)
0532 {
0533 struct innolux_panel *innolux = mipi_dsi_get_drvdata(dsi);
0534
0535 drm_panel_unprepare(&innolux->base);
0536 drm_panel_disable(&innolux->base);
0537 }
0538
0539 static struct mipi_dsi_driver innolux_panel_driver = {
0540 .driver = {
0541 .name = "panel-innolux-p079zca",
0542 .of_match_table = innolux_of_match,
0543 },
0544 .probe = innolux_panel_probe,
0545 .remove = innolux_panel_remove,
0546 .shutdown = innolux_panel_shutdown,
0547 };
0548 module_mipi_dsi_driver(innolux_panel_driver);
0549
0550 MODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>");
0551 MODULE_AUTHOR("Lin Huang <hl@rock-chips.com>");
0552 MODULE_DESCRIPTION("Innolux P079ZCA panel driver");
0553 MODULE_LICENSE("GPL v2");