linux/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (C) STMicroelectronics SA 2017
   4 *
   5 * Authors: Philippe Cornu <philippe.cornu@st.com>
   6 *          Yannick Fertre <yannick.fertre@st.com>
   7 */
   8
   9#include <drm/drmP.h>
  10#include <drm/drm_mipi_dsi.h>
  11#include <drm/drm_panel.h>
  12#include <linux/backlight.h>
  13#include <linux/gpio/consumer.h>
  14#include <linux/regulator/consumer.h>
  15#include <video/mipi_display.h>
  16
  17#define OTM8009A_BACKLIGHT_DEFAULT      240
  18#define OTM8009A_BACKLIGHT_MAX          255
  19
  20/* Manufacturer Command Set */
  21#define MCS_ADRSFT      0x0000  /* Address Shift Function */
  22#define MCS_PANSET      0xB3A6  /* Panel Type Setting */
  23#define MCS_SD_CTRL     0xC0A2  /* Source Driver Timing Setting */
  24#define MCS_P_DRV_M     0xC0B4  /* Panel Driving Mode */
  25#define MCS_OSC_ADJ     0xC181  /* Oscillator Adjustment for Idle/Normal mode */
  26#define MCS_RGB_VID_SET 0xC1A1  /* RGB Video Mode Setting */
  27#define MCS_SD_PCH_CTRL 0xC480  /* Source Driver Precharge Control */
  28#define MCS_NO_DOC1     0xC48A  /* Command not documented */
  29#define MCS_PWR_CTRL1   0xC580  /* Power Control Setting 1 */
  30#define MCS_PWR_CTRL2   0xC590  /* Power Control Setting 2 for Normal Mode */
  31#define MCS_PWR_CTRL4   0xC5B0  /* Power Control Setting 4 for DC Voltage */
  32#define MCS_PANCTRLSET1 0xCB80  /* Panel Control Setting 1 */
  33#define MCS_PANCTRLSET2 0xCB90  /* Panel Control Setting 2 */
  34#define MCS_PANCTRLSET3 0xCBA0  /* Panel Control Setting 3 */
  35#define MCS_PANCTRLSET4 0xCBB0  /* Panel Control Setting 4 */
  36#define MCS_PANCTRLSET5 0xCBC0  /* Panel Control Setting 5 */
  37#define MCS_PANCTRLSET6 0xCBD0  /* Panel Control Setting 6 */
  38#define MCS_PANCTRLSET7 0xCBE0  /* Panel Control Setting 7 */
  39#define MCS_PANCTRLSET8 0xCBF0  /* Panel Control Setting 8 */
  40#define MCS_PANU2D1     0xCC80  /* Panel U2D Setting 1 */
  41#define MCS_PANU2D2     0xCC90  /* Panel U2D Setting 2 */
  42#define MCS_PANU2D3     0xCCA0  /* Panel U2D Setting 3 */
  43#define MCS_PAND2U1     0xCCB0  /* Panel D2U Setting 1 */
  44#define MCS_PAND2U2     0xCCC0  /* Panel D2U Setting 2 */
  45#define MCS_PAND2U3     0xCCD0  /* Panel D2U Setting 3 */
  46#define MCS_GOAVST      0xCE80  /* GOA VST Setting */
  47#define MCS_GOACLKA1    0xCEA0  /* GOA CLKA1 Setting */
  48#define MCS_GOACLKA3    0xCEB0  /* GOA CLKA3 Setting */
  49#define MCS_GOAECLK     0xCFC0  /* GOA ECLK Setting */
  50#define MCS_NO_DOC2     0xCFD0  /* Command not documented */
  51#define MCS_GVDDSET     0xD800  /* GVDD/NGVDD */
  52#define MCS_VCOMDC      0xD900  /* VCOM Voltage Setting */
  53#define MCS_GMCT2_2P    0xE100  /* Gamma Correction 2.2+ Setting */
  54#define MCS_GMCT2_2N    0xE200  /* Gamma Correction 2.2- Setting */
  55#define MCS_NO_DOC3     0xF5B6  /* Command not documented */
  56#define MCS_CMD2_ENA1   0xFF00  /* Enable Access Command2 "CMD2" */
  57#define MCS_CMD2_ENA2   0xFF80  /* Enable Access Orise Command2 */
  58
  59struct otm8009a {
  60        struct device *dev;
  61        struct drm_panel panel;
  62        struct backlight_device *bl_dev;
  63        struct gpio_desc *reset_gpio;
  64        struct regulator *supply;
  65        bool prepared;
  66        bool enabled;
  67};
  68
  69static const struct drm_display_mode default_mode = {
  70        .clock = 29700,
  71        .hdisplay = 480,
  72        .hsync_start = 480 + 98,
  73        .hsync_end = 480 + 98 + 32,
  74        .htotal = 480 + 98 + 32 + 98,
  75        .vdisplay = 800,
  76        .vsync_start = 800 + 15,
  77        .vsync_end = 800 + 15 + 10,
  78        .vtotal = 800 + 15 + 10 + 14,
  79        .vrefresh = 50,
  80        .flags = 0,
  81        .width_mm = 52,
  82        .height_mm = 86,
  83};
  84
  85static inline struct otm8009a *panel_to_otm8009a(struct drm_panel *panel)
  86{
  87        return container_of(panel, struct otm8009a, panel);
  88}
  89
  90static void otm8009a_dcs_write_buf(struct otm8009a *ctx, const void *data,
  91                                   size_t len)
  92{
  93        struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
  94
  95        if (mipi_dsi_dcs_write_buffer(dsi, data, len) < 0)
  96                DRM_WARN("mipi dsi dcs write buffer failed\n");
  97}
  98
  99static void otm8009a_dcs_write_buf_hs(struct otm8009a *ctx, const void *data,
 100                                      size_t len)
 101{
 102        struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
 103
 104        /* data will be sent in dsi hs mode (ie. no lpm) */
 105        dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
 106
 107        otm8009a_dcs_write_buf(ctx, data, len);
 108
 109        /* restore back the dsi lpm mode */
 110        dsi->mode_flags |= MIPI_DSI_MODE_LPM;
 111}
 112
 113#define dcs_write_seq(ctx, seq...)                      \
 114({                                                      \
 115        static const u8 d[] = { seq };                  \
 116        otm8009a_dcs_write_buf(ctx, d, ARRAY_SIZE(d));  \
 117})
 118
 119#define dcs_write_cmd_at(ctx, cmd, seq...)              \
 120({                                                      \
 121        dcs_write_seq(ctx, MCS_ADRSFT, (cmd) & 0xFF);   \
 122        dcs_write_seq(ctx, (cmd) >> 8, seq);            \
 123})
 124
 125static int otm8009a_init_sequence(struct otm8009a *ctx)
 126{
 127        struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
 128        int ret;
 129
 130        /* Enter CMD2 */
 131        dcs_write_cmd_at(ctx, MCS_CMD2_ENA1, 0x80, 0x09, 0x01);
 132
 133        /* Enter Orise Command2 */
 134        dcs_write_cmd_at(ctx, MCS_CMD2_ENA2, 0x80, 0x09);
 135
 136        dcs_write_cmd_at(ctx, MCS_SD_PCH_CTRL, 0x30);
 137        mdelay(10);
 138
 139        dcs_write_cmd_at(ctx, MCS_NO_DOC1, 0x40);
 140        mdelay(10);
 141
 142        dcs_write_cmd_at(ctx, MCS_PWR_CTRL4 + 1, 0xA9);
 143        dcs_write_cmd_at(ctx, MCS_PWR_CTRL2 + 1, 0x34);
 144        dcs_write_cmd_at(ctx, MCS_P_DRV_M, 0x50);
 145        dcs_write_cmd_at(ctx, MCS_VCOMDC, 0x4E);
 146        dcs_write_cmd_at(ctx, MCS_OSC_ADJ, 0x66); /* 65Hz */
 147        dcs_write_cmd_at(ctx, MCS_PWR_CTRL2 + 2, 0x01);
 148        dcs_write_cmd_at(ctx, MCS_PWR_CTRL2 + 5, 0x34);
 149        dcs_write_cmd_at(ctx, MCS_PWR_CTRL2 + 4, 0x33);
 150        dcs_write_cmd_at(ctx, MCS_GVDDSET, 0x79, 0x79);
 151        dcs_write_cmd_at(ctx, MCS_SD_CTRL + 1, 0x1B);
 152        dcs_write_cmd_at(ctx, MCS_PWR_CTRL1 + 2, 0x83);
 153        dcs_write_cmd_at(ctx, MCS_SD_PCH_CTRL + 1, 0x83);
 154        dcs_write_cmd_at(ctx, MCS_RGB_VID_SET, 0x0E);
 155        dcs_write_cmd_at(ctx, MCS_PANSET, 0x00, 0x01);
 156
 157        dcs_write_cmd_at(ctx, MCS_GOAVST, 0x85, 0x01, 0x00, 0x84, 0x01, 0x00);
 158        dcs_write_cmd_at(ctx, MCS_GOACLKA1, 0x18, 0x04, 0x03, 0x39, 0x00, 0x00,
 159                         0x00, 0x18, 0x03, 0x03, 0x3A, 0x00, 0x00, 0x00);
 160        dcs_write_cmd_at(ctx, MCS_GOACLKA3, 0x18, 0x02, 0x03, 0x3B, 0x00, 0x00,
 161                         0x00, 0x18, 0x01, 0x03, 0x3C, 0x00, 0x00, 0x00);
 162        dcs_write_cmd_at(ctx, MCS_GOAECLK, 0x01, 0x01, 0x20, 0x20, 0x00, 0x00,
 163                         0x01, 0x02, 0x00, 0x00);
 164
 165        dcs_write_cmd_at(ctx, MCS_NO_DOC2, 0x00);
 166
 167        dcs_write_cmd_at(ctx, MCS_PANCTRLSET1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
 168        dcs_write_cmd_at(ctx, MCS_PANCTRLSET2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 169                         0, 0, 0, 0, 0);
 170        dcs_write_cmd_at(ctx, MCS_PANCTRLSET3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 171                         0, 0, 0, 0, 0);
 172        dcs_write_cmd_at(ctx, MCS_PANCTRLSET4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
 173        dcs_write_cmd_at(ctx, MCS_PANCTRLSET5, 0, 4, 4, 4, 4, 4, 0, 0, 0, 0,
 174                         0, 0, 0, 0, 0);
 175        dcs_write_cmd_at(ctx, MCS_PANCTRLSET6, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4,
 176                         4, 0, 0, 0, 0);
 177        dcs_write_cmd_at(ctx, MCS_PANCTRLSET7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
 178        dcs_write_cmd_at(ctx, MCS_PANCTRLSET8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
 179                         0xFF, 0xFF, 0xFF, 0xFF, 0xFF);
 180
 181        dcs_write_cmd_at(ctx, MCS_PANU2D1, 0x00, 0x26, 0x09, 0x0B, 0x01, 0x25,
 182                         0x00, 0x00, 0x00, 0x00);
 183        dcs_write_cmd_at(ctx, MCS_PANU2D2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 184                         0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x0A, 0x0C, 0x02);
 185        dcs_write_cmd_at(ctx, MCS_PANU2D3, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00,
 186                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
 187        dcs_write_cmd_at(ctx, MCS_PAND2U1, 0x00, 0x25, 0x0C, 0x0A, 0x02, 0x26,
 188                         0x00, 0x00, 0x00, 0x00);
 189        dcs_write_cmd_at(ctx, MCS_PAND2U2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 190                         0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x0B, 0x09, 0x01);
 191        dcs_write_cmd_at(ctx, MCS_PAND2U3, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00,
 192                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
 193
 194        dcs_write_cmd_at(ctx, MCS_PWR_CTRL1 + 1, 0x66);
 195
 196        dcs_write_cmd_at(ctx, MCS_NO_DOC3, 0x06);
 197
 198        dcs_write_cmd_at(ctx, MCS_GMCT2_2P, 0x00, 0x09, 0x0F, 0x0E, 0x07, 0x10,
 199                         0x0B, 0x0A, 0x04, 0x07, 0x0B, 0x08, 0x0F, 0x10, 0x0A,
 200                         0x01);
 201        dcs_write_cmd_at(ctx, MCS_GMCT2_2N, 0x00, 0x09, 0x0F, 0x0E, 0x07, 0x10,
 202                         0x0B, 0x0A, 0x04, 0x07, 0x0B, 0x08, 0x0F, 0x10, 0x0A,
 203                         0x01);
 204
 205        /* Exit CMD2 */
 206        dcs_write_cmd_at(ctx, MCS_CMD2_ENA1, 0xFF, 0xFF, 0xFF);
 207
 208        ret = mipi_dsi_dcs_nop(dsi);
 209        if (ret)
 210                return ret;
 211
 212        ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
 213        if (ret)
 214                return ret;
 215
 216        /* Wait for sleep out exit */
 217        mdelay(120);
 218
 219        /* Default portrait 480x800 rgb24 */
 220        dcs_write_seq(ctx, MIPI_DCS_SET_ADDRESS_MODE, 0x00);
 221
 222        ret = mipi_dsi_dcs_set_column_address(dsi, 0,
 223                                              default_mode.hdisplay - 1);
 224        if (ret)
 225                return ret;
 226
 227        ret = mipi_dsi_dcs_set_page_address(dsi, 0, default_mode.vdisplay - 1);
 228        if (ret)
 229                return ret;
 230
 231        /* See otm8009a driver documentation for pixel format descriptions */
 232        ret = mipi_dsi_dcs_set_pixel_format(dsi, MIPI_DCS_PIXEL_FMT_24BIT |
 233                                            MIPI_DCS_PIXEL_FMT_24BIT << 4);
 234        if (ret)
 235                return ret;
 236
 237        /* Disable CABC feature */
 238        dcs_write_seq(ctx, MIPI_DCS_WRITE_POWER_SAVE, 0x00);
 239
 240        ret = mipi_dsi_dcs_set_display_on(dsi);
 241        if (ret)
 242                return ret;
 243
 244        ret = mipi_dsi_dcs_nop(dsi);
 245        if (ret)
 246                return ret;
 247
 248        /* Send Command GRAM memory write (no parameters) */
 249        dcs_write_seq(ctx, MIPI_DCS_WRITE_MEMORY_START);
 250
 251        /* Wait a short while to let the panel be ready before the 1st frame */
 252        mdelay(10);
 253
 254        return 0;
 255}
 256
 257static int otm8009a_disable(struct drm_panel *panel)
 258{
 259        struct otm8009a *ctx = panel_to_otm8009a(panel);
 260        struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
 261        int ret;
 262
 263        if (!ctx->enabled)
 264                return 0; /* This is not an issue so we return 0 here */
 265
 266        backlight_disable(ctx->bl_dev);
 267
 268        ret = mipi_dsi_dcs_set_display_off(dsi);
 269        if (ret)
 270                return ret;
 271
 272        ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
 273        if (ret)
 274                return ret;
 275
 276        msleep(120);
 277
 278        ctx->enabled = false;
 279
 280        return 0;
 281}
 282
 283static int otm8009a_unprepare(struct drm_panel *panel)
 284{
 285        struct otm8009a *ctx = panel_to_otm8009a(panel);
 286
 287        if (!ctx->prepared)
 288                return 0;
 289
 290        if (ctx->reset_gpio) {
 291                gpiod_set_value_cansleep(ctx->reset_gpio, 1);
 292                msleep(20);
 293        }
 294
 295        regulator_disable(ctx->supply);
 296
 297        ctx->prepared = false;
 298
 299        return 0;
 300}
 301
 302static int otm8009a_prepare(struct drm_panel *panel)
 303{
 304        struct otm8009a *ctx = panel_to_otm8009a(panel);
 305        int ret;
 306
 307        if (ctx->prepared)
 308                return 0;
 309
 310        ret = regulator_enable(ctx->supply);
 311        if (ret < 0) {
 312                DRM_ERROR("failed to enable supply: %d\n", ret);
 313                return ret;
 314        }
 315
 316        if (ctx->reset_gpio) {
 317                gpiod_set_value_cansleep(ctx->reset_gpio, 0);
 318                gpiod_set_value_cansleep(ctx->reset_gpio, 1);
 319                msleep(20);
 320                gpiod_set_value_cansleep(ctx->reset_gpio, 0);
 321                msleep(100);
 322        }
 323
 324        ret = otm8009a_init_sequence(ctx);
 325        if (ret)
 326                return ret;
 327
 328        ctx->prepared = true;
 329
 330        return 0;
 331}
 332
 333static int otm8009a_enable(struct drm_panel *panel)
 334{
 335        struct otm8009a *ctx = panel_to_otm8009a(panel);
 336
 337        if (ctx->enabled)
 338                return 0;
 339
 340        backlight_enable(ctx->bl_dev);
 341
 342        ctx->enabled = true;
 343
 344        return 0;
 345}
 346
 347static int otm8009a_get_modes(struct drm_panel *panel)
 348{
 349        struct drm_display_mode *mode;
 350
 351        mode = drm_mode_duplicate(panel->drm, &default_mode);
 352        if (!mode) {
 353                DRM_ERROR("failed to add mode %ux%ux@%u\n",
 354                          default_mode.hdisplay, default_mode.vdisplay,
 355                          default_mode.vrefresh);
 356                return -ENOMEM;
 357        }
 358
 359        drm_mode_set_name(mode);
 360
 361        mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
 362        drm_mode_probed_add(panel->connector, mode);
 363
 364        panel->connector->display_info.width_mm = mode->width_mm;
 365        panel->connector->display_info.height_mm = mode->height_mm;
 366
 367        return 1;
 368}
 369
 370static const struct drm_panel_funcs otm8009a_drm_funcs = {
 371        .disable   = otm8009a_disable,
 372        .unprepare = otm8009a_unprepare,
 373        .prepare   = otm8009a_prepare,
 374        .enable    = otm8009a_enable,
 375        .get_modes = otm8009a_get_modes,
 376};
 377
 378/*
 379 * DSI-BASED BACKLIGHT
 380 */
 381
 382static int otm8009a_backlight_update_status(struct backlight_device *bd)
 383{
 384        struct otm8009a *ctx = bl_get_data(bd);
 385        u8 data[2];
 386
 387        if (!ctx->prepared) {
 388                DRM_DEBUG("lcd not ready yet for setting its backlight!\n");
 389                return -ENXIO;
 390        }
 391
 392        if (bd->props.power <= FB_BLANK_NORMAL) {
 393                /* Power on the backlight with the requested brightness
 394                 * Note We can not use mipi_dsi_dcs_set_display_brightness()
 395                 * as otm8009a driver support only 8-bit brightness (1 param).
 396                 */
 397                data[0] = MIPI_DCS_SET_DISPLAY_BRIGHTNESS;
 398                data[1] = bd->props.brightness;
 399                otm8009a_dcs_write_buf_hs(ctx, data, ARRAY_SIZE(data));
 400
 401                /* set Brightness Control & Backlight on */
 402                data[1] = 0x24;
 403
 404        } else {
 405                /* Power off the backlight: set Brightness Control & Bl off */
 406                data[1] = 0;
 407        }
 408
 409        /* Update Brightness Control & Backlight */
 410        data[0] = MIPI_DCS_WRITE_CONTROL_DISPLAY;
 411        otm8009a_dcs_write_buf_hs(ctx, data, ARRAY_SIZE(data));
 412
 413        return 0;
 414}
 415
 416static const struct backlight_ops otm8009a_backlight_ops = {
 417        .update_status = otm8009a_backlight_update_status,
 418};
 419
 420static int otm8009a_probe(struct mipi_dsi_device *dsi)
 421{
 422        struct device *dev = &dsi->dev;
 423        struct otm8009a *ctx;
 424        int ret;
 425
 426        ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
 427        if (!ctx)
 428                return -ENOMEM;
 429
 430        ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
 431        if (IS_ERR(ctx->reset_gpio)) {
 432                dev_err(dev, "cannot get reset-gpio\n");
 433                return PTR_ERR(ctx->reset_gpio);
 434        }
 435
 436        ctx->supply = devm_regulator_get(dev, "power");
 437        if (IS_ERR(ctx->supply)) {
 438                ret = PTR_ERR(ctx->supply);
 439                if (ret != -EPROBE_DEFER)
 440                        dev_err(dev, "failed to request regulator: %d\n", ret);
 441                return ret;
 442        }
 443
 444        mipi_dsi_set_drvdata(dsi, ctx);
 445
 446        ctx->dev = dev;
 447
 448        dsi->lanes = 2;
 449        dsi->format = MIPI_DSI_FMT_RGB888;
 450        dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
 451                          MIPI_DSI_MODE_LPM;
 452
 453        drm_panel_init(&ctx->panel);
 454        ctx->panel.dev = dev;
 455        ctx->panel.funcs = &otm8009a_drm_funcs;
 456
 457        ctx->bl_dev = devm_backlight_device_register(dev, dev_name(dev),
 458                                                     dsi->host->dev, ctx,
 459                                                     &otm8009a_backlight_ops,
 460                                                     NULL);
 461        if (IS_ERR(ctx->bl_dev)) {
 462                ret = PTR_ERR(ctx->bl_dev);
 463                dev_err(dev, "failed to register backlight: %d\n", ret);
 464                return ret;
 465        }
 466
 467        ctx->bl_dev->props.max_brightness = OTM8009A_BACKLIGHT_MAX;
 468        ctx->bl_dev->props.brightness = OTM8009A_BACKLIGHT_DEFAULT;
 469        ctx->bl_dev->props.power = FB_BLANK_POWERDOWN;
 470        ctx->bl_dev->props.type = BACKLIGHT_RAW;
 471
 472        drm_panel_add(&ctx->panel);
 473
 474        ret = mipi_dsi_attach(dsi);
 475        if (ret < 0) {
 476                dev_err(dev, "mipi_dsi_attach failed. Is host ready?\n");
 477                drm_panel_remove(&ctx->panel);
 478                backlight_device_unregister(ctx->bl_dev);
 479                return ret;
 480        }
 481
 482        return 0;
 483}
 484
 485static int otm8009a_remove(struct mipi_dsi_device *dsi)
 486{
 487        struct otm8009a *ctx = mipi_dsi_get_drvdata(dsi);
 488
 489        mipi_dsi_detach(dsi);
 490        drm_panel_remove(&ctx->panel);
 491
 492        return 0;
 493}
 494
 495static const struct of_device_id orisetech_otm8009a_of_match[] = {
 496        { .compatible = "orisetech,otm8009a" },
 497        { }
 498};
 499MODULE_DEVICE_TABLE(of, orisetech_otm8009a_of_match);
 500
 501static struct mipi_dsi_driver orisetech_otm8009a_driver = {
 502        .probe  = otm8009a_probe,
 503        .remove = otm8009a_remove,
 504        .driver = {
 505                .name = "panel-orisetech-otm8009a",
 506                .of_match_table = orisetech_otm8009a_of_match,
 507        },
 508};
 509module_mipi_dsi_driver(orisetech_otm8009a_driver);
 510
 511MODULE_AUTHOR("Philippe Cornu <philippe.cornu@st.com>");
 512MODULE_AUTHOR("Yannick Fertre <yannick.fertre@st.com>");
 513MODULE_DESCRIPTION("DRM driver for Orise Tech OTM8009A MIPI DSI panel");
 514MODULE_LICENSE("GPL v2");
 515