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/delay.h>
   7#include <linux/device.h>
   8#include <linux/err.h>
   9#include <linux/errno.h>
  10#include <linux/fb.h>
  11#include <linux/kernel.h>
  12#include <linux/module.h>
  13#include <linux/of_device.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
  24enum ili9881c_op {
  25        ILI9881C_SWITCH_PAGE,
  26        ILI9881C_COMMAND,
  27};
  28
  29struct ili9881c_instr {
  30        enum ili9881c_op        op;
  31
  32        union arg {
  33                struct cmd {
  34                        u8      cmd;
  35                        u8      data;
  36                } cmd;
  37                u8      page;
  38        } arg;
  39};
  40
  41struct ili9881c_desc {
  42        const struct ili9881c_instr *init;
  43        const size_t init_length;
  44        const struct drm_display_mode *mode;
  45        const unsigned long mode_flags;
  46};
  47
  48struct ili9881c {
  49        struct drm_panel        panel;
  50        struct mipi_dsi_device  *dsi;
  51        const struct ili9881c_desc      *desc;
  52
  53        struct regulator        *power;
  54        struct gpio_desc        *reset;
  55
  56        enum drm_panel_orientation      orientation;
  57};
  58
  59#define ILI9881C_SWITCH_PAGE_INSTR(_page)       \
  60        {                                       \
  61                .op = ILI9881C_SWITCH_PAGE,     \
  62                .arg = {                        \
  63                        .page = (_page),        \
  64                },                              \
  65        }
  66
  67#define ILI9881C_COMMAND_INSTR(_cmd, _data)             \
  68        {                                               \
  69                .op = ILI9881C_COMMAND,         \
  70                .arg = {                                \
  71                        .cmd = {                        \
  72                                .cmd = (_cmd),          \
  73                                .data = (_data),        \
  74                        },                              \
  75                },                                      \
  76        }
  77
  78static const struct ili9881c_instr lhr050h41_init[] = {
  79        ILI9881C_SWITCH_PAGE_INSTR(3),
  80        ILI9881C_COMMAND_INSTR(0x01, 0x00),
  81        ILI9881C_COMMAND_INSTR(0x02, 0x00),
  82        ILI9881C_COMMAND_INSTR(0x03, 0x73),
  83        ILI9881C_COMMAND_INSTR(0x04, 0x03),
  84        ILI9881C_COMMAND_INSTR(0x05, 0x00),
  85        ILI9881C_COMMAND_INSTR(0x06, 0x06),
  86        ILI9881C_COMMAND_INSTR(0x07, 0x06),
  87        ILI9881C_COMMAND_INSTR(0x08, 0x00),
  88        ILI9881C_COMMAND_INSTR(0x09, 0x18),
  89        ILI9881C_COMMAND_INSTR(0x0a, 0x04),
  90        ILI9881C_COMMAND_INSTR(0x0b, 0x00),
  91        ILI9881C_COMMAND_INSTR(0x0c, 0x02),
  92        ILI9881C_COMMAND_INSTR(0x0d, 0x03),
  93        ILI9881C_COMMAND_INSTR(0x0e, 0x00),
  94        ILI9881C_COMMAND_INSTR(0x0f, 0x25),
  95        ILI9881C_COMMAND_INSTR(0x10, 0x25),
  96        ILI9881C_COMMAND_INSTR(0x11, 0x00),
  97        ILI9881C_COMMAND_INSTR(0x12, 0x00),
  98        ILI9881C_COMMAND_INSTR(0x13, 0x00),
  99        ILI9881C_COMMAND_INSTR(0x14, 0x00),
 100        ILI9881C_COMMAND_INSTR(0x15, 0x00),
 101        ILI9881C_COMMAND_INSTR(0x16, 0x0C),
 102        ILI9881C_COMMAND_INSTR(0x17, 0x00),
 103        ILI9881C_COMMAND_INSTR(0x18, 0x00),
 104        ILI9881C_COMMAND_INSTR(0x19, 0x00),
 105        ILI9881C_COMMAND_INSTR(0x1a, 0x00),
 106        ILI9881C_COMMAND_INSTR(0x1b, 0x00),
 107        ILI9881C_COMMAND_INSTR(0x1c, 0x00),
 108        ILI9881C_COMMAND_INSTR(0x1d, 0x00),
 109        ILI9881C_COMMAND_INSTR(0x1e, 0xC0),
 110        ILI9881C_COMMAND_INSTR(0x1f, 0x80),
 111        ILI9881C_COMMAND_INSTR(0x20, 0x04),
 112        ILI9881C_COMMAND_INSTR(0x21, 0x01),
 113        ILI9881C_COMMAND_INSTR(0x22, 0x00),
 114        ILI9881C_COMMAND_INSTR(0x23, 0x00),
 115        ILI9881C_COMMAND_INSTR(0x24, 0x00),
 116        ILI9881C_COMMAND_INSTR(0x25, 0x00),
 117        ILI9881C_COMMAND_INSTR(0x26, 0x00),
 118        ILI9881C_COMMAND_INSTR(0x27, 0x00),
 119        ILI9881C_COMMAND_INSTR(0x28, 0x33),
 120        ILI9881C_COMMAND_INSTR(0x29, 0x03),
 121        ILI9881C_COMMAND_INSTR(0x2a, 0x00),
 122        ILI9881C_COMMAND_INSTR(0x2b, 0x00),
 123        ILI9881C_COMMAND_INSTR(0x2c, 0x00),
 124        ILI9881C_COMMAND_INSTR(0x2d, 0x00),
 125        ILI9881C_COMMAND_INSTR(0x2e, 0x00),
 126        ILI9881C_COMMAND_INSTR(0x2f, 0x00),
 127        ILI9881C_COMMAND_INSTR(0x30, 0x00),
 128        ILI9881C_COMMAND_INSTR(0x31, 0x00),
 129        ILI9881C_COMMAND_INSTR(0x32, 0x00),
 130        ILI9881C_COMMAND_INSTR(0x33, 0x00),
 131        ILI9881C_COMMAND_INSTR(0x34, 0x04),
 132        ILI9881C_COMMAND_INSTR(0x35, 0x00),
 133        ILI9881C_COMMAND_INSTR(0x36, 0x00),
 134        ILI9881C_COMMAND_INSTR(0x37, 0x00),
 135        ILI9881C_COMMAND_INSTR(0x38, 0x3C),
 136        ILI9881C_COMMAND_INSTR(0x39, 0x00),
 137        ILI9881C_COMMAND_INSTR(0x3a, 0x00),
 138        ILI9881C_COMMAND_INSTR(0x3b, 0x00),
 139        ILI9881C_COMMAND_INSTR(0x3c, 0x00),
 140        ILI9881C_COMMAND_INSTR(0x3d, 0x00),
 141        ILI9881C_COMMAND_INSTR(0x3e, 0x00),
 142        ILI9881C_COMMAND_INSTR(0x3f, 0x00),
 143        ILI9881C_COMMAND_INSTR(0x40, 0x00),
 144        ILI9881C_COMMAND_INSTR(0x41, 0x00),
 145        ILI9881C_COMMAND_INSTR(0x42, 0x00),
 146        ILI9881C_COMMAND_INSTR(0x43, 0x00),
 147        ILI9881C_COMMAND_INSTR(0x44, 0x00),
 148        ILI9881C_COMMAND_INSTR(0x50, 0x01),
 149        ILI9881C_COMMAND_INSTR(0x51, 0x23),
 150        ILI9881C_COMMAND_INSTR(0x52, 0x45),
 151        ILI9881C_COMMAND_INSTR(0x53, 0x67),
 152        ILI9881C_COMMAND_INSTR(0x54, 0x89),
 153        ILI9881C_COMMAND_INSTR(0x55, 0xab),
 154        ILI9881C_COMMAND_INSTR(0x56, 0x01),
 155        ILI9881C_COMMAND_INSTR(0x57, 0x23),
 156        ILI9881C_COMMAND_INSTR(0x58, 0x45),
 157        ILI9881C_COMMAND_INSTR(0x59, 0x67),
 158        ILI9881C_COMMAND_INSTR(0x5a, 0x89),
 159        ILI9881C_COMMAND_INSTR(0x5b, 0xab),
 160        ILI9881C_COMMAND_INSTR(0x5c, 0xcd),
 161        ILI9881C_COMMAND_INSTR(0x5d, 0xef),
 162        ILI9881C_COMMAND_INSTR(0x5e, 0x11),
 163        ILI9881C_COMMAND_INSTR(0x5f, 0x02),
 164        ILI9881C_COMMAND_INSTR(0x60, 0x02),
 165        ILI9881C_COMMAND_INSTR(0x61, 0x02),
 166        ILI9881C_COMMAND_INSTR(0x62, 0x02),
 167        ILI9881C_COMMAND_INSTR(0x63, 0x02),
 168        ILI9881C_COMMAND_INSTR(0x64, 0x02),
 169        ILI9881C_COMMAND_INSTR(0x65, 0x02),
 170        ILI9881C_COMMAND_INSTR(0x66, 0x02),
 171        ILI9881C_COMMAND_INSTR(0x67, 0x02),
 172        ILI9881C_COMMAND_INSTR(0x68, 0x02),
 173        ILI9881C_COMMAND_INSTR(0x69, 0x02),
 174        ILI9881C_COMMAND_INSTR(0x6a, 0x0C),
 175        ILI9881C_COMMAND_INSTR(0x6b, 0x02),
 176        ILI9881C_COMMAND_INSTR(0x6c, 0x0F),
 177        ILI9881C_COMMAND_INSTR(0x6d, 0x0E),
 178        ILI9881C_COMMAND_INSTR(0x6e, 0x0D),
 179        ILI9881C_COMMAND_INSTR(0x6f, 0x06),
 180        ILI9881C_COMMAND_INSTR(0x70, 0x07),
 181        ILI9881C_COMMAND_INSTR(0x71, 0x02),
 182        ILI9881C_COMMAND_INSTR(0x72, 0x02),
 183        ILI9881C_COMMAND_INSTR(0x73, 0x02),
 184        ILI9881C_COMMAND_INSTR(0x74, 0x02),
 185        ILI9881C_COMMAND_INSTR(0x75, 0x02),
 186        ILI9881C_COMMAND_INSTR(0x76, 0x02),
 187        ILI9881C_COMMAND_INSTR(0x77, 0x02),
 188        ILI9881C_COMMAND_INSTR(0x78, 0x02),
 189        ILI9881C_COMMAND_INSTR(0x79, 0x02),
 190        ILI9881C_COMMAND_INSTR(0x7a, 0x02),
 191        ILI9881C_COMMAND_INSTR(0x7b, 0x02),
 192        ILI9881C_COMMAND_INSTR(0x7c, 0x02),
 193        ILI9881C_COMMAND_INSTR(0x7d, 0x02),
 194        ILI9881C_COMMAND_INSTR(0x7e, 0x02),
 195        ILI9881C_COMMAND_INSTR(0x7f, 0x02),
 196        ILI9881C_COMMAND_INSTR(0x80, 0x0C),
 197        ILI9881C_COMMAND_INSTR(0x81, 0x02),
 198        ILI9881C_COMMAND_INSTR(0x82, 0x0F),
 199        ILI9881C_COMMAND_INSTR(0x83, 0x0E),
 200        ILI9881C_COMMAND_INSTR(0x84, 0x0D),
 201        ILI9881C_COMMAND_INSTR(0x85, 0x06),
 202        ILI9881C_COMMAND_INSTR(0x86, 0x07),
 203        ILI9881C_COMMAND_INSTR(0x87, 0x02),
 204        ILI9881C_COMMAND_INSTR(0x88, 0x02),
 205        ILI9881C_COMMAND_INSTR(0x89, 0x02),
 206        ILI9881C_COMMAND_INSTR(0x8A, 0x02),
 207        ILI9881C_SWITCH_PAGE_INSTR(4),
 208        ILI9881C_COMMAND_INSTR(0x6C, 0x15),
 209        ILI9881C_COMMAND_INSTR(0x6E, 0x22),
 210        ILI9881C_COMMAND_INSTR(0x6F, 0x33),
 211        ILI9881C_COMMAND_INSTR(0x3A, 0xA4),
 212        ILI9881C_COMMAND_INSTR(0x8D, 0x0D),
 213        ILI9881C_COMMAND_INSTR(0x87, 0xBA),
 214        ILI9881C_COMMAND_INSTR(0x26, 0x76),
 215        ILI9881C_COMMAND_INSTR(0xB2, 0xD1),
 216        ILI9881C_SWITCH_PAGE_INSTR(1),
 217        ILI9881C_COMMAND_INSTR(0x22, 0x0A),
 218        ILI9881C_COMMAND_INSTR(0x53, 0xDC),
 219        ILI9881C_COMMAND_INSTR(0x55, 0xA7),
 220        ILI9881C_COMMAND_INSTR(0x50, 0x78),
 221        ILI9881C_COMMAND_INSTR(0x51, 0x78),
 222        ILI9881C_COMMAND_INSTR(0x31, 0x02),
 223        ILI9881C_COMMAND_INSTR(0x60, 0x14),
 224        ILI9881C_COMMAND_INSTR(0xA0, 0x2A),
 225        ILI9881C_COMMAND_INSTR(0xA1, 0x39),
 226        ILI9881C_COMMAND_INSTR(0xA2, 0x46),
 227        ILI9881C_COMMAND_INSTR(0xA3, 0x0e),
 228        ILI9881C_COMMAND_INSTR(0xA4, 0x12),
 229        ILI9881C_COMMAND_INSTR(0xA5, 0x25),
 230        ILI9881C_COMMAND_INSTR(0xA6, 0x19),
 231        ILI9881C_COMMAND_INSTR(0xA7, 0x1d),
 232        ILI9881C_COMMAND_INSTR(0xA8, 0xa6),
 233        ILI9881C_COMMAND_INSTR(0xA9, 0x1C),
 234        ILI9881C_COMMAND_INSTR(0xAA, 0x29),
 235        ILI9881C_COMMAND_INSTR(0xAB, 0x85),
 236        ILI9881C_COMMAND_INSTR(0xAC, 0x1C),
 237        ILI9881C_COMMAND_INSTR(0xAD, 0x1B),
 238        ILI9881C_COMMAND_INSTR(0xAE, 0x51),
 239        ILI9881C_COMMAND_INSTR(0xAF, 0x22),
 240        ILI9881C_COMMAND_INSTR(0xB0, 0x2d),
 241        ILI9881C_COMMAND_INSTR(0xB1, 0x4f),
 242        ILI9881C_COMMAND_INSTR(0xB2, 0x59),
 243        ILI9881C_COMMAND_INSTR(0xB3, 0x3F),
 244        ILI9881C_COMMAND_INSTR(0xC0, 0x2A),
 245        ILI9881C_COMMAND_INSTR(0xC1, 0x3a),
 246        ILI9881C_COMMAND_INSTR(0xC2, 0x45),
 247        ILI9881C_COMMAND_INSTR(0xC3, 0x0e),
 248        ILI9881C_COMMAND_INSTR(0xC4, 0x11),
 249        ILI9881C_COMMAND_INSTR(0xC5, 0x24),
 250        ILI9881C_COMMAND_INSTR(0xC6, 0x1a),
 251        ILI9881C_COMMAND_INSTR(0xC7, 0x1c),
 252        ILI9881C_COMMAND_INSTR(0xC8, 0xaa),
 253        ILI9881C_COMMAND_INSTR(0xC9, 0x1C),
 254        ILI9881C_COMMAND_INSTR(0xCA, 0x29),
 255        ILI9881C_COMMAND_INSTR(0xCB, 0x96),
 256        ILI9881C_COMMAND_INSTR(0xCC, 0x1C),
 257        ILI9881C_COMMAND_INSTR(0xCD, 0x1B),
 258        ILI9881C_COMMAND_INSTR(0xCE, 0x51),
 259        ILI9881C_COMMAND_INSTR(0xCF, 0x22),
 260        ILI9881C_COMMAND_INSTR(0xD0, 0x2b),
 261        ILI9881C_COMMAND_INSTR(0xD1, 0x4b),
 262        ILI9881C_COMMAND_INSTR(0xD2, 0x59),
 263        ILI9881C_COMMAND_INSTR(0xD3, 0x3F),
 264};
 265
 266static const struct ili9881c_instr k101_im2byl02_init[] = {
 267        ILI9881C_SWITCH_PAGE_INSTR(3),
 268        ILI9881C_COMMAND_INSTR(0x01, 0x00),
 269        ILI9881C_COMMAND_INSTR(0x02, 0x00),
 270        ILI9881C_COMMAND_INSTR(0x03, 0x73),
 271        ILI9881C_COMMAND_INSTR(0x04, 0x00),
 272        ILI9881C_COMMAND_INSTR(0x05, 0x00),
 273        ILI9881C_COMMAND_INSTR(0x06, 0x08),
 274        ILI9881C_COMMAND_INSTR(0x07, 0x00),
 275        ILI9881C_COMMAND_INSTR(0x08, 0x00),
 276        ILI9881C_COMMAND_INSTR(0x09, 0x00),
 277        ILI9881C_COMMAND_INSTR(0x0A, 0x01),
 278        ILI9881C_COMMAND_INSTR(0x0B, 0x01),
 279        ILI9881C_COMMAND_INSTR(0x0C, 0x00),
 280        ILI9881C_COMMAND_INSTR(0x0D, 0x01),
 281        ILI9881C_COMMAND_INSTR(0x0E, 0x01),
 282        ILI9881C_COMMAND_INSTR(0x0F, 0x00),
 283        ILI9881C_COMMAND_INSTR(0x10, 0x00),
 284        ILI9881C_COMMAND_INSTR(0x11, 0x00),
 285        ILI9881C_COMMAND_INSTR(0x12, 0x00),
 286        ILI9881C_COMMAND_INSTR(0x13, 0x00),
 287        ILI9881C_COMMAND_INSTR(0x14, 0x00),
 288        ILI9881C_COMMAND_INSTR(0x15, 0x00),
 289        ILI9881C_COMMAND_INSTR(0x16, 0x00),
 290        ILI9881C_COMMAND_INSTR(0x17, 0x00),
 291        ILI9881C_COMMAND_INSTR(0x18, 0x00),
 292        ILI9881C_COMMAND_INSTR(0x19, 0x00),
 293        ILI9881C_COMMAND_INSTR(0x1A, 0x00),
 294        ILI9881C_COMMAND_INSTR(0x1B, 0x00),
 295        ILI9881C_COMMAND_INSTR(0x1C, 0x00),
 296        ILI9881C_COMMAND_INSTR(0x1D, 0x00),
 297        ILI9881C_COMMAND_INSTR(0x1E, 0x40),
 298        ILI9881C_COMMAND_INSTR(0x1F, 0xC0),
 299        ILI9881C_COMMAND_INSTR(0x20, 0x06),
 300        ILI9881C_COMMAND_INSTR(0x21, 0x01),
 301        ILI9881C_COMMAND_INSTR(0x22, 0x06),
 302        ILI9881C_COMMAND_INSTR(0x23, 0x01),
 303        ILI9881C_COMMAND_INSTR(0x24, 0x88),
 304        ILI9881C_COMMAND_INSTR(0x25, 0x88),
 305        ILI9881C_COMMAND_INSTR(0x26, 0x00),
 306        ILI9881C_COMMAND_INSTR(0x27, 0x00),
 307        ILI9881C_COMMAND_INSTR(0x28, 0x3B),
 308        ILI9881C_COMMAND_INSTR(0x29, 0x03),
 309        ILI9881C_COMMAND_INSTR(0x2A, 0x00),
 310        ILI9881C_COMMAND_INSTR(0x2B, 0x00),
 311        ILI9881C_COMMAND_INSTR(0x2C, 0x00),
 312        ILI9881C_COMMAND_INSTR(0x2D, 0x00),
 313        ILI9881C_COMMAND_INSTR(0x2E, 0x00),
 314        ILI9881C_COMMAND_INSTR(0x2F, 0x00),
 315        ILI9881C_COMMAND_INSTR(0x30, 0x00),
 316        ILI9881C_COMMAND_INSTR(0x31, 0x00),
 317        ILI9881C_COMMAND_INSTR(0x32, 0x00),
 318        ILI9881C_COMMAND_INSTR(0x33, 0x00),
 319        ILI9881C_COMMAND_INSTR(0x34, 0x00), /* GPWR1/2 non overlap time 2.62us */
 320        ILI9881C_COMMAND_INSTR(0x35, 0x00),
 321        ILI9881C_COMMAND_INSTR(0x36, 0x00),
 322        ILI9881C_COMMAND_INSTR(0x37, 0x00),
 323        ILI9881C_COMMAND_INSTR(0x38, 0x00),
 324        ILI9881C_COMMAND_INSTR(0x39, 0x00),
 325        ILI9881C_COMMAND_INSTR(0x3A, 0x00),
 326        ILI9881C_COMMAND_INSTR(0x3B, 0x00),
 327        ILI9881C_COMMAND_INSTR(0x3C, 0x00),
 328        ILI9881C_COMMAND_INSTR(0x3D, 0x00),
 329        ILI9881C_COMMAND_INSTR(0x3E, 0x00),
 330        ILI9881C_COMMAND_INSTR(0x3F, 0x00),
 331        ILI9881C_COMMAND_INSTR(0x40, 0x00),
 332        ILI9881C_COMMAND_INSTR(0x41, 0x00),
 333        ILI9881C_COMMAND_INSTR(0x42, 0x00),
 334        ILI9881C_COMMAND_INSTR(0x43, 0x00),
 335        ILI9881C_COMMAND_INSTR(0x44, 0x00),
 336        ILI9881C_COMMAND_INSTR(0x50, 0x01),
 337        ILI9881C_COMMAND_INSTR(0x51, 0x23),
 338        ILI9881C_COMMAND_INSTR(0x52, 0x45),
 339        ILI9881C_COMMAND_INSTR(0x53, 0x67),
 340        ILI9881C_COMMAND_INSTR(0x54, 0x89),
 341        ILI9881C_COMMAND_INSTR(0x55, 0xAB),
 342        ILI9881C_COMMAND_INSTR(0x56, 0x01),
 343        ILI9881C_COMMAND_INSTR(0x57, 0x23),
 344        ILI9881C_COMMAND_INSTR(0x58, 0x45),
 345        ILI9881C_COMMAND_INSTR(0x59, 0x67),
 346        ILI9881C_COMMAND_INSTR(0x5A, 0x89),
 347        ILI9881C_COMMAND_INSTR(0x5B, 0xAB),
 348        ILI9881C_COMMAND_INSTR(0x5C, 0xCD),
 349        ILI9881C_COMMAND_INSTR(0x5D, 0xEF),
 350        ILI9881C_COMMAND_INSTR(0x5E, 0x00),
 351        ILI9881C_COMMAND_INSTR(0x5F, 0x01),
 352        ILI9881C_COMMAND_INSTR(0x60, 0x01),
 353        ILI9881C_COMMAND_INSTR(0x61, 0x06),
 354        ILI9881C_COMMAND_INSTR(0x62, 0x06),
 355        ILI9881C_COMMAND_INSTR(0x63, 0x07),
 356        ILI9881C_COMMAND_INSTR(0x64, 0x07),
 357        ILI9881C_COMMAND_INSTR(0x65, 0x00),
 358        ILI9881C_COMMAND_INSTR(0x66, 0x00),
 359        ILI9881C_COMMAND_INSTR(0x67, 0x02),
 360        ILI9881C_COMMAND_INSTR(0x68, 0x02),
 361        ILI9881C_COMMAND_INSTR(0x69, 0x05),
 362        ILI9881C_COMMAND_INSTR(0x6A, 0x05),
 363        ILI9881C_COMMAND_INSTR(0x6B, 0x02),
 364        ILI9881C_COMMAND_INSTR(0x6C, 0x0D),
 365        ILI9881C_COMMAND_INSTR(0x6D, 0x0D),
 366        ILI9881C_COMMAND_INSTR(0x6E, 0x0C),
 367        ILI9881C_COMMAND_INSTR(0x6F, 0x0C),
 368        ILI9881C_COMMAND_INSTR(0x70, 0x0F),
 369        ILI9881C_COMMAND_INSTR(0x71, 0x0F),
 370        ILI9881C_COMMAND_INSTR(0x72, 0x0E),
 371        ILI9881C_COMMAND_INSTR(0x73, 0x0E),
 372        ILI9881C_COMMAND_INSTR(0x74, 0x02),
 373        ILI9881C_COMMAND_INSTR(0x75, 0x01),
 374        ILI9881C_COMMAND_INSTR(0x76, 0x01),
 375        ILI9881C_COMMAND_INSTR(0x77, 0x06),
 376        ILI9881C_COMMAND_INSTR(0x78, 0x06),
 377        ILI9881C_COMMAND_INSTR(0x79, 0x07),
 378        ILI9881C_COMMAND_INSTR(0x7A, 0x07),
 379        ILI9881C_COMMAND_INSTR(0x7B, 0x00),
 380        ILI9881C_COMMAND_INSTR(0x7C, 0x00),
 381        ILI9881C_COMMAND_INSTR(0x7D, 0x02),
 382        ILI9881C_COMMAND_INSTR(0x7E, 0x02),
 383        ILI9881C_COMMAND_INSTR(0x7F, 0x05),
 384        ILI9881C_COMMAND_INSTR(0x80, 0x05),
 385        ILI9881C_COMMAND_INSTR(0x81, 0x02),
 386        ILI9881C_COMMAND_INSTR(0x82, 0x0D),
 387        ILI9881C_COMMAND_INSTR(0x83, 0x0D),
 388        ILI9881C_COMMAND_INSTR(0x84, 0x0C),
 389        ILI9881C_COMMAND_INSTR(0x85, 0x0C),
 390        ILI9881C_COMMAND_INSTR(0x86, 0x0F),
 391        ILI9881C_COMMAND_INSTR(0x87, 0x0F),
 392        ILI9881C_COMMAND_INSTR(0x88, 0x0E),
 393        ILI9881C_COMMAND_INSTR(0x89, 0x0E),
 394        ILI9881C_COMMAND_INSTR(0x8A, 0x02),
 395        ILI9881C_SWITCH_PAGE_INSTR(4),
 396        ILI9881C_COMMAND_INSTR(0x3B, 0xC0), /* ILI4003D sel */
 397        ILI9881C_COMMAND_INSTR(0x6C, 0x15), /* Set VCORE voltage = 1.5V */
 398        ILI9881C_COMMAND_INSTR(0x6E, 0x2A), /* di_pwr_reg=0 for power mode 2A, VGH clamp 18V */
 399        ILI9881C_COMMAND_INSTR(0x6F, 0x33), /* pumping ratio VGH=5x VGL=-3x */
 400        ILI9881C_COMMAND_INSTR(0x8D, 0x1B), /* VGL clamp -10V */
 401        ILI9881C_COMMAND_INSTR(0x87, 0xBA), /* ESD */
 402        ILI9881C_COMMAND_INSTR(0x3A, 0x24), /* POWER SAVING */
 403        ILI9881C_COMMAND_INSTR(0x26, 0x76),
 404        ILI9881C_COMMAND_INSTR(0xB2, 0xD1),
 405        ILI9881C_SWITCH_PAGE_INSTR(1),
 406        ILI9881C_COMMAND_INSTR(0x22, 0x0A), /* BGR, SS */
 407        ILI9881C_COMMAND_INSTR(0x31, 0x00), /* Zigzag type3 inversion */
 408        ILI9881C_COMMAND_INSTR(0x40, 0x53), /* ILI4003D sel */
 409        ILI9881C_COMMAND_INSTR(0x43, 0x66),
 410        ILI9881C_COMMAND_INSTR(0x53, 0x4C),
 411        ILI9881C_COMMAND_INSTR(0x50, 0x87),
 412        ILI9881C_COMMAND_INSTR(0x51, 0x82),
 413        ILI9881C_COMMAND_INSTR(0x60, 0x15),
 414        ILI9881C_COMMAND_INSTR(0x61, 0x01),
 415        ILI9881C_COMMAND_INSTR(0x62, 0x0C),
 416        ILI9881C_COMMAND_INSTR(0x63, 0x00),
 417        ILI9881C_COMMAND_INSTR(0xA0, 0x00),
 418        ILI9881C_COMMAND_INSTR(0xA1, 0x13), /* VP251 */
 419        ILI9881C_COMMAND_INSTR(0xA2, 0x23), /* VP247 */
 420        ILI9881C_COMMAND_INSTR(0xA3, 0x14), /* VP243 */
 421        ILI9881C_COMMAND_INSTR(0xA4, 0x16), /* VP239 */
 422        ILI9881C_COMMAND_INSTR(0xA5, 0x29), /* VP231 */
 423        ILI9881C_COMMAND_INSTR(0xA6, 0x1E), /* VP219 */
 424        ILI9881C_COMMAND_INSTR(0xA7, 0x1D), /* VP203 */
 425        ILI9881C_COMMAND_INSTR(0xA8, 0x86), /* VP175 */
 426        ILI9881C_COMMAND_INSTR(0xA9, 0x1E), /* VP144 */
 427        ILI9881C_COMMAND_INSTR(0xAA, 0x29), /* VP111 */
 428        ILI9881C_COMMAND_INSTR(0xAB, 0x74), /* VP80 */
 429        ILI9881C_COMMAND_INSTR(0xAC, 0x19), /* VP52 */
 430        ILI9881C_COMMAND_INSTR(0xAD, 0x17), /* VP36 */
 431        ILI9881C_COMMAND_INSTR(0xAE, 0x4B), /* VP24 */
 432        ILI9881C_COMMAND_INSTR(0xAF, 0x20), /* VP16 */
 433        ILI9881C_COMMAND_INSTR(0xB0, 0x26), /* VP12 */
 434        ILI9881C_COMMAND_INSTR(0xB1, 0x4C), /* VP8 */
 435        ILI9881C_COMMAND_INSTR(0xB2, 0x5D), /* VP4 */
 436        ILI9881C_COMMAND_INSTR(0xB3, 0x3F), /* VP0 */
 437        ILI9881C_COMMAND_INSTR(0xC0, 0x00), /* VN255 GAMMA N */
 438        ILI9881C_COMMAND_INSTR(0xC1, 0x13), /* VN251 */
 439        ILI9881C_COMMAND_INSTR(0xC2, 0x23), /* VN247 */
 440        ILI9881C_COMMAND_INSTR(0xC3, 0x14), /* VN243 */
 441        ILI9881C_COMMAND_INSTR(0xC4, 0x16), /* VN239 */
 442        ILI9881C_COMMAND_INSTR(0xC5, 0x29), /* VN231 */
 443        ILI9881C_COMMAND_INSTR(0xC6, 0x1E), /* VN219 */
 444        ILI9881C_COMMAND_INSTR(0xC7, 0x1D), /* VN203 */
 445        ILI9881C_COMMAND_INSTR(0xC8, 0x86), /* VN175 */
 446        ILI9881C_COMMAND_INSTR(0xC9, 0x1E), /* VN144 */
 447        ILI9881C_COMMAND_INSTR(0xCA, 0x29), /* VN111 */
 448        ILI9881C_COMMAND_INSTR(0xCB, 0x74), /* VN80 */
 449        ILI9881C_COMMAND_INSTR(0xCC, 0x19), /* VN52 */
 450        ILI9881C_COMMAND_INSTR(0xCD, 0x17), /* VN36 */
 451        ILI9881C_COMMAND_INSTR(0xCE, 0x4B), /* VN24 */
 452        ILI9881C_COMMAND_INSTR(0xCF, 0x20), /* VN16 */
 453        ILI9881C_COMMAND_INSTR(0xD0, 0x26), /* VN12 */
 454        ILI9881C_COMMAND_INSTR(0xD1, 0x4C), /* VN8 */
 455        ILI9881C_COMMAND_INSTR(0xD2, 0x5D), /* VN4 */
 456        ILI9881C_COMMAND_INSTR(0xD3, 0x3F), /* VN0 */
 457};
 458
 459static const struct ili9881c_instr w552946ab_init[] = {
 460        ILI9881C_SWITCH_PAGE_INSTR(3),
 461        ILI9881C_COMMAND_INSTR(0x01, 0x00),
 462        ILI9881C_COMMAND_INSTR(0x02, 0x00),
 463        ILI9881C_COMMAND_INSTR(0x03, 0x53),
 464        ILI9881C_COMMAND_INSTR(0x04, 0x53),
 465        ILI9881C_COMMAND_INSTR(0x05, 0x13),
 466        ILI9881C_COMMAND_INSTR(0x06, 0x04),
 467        ILI9881C_COMMAND_INSTR(0x07, 0x02),
 468        ILI9881C_COMMAND_INSTR(0x08, 0x02),
 469        ILI9881C_COMMAND_INSTR(0x09, 0x00),
 470        ILI9881C_COMMAND_INSTR(0x0A, 0x00),
 471        ILI9881C_COMMAND_INSTR(0x0B, 0x00),
 472        ILI9881C_COMMAND_INSTR(0x0C, 0x00),
 473        ILI9881C_COMMAND_INSTR(0x0D, 0x00),
 474        ILI9881C_COMMAND_INSTR(0x0E, 0x00),
 475        ILI9881C_COMMAND_INSTR(0x0F, 0x00),
 476
 477        ILI9881C_COMMAND_INSTR(0x10, 0x00),
 478        ILI9881C_COMMAND_INSTR(0x11, 0x00),
 479        ILI9881C_COMMAND_INSTR(0x12, 0x00),
 480        ILI9881C_COMMAND_INSTR(0x13, 0x00),
 481        ILI9881C_COMMAND_INSTR(0x14, 0x00),
 482        ILI9881C_COMMAND_INSTR(0x15, 0x08),
 483        ILI9881C_COMMAND_INSTR(0x16, 0x10),
 484        ILI9881C_COMMAND_INSTR(0x17, 0x00),
 485        ILI9881C_COMMAND_INSTR(0x18, 0x08),
 486        ILI9881C_COMMAND_INSTR(0x19, 0x00),
 487        ILI9881C_COMMAND_INSTR(0x1A, 0x00),
 488        ILI9881C_COMMAND_INSTR(0x1B, 0x00),
 489        ILI9881C_COMMAND_INSTR(0x1C, 0x00),
 490        ILI9881C_COMMAND_INSTR(0x1D, 0x00),
 491        ILI9881C_COMMAND_INSTR(0x1E, 0xC0),
 492        ILI9881C_COMMAND_INSTR(0x1F, 0x80),
 493
 494        ILI9881C_COMMAND_INSTR(0x20, 0x02),
 495        ILI9881C_COMMAND_INSTR(0x21, 0x09),
 496        ILI9881C_COMMAND_INSTR(0x22, 0x00),
 497        ILI9881C_COMMAND_INSTR(0x23, 0x00),
 498        ILI9881C_COMMAND_INSTR(0x24, 0x00),
 499        ILI9881C_COMMAND_INSTR(0x25, 0x00),
 500        ILI9881C_COMMAND_INSTR(0x26, 0x00),
 501        ILI9881C_COMMAND_INSTR(0x27, 0x00),
 502        ILI9881C_COMMAND_INSTR(0x28, 0x55),
 503        ILI9881C_COMMAND_INSTR(0x29, 0x03),
 504        ILI9881C_COMMAND_INSTR(0x2A, 0x00),
 505        ILI9881C_COMMAND_INSTR(0x2B, 0x00),
 506        ILI9881C_COMMAND_INSTR(0x2C, 0x00),
 507        ILI9881C_COMMAND_INSTR(0x2D, 0x00),
 508        ILI9881C_COMMAND_INSTR(0x2E, 0x00),
 509        ILI9881C_COMMAND_INSTR(0x2F, 0x00),
 510
 511        ILI9881C_COMMAND_INSTR(0x30, 0x00),
 512        ILI9881C_COMMAND_INSTR(0x31, 0x00),
 513        ILI9881C_COMMAND_INSTR(0x32, 0x00),
 514        ILI9881C_COMMAND_INSTR(0x33, 0x00),
 515        ILI9881C_COMMAND_INSTR(0x34, 0x04),
 516        ILI9881C_COMMAND_INSTR(0x35, 0x05),
 517        ILI9881C_COMMAND_INSTR(0x36, 0x05),
 518        ILI9881C_COMMAND_INSTR(0x37, 0x00),
 519        ILI9881C_COMMAND_INSTR(0x38, 0x3C),
 520        ILI9881C_COMMAND_INSTR(0x39, 0x35),
 521        ILI9881C_COMMAND_INSTR(0x3A, 0x00),
 522        ILI9881C_COMMAND_INSTR(0x3B, 0x40),
 523        ILI9881C_COMMAND_INSTR(0x3C, 0x00),
 524        ILI9881C_COMMAND_INSTR(0x3D, 0x00),
 525        ILI9881C_COMMAND_INSTR(0x3E, 0x00),
 526        ILI9881C_COMMAND_INSTR(0x3F, 0x00),
 527
 528        ILI9881C_COMMAND_INSTR(0x40, 0x00),
 529        ILI9881C_COMMAND_INSTR(0x41, 0x88),
 530        ILI9881C_COMMAND_INSTR(0x42, 0x00),
 531        ILI9881C_COMMAND_INSTR(0x43, 0x00),
 532        ILI9881C_COMMAND_INSTR(0x44, 0x1F),
 533
 534        ILI9881C_COMMAND_INSTR(0x50, 0x01),
 535        ILI9881C_COMMAND_INSTR(0x51, 0x23),
 536        ILI9881C_COMMAND_INSTR(0x52, 0x45),
 537        ILI9881C_COMMAND_INSTR(0x53, 0x67),
 538        ILI9881C_COMMAND_INSTR(0x54, 0x89),
 539        ILI9881C_COMMAND_INSTR(0x55, 0xaB),
 540        ILI9881C_COMMAND_INSTR(0x56, 0x01),
 541        ILI9881C_COMMAND_INSTR(0x57, 0x23),
 542        ILI9881C_COMMAND_INSTR(0x58, 0x45),
 543        ILI9881C_COMMAND_INSTR(0x59, 0x67),
 544        ILI9881C_COMMAND_INSTR(0x5A, 0x89),
 545        ILI9881C_COMMAND_INSTR(0x5B, 0xAB),
 546        ILI9881C_COMMAND_INSTR(0x5C, 0xCD),
 547        ILI9881C_COMMAND_INSTR(0x5D, 0xEF),
 548        ILI9881C_COMMAND_INSTR(0x5E, 0x03),
 549        ILI9881C_COMMAND_INSTR(0x5F, 0x14),
 550
 551        ILI9881C_COMMAND_INSTR(0x60, 0x15),
 552        ILI9881C_COMMAND_INSTR(0x61, 0x0C),
 553        ILI9881C_COMMAND_INSTR(0x62, 0x0D),
 554        ILI9881C_COMMAND_INSTR(0x63, 0x0E),
 555        ILI9881C_COMMAND_INSTR(0x64, 0x0F),
 556        ILI9881C_COMMAND_INSTR(0x65, 0x10),
 557        ILI9881C_COMMAND_INSTR(0x66, 0x11),
 558        ILI9881C_COMMAND_INSTR(0x67, 0x08),
 559        ILI9881C_COMMAND_INSTR(0x68, 0x02),
 560        ILI9881C_COMMAND_INSTR(0x69, 0x0A),
 561        ILI9881C_COMMAND_INSTR(0x6A, 0x02),
 562        ILI9881C_COMMAND_INSTR(0x6B, 0x02),
 563        ILI9881C_COMMAND_INSTR(0x6C, 0x02),
 564        ILI9881C_COMMAND_INSTR(0x6D, 0x02),
 565        ILI9881C_COMMAND_INSTR(0x6E, 0x02),
 566        ILI9881C_COMMAND_INSTR(0x6F, 0x02),
 567
 568        ILI9881C_COMMAND_INSTR(0x70, 0x02),
 569        ILI9881C_COMMAND_INSTR(0x71, 0x02),
 570        ILI9881C_COMMAND_INSTR(0x72, 0x06),
 571        ILI9881C_COMMAND_INSTR(0x73, 0x02),
 572        ILI9881C_COMMAND_INSTR(0x74, 0x02),
 573        ILI9881C_COMMAND_INSTR(0x75, 0x14),
 574        ILI9881C_COMMAND_INSTR(0x76, 0x15),
 575        ILI9881C_COMMAND_INSTR(0x77, 0x0F),
 576        ILI9881C_COMMAND_INSTR(0x78, 0x0E),
 577        ILI9881C_COMMAND_INSTR(0x79, 0x0D),
 578        ILI9881C_COMMAND_INSTR(0x7A, 0x0C),
 579        ILI9881C_COMMAND_INSTR(0x7B, 0x11),
 580        ILI9881C_COMMAND_INSTR(0x7C, 0x10),
 581        ILI9881C_COMMAND_INSTR(0x7D, 0x06),
 582        ILI9881C_COMMAND_INSTR(0x7E, 0x02),
 583        ILI9881C_COMMAND_INSTR(0x7F, 0x0A),
 584
 585        ILI9881C_COMMAND_INSTR(0x80, 0x02),
 586        ILI9881C_COMMAND_INSTR(0x81, 0x02),
 587        ILI9881C_COMMAND_INSTR(0x82, 0x02),
 588        ILI9881C_COMMAND_INSTR(0x83, 0x02),
 589        ILI9881C_COMMAND_INSTR(0x84, 0x02),
 590        ILI9881C_COMMAND_INSTR(0x85, 0x02),
 591        ILI9881C_COMMAND_INSTR(0x86, 0x02),
 592        ILI9881C_COMMAND_INSTR(0x87, 0x02),
 593        ILI9881C_COMMAND_INSTR(0x88, 0x08),
 594        ILI9881C_COMMAND_INSTR(0x89, 0x02),
 595        ILI9881C_COMMAND_INSTR(0x8A, 0x02),
 596
 597        ILI9881C_SWITCH_PAGE_INSTR(4),
 598        ILI9881C_COMMAND_INSTR(0x00, 0x80),
 599        ILI9881C_COMMAND_INSTR(0x70, 0x00),
 600        ILI9881C_COMMAND_INSTR(0x71, 0x00),
 601        ILI9881C_COMMAND_INSTR(0x66, 0xFE),
 602        ILI9881C_COMMAND_INSTR(0x82, 0x15),
 603        ILI9881C_COMMAND_INSTR(0x84, 0x15),
 604        ILI9881C_COMMAND_INSTR(0x85, 0x15),
 605        ILI9881C_COMMAND_INSTR(0x3a, 0x24),
 606        ILI9881C_COMMAND_INSTR(0x32, 0xAC),
 607        ILI9881C_COMMAND_INSTR(0x8C, 0x80),
 608        ILI9881C_COMMAND_INSTR(0x3C, 0xF5),
 609        ILI9881C_COMMAND_INSTR(0x88, 0x33),
 610
 611        ILI9881C_SWITCH_PAGE_INSTR(1),
 612        ILI9881C_COMMAND_INSTR(0x22, 0x0A),
 613        ILI9881C_COMMAND_INSTR(0x31, 0x00),
 614        ILI9881C_COMMAND_INSTR(0x53, 0x78),
 615        ILI9881C_COMMAND_INSTR(0x50, 0x5B),
 616        ILI9881C_COMMAND_INSTR(0x51, 0x5B),
 617        ILI9881C_COMMAND_INSTR(0x60, 0x20),
 618        ILI9881C_COMMAND_INSTR(0x61, 0x00),
 619        ILI9881C_COMMAND_INSTR(0x62, 0x0D),
 620        ILI9881C_COMMAND_INSTR(0x63, 0x00),
 621
 622        ILI9881C_COMMAND_INSTR(0xA0, 0x00),
 623        ILI9881C_COMMAND_INSTR(0xA1, 0x10),
 624        ILI9881C_COMMAND_INSTR(0xA2, 0x1C),
 625        ILI9881C_COMMAND_INSTR(0xA3, 0x13),
 626        ILI9881C_COMMAND_INSTR(0xA4, 0x15),
 627        ILI9881C_COMMAND_INSTR(0xA5, 0x26),
 628        ILI9881C_COMMAND_INSTR(0xA6, 0x1A),
 629        ILI9881C_COMMAND_INSTR(0xA7, 0x1D),
 630        ILI9881C_COMMAND_INSTR(0xA8, 0x67),
 631        ILI9881C_COMMAND_INSTR(0xA9, 0x1C),
 632        ILI9881C_COMMAND_INSTR(0xAA, 0x29),
 633        ILI9881C_COMMAND_INSTR(0xAB, 0x5B),
 634        ILI9881C_COMMAND_INSTR(0xAC, 0x26),
 635        ILI9881C_COMMAND_INSTR(0xAD, 0x28),
 636        ILI9881C_COMMAND_INSTR(0xAE, 0x5C),
 637        ILI9881C_COMMAND_INSTR(0xAF, 0x30),
 638        ILI9881C_COMMAND_INSTR(0xB0, 0x31),
 639        ILI9881C_COMMAND_INSTR(0xB1, 0x2E),
 640        ILI9881C_COMMAND_INSTR(0xB2, 0x32),
 641        ILI9881C_COMMAND_INSTR(0xB3, 0x00),
 642
 643        ILI9881C_COMMAND_INSTR(0xC0, 0x00),
 644        ILI9881C_COMMAND_INSTR(0xC1, 0x10),
 645        ILI9881C_COMMAND_INSTR(0xC2, 0x1C),
 646        ILI9881C_COMMAND_INSTR(0xC3, 0x13),
 647        ILI9881C_COMMAND_INSTR(0xC4, 0x15),
 648        ILI9881C_COMMAND_INSTR(0xC5, 0x26),
 649        ILI9881C_COMMAND_INSTR(0xC6, 0x1A),
 650        ILI9881C_COMMAND_INSTR(0xC7, 0x1D),
 651        ILI9881C_COMMAND_INSTR(0xC8, 0x67),
 652        ILI9881C_COMMAND_INSTR(0xC9, 0x1C),
 653        ILI9881C_COMMAND_INSTR(0xCA, 0x29),
 654        ILI9881C_COMMAND_INSTR(0xCB, 0x5B),
 655        ILI9881C_COMMAND_INSTR(0xCC, 0x26),
 656        ILI9881C_COMMAND_INSTR(0xCD, 0x28),
 657        ILI9881C_COMMAND_INSTR(0xCE, 0x5C),
 658        ILI9881C_COMMAND_INSTR(0xCF, 0x30),
 659        ILI9881C_COMMAND_INSTR(0xD0, 0x31),
 660        ILI9881C_COMMAND_INSTR(0xD1, 0x2E),
 661        ILI9881C_COMMAND_INSTR(0xD2, 0x32),
 662        ILI9881C_COMMAND_INSTR(0xD3, 0x00),
 663        ILI9881C_SWITCH_PAGE_INSTR(0),
 664};
 665
 666static inline struct ili9881c *panel_to_ili9881c(struct drm_panel *panel)
 667{
 668        return container_of(panel, struct ili9881c, panel);
 669}
 670
 671/*
 672 * The panel seems to accept some private DCS commands that map
 673 * directly to registers.
 674 *
 675 * It is organised by page, with each page having its own set of
 676 * registers, and the first page looks like it's holding the standard
 677 * DCS commands.
 678 *
 679 * So before any attempt at sending a command or data, we have to be
 680 * sure if we're in the right page or not.
 681 */
 682static int ili9881c_switch_page(struct ili9881c *ctx, u8 page)
 683{
 684        u8 buf[4] = { 0xff, 0x98, 0x81, page };
 685        int ret;
 686
 687        ret = mipi_dsi_dcs_write_buffer(ctx->dsi, buf, sizeof(buf));
 688        if (ret < 0)
 689                return ret;
 690
 691        return 0;
 692}
 693
 694static int ili9881c_send_cmd_data(struct ili9881c *ctx, u8 cmd, u8 data)
 695{
 696        u8 buf[2] = { cmd, data };
 697        int ret;
 698
 699        ret = mipi_dsi_dcs_write_buffer(ctx->dsi, buf, sizeof(buf));
 700        if (ret < 0)
 701                return ret;
 702
 703        return 0;
 704}
 705
 706static int ili9881c_prepare(struct drm_panel *panel)
 707{
 708        struct ili9881c *ctx = panel_to_ili9881c(panel);
 709        unsigned int i;
 710        int ret;
 711
 712        /* Power the panel */
 713        ret = regulator_enable(ctx->power);
 714        if (ret)
 715                return ret;
 716        msleep(5);
 717
 718        /* And reset it */
 719        gpiod_set_value(ctx->reset, 1);
 720        msleep(20);
 721
 722        gpiod_set_value(ctx->reset, 0);
 723        msleep(20);
 724
 725        for (i = 0; i < ctx->desc->init_length; i++) {
 726                const struct ili9881c_instr *instr = &ctx->desc->init[i];
 727
 728                if (instr->op == ILI9881C_SWITCH_PAGE)
 729                        ret = ili9881c_switch_page(ctx, instr->arg.page);
 730                else if (instr->op == ILI9881C_COMMAND)
 731                        ret = ili9881c_send_cmd_data(ctx, instr->arg.cmd.cmd,
 732                                                      instr->arg.cmd.data);
 733
 734                if (ret)
 735                        return ret;
 736        }
 737
 738        ret = ili9881c_switch_page(ctx, 0);
 739        if (ret)
 740                return ret;
 741
 742        ret = mipi_dsi_dcs_set_tear_on(ctx->dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
 743        if (ret)
 744                return ret;
 745
 746        ret = mipi_dsi_dcs_exit_sleep_mode(ctx->dsi);
 747        if (ret)
 748                return ret;
 749
 750        return 0;
 751}
 752
 753static int ili9881c_enable(struct drm_panel *panel)
 754{
 755        struct ili9881c *ctx = panel_to_ili9881c(panel);
 756
 757        msleep(120);
 758
 759        mipi_dsi_dcs_set_display_on(ctx->dsi);
 760
 761        return 0;
 762}
 763
 764static int ili9881c_disable(struct drm_panel *panel)
 765{
 766        struct ili9881c *ctx = panel_to_ili9881c(panel);
 767
 768        return mipi_dsi_dcs_set_display_off(ctx->dsi);
 769}
 770
 771static int ili9881c_unprepare(struct drm_panel *panel)
 772{
 773        struct ili9881c *ctx = panel_to_ili9881c(panel);
 774
 775        mipi_dsi_dcs_enter_sleep_mode(ctx->dsi);
 776        regulator_disable(ctx->power);
 777        gpiod_set_value(ctx->reset, 1);
 778
 779        return 0;
 780}
 781
 782static const struct drm_display_mode lhr050h41_default_mode = {
 783        .clock          = 62000,
 784
 785        .hdisplay       = 720,
 786        .hsync_start    = 720 + 10,
 787        .hsync_end      = 720 + 10 + 20,
 788        .htotal         = 720 + 10 + 20 + 30,
 789
 790        .vdisplay       = 1280,
 791        .vsync_start    = 1280 + 10,
 792        .vsync_end      = 1280 + 10 + 10,
 793        .vtotal         = 1280 + 10 + 10 + 20,
 794
 795        .width_mm       = 62,
 796        .height_mm      = 110,
 797};
 798
 799static const struct drm_display_mode k101_im2byl02_default_mode = {
 800        .clock          = 69700,
 801
 802        .hdisplay       = 800,
 803        .hsync_start    = 800 + 52,
 804        .hsync_end      = 800 + 52 + 8,
 805        .htotal         = 800 + 52 + 8 + 48,
 806
 807        .vdisplay       = 1280,
 808        .vsync_start    = 1280 + 16,
 809        .vsync_end      = 1280 + 16 + 6,
 810        .vtotal         = 1280 + 16 + 6 + 15,
 811
 812        .width_mm       = 135,
 813        .height_mm      = 217,
 814};
 815
 816static const struct drm_display_mode w552946aba_default_mode = {
 817        .clock          = 64000,
 818
 819        .hdisplay       = 720,
 820        .hsync_start    = 720 + 40,
 821        .hsync_end      = 720 + 40 + 10,
 822        .htotal         = 720 + 40 + 10 + 40,
 823
 824        .vdisplay       = 1280,
 825        .vsync_start    = 1280 + 22,
 826        .vsync_end      = 1280 + 22 + 4,
 827        .vtotal         = 1280 + 22 + 4 + 11,
 828
 829        .width_mm       = 68,
 830        .height_mm      = 121,
 831};
 832
 833static int ili9881c_get_modes(struct drm_panel *panel,
 834                              struct drm_connector *connector)
 835{
 836        struct ili9881c *ctx = panel_to_ili9881c(panel);
 837        struct drm_display_mode *mode;
 838
 839        mode = drm_mode_duplicate(connector->dev, ctx->desc->mode);
 840        if (!mode) {
 841                dev_err(&ctx->dsi->dev, "failed to add mode %ux%ux@%u\n",
 842                        ctx->desc->mode->hdisplay,
 843                        ctx->desc->mode->vdisplay,
 844                        drm_mode_vrefresh(ctx->desc->mode));
 845                return -ENOMEM;
 846        }
 847
 848        drm_mode_set_name(mode);
 849
 850        mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
 851        drm_mode_probed_add(connector, mode);
 852
 853        connector->display_info.width_mm = mode->width_mm;
 854        connector->display_info.height_mm = mode->height_mm;
 855
 856        drm_connector_set_panel_orientation(connector, ctx->orientation);
 857
 858        return 1;
 859}
 860
 861static const struct drm_panel_funcs ili9881c_funcs = {
 862        .prepare        = ili9881c_prepare,
 863        .unprepare      = ili9881c_unprepare,
 864        .enable         = ili9881c_enable,
 865        .disable        = ili9881c_disable,
 866        .get_modes      = ili9881c_get_modes,
 867};
 868
 869static int ili9881c_dsi_probe(struct mipi_dsi_device *dsi)
 870{
 871        struct ili9881c *ctx;
 872        int ret;
 873
 874        ctx = devm_kzalloc(&dsi->dev, sizeof(*ctx), GFP_KERNEL);
 875        if (!ctx)
 876                return -ENOMEM;
 877        mipi_dsi_set_drvdata(dsi, ctx);
 878        ctx->dsi = dsi;
 879        ctx->desc = of_device_get_match_data(&dsi->dev);
 880
 881        drm_panel_init(&ctx->panel, &dsi->dev, &ili9881c_funcs,
 882                       DRM_MODE_CONNECTOR_DSI);
 883
 884        ctx->power = devm_regulator_get(&dsi->dev, "power");
 885        if (IS_ERR(ctx->power))
 886                return dev_err_probe(&dsi->dev, PTR_ERR(ctx->power),
 887                                     "Couldn't get our power regulator\n");
 888
 889        ctx->reset = devm_gpiod_get_optional(&dsi->dev, "reset", GPIOD_OUT_LOW);
 890        if (IS_ERR(ctx->reset))
 891                return dev_err_probe(&dsi->dev, PTR_ERR(ctx->reset),
 892                                     "Couldn't get our reset GPIO\n");
 893
 894        ret = of_drm_get_panel_orientation(dsi->dev.of_node, &ctx->orientation);
 895        if (ret) {
 896                dev_err(&dsi->dev, "%pOF: failed to get orientation: %d\n",
 897                        dsi->dev.of_node, ret);
 898                return ret;
 899        }
 900
 901        ret = drm_panel_of_backlight(&ctx->panel);
 902        if (ret)
 903                return ret;
 904
 905        drm_panel_add(&ctx->panel);
 906
 907        dsi->mode_flags = ctx->desc->mode_flags;
 908        dsi->format = MIPI_DSI_FMT_RGB888;
 909        dsi->lanes = 4;
 910
 911        return mipi_dsi_attach(dsi);
 912}
 913
 914static int ili9881c_dsi_remove(struct mipi_dsi_device *dsi)
 915{
 916        struct ili9881c *ctx = mipi_dsi_get_drvdata(dsi);
 917
 918        mipi_dsi_detach(dsi);
 919        drm_panel_remove(&ctx->panel);
 920
 921        return 0;
 922}
 923
 924static const struct ili9881c_desc lhr050h41_desc = {
 925        .init = lhr050h41_init,
 926        .init_length = ARRAY_SIZE(lhr050h41_init),
 927        .mode = &lhr050h41_default_mode,
 928        .mode_flags = MIPI_DSI_MODE_VIDEO_SYNC_PULSE,
 929};
 930
 931static const struct ili9881c_desc k101_im2byl02_desc = {
 932        .init = k101_im2byl02_init,
 933        .init_length = ARRAY_SIZE(k101_im2byl02_init),
 934        .mode = &k101_im2byl02_default_mode,
 935        .mode_flags = MIPI_DSI_MODE_VIDEO_SYNC_PULSE,
 936};
 937
 938static const struct ili9881c_desc w552946aba_desc = {
 939        .init = w552946ab_init,
 940        .init_length = ARRAY_SIZE(w552946ab_init),
 941        .mode = &w552946aba_default_mode,
 942        .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
 943                      MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET,
 944};
 945
 946static const struct of_device_id ili9881c_of_match[] = {
 947        { .compatible = "bananapi,lhr050h41", .data = &lhr050h41_desc },
 948        { .compatible = "feixin,k101-im2byl02", .data = &k101_im2byl02_desc },
 949        { .compatible = "wanchanglong,w552946aba", .data = &w552946aba_desc },
 950        { }
 951};
 952MODULE_DEVICE_TABLE(of, ili9881c_of_match);
 953
 954static struct mipi_dsi_driver ili9881c_dsi_driver = {
 955        .probe          = ili9881c_dsi_probe,
 956        .remove         = ili9881c_dsi_remove,
 957        .driver = {
 958                .name           = "ili9881c-dsi",
 959                .of_match_table = ili9881c_of_match,
 960        },
 961};
 962module_mipi_dsi_driver(ili9881c_dsi_driver);
 963
 964MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
 965MODULE_DESCRIPTION("Ilitek ILI9881C Controller Driver");
 966MODULE_LICENSE("GPL v2");
 967