Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Elida kd35t133 5.5" MIPI-DSI panel driver
0004  * Copyright (C) 2020 Theobroma Systems Design und Consulting GmbH
0005  *
0006  * based on
0007  *
0008  * Rockteck jh057n00900 5.5" MIPI-DSI panel driver
0009  * Copyright (C) Purism SPC 2019
0010  */
0011 
0012 #include <linux/delay.h>
0013 #include <linux/gpio/consumer.h>
0014 #include <linux/media-bus-format.h>
0015 #include <linux/module.h>
0016 #include <linux/of.h>
0017 #include <linux/regulator/consumer.h>
0018 
0019 #include <video/display_timing.h>
0020 #include <video/mipi_display.h>
0021 
0022 #include <drm/drm_mipi_dsi.h>
0023 #include <drm/drm_modes.h>
0024 #include <drm/drm_panel.h>
0025 
0026 /* Manufacturer specific Commands send via DSI */
0027 #define KD35T133_CMD_INTERFACEMODECTRL      0xb0
0028 #define KD35T133_CMD_FRAMERATECTRL      0xb1
0029 #define KD35T133_CMD_DISPLAYINVERSIONCTRL   0xb4
0030 #define KD35T133_CMD_DISPLAYFUNCTIONCTRL    0xb6
0031 #define KD35T133_CMD_POWERCONTROL1      0xc0
0032 #define KD35T133_CMD_POWERCONTROL2      0xc1
0033 #define KD35T133_CMD_VCOMCONTROL        0xc5
0034 #define KD35T133_CMD_POSITIVEGAMMA      0xe0
0035 #define KD35T133_CMD_NEGATIVEGAMMA      0xe1
0036 #define KD35T133_CMD_SETIMAGEFUNCTION       0xe9
0037 #define KD35T133_CMD_ADJUSTCONTROL3     0xf7
0038 
0039 struct kd35t133 {
0040     struct device *dev;
0041     struct drm_panel panel;
0042     struct gpio_desc *reset_gpio;
0043     struct regulator *vdd;
0044     struct regulator *iovcc;
0045     enum drm_panel_orientation orientation;
0046     bool prepared;
0047 };
0048 
0049 static inline struct kd35t133 *panel_to_kd35t133(struct drm_panel *panel)
0050 {
0051     return container_of(panel, struct kd35t133, panel);
0052 }
0053 
0054 #define dsi_dcs_write_seq(dsi, cmd, seq...) do {            \
0055         static const u8 b[] = { cmd, seq };         \
0056         int ret;                        \
0057         ret = mipi_dsi_dcs_write_buffer(dsi, b, ARRAY_SIZE(b)); \
0058         if (ret < 0)                        \
0059             return ret;                 \
0060     } while (0)
0061 
0062 static int kd35t133_init_sequence(struct kd35t133 *ctx)
0063 {
0064     struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
0065     struct device *dev = ctx->dev;
0066 
0067     /*
0068      * Init sequence was supplied by the panel vendor with minimal
0069      * documentation.
0070      */
0071     dsi_dcs_write_seq(dsi, KD35T133_CMD_POSITIVEGAMMA,
0072               0x00, 0x13, 0x18, 0x04, 0x0f, 0x06, 0x3a, 0x56,
0073               0x4d, 0x03, 0x0a, 0x06, 0x30, 0x3e, 0x0f);
0074     dsi_dcs_write_seq(dsi, KD35T133_CMD_NEGATIVEGAMMA,
0075               0x00, 0x13, 0x18, 0x01, 0x11, 0x06, 0x38, 0x34,
0076               0x4d, 0x06, 0x0d, 0x0b, 0x31, 0x37, 0x0f);
0077     dsi_dcs_write_seq(dsi, KD35T133_CMD_POWERCONTROL1, 0x18, 0x17);
0078     dsi_dcs_write_seq(dsi, KD35T133_CMD_POWERCONTROL2, 0x41);
0079     dsi_dcs_write_seq(dsi, KD35T133_CMD_VCOMCONTROL, 0x00, 0x1a, 0x80);
0080     dsi_dcs_write_seq(dsi, MIPI_DCS_SET_ADDRESS_MODE, 0x48);
0081     dsi_dcs_write_seq(dsi, MIPI_DCS_SET_PIXEL_FORMAT, 0x55);
0082     dsi_dcs_write_seq(dsi, KD35T133_CMD_INTERFACEMODECTRL, 0x00);
0083     dsi_dcs_write_seq(dsi, KD35T133_CMD_FRAMERATECTRL, 0xa0);
0084     dsi_dcs_write_seq(dsi, KD35T133_CMD_DISPLAYINVERSIONCTRL, 0x02);
0085     dsi_dcs_write_seq(dsi, KD35T133_CMD_DISPLAYFUNCTIONCTRL,
0086               0x20, 0x02);
0087     dsi_dcs_write_seq(dsi, KD35T133_CMD_SETIMAGEFUNCTION, 0x00);
0088     dsi_dcs_write_seq(dsi, KD35T133_CMD_ADJUSTCONTROL3,
0089               0xa9, 0x51, 0x2c, 0x82);
0090     mipi_dsi_dcs_write(dsi, MIPI_DCS_ENTER_INVERT_MODE, NULL, 0);
0091 
0092     dev_dbg(dev, "Panel init sequence done\n");
0093     return 0;
0094 }
0095 
0096 static int kd35t133_unprepare(struct drm_panel *panel)
0097 {
0098     struct kd35t133 *ctx = panel_to_kd35t133(panel);
0099     struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
0100     int ret;
0101 
0102     if (!ctx->prepared)
0103         return 0;
0104 
0105     ret = mipi_dsi_dcs_set_display_off(dsi);
0106     if (ret < 0)
0107         dev_err(ctx->dev, "failed to set display off: %d\n", ret);
0108 
0109     ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
0110     if (ret < 0) {
0111         dev_err(ctx->dev, "failed to enter sleep mode: %d\n", ret);
0112         return ret;
0113     }
0114 
0115     regulator_disable(ctx->iovcc);
0116     regulator_disable(ctx->vdd);
0117 
0118     ctx->prepared = false;
0119 
0120     return 0;
0121 }
0122 
0123 static int kd35t133_prepare(struct drm_panel *panel)
0124 {
0125     struct kd35t133 *ctx = panel_to_kd35t133(panel);
0126     struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
0127     int ret;
0128 
0129     if (ctx->prepared)
0130         return 0;
0131 
0132     dev_dbg(ctx->dev, "Resetting the panel\n");
0133     ret = regulator_enable(ctx->vdd);
0134     if (ret < 0) {
0135         dev_err(ctx->dev, "Failed to enable vdd supply: %d\n", ret);
0136         return ret;
0137     }
0138 
0139     ret = regulator_enable(ctx->iovcc);
0140     if (ret < 0) {
0141         dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret);
0142         goto disable_vdd;
0143     }
0144 
0145     msleep(20);
0146 
0147     gpiod_set_value_cansleep(ctx->reset_gpio, 1);
0148     usleep_range(10, 20);
0149     gpiod_set_value_cansleep(ctx->reset_gpio, 0);
0150 
0151     msleep(20);
0152 
0153     ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
0154     if (ret < 0) {
0155         dev_err(ctx->dev, "Failed to exit sleep mode: %d\n", ret);
0156         goto disable_iovcc;
0157     }
0158 
0159     msleep(250);
0160 
0161     ret = kd35t133_init_sequence(ctx);
0162     if (ret < 0) {
0163         dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret);
0164         goto disable_iovcc;
0165     }
0166 
0167     ret = mipi_dsi_dcs_set_display_on(dsi);
0168     if (ret < 0) {
0169         dev_err(ctx->dev, "Failed to set display on: %d\n", ret);
0170         goto disable_iovcc;
0171     }
0172 
0173     msleep(50);
0174 
0175     ctx->prepared = true;
0176 
0177     return 0;
0178 
0179 disable_iovcc:
0180     regulator_disable(ctx->iovcc);
0181 disable_vdd:
0182     regulator_disable(ctx->vdd);
0183     return ret;
0184 }
0185 
0186 static const struct drm_display_mode default_mode = {
0187     .hdisplay   = 320,
0188     .hsync_start    = 320 + 130,
0189     .hsync_end  = 320 + 130 + 4,
0190     .htotal     = 320 + 130 + 4 + 130,
0191     .vdisplay   = 480,
0192     .vsync_start    = 480 + 2,
0193     .vsync_end  = 480 + 2 + 1,
0194     .vtotal     = 480 + 2 + 1 + 2,
0195     .clock      = 17000,
0196     .width_mm   = 42,
0197     .height_mm  = 82,
0198 };
0199 
0200 static int kd35t133_get_modes(struct drm_panel *panel,
0201                 struct drm_connector *connector)
0202 {
0203     struct kd35t133 *ctx = panel_to_kd35t133(panel);
0204     struct drm_display_mode *mode;
0205 
0206     mode = drm_mode_duplicate(connector->dev, &default_mode);
0207     if (!mode) {
0208         dev_err(ctx->dev, "Failed to add mode %ux%u@%u\n",
0209             default_mode.hdisplay, default_mode.vdisplay,
0210             drm_mode_vrefresh(&default_mode));
0211         return -ENOMEM;
0212     }
0213 
0214     drm_mode_set_name(mode);
0215 
0216     mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
0217     connector->display_info.width_mm = mode->width_mm;
0218     connector->display_info.height_mm = mode->height_mm;
0219     drm_mode_probed_add(connector, mode);
0220     /*
0221      * TODO: Remove once all drm drivers call
0222      * drm_connector_set_orientation_from_panel()
0223      */
0224     drm_connector_set_panel_orientation(connector, ctx->orientation);
0225 
0226     return 1;
0227 }
0228 
0229 static enum drm_panel_orientation kd35t133_get_orientation(struct drm_panel *panel)
0230 {
0231     struct kd35t133 *ctx = panel_to_kd35t133(panel);
0232 
0233     return ctx->orientation;
0234 }
0235 
0236 static const struct drm_panel_funcs kd35t133_funcs = {
0237     .unprepare  = kd35t133_unprepare,
0238     .prepare    = kd35t133_prepare,
0239     .get_modes  = kd35t133_get_modes,
0240     .get_orientation = kd35t133_get_orientation,
0241 };
0242 
0243 static int kd35t133_probe(struct mipi_dsi_device *dsi)
0244 {
0245     struct device *dev = &dsi->dev;
0246     struct kd35t133 *ctx;
0247     int ret;
0248 
0249     ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
0250     if (!ctx)
0251         return -ENOMEM;
0252 
0253     ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
0254     if (IS_ERR(ctx->reset_gpio)) {
0255         dev_err(dev, "cannot get reset gpio\n");
0256         return PTR_ERR(ctx->reset_gpio);
0257     }
0258 
0259     ctx->vdd = devm_regulator_get(dev, "vdd");
0260     if (IS_ERR(ctx->vdd)) {
0261         ret = PTR_ERR(ctx->vdd);
0262         if (ret != -EPROBE_DEFER)
0263             dev_err(dev, "Failed to request vdd regulator: %d\n", ret);
0264         return ret;
0265     }
0266 
0267     ctx->iovcc = devm_regulator_get(dev, "iovcc");
0268     if (IS_ERR(ctx->iovcc)) {
0269         ret = PTR_ERR(ctx->iovcc);
0270         if (ret != -EPROBE_DEFER)
0271             dev_err(dev, "Failed to request iovcc regulator: %d\n", ret);
0272         return ret;
0273     }
0274 
0275     ret = of_drm_get_panel_orientation(dev->of_node, &ctx->orientation);
0276     if (ret < 0) {
0277         dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, ret);
0278         return ret;
0279     }
0280 
0281     mipi_dsi_set_drvdata(dsi, ctx);
0282 
0283     ctx->dev = dev;
0284 
0285     dsi->lanes = 1;
0286     dsi->format = MIPI_DSI_FMT_RGB888;
0287     dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
0288               MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET |
0289               MIPI_DSI_CLOCK_NON_CONTINUOUS;
0290 
0291     drm_panel_init(&ctx->panel, &dsi->dev, &kd35t133_funcs,
0292                DRM_MODE_CONNECTOR_DSI);
0293 
0294     ret = drm_panel_of_backlight(&ctx->panel);
0295     if (ret)
0296         return ret;
0297 
0298     drm_panel_add(&ctx->panel);
0299 
0300     ret = mipi_dsi_attach(dsi);
0301     if (ret < 0) {
0302         dev_err(dev, "mipi_dsi_attach failed: %d\n", ret);
0303         drm_panel_remove(&ctx->panel);
0304         return ret;
0305     }
0306 
0307     return 0;
0308 }
0309 
0310 static void kd35t133_shutdown(struct mipi_dsi_device *dsi)
0311 {
0312     struct kd35t133 *ctx = mipi_dsi_get_drvdata(dsi);
0313     int ret;
0314 
0315     ret = drm_panel_unprepare(&ctx->panel);
0316     if (ret < 0)
0317         dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret);
0318 
0319     ret = drm_panel_disable(&ctx->panel);
0320     if (ret < 0)
0321         dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret);
0322 }
0323 
0324 static int kd35t133_remove(struct mipi_dsi_device *dsi)
0325 {
0326     struct kd35t133 *ctx = mipi_dsi_get_drvdata(dsi);
0327     int ret;
0328 
0329     kd35t133_shutdown(dsi);
0330 
0331     ret = mipi_dsi_detach(dsi);
0332     if (ret < 0)
0333         dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
0334 
0335     drm_panel_remove(&ctx->panel);
0336 
0337     return 0;
0338 }
0339 
0340 static const struct of_device_id kd35t133_of_match[] = {
0341     { .compatible = "elida,kd35t133" },
0342     { /* sentinel */ }
0343 };
0344 MODULE_DEVICE_TABLE(of, kd35t133_of_match);
0345 
0346 static struct mipi_dsi_driver kd35t133_driver = {
0347     .driver = {
0348         .name = "panel-elida-kd35t133",
0349         .of_match_table = kd35t133_of_match,
0350     },
0351     .probe  = kd35t133_probe,
0352     .remove = kd35t133_remove,
0353     .shutdown = kd35t133_shutdown,
0354 };
0355 module_mipi_dsi_driver(kd35t133_driver);
0356 
0357 MODULE_AUTHOR("Heiko Stuebner <heiko.stuebner@theobroma-systems.com>");
0358 MODULE_DESCRIPTION("DRM driver for Elida kd35t133 MIPI DSI panel");
0359 MODULE_LICENSE("GPL v2");