Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * Copyright (c) 2017, Fuzhou Rockchip Electronics Co., Ltd
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/regulator/consumer.h>
0011 
0012 #include <video/mipi_display.h>
0013 
0014 #include <drm/drm_crtc.h>
0015 #include <drm/drm_device.h>
0016 #include <drm/drm_mipi_dsi.h>
0017 #include <drm/drm_modes.h>
0018 #include <drm/drm_panel.h>
0019 
0020 struct kingdisplay_panel {
0021     struct drm_panel base;
0022     struct mipi_dsi_device *link;
0023 
0024     struct regulator *supply;
0025     struct gpio_desc *enable_gpio;
0026 
0027     bool prepared;
0028     bool enabled;
0029 };
0030 
0031 struct kingdisplay_panel_cmd {
0032     char cmd;
0033     char data;
0034 };
0035 
0036 /*
0037  * According to the discussion on
0038  * https://review.coreboot.org/#/c/coreboot/+/22472/
0039  * the panel init array is not part of the panels datasheet but instead
0040  * just came in this form from the panel vendor.
0041  */
0042 static const struct kingdisplay_panel_cmd init_code[] = {
0043     /* voltage setting */
0044     { 0xB0, 0x00 },
0045     { 0xB2, 0x02 },
0046     { 0xB3, 0x11 },
0047     { 0xB4, 0x00 },
0048     { 0xB6, 0x80 },
0049     /* VCOM disable */
0050     { 0xB7, 0x02 },
0051     { 0xB8, 0x80 },
0052     { 0xBA, 0x43 },
0053     /* VCOM setting */
0054     { 0xBB, 0x53 },
0055     /* VSP setting */
0056     { 0xBC, 0x0A },
0057     /* VSN setting */
0058     { 0xBD, 0x4A },
0059     /* VGH setting */
0060     { 0xBE, 0x2F },
0061     /* VGL setting */
0062     { 0xBF, 0x1A },
0063     { 0xF0, 0x39 },
0064     { 0xF1, 0x22 },
0065     /* Gamma setting */
0066     { 0xB0, 0x02 },
0067     { 0xC0, 0x00 },
0068     { 0xC1, 0x01 },
0069     { 0xC2, 0x0B },
0070     { 0xC3, 0x15 },
0071     { 0xC4, 0x22 },
0072     { 0xC5, 0x11 },
0073     { 0xC6, 0x15 },
0074     { 0xC7, 0x19 },
0075     { 0xC8, 0x1A },
0076     { 0xC9, 0x16 },
0077     { 0xCA, 0x18 },
0078     { 0xCB, 0x13 },
0079     { 0xCC, 0x18 },
0080     { 0xCD, 0x13 },
0081     { 0xCE, 0x1C },
0082     { 0xCF, 0x19 },
0083     { 0xD0, 0x21 },
0084     { 0xD1, 0x2C },
0085     { 0xD2, 0x2F },
0086     { 0xD3, 0x30 },
0087     { 0xD4, 0x19 },
0088     { 0xD5, 0x1F },
0089     { 0xD6, 0x00 },
0090     { 0xD7, 0x01 },
0091     { 0xD8, 0x0B },
0092     { 0xD9, 0x15 },
0093     { 0xDA, 0x22 },
0094     { 0xDB, 0x11 },
0095     { 0xDC, 0x15 },
0096     { 0xDD, 0x19 },
0097     { 0xDE, 0x1A },
0098     { 0xDF, 0x16 },
0099     { 0xE0, 0x18 },
0100     { 0xE1, 0x13 },
0101     { 0xE2, 0x18 },
0102     { 0xE3, 0x13 },
0103     { 0xE4, 0x1C },
0104     { 0xE5, 0x19 },
0105     { 0xE6, 0x21 },
0106     { 0xE7, 0x2C },
0107     { 0xE8, 0x2F },
0108     { 0xE9, 0x30 },
0109     { 0xEA, 0x19 },
0110     { 0xEB, 0x1F },
0111     /* GOA MUX setting */
0112     { 0xB0, 0x01 },
0113     { 0xC0, 0x10 },
0114     { 0xC1, 0x0F },
0115     { 0xC2, 0x0E },
0116     { 0xC3, 0x0D },
0117     { 0xC4, 0x0C },
0118     { 0xC5, 0x0B },
0119     { 0xC6, 0x0A },
0120     { 0xC7, 0x09 },
0121     { 0xC8, 0x08 },
0122     { 0xC9, 0x07 },
0123     { 0xCA, 0x06 },
0124     { 0xCB, 0x05 },
0125     { 0xCC, 0x00 },
0126     { 0xCD, 0x01 },
0127     { 0xCE, 0x02 },
0128     { 0xCF, 0x03 },
0129     { 0xD0, 0x04 },
0130     { 0xD6, 0x10 },
0131     { 0xD7, 0x0F },
0132     { 0xD8, 0x0E },
0133     { 0xD9, 0x0D },
0134     { 0xDA, 0x0C },
0135     { 0xDB, 0x0B },
0136     { 0xDC, 0x0A },
0137     { 0xDD, 0x09 },
0138     { 0xDE, 0x08 },
0139     { 0xDF, 0x07 },
0140     { 0xE0, 0x06 },
0141     { 0xE1, 0x05 },
0142     { 0xE2, 0x00 },
0143     { 0xE3, 0x01 },
0144     { 0xE4, 0x02 },
0145     { 0xE5, 0x03 },
0146     { 0xE6, 0x04 },
0147     { 0xE7, 0x00 },
0148     { 0xEC, 0xC0 },
0149     /* GOA timing setting */
0150     { 0xB0, 0x03 },
0151     { 0xC0, 0x01 },
0152     { 0xC2, 0x6F },
0153     { 0xC3, 0x6F },
0154     { 0xC5, 0x36 },
0155     { 0xC8, 0x08 },
0156     { 0xC9, 0x04 },
0157     { 0xCA, 0x41 },
0158     { 0xCC, 0x43 },
0159     { 0xCF, 0x60 },
0160     { 0xD2, 0x04 },
0161     { 0xD3, 0x04 },
0162     { 0xD4, 0x03 },
0163     { 0xD5, 0x02 },
0164     { 0xD6, 0x01 },
0165     { 0xD7, 0x00 },
0166     { 0xDB, 0x01 },
0167     { 0xDE, 0x36 },
0168     { 0xE6, 0x6F },
0169     { 0xE7, 0x6F },
0170     /* GOE setting */
0171     { 0xB0, 0x06 },
0172     { 0xB8, 0xA5 },
0173     { 0xC0, 0xA5 },
0174     { 0xD5, 0x3F },
0175 };
0176 
0177 static inline
0178 struct kingdisplay_panel *to_kingdisplay_panel(struct drm_panel *panel)
0179 {
0180     return container_of(panel, struct kingdisplay_panel, base);
0181 }
0182 
0183 static int kingdisplay_panel_disable(struct drm_panel *panel)
0184 {
0185     struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
0186     int err;
0187 
0188     if (!kingdisplay->enabled)
0189         return 0;
0190 
0191     err = mipi_dsi_dcs_set_display_off(kingdisplay->link);
0192     if (err < 0)
0193         dev_err(panel->dev, "failed to set display off: %d\n", err);
0194 
0195     kingdisplay->enabled = false;
0196 
0197     return 0;
0198 }
0199 
0200 static int kingdisplay_panel_unprepare(struct drm_panel *panel)
0201 {
0202     struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
0203     int err;
0204 
0205     if (!kingdisplay->prepared)
0206         return 0;
0207 
0208     err = mipi_dsi_dcs_enter_sleep_mode(kingdisplay->link);
0209     if (err < 0) {
0210         dev_err(panel->dev, "failed to enter sleep mode: %d\n", err);
0211         return err;
0212     }
0213 
0214     /* T15: 120ms */
0215     msleep(120);
0216 
0217     gpiod_set_value_cansleep(kingdisplay->enable_gpio, 0);
0218 
0219     err = regulator_disable(kingdisplay->supply);
0220     if (err < 0)
0221         return err;
0222 
0223     kingdisplay->prepared = false;
0224 
0225     return 0;
0226 }
0227 
0228 static int kingdisplay_panel_prepare(struct drm_panel *panel)
0229 {
0230     struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
0231     int err, regulator_err;
0232     unsigned int i;
0233 
0234     if (kingdisplay->prepared)
0235         return 0;
0236 
0237     gpiod_set_value_cansleep(kingdisplay->enable_gpio, 0);
0238 
0239     err = regulator_enable(kingdisplay->supply);
0240     if (err < 0)
0241         return err;
0242 
0243     /* T2: 15ms */
0244     usleep_range(15000, 16000);
0245 
0246     gpiod_set_value_cansleep(kingdisplay->enable_gpio, 1);
0247 
0248     /* T4: 15ms */
0249     usleep_range(15000, 16000);
0250 
0251     for (i = 0; i < ARRAY_SIZE(init_code); i++) {
0252         err = mipi_dsi_generic_write(kingdisplay->link, &init_code[i],
0253                     sizeof(struct kingdisplay_panel_cmd));
0254         if (err < 0) {
0255             dev_err(panel->dev, "failed write init cmds: %d\n", err);
0256             goto poweroff;
0257         }
0258     }
0259 
0260     err = mipi_dsi_dcs_exit_sleep_mode(kingdisplay->link);
0261     if (err < 0) {
0262         dev_err(panel->dev, "failed to exit sleep mode: %d\n", err);
0263         goto poweroff;
0264     }
0265 
0266     /* T6: 120ms */
0267     msleep(120);
0268 
0269     err = mipi_dsi_dcs_set_display_on(kingdisplay->link);
0270     if (err < 0) {
0271         dev_err(panel->dev, "failed to set display on: %d\n", err);
0272         goto poweroff;
0273     }
0274 
0275     /* T7: 10ms */
0276     usleep_range(10000, 11000);
0277 
0278     kingdisplay->prepared = true;
0279 
0280     return 0;
0281 
0282 poweroff:
0283     gpiod_set_value_cansleep(kingdisplay->enable_gpio, 0);
0284 
0285     regulator_err = regulator_disable(kingdisplay->supply);
0286     if (regulator_err)
0287         dev_err(panel->dev, "failed to disable regulator: %d\n", regulator_err);
0288 
0289     return err;
0290 }
0291 
0292 static int kingdisplay_panel_enable(struct drm_panel *panel)
0293 {
0294     struct kingdisplay_panel *kingdisplay = to_kingdisplay_panel(panel);
0295 
0296     if (kingdisplay->enabled)
0297         return 0;
0298 
0299     kingdisplay->enabled = true;
0300 
0301     return 0;
0302 }
0303 
0304 static const struct drm_display_mode default_mode = {
0305     .clock = 229000,
0306     .hdisplay = 1536,
0307     .hsync_start = 1536 + 100,
0308     .hsync_end = 1536 + 100 + 24,
0309     .htotal = 1536 + 100 + 24 + 100,
0310     .vdisplay = 2048,
0311     .vsync_start = 2048 + 95,
0312     .vsync_end = 2048 + 95 + 2,
0313     .vtotal = 2048 + 95 + 2 + 23,
0314 };
0315 
0316 static int kingdisplay_panel_get_modes(struct drm_panel *panel,
0317                        struct drm_connector *connector)
0318 {
0319     struct drm_display_mode *mode;
0320 
0321     mode = drm_mode_duplicate(connector->dev, &default_mode);
0322     if (!mode) {
0323         dev_err(panel->dev, "failed to add mode %ux%u@%u\n",
0324             default_mode.hdisplay, default_mode.vdisplay,
0325             drm_mode_vrefresh(&default_mode));
0326         return -ENOMEM;
0327     }
0328 
0329     drm_mode_set_name(mode);
0330 
0331     drm_mode_probed_add(connector, mode);
0332 
0333     connector->display_info.width_mm = 147;
0334     connector->display_info.height_mm = 196;
0335     connector->display_info.bpc = 8;
0336 
0337     return 1;
0338 }
0339 
0340 static const struct drm_panel_funcs kingdisplay_panel_funcs = {
0341     .disable = kingdisplay_panel_disable,
0342     .unprepare = kingdisplay_panel_unprepare,
0343     .prepare = kingdisplay_panel_prepare,
0344     .enable = kingdisplay_panel_enable,
0345     .get_modes = kingdisplay_panel_get_modes,
0346 };
0347 
0348 static const struct of_device_id kingdisplay_of_match[] = {
0349     { .compatible = "kingdisplay,kd097d04", },
0350     { }
0351 };
0352 MODULE_DEVICE_TABLE(of, kingdisplay_of_match);
0353 
0354 static int kingdisplay_panel_add(struct kingdisplay_panel *kingdisplay)
0355 {
0356     struct device *dev = &kingdisplay->link->dev;
0357     int err;
0358 
0359     kingdisplay->supply = devm_regulator_get(dev, "power");
0360     if (IS_ERR(kingdisplay->supply))
0361         return PTR_ERR(kingdisplay->supply);
0362 
0363     kingdisplay->enable_gpio = devm_gpiod_get_optional(dev, "enable",
0364                                GPIOD_OUT_HIGH);
0365     if (IS_ERR(kingdisplay->enable_gpio)) {
0366         err = PTR_ERR(kingdisplay->enable_gpio);
0367         dev_dbg(dev, "failed to get enable gpio: %d\n", err);
0368         kingdisplay->enable_gpio = NULL;
0369     }
0370 
0371     drm_panel_init(&kingdisplay->base, &kingdisplay->link->dev,
0372                &kingdisplay_panel_funcs, DRM_MODE_CONNECTOR_DSI);
0373 
0374     err = drm_panel_of_backlight(&kingdisplay->base);
0375     if (err)
0376         return err;
0377 
0378     drm_panel_add(&kingdisplay->base);
0379 
0380     return 0;
0381 }
0382 
0383 static void kingdisplay_panel_del(struct kingdisplay_panel *kingdisplay)
0384 {
0385     drm_panel_remove(&kingdisplay->base);
0386 }
0387 
0388 static int kingdisplay_panel_probe(struct mipi_dsi_device *dsi)
0389 {
0390     struct kingdisplay_panel *kingdisplay;
0391     int err;
0392 
0393     dsi->lanes = 4;
0394     dsi->format = MIPI_DSI_FMT_RGB888;
0395     dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
0396               MIPI_DSI_MODE_LPM;
0397 
0398     kingdisplay = devm_kzalloc(&dsi->dev, sizeof(*kingdisplay), GFP_KERNEL);
0399     if (!kingdisplay)
0400         return -ENOMEM;
0401 
0402     mipi_dsi_set_drvdata(dsi, kingdisplay);
0403     kingdisplay->link = dsi;
0404 
0405     err = kingdisplay_panel_add(kingdisplay);
0406     if (err < 0)
0407         return err;
0408 
0409     err = mipi_dsi_attach(dsi);
0410     if (err < 0) {
0411         kingdisplay_panel_del(kingdisplay);
0412         return err;
0413     }
0414 
0415     return 0;
0416 }
0417 
0418 static int kingdisplay_panel_remove(struct mipi_dsi_device *dsi)
0419 {
0420     struct kingdisplay_panel *kingdisplay = mipi_dsi_get_drvdata(dsi);
0421     int err;
0422 
0423     err = drm_panel_unprepare(&kingdisplay->base);
0424     if (err < 0)
0425         dev_err(&dsi->dev, "failed to unprepare panel: %d\n", err);
0426 
0427     err = drm_panel_disable(&kingdisplay->base);
0428     if (err < 0)
0429         dev_err(&dsi->dev, "failed to disable panel: %d\n", err);
0430 
0431     err = mipi_dsi_detach(dsi);
0432     if (err < 0)
0433         dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err);
0434 
0435     kingdisplay_panel_del(kingdisplay);
0436 
0437     return 0;
0438 }
0439 
0440 static void kingdisplay_panel_shutdown(struct mipi_dsi_device *dsi)
0441 {
0442     struct kingdisplay_panel *kingdisplay = mipi_dsi_get_drvdata(dsi);
0443 
0444     drm_panel_unprepare(&kingdisplay->base);
0445     drm_panel_disable(&kingdisplay->base);
0446 }
0447 
0448 static struct mipi_dsi_driver kingdisplay_panel_driver = {
0449     .driver = {
0450         .name = "panel-kingdisplay-kd097d04",
0451         .of_match_table = kingdisplay_of_match,
0452     },
0453     .probe = kingdisplay_panel_probe,
0454     .remove = kingdisplay_panel_remove,
0455     .shutdown = kingdisplay_panel_shutdown,
0456 };
0457 module_mipi_dsi_driver(kingdisplay_panel_driver);
0458 
0459 MODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>");
0460 MODULE_AUTHOR("Nickey Yang <nickey.yang@rock-chips.com>");
0461 MODULE_DESCRIPTION("kingdisplay KD097D04 panel driver");
0462 MODULE_LICENSE("GPL v2");