Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2017-2018, Bootlin
0004  */
0005 
0006 #include <linux/delay.h>
0007 #include <linux/device.h>
0008 #include <linux/err.h>
0009 #include <linux/errno.h>
0010 #include <linux/fb.h>
0011 #include <linux/kernel.h>
0012 #include <linux/module.h>
0013 #include <linux/of_device.h>
0014 
0015 #include <linux/gpio/consumer.h>
0016 #include <linux/regulator/consumer.h>
0017 
0018 #include <drm/drm_mipi_dsi.h>
0019 #include <drm/drm_modes.h>
0020 #include <drm/drm_panel.h>
0021 
0022 #include <video/mipi_display.h>
0023 
0024 enum ili9881c_op {
0025     ILI9881C_SWITCH_PAGE,
0026     ILI9881C_COMMAND,
0027 };
0028 
0029 struct ili9881c_instr {
0030     enum ili9881c_op    op;
0031 
0032     union arg {
0033         struct cmd {
0034             u8  cmd;
0035             u8  data;
0036         } cmd;
0037         u8  page;
0038     } arg;
0039 };
0040 
0041 struct ili9881c_desc {
0042     const struct ili9881c_instr *init;
0043     const size_t init_length;
0044     const struct drm_display_mode *mode;
0045     const unsigned long mode_flags;
0046 };
0047 
0048 struct ili9881c {
0049     struct drm_panel    panel;
0050     struct mipi_dsi_device  *dsi;
0051     const struct ili9881c_desc  *desc;
0052 
0053     struct regulator    *power;
0054     struct gpio_desc    *reset;
0055 
0056     enum drm_panel_orientation  orientation;
0057 };
0058 
0059 #define ILI9881C_SWITCH_PAGE_INSTR(_page)   \
0060     {                   \
0061         .op = ILI9881C_SWITCH_PAGE, \
0062         .arg = {            \
0063             .page = (_page),    \
0064         },              \
0065     }
0066 
0067 #define ILI9881C_COMMAND_INSTR(_cmd, _data)     \
0068     {                       \
0069         .op = ILI9881C_COMMAND,     \
0070         .arg = {                \
0071             .cmd = {            \
0072                 .cmd = (_cmd),      \
0073                 .data = (_data),    \
0074             },              \
0075         },                  \
0076     }
0077 
0078 static const struct ili9881c_instr lhr050h41_init[] = {
0079     ILI9881C_SWITCH_PAGE_INSTR(3),
0080     ILI9881C_COMMAND_INSTR(0x01, 0x00),
0081     ILI9881C_COMMAND_INSTR(0x02, 0x00),
0082     ILI9881C_COMMAND_INSTR(0x03, 0x73),
0083     ILI9881C_COMMAND_INSTR(0x04, 0x03),
0084     ILI9881C_COMMAND_INSTR(0x05, 0x00),
0085     ILI9881C_COMMAND_INSTR(0x06, 0x06),
0086     ILI9881C_COMMAND_INSTR(0x07, 0x06),
0087     ILI9881C_COMMAND_INSTR(0x08, 0x00),
0088     ILI9881C_COMMAND_INSTR(0x09, 0x18),
0089     ILI9881C_COMMAND_INSTR(0x0a, 0x04),
0090     ILI9881C_COMMAND_INSTR(0x0b, 0x00),
0091     ILI9881C_COMMAND_INSTR(0x0c, 0x02),
0092     ILI9881C_COMMAND_INSTR(0x0d, 0x03),
0093     ILI9881C_COMMAND_INSTR(0x0e, 0x00),
0094     ILI9881C_COMMAND_INSTR(0x0f, 0x25),
0095     ILI9881C_COMMAND_INSTR(0x10, 0x25),
0096     ILI9881C_COMMAND_INSTR(0x11, 0x00),
0097     ILI9881C_COMMAND_INSTR(0x12, 0x00),
0098     ILI9881C_COMMAND_INSTR(0x13, 0x00),
0099     ILI9881C_COMMAND_INSTR(0x14, 0x00),
0100     ILI9881C_COMMAND_INSTR(0x15, 0x00),
0101     ILI9881C_COMMAND_INSTR(0x16, 0x0C),
0102     ILI9881C_COMMAND_INSTR(0x17, 0x00),
0103     ILI9881C_COMMAND_INSTR(0x18, 0x00),
0104     ILI9881C_COMMAND_INSTR(0x19, 0x00),
0105     ILI9881C_COMMAND_INSTR(0x1a, 0x00),
0106     ILI9881C_COMMAND_INSTR(0x1b, 0x00),
0107     ILI9881C_COMMAND_INSTR(0x1c, 0x00),
0108     ILI9881C_COMMAND_INSTR(0x1d, 0x00),
0109     ILI9881C_COMMAND_INSTR(0x1e, 0xC0),
0110     ILI9881C_COMMAND_INSTR(0x1f, 0x80),
0111     ILI9881C_COMMAND_INSTR(0x20, 0x04),
0112     ILI9881C_COMMAND_INSTR(0x21, 0x01),
0113     ILI9881C_COMMAND_INSTR(0x22, 0x00),
0114     ILI9881C_COMMAND_INSTR(0x23, 0x00),
0115     ILI9881C_COMMAND_INSTR(0x24, 0x00),
0116     ILI9881C_COMMAND_INSTR(0x25, 0x00),
0117     ILI9881C_COMMAND_INSTR(0x26, 0x00),
0118     ILI9881C_COMMAND_INSTR(0x27, 0x00),
0119     ILI9881C_COMMAND_INSTR(0x28, 0x33),
0120     ILI9881C_COMMAND_INSTR(0x29, 0x03),
0121     ILI9881C_COMMAND_INSTR(0x2a, 0x00),
0122     ILI9881C_COMMAND_INSTR(0x2b, 0x00),
0123     ILI9881C_COMMAND_INSTR(0x2c, 0x00),
0124     ILI9881C_COMMAND_INSTR(0x2d, 0x00),
0125     ILI9881C_COMMAND_INSTR(0x2e, 0x00),
0126     ILI9881C_COMMAND_INSTR(0x2f, 0x00),
0127     ILI9881C_COMMAND_INSTR(0x30, 0x00),
0128     ILI9881C_COMMAND_INSTR(0x31, 0x00),
0129     ILI9881C_COMMAND_INSTR(0x32, 0x00),
0130     ILI9881C_COMMAND_INSTR(0x33, 0x00),
0131     ILI9881C_COMMAND_INSTR(0x34, 0x04),
0132     ILI9881C_COMMAND_INSTR(0x35, 0x00),
0133     ILI9881C_COMMAND_INSTR(0x36, 0x00),
0134     ILI9881C_COMMAND_INSTR(0x37, 0x00),
0135     ILI9881C_COMMAND_INSTR(0x38, 0x3C),
0136     ILI9881C_COMMAND_INSTR(0x39, 0x00),
0137     ILI9881C_COMMAND_INSTR(0x3a, 0x00),
0138     ILI9881C_COMMAND_INSTR(0x3b, 0x00),
0139     ILI9881C_COMMAND_INSTR(0x3c, 0x00),
0140     ILI9881C_COMMAND_INSTR(0x3d, 0x00),
0141     ILI9881C_COMMAND_INSTR(0x3e, 0x00),
0142     ILI9881C_COMMAND_INSTR(0x3f, 0x00),
0143     ILI9881C_COMMAND_INSTR(0x40, 0x00),
0144     ILI9881C_COMMAND_INSTR(0x41, 0x00),
0145     ILI9881C_COMMAND_INSTR(0x42, 0x00),
0146     ILI9881C_COMMAND_INSTR(0x43, 0x00),
0147     ILI9881C_COMMAND_INSTR(0x44, 0x00),
0148     ILI9881C_COMMAND_INSTR(0x50, 0x01),
0149     ILI9881C_COMMAND_INSTR(0x51, 0x23),
0150     ILI9881C_COMMAND_INSTR(0x52, 0x45),
0151     ILI9881C_COMMAND_INSTR(0x53, 0x67),
0152     ILI9881C_COMMAND_INSTR(0x54, 0x89),
0153     ILI9881C_COMMAND_INSTR(0x55, 0xab),
0154     ILI9881C_COMMAND_INSTR(0x56, 0x01),
0155     ILI9881C_COMMAND_INSTR(0x57, 0x23),
0156     ILI9881C_COMMAND_INSTR(0x58, 0x45),
0157     ILI9881C_COMMAND_INSTR(0x59, 0x67),
0158     ILI9881C_COMMAND_INSTR(0x5a, 0x89),
0159     ILI9881C_COMMAND_INSTR(0x5b, 0xab),
0160     ILI9881C_COMMAND_INSTR(0x5c, 0xcd),
0161     ILI9881C_COMMAND_INSTR(0x5d, 0xef),
0162     ILI9881C_COMMAND_INSTR(0x5e, 0x11),
0163     ILI9881C_COMMAND_INSTR(0x5f, 0x02),
0164     ILI9881C_COMMAND_INSTR(0x60, 0x02),
0165     ILI9881C_COMMAND_INSTR(0x61, 0x02),
0166     ILI9881C_COMMAND_INSTR(0x62, 0x02),
0167     ILI9881C_COMMAND_INSTR(0x63, 0x02),
0168     ILI9881C_COMMAND_INSTR(0x64, 0x02),
0169     ILI9881C_COMMAND_INSTR(0x65, 0x02),
0170     ILI9881C_COMMAND_INSTR(0x66, 0x02),
0171     ILI9881C_COMMAND_INSTR(0x67, 0x02),
0172     ILI9881C_COMMAND_INSTR(0x68, 0x02),
0173     ILI9881C_COMMAND_INSTR(0x69, 0x02),
0174     ILI9881C_COMMAND_INSTR(0x6a, 0x0C),
0175     ILI9881C_COMMAND_INSTR(0x6b, 0x02),
0176     ILI9881C_COMMAND_INSTR(0x6c, 0x0F),
0177     ILI9881C_COMMAND_INSTR(0x6d, 0x0E),
0178     ILI9881C_COMMAND_INSTR(0x6e, 0x0D),
0179     ILI9881C_COMMAND_INSTR(0x6f, 0x06),
0180     ILI9881C_COMMAND_INSTR(0x70, 0x07),
0181     ILI9881C_COMMAND_INSTR(0x71, 0x02),
0182     ILI9881C_COMMAND_INSTR(0x72, 0x02),
0183     ILI9881C_COMMAND_INSTR(0x73, 0x02),
0184     ILI9881C_COMMAND_INSTR(0x74, 0x02),
0185     ILI9881C_COMMAND_INSTR(0x75, 0x02),
0186     ILI9881C_COMMAND_INSTR(0x76, 0x02),
0187     ILI9881C_COMMAND_INSTR(0x77, 0x02),
0188     ILI9881C_COMMAND_INSTR(0x78, 0x02),
0189     ILI9881C_COMMAND_INSTR(0x79, 0x02),
0190     ILI9881C_COMMAND_INSTR(0x7a, 0x02),
0191     ILI9881C_COMMAND_INSTR(0x7b, 0x02),
0192     ILI9881C_COMMAND_INSTR(0x7c, 0x02),
0193     ILI9881C_COMMAND_INSTR(0x7d, 0x02),
0194     ILI9881C_COMMAND_INSTR(0x7e, 0x02),
0195     ILI9881C_COMMAND_INSTR(0x7f, 0x02),
0196     ILI9881C_COMMAND_INSTR(0x80, 0x0C),
0197     ILI9881C_COMMAND_INSTR(0x81, 0x02),
0198     ILI9881C_COMMAND_INSTR(0x82, 0x0F),
0199     ILI9881C_COMMAND_INSTR(0x83, 0x0E),
0200     ILI9881C_COMMAND_INSTR(0x84, 0x0D),
0201     ILI9881C_COMMAND_INSTR(0x85, 0x06),
0202     ILI9881C_COMMAND_INSTR(0x86, 0x07),
0203     ILI9881C_COMMAND_INSTR(0x87, 0x02),
0204     ILI9881C_COMMAND_INSTR(0x88, 0x02),
0205     ILI9881C_COMMAND_INSTR(0x89, 0x02),
0206     ILI9881C_COMMAND_INSTR(0x8A, 0x02),
0207     ILI9881C_SWITCH_PAGE_INSTR(4),
0208     ILI9881C_COMMAND_INSTR(0x6C, 0x15),
0209     ILI9881C_COMMAND_INSTR(0x6E, 0x22),
0210     ILI9881C_COMMAND_INSTR(0x6F, 0x33),
0211     ILI9881C_COMMAND_INSTR(0x3A, 0xA4),
0212     ILI9881C_COMMAND_INSTR(0x8D, 0x0D),
0213     ILI9881C_COMMAND_INSTR(0x87, 0xBA),
0214     ILI9881C_COMMAND_INSTR(0x26, 0x76),
0215     ILI9881C_COMMAND_INSTR(0xB2, 0xD1),
0216     ILI9881C_SWITCH_PAGE_INSTR(1),
0217     ILI9881C_COMMAND_INSTR(0x22, 0x0A),
0218     ILI9881C_COMMAND_INSTR(0x53, 0xDC),
0219     ILI9881C_COMMAND_INSTR(0x55, 0xA7),
0220     ILI9881C_COMMAND_INSTR(0x50, 0x78),
0221     ILI9881C_COMMAND_INSTR(0x51, 0x78),
0222     ILI9881C_COMMAND_INSTR(0x31, 0x02),
0223     ILI9881C_COMMAND_INSTR(0x60, 0x14),
0224     ILI9881C_COMMAND_INSTR(0xA0, 0x2A),
0225     ILI9881C_COMMAND_INSTR(0xA1, 0x39),
0226     ILI9881C_COMMAND_INSTR(0xA2, 0x46),
0227     ILI9881C_COMMAND_INSTR(0xA3, 0x0e),
0228     ILI9881C_COMMAND_INSTR(0xA4, 0x12),
0229     ILI9881C_COMMAND_INSTR(0xA5, 0x25),
0230     ILI9881C_COMMAND_INSTR(0xA6, 0x19),
0231     ILI9881C_COMMAND_INSTR(0xA7, 0x1d),
0232     ILI9881C_COMMAND_INSTR(0xA8, 0xa6),
0233     ILI9881C_COMMAND_INSTR(0xA9, 0x1C),
0234     ILI9881C_COMMAND_INSTR(0xAA, 0x29),
0235     ILI9881C_COMMAND_INSTR(0xAB, 0x85),
0236     ILI9881C_COMMAND_INSTR(0xAC, 0x1C),
0237     ILI9881C_COMMAND_INSTR(0xAD, 0x1B),
0238     ILI9881C_COMMAND_INSTR(0xAE, 0x51),
0239     ILI9881C_COMMAND_INSTR(0xAF, 0x22),
0240     ILI9881C_COMMAND_INSTR(0xB0, 0x2d),
0241     ILI9881C_COMMAND_INSTR(0xB1, 0x4f),
0242     ILI9881C_COMMAND_INSTR(0xB2, 0x59),
0243     ILI9881C_COMMAND_INSTR(0xB3, 0x3F),
0244     ILI9881C_COMMAND_INSTR(0xC0, 0x2A),
0245     ILI9881C_COMMAND_INSTR(0xC1, 0x3a),
0246     ILI9881C_COMMAND_INSTR(0xC2, 0x45),
0247     ILI9881C_COMMAND_INSTR(0xC3, 0x0e),
0248     ILI9881C_COMMAND_INSTR(0xC4, 0x11),
0249     ILI9881C_COMMAND_INSTR(0xC5, 0x24),
0250     ILI9881C_COMMAND_INSTR(0xC6, 0x1a),
0251     ILI9881C_COMMAND_INSTR(0xC7, 0x1c),
0252     ILI9881C_COMMAND_INSTR(0xC8, 0xaa),
0253     ILI9881C_COMMAND_INSTR(0xC9, 0x1C),
0254     ILI9881C_COMMAND_INSTR(0xCA, 0x29),
0255     ILI9881C_COMMAND_INSTR(0xCB, 0x96),
0256     ILI9881C_COMMAND_INSTR(0xCC, 0x1C),
0257     ILI9881C_COMMAND_INSTR(0xCD, 0x1B),
0258     ILI9881C_COMMAND_INSTR(0xCE, 0x51),
0259     ILI9881C_COMMAND_INSTR(0xCF, 0x22),
0260     ILI9881C_COMMAND_INSTR(0xD0, 0x2b),
0261     ILI9881C_COMMAND_INSTR(0xD1, 0x4b),
0262     ILI9881C_COMMAND_INSTR(0xD2, 0x59),
0263     ILI9881C_COMMAND_INSTR(0xD3, 0x3F),
0264 };
0265 
0266 static const struct ili9881c_instr k101_im2byl02_init[] = {
0267     ILI9881C_SWITCH_PAGE_INSTR(3),
0268     ILI9881C_COMMAND_INSTR(0x01, 0x00),
0269     ILI9881C_COMMAND_INSTR(0x02, 0x00),
0270     ILI9881C_COMMAND_INSTR(0x03, 0x73),
0271     ILI9881C_COMMAND_INSTR(0x04, 0x00),
0272     ILI9881C_COMMAND_INSTR(0x05, 0x00),
0273     ILI9881C_COMMAND_INSTR(0x06, 0x08),
0274     ILI9881C_COMMAND_INSTR(0x07, 0x00),
0275     ILI9881C_COMMAND_INSTR(0x08, 0x00),
0276     ILI9881C_COMMAND_INSTR(0x09, 0x00),
0277     ILI9881C_COMMAND_INSTR(0x0A, 0x01),
0278     ILI9881C_COMMAND_INSTR(0x0B, 0x01),
0279     ILI9881C_COMMAND_INSTR(0x0C, 0x00),
0280     ILI9881C_COMMAND_INSTR(0x0D, 0x01),
0281     ILI9881C_COMMAND_INSTR(0x0E, 0x01),
0282     ILI9881C_COMMAND_INSTR(0x0F, 0x00),
0283     ILI9881C_COMMAND_INSTR(0x10, 0x00),
0284     ILI9881C_COMMAND_INSTR(0x11, 0x00),
0285     ILI9881C_COMMAND_INSTR(0x12, 0x00),
0286     ILI9881C_COMMAND_INSTR(0x13, 0x00),
0287     ILI9881C_COMMAND_INSTR(0x14, 0x00),
0288     ILI9881C_COMMAND_INSTR(0x15, 0x00),
0289     ILI9881C_COMMAND_INSTR(0x16, 0x00),
0290     ILI9881C_COMMAND_INSTR(0x17, 0x00),
0291     ILI9881C_COMMAND_INSTR(0x18, 0x00),
0292     ILI9881C_COMMAND_INSTR(0x19, 0x00),
0293     ILI9881C_COMMAND_INSTR(0x1A, 0x00),
0294     ILI9881C_COMMAND_INSTR(0x1B, 0x00),
0295     ILI9881C_COMMAND_INSTR(0x1C, 0x00),
0296     ILI9881C_COMMAND_INSTR(0x1D, 0x00),
0297     ILI9881C_COMMAND_INSTR(0x1E, 0x40),
0298     ILI9881C_COMMAND_INSTR(0x1F, 0xC0),
0299     ILI9881C_COMMAND_INSTR(0x20, 0x06),
0300     ILI9881C_COMMAND_INSTR(0x21, 0x01),
0301     ILI9881C_COMMAND_INSTR(0x22, 0x06),
0302     ILI9881C_COMMAND_INSTR(0x23, 0x01),
0303     ILI9881C_COMMAND_INSTR(0x24, 0x88),
0304     ILI9881C_COMMAND_INSTR(0x25, 0x88),
0305     ILI9881C_COMMAND_INSTR(0x26, 0x00),
0306     ILI9881C_COMMAND_INSTR(0x27, 0x00),
0307     ILI9881C_COMMAND_INSTR(0x28, 0x3B),
0308     ILI9881C_COMMAND_INSTR(0x29, 0x03),
0309     ILI9881C_COMMAND_INSTR(0x2A, 0x00),
0310     ILI9881C_COMMAND_INSTR(0x2B, 0x00),
0311     ILI9881C_COMMAND_INSTR(0x2C, 0x00),
0312     ILI9881C_COMMAND_INSTR(0x2D, 0x00),
0313     ILI9881C_COMMAND_INSTR(0x2E, 0x00),
0314     ILI9881C_COMMAND_INSTR(0x2F, 0x00),
0315     ILI9881C_COMMAND_INSTR(0x30, 0x00),
0316     ILI9881C_COMMAND_INSTR(0x31, 0x00),
0317     ILI9881C_COMMAND_INSTR(0x32, 0x00),
0318     ILI9881C_COMMAND_INSTR(0x33, 0x00),
0319     ILI9881C_COMMAND_INSTR(0x34, 0x00), /* GPWR1/2 non overlap time 2.62us */
0320     ILI9881C_COMMAND_INSTR(0x35, 0x00),
0321     ILI9881C_COMMAND_INSTR(0x36, 0x00),
0322     ILI9881C_COMMAND_INSTR(0x37, 0x00),
0323     ILI9881C_COMMAND_INSTR(0x38, 0x00),
0324     ILI9881C_COMMAND_INSTR(0x39, 0x00),
0325     ILI9881C_COMMAND_INSTR(0x3A, 0x00),
0326     ILI9881C_COMMAND_INSTR(0x3B, 0x00),
0327     ILI9881C_COMMAND_INSTR(0x3C, 0x00),
0328     ILI9881C_COMMAND_INSTR(0x3D, 0x00),
0329     ILI9881C_COMMAND_INSTR(0x3E, 0x00),
0330     ILI9881C_COMMAND_INSTR(0x3F, 0x00),
0331     ILI9881C_COMMAND_INSTR(0x40, 0x00),
0332     ILI9881C_COMMAND_INSTR(0x41, 0x00),
0333     ILI9881C_COMMAND_INSTR(0x42, 0x00),
0334     ILI9881C_COMMAND_INSTR(0x43, 0x00),
0335     ILI9881C_COMMAND_INSTR(0x44, 0x00),
0336     ILI9881C_COMMAND_INSTR(0x50, 0x01),
0337     ILI9881C_COMMAND_INSTR(0x51, 0x23),
0338     ILI9881C_COMMAND_INSTR(0x52, 0x45),
0339     ILI9881C_COMMAND_INSTR(0x53, 0x67),
0340     ILI9881C_COMMAND_INSTR(0x54, 0x89),
0341     ILI9881C_COMMAND_INSTR(0x55, 0xAB),
0342     ILI9881C_COMMAND_INSTR(0x56, 0x01),
0343     ILI9881C_COMMAND_INSTR(0x57, 0x23),
0344     ILI9881C_COMMAND_INSTR(0x58, 0x45),
0345     ILI9881C_COMMAND_INSTR(0x59, 0x67),
0346     ILI9881C_COMMAND_INSTR(0x5A, 0x89),
0347     ILI9881C_COMMAND_INSTR(0x5B, 0xAB),
0348     ILI9881C_COMMAND_INSTR(0x5C, 0xCD),
0349     ILI9881C_COMMAND_INSTR(0x5D, 0xEF),
0350     ILI9881C_COMMAND_INSTR(0x5E, 0x00),
0351     ILI9881C_COMMAND_INSTR(0x5F, 0x01),
0352     ILI9881C_COMMAND_INSTR(0x60, 0x01),
0353     ILI9881C_COMMAND_INSTR(0x61, 0x06),
0354     ILI9881C_COMMAND_INSTR(0x62, 0x06),
0355     ILI9881C_COMMAND_INSTR(0x63, 0x07),
0356     ILI9881C_COMMAND_INSTR(0x64, 0x07),
0357     ILI9881C_COMMAND_INSTR(0x65, 0x00),
0358     ILI9881C_COMMAND_INSTR(0x66, 0x00),
0359     ILI9881C_COMMAND_INSTR(0x67, 0x02),
0360     ILI9881C_COMMAND_INSTR(0x68, 0x02),
0361     ILI9881C_COMMAND_INSTR(0x69, 0x05),
0362     ILI9881C_COMMAND_INSTR(0x6A, 0x05),
0363     ILI9881C_COMMAND_INSTR(0x6B, 0x02),
0364     ILI9881C_COMMAND_INSTR(0x6C, 0x0D),
0365     ILI9881C_COMMAND_INSTR(0x6D, 0x0D),
0366     ILI9881C_COMMAND_INSTR(0x6E, 0x0C),
0367     ILI9881C_COMMAND_INSTR(0x6F, 0x0C),
0368     ILI9881C_COMMAND_INSTR(0x70, 0x0F),
0369     ILI9881C_COMMAND_INSTR(0x71, 0x0F),
0370     ILI9881C_COMMAND_INSTR(0x72, 0x0E),
0371     ILI9881C_COMMAND_INSTR(0x73, 0x0E),
0372     ILI9881C_COMMAND_INSTR(0x74, 0x02),
0373     ILI9881C_COMMAND_INSTR(0x75, 0x01),
0374     ILI9881C_COMMAND_INSTR(0x76, 0x01),
0375     ILI9881C_COMMAND_INSTR(0x77, 0x06),
0376     ILI9881C_COMMAND_INSTR(0x78, 0x06),
0377     ILI9881C_COMMAND_INSTR(0x79, 0x07),
0378     ILI9881C_COMMAND_INSTR(0x7A, 0x07),
0379     ILI9881C_COMMAND_INSTR(0x7B, 0x00),
0380     ILI9881C_COMMAND_INSTR(0x7C, 0x00),
0381     ILI9881C_COMMAND_INSTR(0x7D, 0x02),
0382     ILI9881C_COMMAND_INSTR(0x7E, 0x02),
0383     ILI9881C_COMMAND_INSTR(0x7F, 0x05),
0384     ILI9881C_COMMAND_INSTR(0x80, 0x05),
0385     ILI9881C_COMMAND_INSTR(0x81, 0x02),
0386     ILI9881C_COMMAND_INSTR(0x82, 0x0D),
0387     ILI9881C_COMMAND_INSTR(0x83, 0x0D),
0388     ILI9881C_COMMAND_INSTR(0x84, 0x0C),
0389     ILI9881C_COMMAND_INSTR(0x85, 0x0C),
0390     ILI9881C_COMMAND_INSTR(0x86, 0x0F),
0391     ILI9881C_COMMAND_INSTR(0x87, 0x0F),
0392     ILI9881C_COMMAND_INSTR(0x88, 0x0E),
0393     ILI9881C_COMMAND_INSTR(0x89, 0x0E),
0394     ILI9881C_COMMAND_INSTR(0x8A, 0x02),
0395     ILI9881C_SWITCH_PAGE_INSTR(4),
0396     ILI9881C_COMMAND_INSTR(0x3B, 0xC0), /* ILI4003D sel */
0397     ILI9881C_COMMAND_INSTR(0x6C, 0x15), /* Set VCORE voltage = 1.5V */
0398     ILI9881C_COMMAND_INSTR(0x6E, 0x2A), /* di_pwr_reg=0 for power mode 2A, VGH clamp 18V */
0399     ILI9881C_COMMAND_INSTR(0x6F, 0x33), /* pumping ratio VGH=5x VGL=-3x */
0400     ILI9881C_COMMAND_INSTR(0x8D, 0x1B), /* VGL clamp -10V */
0401     ILI9881C_COMMAND_INSTR(0x87, 0xBA), /* ESD */
0402     ILI9881C_COMMAND_INSTR(0x3A, 0x24), /* POWER SAVING */
0403     ILI9881C_COMMAND_INSTR(0x26, 0x76),
0404     ILI9881C_COMMAND_INSTR(0xB2, 0xD1),
0405     ILI9881C_SWITCH_PAGE_INSTR(1),
0406     ILI9881C_COMMAND_INSTR(0x22, 0x0A), /* BGR, SS */
0407     ILI9881C_COMMAND_INSTR(0x31, 0x00), /* Zigzag type3 inversion */
0408     ILI9881C_COMMAND_INSTR(0x40, 0x53), /* ILI4003D sel */
0409     ILI9881C_COMMAND_INSTR(0x43, 0x66),
0410     ILI9881C_COMMAND_INSTR(0x53, 0x4C),
0411     ILI9881C_COMMAND_INSTR(0x50, 0x87),
0412     ILI9881C_COMMAND_INSTR(0x51, 0x82),
0413     ILI9881C_COMMAND_INSTR(0x60, 0x15),
0414     ILI9881C_COMMAND_INSTR(0x61, 0x01),
0415     ILI9881C_COMMAND_INSTR(0x62, 0x0C),
0416     ILI9881C_COMMAND_INSTR(0x63, 0x00),
0417     ILI9881C_COMMAND_INSTR(0xA0, 0x00),
0418     ILI9881C_COMMAND_INSTR(0xA1, 0x13), /* VP251 */
0419     ILI9881C_COMMAND_INSTR(0xA2, 0x23), /* VP247 */
0420     ILI9881C_COMMAND_INSTR(0xA3, 0x14), /* VP243 */
0421     ILI9881C_COMMAND_INSTR(0xA4, 0x16), /* VP239 */
0422     ILI9881C_COMMAND_INSTR(0xA5, 0x29), /* VP231 */
0423     ILI9881C_COMMAND_INSTR(0xA6, 0x1E), /* VP219 */
0424     ILI9881C_COMMAND_INSTR(0xA7, 0x1D), /* VP203 */
0425     ILI9881C_COMMAND_INSTR(0xA8, 0x86), /* VP175 */
0426     ILI9881C_COMMAND_INSTR(0xA9, 0x1E), /* VP144 */
0427     ILI9881C_COMMAND_INSTR(0xAA, 0x29), /* VP111 */
0428     ILI9881C_COMMAND_INSTR(0xAB, 0x74), /* VP80 */
0429     ILI9881C_COMMAND_INSTR(0xAC, 0x19), /* VP52 */
0430     ILI9881C_COMMAND_INSTR(0xAD, 0x17), /* VP36 */
0431     ILI9881C_COMMAND_INSTR(0xAE, 0x4B), /* VP24 */
0432     ILI9881C_COMMAND_INSTR(0xAF, 0x20), /* VP16 */
0433     ILI9881C_COMMAND_INSTR(0xB0, 0x26), /* VP12 */
0434     ILI9881C_COMMAND_INSTR(0xB1, 0x4C), /* VP8 */
0435     ILI9881C_COMMAND_INSTR(0xB2, 0x5D), /* VP4 */
0436     ILI9881C_COMMAND_INSTR(0xB3, 0x3F), /* VP0 */
0437     ILI9881C_COMMAND_INSTR(0xC0, 0x00), /* VN255 GAMMA N */
0438     ILI9881C_COMMAND_INSTR(0xC1, 0x13), /* VN251 */
0439     ILI9881C_COMMAND_INSTR(0xC2, 0x23), /* VN247 */
0440     ILI9881C_COMMAND_INSTR(0xC3, 0x14), /* VN243 */
0441     ILI9881C_COMMAND_INSTR(0xC4, 0x16), /* VN239 */
0442     ILI9881C_COMMAND_INSTR(0xC5, 0x29), /* VN231 */
0443     ILI9881C_COMMAND_INSTR(0xC6, 0x1E), /* VN219 */
0444     ILI9881C_COMMAND_INSTR(0xC7, 0x1D), /* VN203 */
0445     ILI9881C_COMMAND_INSTR(0xC8, 0x86), /* VN175 */
0446     ILI9881C_COMMAND_INSTR(0xC9, 0x1E), /* VN144 */
0447     ILI9881C_COMMAND_INSTR(0xCA, 0x29), /* VN111 */
0448     ILI9881C_COMMAND_INSTR(0xCB, 0x74), /* VN80 */
0449     ILI9881C_COMMAND_INSTR(0xCC, 0x19), /* VN52 */
0450     ILI9881C_COMMAND_INSTR(0xCD, 0x17), /* VN36 */
0451     ILI9881C_COMMAND_INSTR(0xCE, 0x4B), /* VN24 */
0452     ILI9881C_COMMAND_INSTR(0xCF, 0x20), /* VN16 */
0453     ILI9881C_COMMAND_INSTR(0xD0, 0x26), /* VN12 */
0454     ILI9881C_COMMAND_INSTR(0xD1, 0x4C), /* VN8 */
0455     ILI9881C_COMMAND_INSTR(0xD2, 0x5D), /* VN4 */
0456     ILI9881C_COMMAND_INSTR(0xD3, 0x3F), /* VN0 */
0457 };
0458 
0459 static const struct ili9881c_instr w552946ab_init[] = {
0460     ILI9881C_SWITCH_PAGE_INSTR(3),
0461     ILI9881C_COMMAND_INSTR(0x01, 0x00),
0462     ILI9881C_COMMAND_INSTR(0x02, 0x00),
0463     ILI9881C_COMMAND_INSTR(0x03, 0x53),
0464     ILI9881C_COMMAND_INSTR(0x04, 0x53),
0465     ILI9881C_COMMAND_INSTR(0x05, 0x13),
0466     ILI9881C_COMMAND_INSTR(0x06, 0x04),
0467     ILI9881C_COMMAND_INSTR(0x07, 0x02),
0468     ILI9881C_COMMAND_INSTR(0x08, 0x02),
0469     ILI9881C_COMMAND_INSTR(0x09, 0x00),
0470     ILI9881C_COMMAND_INSTR(0x0A, 0x00),
0471     ILI9881C_COMMAND_INSTR(0x0B, 0x00),
0472     ILI9881C_COMMAND_INSTR(0x0C, 0x00),
0473     ILI9881C_COMMAND_INSTR(0x0D, 0x00),
0474     ILI9881C_COMMAND_INSTR(0x0E, 0x00),
0475     ILI9881C_COMMAND_INSTR(0x0F, 0x00),
0476 
0477     ILI9881C_COMMAND_INSTR(0x10, 0x00),
0478     ILI9881C_COMMAND_INSTR(0x11, 0x00),
0479     ILI9881C_COMMAND_INSTR(0x12, 0x00),
0480     ILI9881C_COMMAND_INSTR(0x13, 0x00),
0481     ILI9881C_COMMAND_INSTR(0x14, 0x00),
0482     ILI9881C_COMMAND_INSTR(0x15, 0x08),
0483     ILI9881C_COMMAND_INSTR(0x16, 0x10),
0484     ILI9881C_COMMAND_INSTR(0x17, 0x00),
0485     ILI9881C_COMMAND_INSTR(0x18, 0x08),
0486     ILI9881C_COMMAND_INSTR(0x19, 0x00),
0487     ILI9881C_COMMAND_INSTR(0x1A, 0x00),
0488     ILI9881C_COMMAND_INSTR(0x1B, 0x00),
0489     ILI9881C_COMMAND_INSTR(0x1C, 0x00),
0490     ILI9881C_COMMAND_INSTR(0x1D, 0x00),
0491     ILI9881C_COMMAND_INSTR(0x1E, 0xC0),
0492     ILI9881C_COMMAND_INSTR(0x1F, 0x80),
0493 
0494     ILI9881C_COMMAND_INSTR(0x20, 0x02),
0495     ILI9881C_COMMAND_INSTR(0x21, 0x09),
0496     ILI9881C_COMMAND_INSTR(0x22, 0x00),
0497     ILI9881C_COMMAND_INSTR(0x23, 0x00),
0498     ILI9881C_COMMAND_INSTR(0x24, 0x00),
0499     ILI9881C_COMMAND_INSTR(0x25, 0x00),
0500     ILI9881C_COMMAND_INSTR(0x26, 0x00),
0501     ILI9881C_COMMAND_INSTR(0x27, 0x00),
0502     ILI9881C_COMMAND_INSTR(0x28, 0x55),
0503     ILI9881C_COMMAND_INSTR(0x29, 0x03),
0504     ILI9881C_COMMAND_INSTR(0x2A, 0x00),
0505     ILI9881C_COMMAND_INSTR(0x2B, 0x00),
0506     ILI9881C_COMMAND_INSTR(0x2C, 0x00),
0507     ILI9881C_COMMAND_INSTR(0x2D, 0x00),
0508     ILI9881C_COMMAND_INSTR(0x2E, 0x00),
0509     ILI9881C_COMMAND_INSTR(0x2F, 0x00),
0510 
0511     ILI9881C_COMMAND_INSTR(0x30, 0x00),
0512     ILI9881C_COMMAND_INSTR(0x31, 0x00),
0513     ILI9881C_COMMAND_INSTR(0x32, 0x00),
0514     ILI9881C_COMMAND_INSTR(0x33, 0x00),
0515     ILI9881C_COMMAND_INSTR(0x34, 0x04),
0516     ILI9881C_COMMAND_INSTR(0x35, 0x05),
0517     ILI9881C_COMMAND_INSTR(0x36, 0x05),
0518     ILI9881C_COMMAND_INSTR(0x37, 0x00),
0519     ILI9881C_COMMAND_INSTR(0x38, 0x3C),
0520     ILI9881C_COMMAND_INSTR(0x39, 0x35),
0521     ILI9881C_COMMAND_INSTR(0x3A, 0x00),
0522     ILI9881C_COMMAND_INSTR(0x3B, 0x40),
0523     ILI9881C_COMMAND_INSTR(0x3C, 0x00),
0524     ILI9881C_COMMAND_INSTR(0x3D, 0x00),
0525     ILI9881C_COMMAND_INSTR(0x3E, 0x00),
0526     ILI9881C_COMMAND_INSTR(0x3F, 0x00),
0527 
0528     ILI9881C_COMMAND_INSTR(0x40, 0x00),
0529     ILI9881C_COMMAND_INSTR(0x41, 0x88),
0530     ILI9881C_COMMAND_INSTR(0x42, 0x00),
0531     ILI9881C_COMMAND_INSTR(0x43, 0x00),
0532     ILI9881C_COMMAND_INSTR(0x44, 0x1F),
0533 
0534     ILI9881C_COMMAND_INSTR(0x50, 0x01),
0535     ILI9881C_COMMAND_INSTR(0x51, 0x23),
0536     ILI9881C_COMMAND_INSTR(0x52, 0x45),
0537     ILI9881C_COMMAND_INSTR(0x53, 0x67),
0538     ILI9881C_COMMAND_INSTR(0x54, 0x89),
0539     ILI9881C_COMMAND_INSTR(0x55, 0xaB),
0540     ILI9881C_COMMAND_INSTR(0x56, 0x01),
0541     ILI9881C_COMMAND_INSTR(0x57, 0x23),
0542     ILI9881C_COMMAND_INSTR(0x58, 0x45),
0543     ILI9881C_COMMAND_INSTR(0x59, 0x67),
0544     ILI9881C_COMMAND_INSTR(0x5A, 0x89),
0545     ILI9881C_COMMAND_INSTR(0x5B, 0xAB),
0546     ILI9881C_COMMAND_INSTR(0x5C, 0xCD),
0547     ILI9881C_COMMAND_INSTR(0x5D, 0xEF),
0548     ILI9881C_COMMAND_INSTR(0x5E, 0x03),
0549     ILI9881C_COMMAND_INSTR(0x5F, 0x14),
0550 
0551     ILI9881C_COMMAND_INSTR(0x60, 0x15),
0552     ILI9881C_COMMAND_INSTR(0x61, 0x0C),
0553     ILI9881C_COMMAND_INSTR(0x62, 0x0D),
0554     ILI9881C_COMMAND_INSTR(0x63, 0x0E),
0555     ILI9881C_COMMAND_INSTR(0x64, 0x0F),
0556     ILI9881C_COMMAND_INSTR(0x65, 0x10),
0557     ILI9881C_COMMAND_INSTR(0x66, 0x11),
0558     ILI9881C_COMMAND_INSTR(0x67, 0x08),
0559     ILI9881C_COMMAND_INSTR(0x68, 0x02),
0560     ILI9881C_COMMAND_INSTR(0x69, 0x0A),
0561     ILI9881C_COMMAND_INSTR(0x6A, 0x02),
0562     ILI9881C_COMMAND_INSTR(0x6B, 0x02),
0563     ILI9881C_COMMAND_INSTR(0x6C, 0x02),
0564     ILI9881C_COMMAND_INSTR(0x6D, 0x02),
0565     ILI9881C_COMMAND_INSTR(0x6E, 0x02),
0566     ILI9881C_COMMAND_INSTR(0x6F, 0x02),
0567 
0568     ILI9881C_COMMAND_INSTR(0x70, 0x02),
0569     ILI9881C_COMMAND_INSTR(0x71, 0x02),
0570     ILI9881C_COMMAND_INSTR(0x72, 0x06),
0571     ILI9881C_COMMAND_INSTR(0x73, 0x02),
0572     ILI9881C_COMMAND_INSTR(0x74, 0x02),
0573     ILI9881C_COMMAND_INSTR(0x75, 0x14),
0574     ILI9881C_COMMAND_INSTR(0x76, 0x15),
0575     ILI9881C_COMMAND_INSTR(0x77, 0x0F),
0576     ILI9881C_COMMAND_INSTR(0x78, 0x0E),
0577     ILI9881C_COMMAND_INSTR(0x79, 0x0D),
0578     ILI9881C_COMMAND_INSTR(0x7A, 0x0C),
0579     ILI9881C_COMMAND_INSTR(0x7B, 0x11),
0580     ILI9881C_COMMAND_INSTR(0x7C, 0x10),
0581     ILI9881C_COMMAND_INSTR(0x7D, 0x06),
0582     ILI9881C_COMMAND_INSTR(0x7E, 0x02),
0583     ILI9881C_COMMAND_INSTR(0x7F, 0x0A),
0584 
0585     ILI9881C_COMMAND_INSTR(0x80, 0x02),
0586     ILI9881C_COMMAND_INSTR(0x81, 0x02),
0587     ILI9881C_COMMAND_INSTR(0x82, 0x02),
0588     ILI9881C_COMMAND_INSTR(0x83, 0x02),
0589     ILI9881C_COMMAND_INSTR(0x84, 0x02),
0590     ILI9881C_COMMAND_INSTR(0x85, 0x02),
0591     ILI9881C_COMMAND_INSTR(0x86, 0x02),
0592     ILI9881C_COMMAND_INSTR(0x87, 0x02),
0593     ILI9881C_COMMAND_INSTR(0x88, 0x08),
0594     ILI9881C_COMMAND_INSTR(0x89, 0x02),
0595     ILI9881C_COMMAND_INSTR(0x8A, 0x02),
0596 
0597     ILI9881C_SWITCH_PAGE_INSTR(4),
0598     ILI9881C_COMMAND_INSTR(0x00, 0x80),
0599     ILI9881C_COMMAND_INSTR(0x70, 0x00),
0600     ILI9881C_COMMAND_INSTR(0x71, 0x00),
0601     ILI9881C_COMMAND_INSTR(0x66, 0xFE),
0602     ILI9881C_COMMAND_INSTR(0x82, 0x15),
0603     ILI9881C_COMMAND_INSTR(0x84, 0x15),
0604     ILI9881C_COMMAND_INSTR(0x85, 0x15),
0605     ILI9881C_COMMAND_INSTR(0x3a, 0x24),
0606     ILI9881C_COMMAND_INSTR(0x32, 0xAC),
0607     ILI9881C_COMMAND_INSTR(0x8C, 0x80),
0608     ILI9881C_COMMAND_INSTR(0x3C, 0xF5),
0609     ILI9881C_COMMAND_INSTR(0x88, 0x33),
0610 
0611     ILI9881C_SWITCH_PAGE_INSTR(1),
0612     ILI9881C_COMMAND_INSTR(0x22, 0x0A),
0613     ILI9881C_COMMAND_INSTR(0x31, 0x00),
0614     ILI9881C_COMMAND_INSTR(0x53, 0x78),
0615     ILI9881C_COMMAND_INSTR(0x50, 0x5B),
0616     ILI9881C_COMMAND_INSTR(0x51, 0x5B),
0617     ILI9881C_COMMAND_INSTR(0x60, 0x20),
0618     ILI9881C_COMMAND_INSTR(0x61, 0x00),
0619     ILI9881C_COMMAND_INSTR(0x62, 0x0D),
0620     ILI9881C_COMMAND_INSTR(0x63, 0x00),
0621 
0622     ILI9881C_COMMAND_INSTR(0xA0, 0x00),
0623     ILI9881C_COMMAND_INSTR(0xA1, 0x10),
0624     ILI9881C_COMMAND_INSTR(0xA2, 0x1C),
0625     ILI9881C_COMMAND_INSTR(0xA3, 0x13),
0626     ILI9881C_COMMAND_INSTR(0xA4, 0x15),
0627     ILI9881C_COMMAND_INSTR(0xA5, 0x26),
0628     ILI9881C_COMMAND_INSTR(0xA6, 0x1A),
0629     ILI9881C_COMMAND_INSTR(0xA7, 0x1D),
0630     ILI9881C_COMMAND_INSTR(0xA8, 0x67),
0631     ILI9881C_COMMAND_INSTR(0xA9, 0x1C),
0632     ILI9881C_COMMAND_INSTR(0xAA, 0x29),
0633     ILI9881C_COMMAND_INSTR(0xAB, 0x5B),
0634     ILI9881C_COMMAND_INSTR(0xAC, 0x26),
0635     ILI9881C_COMMAND_INSTR(0xAD, 0x28),
0636     ILI9881C_COMMAND_INSTR(0xAE, 0x5C),
0637     ILI9881C_COMMAND_INSTR(0xAF, 0x30),
0638     ILI9881C_COMMAND_INSTR(0xB0, 0x31),
0639     ILI9881C_COMMAND_INSTR(0xB1, 0x2E),
0640     ILI9881C_COMMAND_INSTR(0xB2, 0x32),
0641     ILI9881C_COMMAND_INSTR(0xB3, 0x00),
0642 
0643     ILI9881C_COMMAND_INSTR(0xC0, 0x00),
0644     ILI9881C_COMMAND_INSTR(0xC1, 0x10),
0645     ILI9881C_COMMAND_INSTR(0xC2, 0x1C),
0646     ILI9881C_COMMAND_INSTR(0xC3, 0x13),
0647     ILI9881C_COMMAND_INSTR(0xC4, 0x15),
0648     ILI9881C_COMMAND_INSTR(0xC5, 0x26),
0649     ILI9881C_COMMAND_INSTR(0xC6, 0x1A),
0650     ILI9881C_COMMAND_INSTR(0xC7, 0x1D),
0651     ILI9881C_COMMAND_INSTR(0xC8, 0x67),
0652     ILI9881C_COMMAND_INSTR(0xC9, 0x1C),
0653     ILI9881C_COMMAND_INSTR(0xCA, 0x29),
0654     ILI9881C_COMMAND_INSTR(0xCB, 0x5B),
0655     ILI9881C_COMMAND_INSTR(0xCC, 0x26),
0656     ILI9881C_COMMAND_INSTR(0xCD, 0x28),
0657     ILI9881C_COMMAND_INSTR(0xCE, 0x5C),
0658     ILI9881C_COMMAND_INSTR(0xCF, 0x30),
0659     ILI9881C_COMMAND_INSTR(0xD0, 0x31),
0660     ILI9881C_COMMAND_INSTR(0xD1, 0x2E),
0661     ILI9881C_COMMAND_INSTR(0xD2, 0x32),
0662     ILI9881C_COMMAND_INSTR(0xD3, 0x00),
0663     ILI9881C_SWITCH_PAGE_INSTR(0),
0664 };
0665 
0666 static inline struct ili9881c *panel_to_ili9881c(struct drm_panel *panel)
0667 {
0668     return container_of(panel, struct ili9881c, panel);
0669 }
0670 
0671 /*
0672  * The panel seems to accept some private DCS commands that map
0673  * directly to registers.
0674  *
0675  * It is organised by page, with each page having its own set of
0676  * registers, and the first page looks like it's holding the standard
0677  * DCS commands.
0678  *
0679  * So before any attempt at sending a command or data, we have to be
0680  * sure if we're in the right page or not.
0681  */
0682 static int ili9881c_switch_page(struct ili9881c *ctx, u8 page)
0683 {
0684     u8 buf[4] = { 0xff, 0x98, 0x81, page };
0685     int ret;
0686 
0687     ret = mipi_dsi_dcs_write_buffer(ctx->dsi, buf, sizeof(buf));
0688     if (ret < 0)
0689         return ret;
0690 
0691     return 0;
0692 }
0693 
0694 static int ili9881c_send_cmd_data(struct ili9881c *ctx, u8 cmd, u8 data)
0695 {
0696     u8 buf[2] = { cmd, data };
0697     int ret;
0698 
0699     ret = mipi_dsi_dcs_write_buffer(ctx->dsi, buf, sizeof(buf));
0700     if (ret < 0)
0701         return ret;
0702 
0703     return 0;
0704 }
0705 
0706 static int ili9881c_prepare(struct drm_panel *panel)
0707 {
0708     struct ili9881c *ctx = panel_to_ili9881c(panel);
0709     unsigned int i;
0710     int ret;
0711 
0712     /* Power the panel */
0713     ret = regulator_enable(ctx->power);
0714     if (ret)
0715         return ret;
0716     msleep(5);
0717 
0718     /* And reset it */
0719     gpiod_set_value(ctx->reset, 1);
0720     msleep(20);
0721 
0722     gpiod_set_value(ctx->reset, 0);
0723     msleep(20);
0724 
0725     for (i = 0; i < ctx->desc->init_length; i++) {
0726         const struct ili9881c_instr *instr = &ctx->desc->init[i];
0727 
0728         if (instr->op == ILI9881C_SWITCH_PAGE)
0729             ret = ili9881c_switch_page(ctx, instr->arg.page);
0730         else if (instr->op == ILI9881C_COMMAND)
0731             ret = ili9881c_send_cmd_data(ctx, instr->arg.cmd.cmd,
0732                               instr->arg.cmd.data);
0733 
0734         if (ret)
0735             return ret;
0736     }
0737 
0738     ret = ili9881c_switch_page(ctx, 0);
0739     if (ret)
0740         return ret;
0741 
0742     ret = mipi_dsi_dcs_set_tear_on(ctx->dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
0743     if (ret)
0744         return ret;
0745 
0746     ret = mipi_dsi_dcs_exit_sleep_mode(ctx->dsi);
0747     if (ret)
0748         return ret;
0749 
0750     return 0;
0751 }
0752 
0753 static int ili9881c_enable(struct drm_panel *panel)
0754 {
0755     struct ili9881c *ctx = panel_to_ili9881c(panel);
0756 
0757     msleep(120);
0758 
0759     mipi_dsi_dcs_set_display_on(ctx->dsi);
0760 
0761     return 0;
0762 }
0763 
0764 static int ili9881c_disable(struct drm_panel *panel)
0765 {
0766     struct ili9881c *ctx = panel_to_ili9881c(panel);
0767 
0768     return mipi_dsi_dcs_set_display_off(ctx->dsi);
0769 }
0770 
0771 static int ili9881c_unprepare(struct drm_panel *panel)
0772 {
0773     struct ili9881c *ctx = panel_to_ili9881c(panel);
0774 
0775     mipi_dsi_dcs_enter_sleep_mode(ctx->dsi);
0776     regulator_disable(ctx->power);
0777     gpiod_set_value(ctx->reset, 1);
0778 
0779     return 0;
0780 }
0781 
0782 static const struct drm_display_mode lhr050h41_default_mode = {
0783     .clock      = 62000,
0784 
0785     .hdisplay   = 720,
0786     .hsync_start    = 720 + 10,
0787     .hsync_end  = 720 + 10 + 20,
0788     .htotal     = 720 + 10 + 20 + 30,
0789 
0790     .vdisplay   = 1280,
0791     .vsync_start    = 1280 + 10,
0792     .vsync_end  = 1280 + 10 + 10,
0793     .vtotal     = 1280 + 10 + 10 + 20,
0794 
0795     .width_mm   = 62,
0796     .height_mm  = 110,
0797 };
0798 
0799 static const struct drm_display_mode k101_im2byl02_default_mode = {
0800     .clock      = 69700,
0801 
0802     .hdisplay   = 800,
0803     .hsync_start    = 800 + 52,
0804     .hsync_end  = 800 + 52 + 8,
0805     .htotal     = 800 + 52 + 8 + 48,
0806 
0807     .vdisplay   = 1280,
0808     .vsync_start    = 1280 + 16,
0809     .vsync_end  = 1280 + 16 + 6,
0810     .vtotal     = 1280 + 16 + 6 + 15,
0811 
0812     .width_mm   = 135,
0813     .height_mm  = 217,
0814 };
0815 
0816 static const struct drm_display_mode w552946aba_default_mode = {
0817     .clock      = 64000,
0818 
0819     .hdisplay   = 720,
0820     .hsync_start    = 720 + 40,
0821     .hsync_end  = 720 + 40 + 10,
0822     .htotal     = 720 + 40 + 10 + 40,
0823 
0824     .vdisplay   = 1280,
0825     .vsync_start    = 1280 + 22,
0826     .vsync_end  = 1280 + 22 + 4,
0827     .vtotal     = 1280 + 22 + 4 + 11,
0828 
0829     .width_mm   = 68,
0830     .height_mm  = 121,
0831 };
0832 
0833 static int ili9881c_get_modes(struct drm_panel *panel,
0834                   struct drm_connector *connector)
0835 {
0836     struct ili9881c *ctx = panel_to_ili9881c(panel);
0837     struct drm_display_mode *mode;
0838 
0839     mode = drm_mode_duplicate(connector->dev, ctx->desc->mode);
0840     if (!mode) {
0841         dev_err(&ctx->dsi->dev, "failed to add mode %ux%ux@%u\n",
0842             ctx->desc->mode->hdisplay,
0843             ctx->desc->mode->vdisplay,
0844             drm_mode_vrefresh(ctx->desc->mode));
0845         return -ENOMEM;
0846     }
0847 
0848     drm_mode_set_name(mode);
0849 
0850     mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
0851     drm_mode_probed_add(connector, mode);
0852 
0853     connector->display_info.width_mm = mode->width_mm;
0854     connector->display_info.height_mm = mode->height_mm;
0855 
0856     /*
0857      * TODO: Remove once all drm drivers call
0858      * drm_connector_set_orientation_from_panel()
0859      */
0860     drm_connector_set_panel_orientation(connector, ctx->orientation);
0861 
0862     return 1;
0863 }
0864 
0865 static enum drm_panel_orientation ili9881c_get_orientation(struct drm_panel *panel)
0866 {
0867     struct ili9881c *ctx = panel_to_ili9881c(panel);
0868 
0869     return ctx->orientation;
0870 }
0871 
0872 static const struct drm_panel_funcs ili9881c_funcs = {
0873     .prepare    = ili9881c_prepare,
0874     .unprepare  = ili9881c_unprepare,
0875     .enable     = ili9881c_enable,
0876     .disable    = ili9881c_disable,
0877     .get_modes  = ili9881c_get_modes,
0878     .get_orientation = ili9881c_get_orientation,
0879 };
0880 
0881 static int ili9881c_dsi_probe(struct mipi_dsi_device *dsi)
0882 {
0883     struct ili9881c *ctx;
0884     int ret;
0885 
0886     ctx = devm_kzalloc(&dsi->dev, sizeof(*ctx), GFP_KERNEL);
0887     if (!ctx)
0888         return -ENOMEM;
0889     mipi_dsi_set_drvdata(dsi, ctx);
0890     ctx->dsi = dsi;
0891     ctx->desc = of_device_get_match_data(&dsi->dev);
0892 
0893     drm_panel_init(&ctx->panel, &dsi->dev, &ili9881c_funcs,
0894                DRM_MODE_CONNECTOR_DSI);
0895 
0896     ctx->power = devm_regulator_get(&dsi->dev, "power");
0897     if (IS_ERR(ctx->power))
0898         return dev_err_probe(&dsi->dev, PTR_ERR(ctx->power),
0899                      "Couldn't get our power regulator\n");
0900 
0901     ctx->reset = devm_gpiod_get_optional(&dsi->dev, "reset", GPIOD_OUT_LOW);
0902     if (IS_ERR(ctx->reset))
0903         return dev_err_probe(&dsi->dev, PTR_ERR(ctx->reset),
0904                      "Couldn't get our reset GPIO\n");
0905 
0906     ret = of_drm_get_panel_orientation(dsi->dev.of_node, &ctx->orientation);
0907     if (ret) {
0908         dev_err(&dsi->dev, "%pOF: failed to get orientation: %d\n",
0909             dsi->dev.of_node, ret);
0910         return ret;
0911     }
0912 
0913     ret = drm_panel_of_backlight(&ctx->panel);
0914     if (ret)
0915         return ret;
0916 
0917     drm_panel_add(&ctx->panel);
0918 
0919     dsi->mode_flags = ctx->desc->mode_flags;
0920     dsi->format = MIPI_DSI_FMT_RGB888;
0921     dsi->lanes = 4;
0922 
0923     return mipi_dsi_attach(dsi);
0924 }
0925 
0926 static int ili9881c_dsi_remove(struct mipi_dsi_device *dsi)
0927 {
0928     struct ili9881c *ctx = mipi_dsi_get_drvdata(dsi);
0929 
0930     mipi_dsi_detach(dsi);
0931     drm_panel_remove(&ctx->panel);
0932 
0933     return 0;
0934 }
0935 
0936 static const struct ili9881c_desc lhr050h41_desc = {
0937     .init = lhr050h41_init,
0938     .init_length = ARRAY_SIZE(lhr050h41_init),
0939     .mode = &lhr050h41_default_mode,
0940     .mode_flags = MIPI_DSI_MODE_VIDEO_SYNC_PULSE,
0941 };
0942 
0943 static const struct ili9881c_desc k101_im2byl02_desc = {
0944     .init = k101_im2byl02_init,
0945     .init_length = ARRAY_SIZE(k101_im2byl02_init),
0946     .mode = &k101_im2byl02_default_mode,
0947     .mode_flags = MIPI_DSI_MODE_VIDEO_SYNC_PULSE,
0948 };
0949 
0950 static const struct ili9881c_desc w552946aba_desc = {
0951     .init = w552946ab_init,
0952     .init_length = ARRAY_SIZE(w552946ab_init),
0953     .mode = &w552946aba_default_mode,
0954     .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
0955               MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET,
0956 };
0957 
0958 static const struct of_device_id ili9881c_of_match[] = {
0959     { .compatible = "bananapi,lhr050h41", .data = &lhr050h41_desc },
0960     { .compatible = "feixin,k101-im2byl02", .data = &k101_im2byl02_desc },
0961     { .compatible = "wanchanglong,w552946aba", .data = &w552946aba_desc },
0962     { }
0963 };
0964 MODULE_DEVICE_TABLE(of, ili9881c_of_match);
0965 
0966 static struct mipi_dsi_driver ili9881c_dsi_driver = {
0967     .probe      = ili9881c_dsi_probe,
0968     .remove     = ili9881c_dsi_remove,
0969     .driver = {
0970         .name       = "ili9881c-dsi",
0971         .of_match_table = ili9881c_of_match,
0972     },
0973 };
0974 module_mipi_dsi_driver(ili9881c_dsi_driver);
0975 
0976 MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
0977 MODULE_DESCRIPTION("Ilitek ILI9881C Controller Driver");
0978 MODULE_LICENSE("GPL v2");