linux/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (C) 2017-2018, Bootlin
   4 */
   5
   6#include <linux/backlight.h>
   7#include <linux/delay.h>
   8#include <linux/device.h>
   9#include <linux/err.h>
  10#include <linux/errno.h>
  11#include <linux/fb.h>
  12#include <linux/kernel.h>
  13#include <linux/module.h>
  14
  15#include <linux/gpio/consumer.h>
  16#include <linux/regulator/consumer.h>
  17
  18#include <drm/drm_mipi_dsi.h>
  19#include <drm/drm_modes.h>
  20#include <drm/drm_panel.h>
  21
  22#include <video/mipi_display.h>
  23
  24struct ili9881c {
  25        struct drm_panel        panel;
  26        struct mipi_dsi_device  *dsi;
  27
  28        struct backlight_device *backlight;
  29        struct regulator        *power;
  30        struct gpio_desc        *reset;
  31};
  32
  33enum ili9881c_op {
  34        ILI9881C_SWITCH_PAGE,
  35        ILI9881C_COMMAND,
  36};
  37
  38struct ili9881c_instr {
  39        enum ili9881c_op        op;
  40
  41        union arg {
  42                struct cmd {
  43                        u8      cmd;
  44                        u8      data;
  45                } cmd;
  46                u8      page;
  47        } arg;
  48};
  49
  50#define ILI9881C_SWITCH_PAGE_INSTR(_page)       \
  51        {                                       \
  52                .op = ILI9881C_SWITCH_PAGE,     \
  53                .arg = {                        \
  54                        .page = (_page),        \
  55                },                              \
  56        }
  57
  58#define ILI9881C_COMMAND_INSTR(_cmd, _data)             \
  59        {                                               \
  60                .op = ILI9881C_COMMAND,         \
  61                .arg = {                                \
  62                        .cmd = {                        \
  63                                .cmd = (_cmd),          \
  64                                .data = (_data),        \
  65                        },                              \
  66                },                                      \
  67        }
  68
  69static const struct ili9881c_instr ili9881c_init[] = {
  70        ILI9881C_SWITCH_PAGE_INSTR(3),
  71        ILI9881C_COMMAND_INSTR(0x01, 0x00),
  72        ILI9881C_COMMAND_INSTR(0x02, 0x00),
  73        ILI9881C_COMMAND_INSTR(0x03, 0x73),
  74        ILI9881C_COMMAND_INSTR(0x04, 0x03),
  75        ILI9881C_COMMAND_INSTR(0x05, 0x00),
  76        ILI9881C_COMMAND_INSTR(0x06, 0x06),
  77        ILI9881C_COMMAND_INSTR(0x07, 0x06),
  78        ILI9881C_COMMAND_INSTR(0x08, 0x00),
  79        ILI9881C_COMMAND_INSTR(0x09, 0x18),
  80        ILI9881C_COMMAND_INSTR(0x0a, 0x04),
  81        ILI9881C_COMMAND_INSTR(0x0b, 0x00),
  82        ILI9881C_COMMAND_INSTR(0x0c, 0x02),
  83        ILI9881C_COMMAND_INSTR(0x0d, 0x03),
  84        ILI9881C_COMMAND_INSTR(0x0e, 0x00),
  85        ILI9881C_COMMAND_INSTR(0x0f, 0x25),
  86        ILI9881C_COMMAND_INSTR(0x10, 0x25),
  87        ILI9881C_COMMAND_INSTR(0x11, 0x00),
  88        ILI9881C_COMMAND_INSTR(0x12, 0x00),
  89        ILI9881C_COMMAND_INSTR(0x13, 0x00),
  90        ILI9881C_COMMAND_INSTR(0x14, 0x00),
  91        ILI9881C_COMMAND_INSTR(0x15, 0x00),
  92        ILI9881C_COMMAND_INSTR(0x16, 0x0C),
  93        ILI9881C_COMMAND_INSTR(0x17, 0x00),
  94        ILI9881C_COMMAND_INSTR(0x18, 0x00),
  95        ILI9881C_COMMAND_INSTR(0x19, 0x00),
  96        ILI9881C_COMMAND_INSTR(0x1a, 0x00),
  97        ILI9881C_COMMAND_INSTR(0x1b, 0x00),
  98        ILI9881C_COMMAND_INSTR(0x1c, 0x00),
  99        ILI9881C_COMMAND_INSTR(0x1d, 0x00),
 100        ILI9881C_COMMAND_INSTR(0x1e, 0xC0),
 101        ILI9881C_COMMAND_INSTR(0x1f, 0x80),
 102        ILI9881C_COMMAND_INSTR(0x20, 0x04),
 103        ILI9881C_COMMAND_INSTR(0x21, 0x01),
 104        ILI9881C_COMMAND_INSTR(0x22, 0x00),
 105        ILI9881C_COMMAND_INSTR(0x23, 0x00),
 106        ILI9881C_COMMAND_INSTR(0x24, 0x00),
 107        ILI9881C_COMMAND_INSTR(0x25, 0x00),
 108        ILI9881C_COMMAND_INSTR(0x26, 0x00),
 109        ILI9881C_COMMAND_INSTR(0x27, 0x00),
 110        ILI9881C_COMMAND_INSTR(0x28, 0x33),
 111        ILI9881C_COMMAND_INSTR(0x29, 0x03),
 112        ILI9881C_COMMAND_INSTR(0x2a, 0x00),
 113        ILI9881C_COMMAND_INSTR(0x2b, 0x00),
 114        ILI9881C_COMMAND_INSTR(0x2c, 0x00),
 115        ILI9881C_COMMAND_INSTR(0x2d, 0x00),
 116        ILI9881C_COMMAND_INSTR(0x2e, 0x00),
 117        ILI9881C_COMMAND_INSTR(0x2f, 0x00),
 118        ILI9881C_COMMAND_INSTR(0x30, 0x00),
 119        ILI9881C_COMMAND_INSTR(0x31, 0x00),
 120        ILI9881C_COMMAND_INSTR(0x32, 0x00),
 121        ILI9881C_COMMAND_INSTR(0x33, 0x00),
 122        ILI9881C_COMMAND_INSTR(0x34, 0x04),
 123        ILI9881C_COMMAND_INSTR(0x35, 0x00),
 124        ILI9881C_COMMAND_INSTR(0x36, 0x00),
 125        ILI9881C_COMMAND_INSTR(0x37, 0x00),
 126        ILI9881C_COMMAND_INSTR(0x38, 0x3C),
 127        ILI9881C_COMMAND_INSTR(0x39, 0x00),
 128        ILI9881C_COMMAND_INSTR(0x3a, 0x00),
 129        ILI9881C_COMMAND_INSTR(0x3b, 0x00),
 130        ILI9881C_COMMAND_INSTR(0x3c, 0x00),
 131        ILI9881C_COMMAND_INSTR(0x3d, 0x00),
 132        ILI9881C_COMMAND_INSTR(0x3e, 0x00),
 133        ILI9881C_COMMAND_INSTR(0x3f, 0x00),
 134        ILI9881C_COMMAND_INSTR(0x40, 0x00),
 135        ILI9881C_COMMAND_INSTR(0x41, 0x00),
 136        ILI9881C_COMMAND_INSTR(0x42, 0x00),
 137        ILI9881C_COMMAND_INSTR(0x43, 0x00),
 138        ILI9881C_COMMAND_INSTR(0x44, 0x00),
 139        ILI9881C_COMMAND_INSTR(0x50, 0x01),
 140        ILI9881C_COMMAND_INSTR(0x51, 0x23),
 141        ILI9881C_COMMAND_INSTR(0x52, 0x45),
 142        ILI9881C_COMMAND_INSTR(0x53, 0x67),
 143        ILI9881C_COMMAND_INSTR(0x54, 0x89),
 144        ILI9881C_COMMAND_INSTR(0x55, 0xab),
 145        ILI9881C_COMMAND_INSTR(0x56, 0x01),
 146        ILI9881C_COMMAND_INSTR(0x57, 0x23),
 147        ILI9881C_COMMAND_INSTR(0x58, 0x45),
 148        ILI9881C_COMMAND_INSTR(0x59, 0x67),
 149        ILI9881C_COMMAND_INSTR(0x5a, 0x89),
 150        ILI9881C_COMMAND_INSTR(0x5b, 0xab),
 151        ILI9881C_COMMAND_INSTR(0x5c, 0xcd),
 152        ILI9881C_COMMAND_INSTR(0x5d, 0xef),
 153        ILI9881C_COMMAND_INSTR(0x5e, 0x11),
 154        ILI9881C_COMMAND_INSTR(0x5f, 0x02),
 155        ILI9881C_COMMAND_INSTR(0x60, 0x02),
 156        ILI9881C_COMMAND_INSTR(0x61, 0x02),
 157        ILI9881C_COMMAND_INSTR(0x62, 0x02),
 158        ILI9881C_COMMAND_INSTR(0x63, 0x02),
 159        ILI9881C_COMMAND_INSTR(0x64, 0x02),
 160        ILI9881C_COMMAND_INSTR(0x65, 0x02),
 161        ILI9881C_COMMAND_INSTR(0x66, 0x02),
 162        ILI9881C_COMMAND_INSTR(0x67, 0x02),
 163        ILI9881C_COMMAND_INSTR(0x68, 0x02),
 164        ILI9881C_COMMAND_INSTR(0x69, 0x02),
 165        ILI9881C_COMMAND_INSTR(0x6a, 0x0C),
 166        ILI9881C_COMMAND_INSTR(0x6b, 0x02),
 167        ILI9881C_COMMAND_INSTR(0x6c, 0x0F),
 168        ILI9881C_COMMAND_INSTR(0x6d, 0x0E),
 169        ILI9881C_COMMAND_INSTR(0x6e, 0x0D),
 170        ILI9881C_COMMAND_INSTR(0x6f, 0x06),
 171        ILI9881C_COMMAND_INSTR(0x70, 0x07),
 172        ILI9881C_COMMAND_INSTR(0x71, 0x02),
 173        ILI9881C_COMMAND_INSTR(0x72, 0x02),
 174        ILI9881C_COMMAND_INSTR(0x73, 0x02),
 175        ILI9881C_COMMAND_INSTR(0x74, 0x02),
 176        ILI9881C_COMMAND_INSTR(0x75, 0x02),
 177        ILI9881C_COMMAND_INSTR(0x76, 0x02),
 178        ILI9881C_COMMAND_INSTR(0x77, 0x02),
 179        ILI9881C_COMMAND_INSTR(0x78, 0x02),
 180        ILI9881C_COMMAND_INSTR(0x79, 0x02),
 181        ILI9881C_COMMAND_INSTR(0x7a, 0x02),
 182        ILI9881C_COMMAND_INSTR(0x7b, 0x02),
 183        ILI9881C_COMMAND_INSTR(0x7c, 0x02),
 184        ILI9881C_COMMAND_INSTR(0x7d, 0x02),
 185        ILI9881C_COMMAND_INSTR(0x7e, 0x02),
 186        ILI9881C_COMMAND_INSTR(0x7f, 0x02),
 187        ILI9881C_COMMAND_INSTR(0x80, 0x0C),
 188        ILI9881C_COMMAND_INSTR(0x81, 0x02),
 189        ILI9881C_COMMAND_INSTR(0x82, 0x0F),
 190        ILI9881C_COMMAND_INSTR(0x83, 0x0E),
 191        ILI9881C_COMMAND_INSTR(0x84, 0x0D),
 192        ILI9881C_COMMAND_INSTR(0x85, 0x06),
 193        ILI9881C_COMMAND_INSTR(0x86, 0x07),
 194        ILI9881C_COMMAND_INSTR(0x87, 0x02),
 195        ILI9881C_COMMAND_INSTR(0x88, 0x02),
 196        ILI9881C_COMMAND_INSTR(0x89, 0x02),
 197        ILI9881C_COMMAND_INSTR(0x8A, 0x02),
 198        ILI9881C_SWITCH_PAGE_INSTR(4),
 199        ILI9881C_COMMAND_INSTR(0x6C, 0x15),
 200        ILI9881C_COMMAND_INSTR(0x6E, 0x22),
 201        ILI9881C_COMMAND_INSTR(0x6F, 0x33),
 202        ILI9881C_COMMAND_INSTR(0x3A, 0xA4),
 203        ILI9881C_COMMAND_INSTR(0x8D, 0x0D),
 204        ILI9881C_COMMAND_INSTR(0x87, 0xBA),
 205        ILI9881C_COMMAND_INSTR(0x26, 0x76),
 206        ILI9881C_COMMAND_INSTR(0xB2, 0xD1),
 207        ILI9881C_SWITCH_PAGE_INSTR(1),
 208        ILI9881C_COMMAND_INSTR(0x22, 0x0A),
 209        ILI9881C_COMMAND_INSTR(0x53, 0xDC),
 210        ILI9881C_COMMAND_INSTR(0x55, 0xA7),
 211        ILI9881C_COMMAND_INSTR(0x50, 0x78),
 212        ILI9881C_COMMAND_INSTR(0x51, 0x78),
 213        ILI9881C_COMMAND_INSTR(0x31, 0x02),
 214        ILI9881C_COMMAND_INSTR(0x60, 0x14),
 215        ILI9881C_COMMAND_INSTR(0xA0, 0x2A),
 216        ILI9881C_COMMAND_INSTR(0xA1, 0x39),
 217        ILI9881C_COMMAND_INSTR(0xA2, 0x46),
 218        ILI9881C_COMMAND_INSTR(0xA3, 0x0e),
 219        ILI9881C_COMMAND_INSTR(0xA4, 0x12),
 220        ILI9881C_COMMAND_INSTR(0xA5, 0x25),
 221        ILI9881C_COMMAND_INSTR(0xA6, 0x19),
 222        ILI9881C_COMMAND_INSTR(0xA7, 0x1d),
 223        ILI9881C_COMMAND_INSTR(0xA8, 0xa6),
 224        ILI9881C_COMMAND_INSTR(0xA9, 0x1C),
 225        ILI9881C_COMMAND_INSTR(0xAA, 0x29),
 226        ILI9881C_COMMAND_INSTR(0xAB, 0x85),
 227        ILI9881C_COMMAND_INSTR(0xAC, 0x1C),
 228        ILI9881C_COMMAND_INSTR(0xAD, 0x1B),
 229        ILI9881C_COMMAND_INSTR(0xAE, 0x51),
 230        ILI9881C_COMMAND_INSTR(0xAF, 0x22),
 231        ILI9881C_COMMAND_INSTR(0xB0, 0x2d),
 232        ILI9881C_COMMAND_INSTR(0xB1, 0x4f),
 233        ILI9881C_COMMAND_INSTR(0xB2, 0x59),
 234        ILI9881C_COMMAND_INSTR(0xB3, 0x3F),
 235        ILI9881C_COMMAND_INSTR(0xC0, 0x2A),
 236        ILI9881C_COMMAND_INSTR(0xC1, 0x3a),
 237        ILI9881C_COMMAND_INSTR(0xC2, 0x45),
 238        ILI9881C_COMMAND_INSTR(0xC3, 0x0e),
 239        ILI9881C_COMMAND_INSTR(0xC4, 0x11),
 240        ILI9881C_COMMAND_INSTR(0xC5, 0x24),
 241        ILI9881C_COMMAND_INSTR(0xC6, 0x1a),
 242        ILI9881C_COMMAND_INSTR(0xC7, 0x1c),
 243        ILI9881C_COMMAND_INSTR(0xC8, 0xaa),
 244        ILI9881C_COMMAND_INSTR(0xC9, 0x1C),
 245        ILI9881C_COMMAND_INSTR(0xCA, 0x29),
 246        ILI9881C_COMMAND_INSTR(0xCB, 0x96),
 247        ILI9881C_COMMAND_INSTR(0xCC, 0x1C),
 248        ILI9881C_COMMAND_INSTR(0xCD, 0x1B),
 249        ILI9881C_COMMAND_INSTR(0xCE, 0x51),
 250        ILI9881C_COMMAND_INSTR(0xCF, 0x22),
 251        ILI9881C_COMMAND_INSTR(0xD0, 0x2b),
 252        ILI9881C_COMMAND_INSTR(0xD1, 0x4b),
 253        ILI9881C_COMMAND_INSTR(0xD2, 0x59),
 254        ILI9881C_COMMAND_INSTR(0xD3, 0x3F),
 255};
 256
 257static inline struct ili9881c *panel_to_ili9881c(struct drm_panel *panel)
 258{
 259        return container_of(panel, struct ili9881c, panel);
 260}
 261
 262/*
 263 * The panel seems to accept some private DCS commands that map
 264 * directly to registers.
 265 *
 266 * It is organised by page, with each page having its own set of
 267 * registers, and the first page looks like it's holding the standard
 268 * DCS commands.
 269 *
 270 * So before any attempt at sending a command or data, we have to be
 271 * sure if we're in the right page or not.
 272 */
 273static int ili9881c_switch_page(struct ili9881c *ctx, u8 page)
 274{
 275        u8 buf[4] = { 0xff, 0x98, 0x81, page };
 276        int ret;
 277
 278        ret = mipi_dsi_dcs_write_buffer(ctx->dsi, buf, sizeof(buf));
 279        if (ret < 0)
 280                return ret;
 281
 282        return 0;
 283}
 284
 285static int ili9881c_send_cmd_data(struct ili9881c *ctx, u8 cmd, u8 data)
 286{
 287        u8 buf[2] = { cmd, data };
 288        int ret;
 289
 290        ret = mipi_dsi_dcs_write_buffer(ctx->dsi, buf, sizeof(buf));
 291        if (ret < 0)
 292                return ret;
 293
 294        return 0;
 295}
 296
 297static int ili9881c_prepare(struct drm_panel *panel)
 298{
 299        struct ili9881c *ctx = panel_to_ili9881c(panel);
 300        unsigned int i;
 301        int ret;
 302
 303        /* Power the panel */
 304        ret = regulator_enable(ctx->power);
 305        if (ret)
 306                return ret;
 307        msleep(5);
 308
 309        /* And reset it */
 310        gpiod_set_value(ctx->reset, 1);
 311        msleep(20);
 312
 313        gpiod_set_value(ctx->reset, 0);
 314        msleep(20);
 315
 316        for (i = 0; i < ARRAY_SIZE(ili9881c_init); i++) {
 317                const struct ili9881c_instr *instr = &ili9881c_init[i];
 318
 319                if (instr->op == ILI9881C_SWITCH_PAGE)
 320                        ret = ili9881c_switch_page(ctx, instr->arg.page);
 321                else if (instr->op == ILI9881C_COMMAND)
 322                        ret = ili9881c_send_cmd_data(ctx, instr->arg.cmd.cmd,
 323                                                      instr->arg.cmd.data);
 324
 325                if (ret)
 326                        return ret;
 327        }
 328
 329        ret = ili9881c_switch_page(ctx, 0);
 330        if (ret)
 331                return ret;
 332
 333        ret = mipi_dsi_dcs_set_tear_on(ctx->dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
 334        if (ret)
 335                return ret;
 336
 337        ret = mipi_dsi_dcs_exit_sleep_mode(ctx->dsi);
 338        if (ret)
 339                return ret;
 340
 341        return 0;
 342}
 343
 344static int ili9881c_enable(struct drm_panel *panel)
 345{
 346        struct ili9881c *ctx = panel_to_ili9881c(panel);
 347
 348        msleep(120);
 349
 350        mipi_dsi_dcs_set_display_on(ctx->dsi);
 351        backlight_enable(ctx->backlight);
 352
 353        return 0;
 354}
 355
 356static int ili9881c_disable(struct drm_panel *panel)
 357{
 358        struct ili9881c *ctx = panel_to_ili9881c(panel);
 359
 360        backlight_disable(ctx->backlight);
 361        return mipi_dsi_dcs_set_display_off(ctx->dsi);
 362}
 363
 364static int ili9881c_unprepare(struct drm_panel *panel)
 365{
 366        struct ili9881c *ctx = panel_to_ili9881c(panel);
 367
 368        mipi_dsi_dcs_enter_sleep_mode(ctx->dsi);
 369        regulator_disable(ctx->power);
 370        gpiod_set_value(ctx->reset, 1);
 371
 372        return 0;
 373}
 374
 375static const struct drm_display_mode bananapi_default_mode = {
 376        .clock          = 62000,
 377        .vrefresh       = 60,
 378
 379        .hdisplay       = 720,
 380        .hsync_start    = 720 + 10,
 381        .hsync_end      = 720 + 10 + 20,
 382        .htotal         = 720 + 10 + 20 + 30,
 383
 384        .vdisplay       = 1280,
 385        .vsync_start    = 1280 + 10,
 386        .vsync_end      = 1280 + 10 + 10,
 387        .vtotal         = 1280 + 10 + 10 + 20,
 388};
 389
 390static int ili9881c_get_modes(struct drm_panel *panel)
 391{
 392        struct drm_connector *connector = panel->connector;
 393        struct ili9881c *ctx = panel_to_ili9881c(panel);
 394        struct drm_display_mode *mode;
 395
 396        mode = drm_mode_duplicate(panel->drm, &bananapi_default_mode);
 397        if (!mode) {
 398                dev_err(&ctx->dsi->dev, "failed to add mode %ux%ux@%u\n",
 399                        bananapi_default_mode.hdisplay,
 400                        bananapi_default_mode.vdisplay,
 401                        bananapi_default_mode.vrefresh);
 402                return -ENOMEM;
 403        }
 404
 405        drm_mode_set_name(mode);
 406
 407        mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
 408        drm_mode_probed_add(connector, mode);
 409
 410        panel->connector->display_info.width_mm = 62;
 411        panel->connector->display_info.height_mm = 110;
 412
 413        return 1;
 414}
 415
 416static const struct drm_panel_funcs ili9881c_funcs = {
 417        .prepare        = ili9881c_prepare,
 418        .unprepare      = ili9881c_unprepare,
 419        .enable         = ili9881c_enable,
 420        .disable        = ili9881c_disable,
 421        .get_modes      = ili9881c_get_modes,
 422};
 423
 424static int ili9881c_dsi_probe(struct mipi_dsi_device *dsi)
 425{
 426        struct device_node *np;
 427        struct ili9881c *ctx;
 428        int ret;
 429
 430        ctx = devm_kzalloc(&dsi->dev, sizeof(*ctx), GFP_KERNEL);
 431        if (!ctx)
 432                return -ENOMEM;
 433        mipi_dsi_set_drvdata(dsi, ctx);
 434        ctx->dsi = dsi;
 435
 436        drm_panel_init(&ctx->panel, &dsi->dev, &ili9881c_funcs,
 437                       DRM_MODE_CONNECTOR_DSI);
 438
 439        ctx->power = devm_regulator_get(&dsi->dev, "power");
 440        if (IS_ERR(ctx->power)) {
 441                dev_err(&dsi->dev, "Couldn't get our power regulator\n");
 442                return PTR_ERR(ctx->power);
 443        }
 444
 445        ctx->reset = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_LOW);
 446        if (IS_ERR(ctx->reset)) {
 447                dev_err(&dsi->dev, "Couldn't get our reset GPIO\n");
 448                return PTR_ERR(ctx->reset);
 449        }
 450
 451        np = of_parse_phandle(dsi->dev.of_node, "backlight", 0);
 452        if (np) {
 453                ctx->backlight = of_find_backlight_by_node(np);
 454                of_node_put(np);
 455
 456                if (!ctx->backlight)
 457                        return -EPROBE_DEFER;
 458        }
 459
 460        ret = drm_panel_add(&ctx->panel);
 461        if (ret < 0)
 462                return ret;
 463
 464        dsi->mode_flags = MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
 465        dsi->format = MIPI_DSI_FMT_RGB888;
 466        dsi->lanes = 4;
 467
 468        return mipi_dsi_attach(dsi);
 469}
 470
 471static int ili9881c_dsi_remove(struct mipi_dsi_device *dsi)
 472{
 473        struct ili9881c *ctx = mipi_dsi_get_drvdata(dsi);
 474
 475        mipi_dsi_detach(dsi);
 476        drm_panel_remove(&ctx->panel);
 477
 478        if (ctx->backlight)
 479                put_device(&ctx->backlight->dev);
 480
 481        return 0;
 482}
 483
 484static const struct of_device_id ili9881c_of_match[] = {
 485        { .compatible = "bananapi,lhr050h41" },
 486        { }
 487};
 488MODULE_DEVICE_TABLE(of, ili9881c_of_match);
 489
 490static struct mipi_dsi_driver ili9881c_dsi_driver = {
 491        .probe          = ili9881c_dsi_probe,
 492        .remove         = ili9881c_dsi_remove,
 493        .driver = {
 494                .name           = "ili9881c-dsi",
 495                .of_match_table = ili9881c_of_match,
 496        },
 497};
 498module_mipi_dsi_driver(ili9881c_dsi_driver);
 499
 500MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
 501MODULE_DESCRIPTION("Ilitek ILI9881C Controller Driver");
 502MODULE_LICENSE("GPL v2");
 503