root/drivers/gpu/drm/panel/panel-rocktech-jh057n00900.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. panel_to_jh057n
  2. jh057n_init_sequence
  3. jh057n_enable
  4. jh057n_disable
  5. jh057n_unprepare
  6. jh057n_prepare
  7. jh057n_get_modes
  8. allpixelson_set
  9. jh057n_debugfs_init
  10. jh057n_debugfs_remove
  11. jh057n_probe
  12. jh057n_shutdown
  13. jh057n_remove

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Rockteck jh057n00900 5.5" MIPI-DSI panel driver
   4  *
   5  * Copyright (C) Purism SPC 2019
   6  */
   7 
   8 #include <drm/drm_mipi_dsi.h>
   9 #include <drm/drm_modes.h>
  10 #include <drm/drm_panel.h>
  11 #include <drm/drm_print.h>
  12 #include <linux/backlight.h>
  13 #include <linux/debugfs.h>
  14 #include <linux/delay.h>
  15 #include <linux/gpio/consumer.h>
  16 #include <linux/media-bus-format.h>
  17 #include <linux/module.h>
  18 #include <linux/regulator/consumer.h>
  19 #include <video/display_timing.h>
  20 #include <video/mipi_display.h>
  21 
  22 #define DRV_NAME "panel-rocktech-jh057n00900"
  23 
  24 /* Manufacturer specific Commands send via DSI */
  25 #define ST7703_CMD_ALL_PIXEL_OFF 0x22
  26 #define ST7703_CMD_ALL_PIXEL_ON  0x23
  27 #define ST7703_CMD_SETDISP       0xB2
  28 #define ST7703_CMD_SETRGBIF      0xB3
  29 #define ST7703_CMD_SETCYC        0xB4
  30 #define ST7703_CMD_SETBGP        0xB5
  31 #define ST7703_CMD_SETVCOM       0xB6
  32 #define ST7703_CMD_SETOTP        0xB7
  33 #define ST7703_CMD_SETPOWER_EXT  0xB8
  34 #define ST7703_CMD_SETEXTC       0xB9
  35 #define ST7703_CMD_SETMIPI       0xBA
  36 #define ST7703_CMD_SETVDC        0xBC
  37 #define ST7703_CMD_UNKNOWN0      0xBF
  38 #define ST7703_CMD_SETSCR        0xC0
  39 #define ST7703_CMD_SETPOWER      0xC1
  40 #define ST7703_CMD_SETPANEL      0xCC
  41 #define ST7703_CMD_SETGAMMA      0xE0
  42 #define ST7703_CMD_SETEQ         0xE3
  43 #define ST7703_CMD_SETGIP1       0xE9
  44 #define ST7703_CMD_SETGIP2       0xEA
  45 
  46 struct jh057n {
  47         struct device *dev;
  48         struct drm_panel panel;
  49         struct gpio_desc *reset_gpio;
  50         struct backlight_device *backlight;
  51         struct regulator *vcc;
  52         struct regulator *iovcc;
  53         bool prepared;
  54 
  55         struct dentry *debugfs;
  56 };
  57 
  58 static inline struct jh057n *panel_to_jh057n(struct drm_panel *panel)
  59 {
  60         return container_of(panel, struct jh057n, panel);
  61 }
  62 
  63 #define dsi_generic_write_seq(dsi, seq...) do {                         \
  64                 static const u8 d[] = { seq };                          \
  65                 int ret;                                                \
  66                 ret = mipi_dsi_generic_write(dsi, d, ARRAY_SIZE(d));    \
  67                 if (ret < 0)                                            \
  68                         return ret;                                     \
  69         } while (0)
  70 
  71 static int jh057n_init_sequence(struct jh057n *ctx)
  72 {
  73         struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
  74         struct device *dev = ctx->dev;
  75         int ret;
  76 
  77         /*
  78          * Init sequence was supplied by the panel vendor. Most of the commands
  79          * resemble the ST7703 but the number of parameters often don't match
  80          * so it's likely a clone.
  81          */
  82         dsi_generic_write_seq(dsi, ST7703_CMD_SETEXTC,
  83                               0xF1, 0x12, 0x83);
  84         dsi_generic_write_seq(dsi, ST7703_CMD_SETRGBIF,
  85                               0x10, 0x10, 0x05, 0x05, 0x03, 0xFF, 0x00, 0x00,
  86                               0x00, 0x00);
  87         dsi_generic_write_seq(dsi, ST7703_CMD_SETSCR,
  88                               0x73, 0x73, 0x50, 0x50, 0x00, 0x00, 0x08, 0x70,
  89                               0x00);
  90         dsi_generic_write_seq(dsi, ST7703_CMD_SETVDC, 0x4E);
  91         dsi_generic_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0B);
  92         dsi_generic_write_seq(dsi, ST7703_CMD_SETCYC, 0x80);
  93         dsi_generic_write_seq(dsi, ST7703_CMD_SETDISP, 0xF0, 0x12, 0x30);
  94         dsi_generic_write_seq(dsi, ST7703_CMD_SETEQ,
  95                               0x07, 0x07, 0x0B, 0x0B, 0x03, 0x0B, 0x00, 0x00,
  96                               0x00, 0x00, 0xFF, 0x00, 0xC0, 0x10);
  97         dsi_generic_write_seq(dsi, ST7703_CMD_SETBGP, 0x08, 0x08);
  98         msleep(20);
  99 
 100         dsi_generic_write_seq(dsi, ST7703_CMD_SETVCOM, 0x3F, 0x3F);
 101         dsi_generic_write_seq(dsi, ST7703_CMD_UNKNOWN0, 0x02, 0x11, 0x00);
 102         dsi_generic_write_seq(dsi, ST7703_CMD_SETGIP1,
 103                               0x82, 0x10, 0x06, 0x05, 0x9E, 0x0A, 0xA5, 0x12,
 104                               0x31, 0x23, 0x37, 0x83, 0x04, 0xBC, 0x27, 0x38,
 105                               0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00,
 106                               0x03, 0x00, 0x00, 0x00, 0x75, 0x75, 0x31, 0x88,
 107                               0x88, 0x88, 0x88, 0x88, 0x88, 0x13, 0x88, 0x64,
 108                               0x64, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
 109                               0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 110                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
 111         dsi_generic_write_seq(dsi, ST7703_CMD_SETGIP2,
 112                               0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 113                               0x00, 0x00, 0x00, 0x00, 0x02, 0x46, 0x02, 0x88,
 114                               0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x88, 0x13,
 115                               0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
 116                               0x75, 0x88, 0x23, 0x14, 0x00, 0x00, 0x02, 0x00,
 117                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 118                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0A,
 119                               0xA5, 0x00, 0x00, 0x00, 0x00);
 120         dsi_generic_write_seq(dsi, ST7703_CMD_SETGAMMA,
 121                               0x00, 0x09, 0x0E, 0x29, 0x2D, 0x3C, 0x41, 0x37,
 122                               0x07, 0x0B, 0x0D, 0x10, 0x11, 0x0F, 0x10, 0x11,
 123                               0x18, 0x00, 0x09, 0x0E, 0x29, 0x2D, 0x3C, 0x41,
 124                               0x37, 0x07, 0x0B, 0x0D, 0x10, 0x11, 0x0F, 0x10,
 125                               0x11, 0x18);
 126         msleep(20);
 127 
 128         ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
 129         if (ret < 0) {
 130                 DRM_DEV_ERROR(dev, "Failed to exit sleep mode: %d\n", ret);
 131                 return ret;
 132         }
 133         /* Panel is operational 120 msec after reset */
 134         msleep(60);
 135         ret = mipi_dsi_dcs_set_display_on(dsi);
 136         if (ret)
 137                 return ret;
 138 
 139         DRM_DEV_DEBUG_DRIVER(dev, "Panel init sequence done\n");
 140         return 0;
 141 }
 142 
 143 static int jh057n_enable(struct drm_panel *panel)
 144 {
 145         struct jh057n *ctx = panel_to_jh057n(panel);
 146         int ret;
 147 
 148         ret = jh057n_init_sequence(ctx);
 149         if (ret < 0) {
 150                 DRM_DEV_ERROR(ctx->dev, "Panel init sequence failed: %d\n",
 151                               ret);
 152                 return ret;
 153         }
 154 
 155         return backlight_enable(ctx->backlight);
 156 }
 157 
 158 static int jh057n_disable(struct drm_panel *panel)
 159 {
 160         struct jh057n *ctx = panel_to_jh057n(panel);
 161         struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
 162 
 163         backlight_disable(ctx->backlight);
 164         return mipi_dsi_dcs_set_display_off(dsi);
 165 }
 166 
 167 static int jh057n_unprepare(struct drm_panel *panel)
 168 {
 169         struct jh057n *ctx = panel_to_jh057n(panel);
 170 
 171         if (!ctx->prepared)
 172                 return 0;
 173 
 174         regulator_disable(ctx->iovcc);
 175         regulator_disable(ctx->vcc);
 176         ctx->prepared = false;
 177 
 178         return 0;
 179 }
 180 
 181 static int jh057n_prepare(struct drm_panel *panel)
 182 {
 183         struct jh057n *ctx = panel_to_jh057n(panel);
 184         int ret;
 185 
 186         if (ctx->prepared)
 187                 return 0;
 188 
 189         DRM_DEV_DEBUG_DRIVER(ctx->dev, "Resetting the panel\n");
 190         ret = regulator_enable(ctx->vcc);
 191         if (ret < 0) {
 192                 DRM_DEV_ERROR(ctx->dev,
 193                               "Failed to enable vcc supply: %d\n", ret);
 194                 return ret;
 195         }
 196         ret = regulator_enable(ctx->iovcc);
 197         if (ret < 0) {
 198                 DRM_DEV_ERROR(ctx->dev,
 199                               "Failed to enable iovcc supply: %d\n", ret);
 200                 goto disable_vcc;
 201         }
 202 
 203         gpiod_set_value_cansleep(ctx->reset_gpio, 1);
 204         usleep_range(20, 40);
 205         gpiod_set_value_cansleep(ctx->reset_gpio, 0);
 206         msleep(20);
 207 
 208         ctx->prepared = true;
 209 
 210         return 0;
 211 
 212 disable_vcc:
 213         regulator_disable(ctx->vcc);
 214         return ret;
 215 }
 216 
 217 static const struct drm_display_mode default_mode = {
 218         .hdisplay    = 720,
 219         .hsync_start = 720 + 90,
 220         .hsync_end   = 720 + 90 + 20,
 221         .htotal      = 720 + 90 + 20 + 20,
 222         .vdisplay    = 1440,
 223         .vsync_start = 1440 + 20,
 224         .vsync_end   = 1440 + 20 + 4,
 225         .vtotal      = 1440 + 20 + 4 + 12,
 226         .vrefresh    = 60,
 227         .clock       = 75276,
 228         .flags       = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
 229         .width_mm    = 65,
 230         .height_mm   = 130,
 231 };
 232 
 233 static int jh057n_get_modes(struct drm_panel *panel)
 234 {
 235         struct jh057n *ctx = panel_to_jh057n(panel);
 236         struct drm_display_mode *mode;
 237 
 238         mode = drm_mode_duplicate(panel->drm, &default_mode);
 239         if (!mode) {
 240                 DRM_DEV_ERROR(ctx->dev, "Failed to add mode %ux%u@%u\n",
 241                               default_mode.hdisplay, default_mode.vdisplay,
 242                               default_mode.vrefresh);
 243                 return -ENOMEM;
 244         }
 245 
 246         drm_mode_set_name(mode);
 247 
 248         mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
 249         panel->connector->display_info.width_mm = mode->width_mm;
 250         panel->connector->display_info.height_mm = mode->height_mm;
 251         drm_mode_probed_add(panel->connector, mode);
 252 
 253         return 1;
 254 }
 255 
 256 static const struct drm_panel_funcs jh057n_drm_funcs = {
 257         .disable   = jh057n_disable,
 258         .unprepare = jh057n_unprepare,
 259         .prepare   = jh057n_prepare,
 260         .enable    = jh057n_enable,
 261         .get_modes = jh057n_get_modes,
 262 };
 263 
 264 static int allpixelson_set(void *data, u64 val)
 265 {
 266         struct jh057n *ctx = data;
 267         struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
 268 
 269         DRM_DEV_DEBUG_DRIVER(ctx->dev, "Setting all pixels on\n");
 270         dsi_generic_write_seq(dsi, ST7703_CMD_ALL_PIXEL_ON);
 271         msleep(val * 1000);
 272         /* Reset the panel to get video back */
 273         drm_panel_disable(&ctx->panel);
 274         drm_panel_unprepare(&ctx->panel);
 275         drm_panel_prepare(&ctx->panel);
 276         drm_panel_enable(&ctx->panel);
 277 
 278         return 0;
 279 }
 280 
 281 DEFINE_SIMPLE_ATTRIBUTE(allpixelson_fops, NULL,
 282                         allpixelson_set, "%llu\n");
 283 
 284 static void jh057n_debugfs_init(struct jh057n *ctx)
 285 {
 286         ctx->debugfs = debugfs_create_dir(DRV_NAME, NULL);
 287 
 288         debugfs_create_file("allpixelson", 0600, ctx->debugfs, ctx,
 289                             &allpixelson_fops);
 290 }
 291 
 292 static void jh057n_debugfs_remove(struct jh057n *ctx)
 293 {
 294         debugfs_remove_recursive(ctx->debugfs);
 295         ctx->debugfs = NULL;
 296 }
 297 
 298 static int jh057n_probe(struct mipi_dsi_device *dsi)
 299 {
 300         struct device *dev = &dsi->dev;
 301         struct jh057n *ctx;
 302         int ret;
 303 
 304         ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
 305         if (!ctx)
 306                 return -ENOMEM;
 307 
 308         ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
 309         if (IS_ERR(ctx->reset_gpio)) {
 310                 DRM_DEV_ERROR(dev, "cannot get reset gpio\n");
 311                 return PTR_ERR(ctx->reset_gpio);
 312         }
 313 
 314         mipi_dsi_set_drvdata(dsi, ctx);
 315 
 316         ctx->dev = dev;
 317 
 318         dsi->lanes = 4;
 319         dsi->format = MIPI_DSI_FMT_RGB888;
 320         dsi->mode_flags = MIPI_DSI_MODE_VIDEO |
 321                 MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
 322 
 323         ctx->backlight = devm_of_find_backlight(dev);
 324         if (IS_ERR(ctx->backlight))
 325                 return PTR_ERR(ctx->backlight);
 326 
 327         ctx->vcc = devm_regulator_get(dev, "vcc");
 328         if (IS_ERR(ctx->vcc)) {
 329                 ret = PTR_ERR(ctx->vcc);
 330                 if (ret != -EPROBE_DEFER)
 331                         DRM_DEV_ERROR(dev,
 332                                       "Failed to request vcc regulator: %d\n",
 333                                       ret);
 334                 return ret;
 335         }
 336         ctx->iovcc = devm_regulator_get(dev, "iovcc");
 337         if (IS_ERR(ctx->iovcc)) {
 338                 ret = PTR_ERR(ctx->iovcc);
 339                 if (ret != -EPROBE_DEFER)
 340                         DRM_DEV_ERROR(dev,
 341                                       "Failed to request iovcc regulator: %d\n",
 342                                       ret);
 343                 return ret;
 344         }
 345 
 346         drm_panel_init(&ctx->panel);
 347         ctx->panel.dev = dev;
 348         ctx->panel.funcs = &jh057n_drm_funcs;
 349 
 350         drm_panel_add(&ctx->panel);
 351 
 352         ret = mipi_dsi_attach(dsi);
 353         if (ret < 0) {
 354                 DRM_DEV_ERROR(dev,
 355                               "mipi_dsi_attach failed (%d). Is host ready?\n",
 356                               ret);
 357                 drm_panel_remove(&ctx->panel);
 358                 return ret;
 359         }
 360 
 361         DRM_DEV_INFO(dev, "%ux%u@%u %ubpp dsi %udl - ready\n",
 362                      default_mode.hdisplay, default_mode.vdisplay,
 363                      default_mode.vrefresh,
 364                      mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes);
 365 
 366         jh057n_debugfs_init(ctx);
 367         return 0;
 368 }
 369 
 370 static void jh057n_shutdown(struct mipi_dsi_device *dsi)
 371 {
 372         struct jh057n *ctx = mipi_dsi_get_drvdata(dsi);
 373         int ret;
 374 
 375         ret = drm_panel_unprepare(&ctx->panel);
 376         if (ret < 0)
 377                 DRM_DEV_ERROR(&dsi->dev, "Failed to unprepare panel: %d\n",
 378                               ret);
 379 
 380         ret = drm_panel_disable(&ctx->panel);
 381         if (ret < 0)
 382                 DRM_DEV_ERROR(&dsi->dev, "Failed to disable panel: %d\n",
 383                               ret);
 384 }
 385 
 386 static int jh057n_remove(struct mipi_dsi_device *dsi)
 387 {
 388         struct jh057n *ctx = mipi_dsi_get_drvdata(dsi);
 389         int ret;
 390 
 391         jh057n_shutdown(dsi);
 392 
 393         ret = mipi_dsi_detach(dsi);
 394         if (ret < 0)
 395                 DRM_DEV_ERROR(&dsi->dev, "Failed to detach from DSI host: %d\n",
 396                               ret);
 397 
 398         drm_panel_remove(&ctx->panel);
 399 
 400         jh057n_debugfs_remove(ctx);
 401 
 402         return 0;
 403 }
 404 
 405 static const struct of_device_id jh057n_of_match[] = {
 406         { .compatible = "rocktech,jh057n00900" },
 407         { /* sentinel */ }
 408 };
 409 MODULE_DEVICE_TABLE(of, jh057n_of_match);
 410 
 411 static struct mipi_dsi_driver jh057n_driver = {
 412         .probe  = jh057n_probe,
 413         .remove = jh057n_remove,
 414         .shutdown = jh057n_shutdown,
 415         .driver = {
 416                 .name = DRV_NAME,
 417                 .of_match_table = jh057n_of_match,
 418         },
 419 };
 420 module_mipi_dsi_driver(jh057n_driver);
 421 
 422 MODULE_AUTHOR("Guido Günther <agx@sigxcpu.org>");
 423 MODULE_DESCRIPTION("DRM driver for Rocktech JH057N00900 MIPI DSI panel");
 424 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */