1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Driver for panels based on Himax HX83102 controller, such as: 4 * 5 * - Starry 10.51" WUXGA MIPI-DSI panel 6 * 7 * Based on drivers/gpu/drm/panel/panel-himax-hx8394.c 8 */ 9 10 #include <linux/delay.h> 11 #include <linux/gpio/consumer.h> 12 #include <linux/module.h> 13 #include <linux/of.h> 14 #include <linux/regulator/consumer.h> 15 16 #include <drm/drm_connector.h> 17 #include <drm/drm_crtc.h> 18 #include <drm/drm_mipi_dsi.h> 19 #include <drm/drm_panel.h> 20 21 #include <video/mipi_display.h> 22 23 /* Manufacturer specific DSI commands */ 24 #define HX83102_SETPOWER 0xb1 25 #define HX83102_SETDISP 0xb2 26 #define HX83102_SETCYC 0xb4 27 #define HX83102_SETEXTC 0xb9 28 #define HX83102_SETMIPI 0xba 29 #define HX83102_SETVDC 0xbc 30 #define HX83102_SETBANK 0xbd 31 #define HX83102_UNKNOWN_BE 0xbe 32 #define HX83102_SETPTBA 0xbf 33 #define HX83102_SETSTBA 0xc0 34 #define HX83102_SETTCON 0xc7 35 #define HX83102_SETRAMDMY 0xc8 36 #define HX83102_SETPWM 0xc9 37 #define HX83102_SETCLOCK 0xcb 38 #define HX83102_SETPANEL 0xcc 39 #define HX83102_SETCASCADE 0xd0 40 #define HX83102_SETPCTRL 0xd1 41 #define HX83102_UNKNOWN_D2 0xd2 42 #define HX83102_SETGIP0 0xd3 43 #define HX83102_SETGIP1 0xd5 44 #define HX83102_SETGIP2 0xd6 45 #define HX83102_SETGIP3 0xd8 46 #define HX83102_SETGMA 0xe0 47 #define HX83102_UNKNOWN_E1 0xe1 48 #define HX83102_SETTP1 0xe7 49 #define HX83102_SETSPCCMD 0xe9 50 51 struct hx83102 { 52 struct drm_panel base; 53 struct mipi_dsi_device *dsi; 54 55 const struct hx83102_panel_desc *desc; 56 57 enum drm_panel_orientation orientation; 58 struct regulator *pp1800; 59 struct regulator *avee; 60 struct regulator *avdd; 61 struct gpio_desc *enable_gpio; 62 }; 63 64 struct hx83102_panel_desc { 65 const struct drm_display_mode *modes; 66 67 /** 68 * @width_mm: width of the panel's active display area 69 * @height_mm: height of the panel's active display area 70 */ 71 struct { 72 unsigned int width_mm; 73 unsigned int height_mm; 74 } size; 75 76 int (*init)(struct hx83102 *ctx); 77 }; 78 79 static inline struct hx83102 *panel_to_hx83102(struct drm_panel *panel) 80 { 81 return container_of(panel, struct hx83102, base); 82 } 83 84 static void hx83102_enable_extended_cmds(struct mipi_dsi_multi_context *dsi_ctx, bool enable) 85 { 86 if (enable) 87 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX83102_SETEXTC, 0x83, 0x10, 0x21, 0x55, 0x00); 88 else 89 mipi_dsi_dcs_write_seq_multi(dsi_ctx, HX83102_SETEXTC, 0x00, 0x00, 0x00); 90 } 91 92 static int starry_himax83102_j02_init(struct hx83102 *ctx) 93 { 94 struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi }; 95 96 hx83102_enable_extended_cmds(&dsi_ctx, true); 97 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETPOWER, 0x2c, 0xb5, 0xb5, 0x31, 0xf1, 98 0x31, 0xd7, 0x2f, 0x36, 0x36, 0x36, 0x36, 0x1a, 0x8b, 0x11, 99 0x65, 0x00, 0x88, 0xfa, 0xff, 0xff, 0x8f, 0xff, 0x08, 0x74, 100 0x33); 101 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETDISP, 0x00, 0x47, 0xb0, 0x80, 0x00, 102 0x12, 0x72, 0x3c, 0xa3, 0x03, 0x03, 0x00, 0x00, 0x88, 0xf5); 103 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETCYC, 0x76, 0x76, 0x76, 0x76, 0x76, 104 0x76, 0x63, 0x5c, 0x63, 0x5c, 0x01, 0x9e); 105 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xcd); 106 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETMIPI, 0x84); 107 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0x3f); 108 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETVDC, 0x1b, 0x04); 109 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_UNKNOWN_BE, 0x20); 110 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETPTBA, 0xfc, 0xc4); 111 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSTBA, 0x36, 0x36, 0x22, 0x11, 0x22, 112 0xa0, 0x61, 0x08, 0xf5, 0x03); 113 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xcc); 114 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETTCON, 0x80); 115 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0x3f); 116 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xc6); 117 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETRAMDMY, 0x97); 118 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0x3f); 119 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETPWM, 0x00, 0x1e, 0x13, 0x88, 0x01); 120 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETCLOCK, 0x08, 0x13, 0x07, 0x00, 0x0f, 0x33); 121 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETPANEL, 0x02); 122 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xc4); 123 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETCASCADE, 0x03); 124 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0x3f); 125 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETPCTRL, 0x37, 0x06, 0x00, 0x02, 0x04, 0x0c, 126 0xff); 127 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_UNKNOWN_D2, 0x1f, 0x11, 0x1f); 128 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGIP0, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 129 0x08, 0x00, 0x08, 0x37, 0x47, 0x34, 0x3b, 0x12, 0x12, 0x03, 0x03, 130 0x32, 0x10, 0x10, 0x00, 0x10, 0x32, 0x10, 0x08, 0x00, 0x08, 0x32, 131 0x17, 0x94, 0x07, 0x94, 0x00, 0x00); 132 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGIP1, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 133 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x40, 0x40, 0x1a, 0x1a, 0x1b, 134 0x1b, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x20, 0x21, 135 0x28, 0x29, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 136 0x18, 0x18, 0x18, 0x18, 0x18); 137 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGIP2, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 138 0x18, 0x18, 0x18, 0x18, 0x40, 0x40, 0x19, 0x19, 0x1a, 0x1a, 0x1b, 139 0x1b, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x29, 0x28, 140 0x21, 0x20, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 141 0x18, 0x18, 0x18, 0x18, 0x18); 142 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGIP3, 0xaa, 0xba, 0xea, 0xaa, 0xaa, 0xa0, 143 0xaa, 0xba, 0xea, 0xaa, 0xaa, 0xa0, 0xaa, 0xba, 0xea, 0xaa, 0xaa, 144 0xa0, 0xaa, 0xba, 0xea, 0xaa, 0xaa, 0xa0, 0xaa, 0xba, 0xea, 0xaa, 145 0xaa, 0xa0, 0xaa, 0xba, 0xea, 0xaa, 0xaa, 0xa0); 146 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGMA, 0x00, 0x09, 0x14, 0x1e, 0x26, 0x48, 147 0x61, 0x67, 0x6c, 0x67, 0x7d, 0x7f, 0x80, 0x8b, 0x87, 0x8f, 0x98, 148 0xab, 0xab, 0x55, 0x5c, 0x68, 0x73, 0x00, 0x09, 0x14, 0x1e, 0x26, 149 0x48, 0x61, 0x67, 0x6c, 0x67, 0x7d, 0x7f, 0x80, 0x8b, 0x87, 0x8f, 150 0x98, 0xab, 0xab, 0x55, 0x5c, 0x68, 0x73); 151 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETTP1, 0x0e, 0x10, 0x10, 0x21, 0x2b, 0x9a, 152 0x02, 0x54, 0x9a, 0x14, 0x14, 0x00, 0x00, 0x00, 0x00, 0x12, 0x05, 153 0x02, 0x02, 0x10); 154 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETBANK, 0x01); 155 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETPOWER, 0x01, 0xbf, 0x11); 156 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETCLOCK, 0x86); 157 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_UNKNOWN_D2, 0x3c, 0xfa); 158 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGIP0, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 159 0x00, 0x00, 0x80, 0x0c, 0x01); 160 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETTP1, 0x02, 0x00, 0x28, 0x01, 0x7e, 0x0f, 161 0x7e, 0x10, 0xa0, 0x00, 0x00, 0x20, 0x40, 0x50, 0x40); 162 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETBANK, 0x02); 163 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGIP3, 0xff, 0xff, 0xbf, 0xfe, 0xaa, 0xa0, 164 0xff, 0xff, 0xbf, 0xfe, 0xaa, 0xa0); 165 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETTP1, 0xfe, 0x04, 0xfe, 0x04, 0xfe, 0x04, 166 0x03, 0x03, 0x03, 0x26, 0x00, 0x26, 0x81, 0x02, 0x40, 0x00, 0x20, 167 0x9e, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00); 168 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETBANK, 0x03); 169 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xc6); 170 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETCYC, 0x03, 0xff, 0xf8); 171 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0x3f); 172 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGIP3, 0x00, 0x2a, 0xaa, 0xa8, 0x00, 0x00, 173 0x00, 0x2a, 0xaa, 0xa8, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xfc, 0x00, 174 0x00, 0x00, 0x3f, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x2a, 0xaa, 0xa8, 175 0x00, 0x00, 0x00, 0x2a, 0xaa, 0xa8, 0x00, 0x00); 176 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETBANK, 0x00); 177 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xc4); 178 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETMIPI, 0x96); 179 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0x3f); 180 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETBANK, 0x01); 181 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xc5); 182 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETMIPI, 0x4f); 183 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0x3f); 184 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETBANK, 0x00); 185 186 return dsi_ctx.accum_err; 187 }; 188 189 static int boe_nv110wum_init(struct hx83102 *ctx) 190 { 191 struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi }; 192 193 msleep(60); 194 195 hx83102_enable_extended_cmds(&dsi_ctx, true); 196 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETPOWER, 0x2c, 0xaf, 0xaf, 0x2b, 0xeb, 0x42, 197 0xe1, 0x4d, 0x36, 0x36, 0x36, 0x36, 0x1a, 0x8b, 0x11, 0x65, 0x00, 198 0x88, 0xfa, 0xff, 0xff, 0x8f, 0xff, 0x08, 0x9a, 0x33); 199 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETDISP, 0x00, 0x47, 0xb0, 0x80, 0x00, 0x12, 200 0x71, 0x3c, 0xa3, 0x11, 0x00, 0x00, 0x00, 0x88, 0xf5, 0x22, 0x8f); 201 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETCYC, 0x49, 0x49, 0x32, 0x32, 0x14, 0x32, 202 0x84, 0x6e, 0x84, 0x6e, 0x01, 0x9c); 203 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xcd); 204 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETMIPI, 0x84); 205 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0x3f); 206 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETVDC, 0x1b, 0x04); 207 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_UNKNOWN_BE, 0x20); 208 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETPTBA, 0xfc, 0x84); 209 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSTBA, 0x36, 0x36, 0x22, 0x00, 0x00, 0xa0, 210 0x61, 0x08, 0xf5, 0x03); 211 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xcc); 212 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETTCON, 0x80); 213 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0x3f); 214 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xc6); 215 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETRAMDMY, 0x97); 216 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0x3f); 217 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETPWM, 0x00, 0x1e, 0x30, 0xd4, 0x01); 218 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETCLOCK, 0x08, 0x13, 0x07, 0x00, 0x0f, 0x34); 219 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETPANEL, 0x02, 0x03, 0x44); 220 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xc4); 221 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETCASCADE, 0x03); 222 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0x3f); 223 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETPCTRL, 0x37, 0x06, 0x00, 0x02, 0x04, 0x0c, 0xff); 224 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_UNKNOWN_D2, 0x1f, 0x11, 0x1f, 0x11); 225 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGIP0, 0x06, 0x00, 0x00, 0x00, 0x00, 0x04, 226 0x08, 0x04, 0x08, 0x37, 0x37, 0x64, 0x4b, 0x11, 0x11, 0x03, 0x03, 0x32, 227 0x10, 0x0e, 0x00, 0x0e, 0x32, 0x10, 0x0a, 0x00, 0x0a, 0x32, 0x17, 0x98, 228 0x07, 0x98, 0x00, 0x00); 229 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGIP1, 0x18, 0x18, 0x18, 0x18, 0x1e, 0x1e, 230 0x1e, 0x1e, 0x1f, 0x1f, 0x1f, 0x1f, 0x24, 0x24, 0x24, 0x24, 0x07, 0x06, 231 0x07, 0x06, 0x05, 0x04, 0x05, 0x04, 0x03, 0x02, 0x03, 0x02, 0x01, 0x00, 232 0x01, 0x00, 0x21, 0x20, 0x21, 0x20, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 233 0x18, 0x18); 234 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGIP3, 0xaf, 0xaa, 0xaa, 0xaa, 0xaa, 0xa0, 235 0xaf, 0xaa, 0xaa, 0xaa, 0xaa, 0xa0); 236 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGMA, 0x00, 0x05, 0x0d, 0x14, 0x1b, 0x2c, 237 0x44, 0x49, 0x51, 0x4c, 0x67, 0x6c, 0x71, 0x80, 0x7d, 0x84, 0x8d, 0xa0, 238 0xa0, 0x4f, 0x58, 0x64, 0x73, 0x00, 0x05, 0x0d, 0x14, 0x1b, 0x2c, 0x44, 239 0x49, 0x51, 0x4c, 0x67, 0x6c, 0x71, 0x80, 0x7d, 0x84, 0x8d, 0xa0, 0xa0, 240 0x4f, 0x58, 0x64, 0x73); 241 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETTP1, 0x07, 0x10, 0x10, 0x1a, 0x26, 0x9e, 242 0x00, 0x53, 0x9b, 0x14, 0x14); 243 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_UNKNOWN_E1, 0x11, 0x00, 0x00, 0x89, 0x30, 0x80, 244 0x07, 0x80, 0x02, 0x58, 0x00, 0x14, 0x02, 0x58, 0x02, 0x58, 0x02, 0x00, 245 0x02, 0x2c, 0x00, 0x20, 0x02, 0x02, 0x00, 0x08, 0x00, 0x0c, 0x05, 0x0e, 246 0x04, 0x94, 0x18, 0x00, 0x10, 0xf0, 0x03, 0x0c, 0x20, 0x00, 0x06, 0x0b, 247 0x0b, 0x33, 0x0e); 248 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETBANK, 0x01); 249 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGIP3, 0xff, 0xff, 0xff, 0xff, 0xfa, 0xa0, 250 0xff, 0xff, 0xff, 0xff, 0xfa, 0xa0); 251 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETPOWER, 0x01, 0xbf, 0x11); 252 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETCLOCK, 0x86); 253 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_UNKNOWN_D2, 0x96); 254 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xc9); 255 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGIP0, 0x84); 256 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0x3f); 257 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xd1); 258 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_UNKNOWN_E1, 0xf6, 0x2b, 0x34, 0x2b, 0x74, 0x3b, 259 0x74, 0x6b, 0x74); 260 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0x3f); 261 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETTP1, 0x02, 0x00, 0x2b, 0x01, 0x7e, 0x0f, 262 0x7e, 0x10, 0xa0, 0x00, 0x00); 263 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETBANK, 0x02); 264 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETCYC, 0x02, 0x00, 0xbb, 0x11); 265 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGIP3, 0xff, 0xaf, 0xff, 0xff, 0xfa, 0xa0, 266 0xff, 0xaf, 0xff, 0xff, 0xfa, 0xa0); 267 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETTP1, 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01, 268 0x00, 0x00, 0x00, 0x23, 0x00, 0x23, 0x81, 0x02, 0x40, 0x00, 0x20, 0x65, 269 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00); 270 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETBANK, 0x03); 271 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGIP3, 0xaa, 0xaf, 0xaa, 0xaa, 0xa0, 0x00, 272 0xaa, 0xaf, 0xaa, 0xaa, 0xa0, 0x00, 0xaa, 0xaf, 0xaa, 0xaa, 0xa0, 0x00, 273 0xaa, 0xaf, 0xaa, 0xaa, 0xa0, 0x00); 274 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xc6); 275 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETCYC, 0x03, 0xff, 0xf8); 276 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0x3f); 277 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_UNKNOWN_E1, 0x00); 278 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETBANK, 0x00); 279 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xc4); 280 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETMIPI, 0x96); 281 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0x3f); 282 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETBANK, 0x01); 283 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xc5); 284 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETMIPI, 0x4f); 285 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0x3f); 286 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETBANK, 0x00); 287 hx83102_enable_extended_cmds(&dsi_ctx, false); 288 289 mipi_dsi_msleep(&dsi_ctx, 50); 290 291 return dsi_ctx.accum_err; 292 }; 293 294 static int ivo_t109nw41_init(struct hx83102 *ctx) 295 { 296 struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi }; 297 298 msleep(60); 299 300 hx83102_enable_extended_cmds(&dsi_ctx, true); 301 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETPOWER, 0x2c, 0xed, 0xed, 0x27, 0xe7, 0x52, 302 0xf5, 0x39, 0x36, 0x36, 0x36, 0x36, 0x32, 0x8b, 0x11, 0x65, 0x00, 0x88, 303 0xfa, 0xff, 0xff, 0x8f, 0xff, 0x08, 0xd6, 0x33); 304 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETDISP, 0x00, 0x47, 0xb0, 0x80, 0x00, 0x12, 305 0x71, 0x3c, 0xa3, 0x22, 0x20, 0x00, 0x00, 0x88, 0x01); 306 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETCYC, 0x35, 0x35, 0x43, 0x43, 0x35, 0x35, 307 0x30, 0x7a, 0x30, 0x7a, 0x01, 0x9d); 308 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xcd); 309 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETMIPI, 0x84); 310 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0x3f); 311 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETVDC, 0x1b, 0x04); 312 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_UNKNOWN_BE, 0x20); 313 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETPTBA, 0xfc, 0xc4); 314 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSTBA, 0x34, 0x34, 0x22, 0x11, 0x22, 0xa0, 315 0x31, 0x08, 0xf5, 0x03); 316 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xcc); 317 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETTCON, 0x80); 318 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0x3f); 319 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xd3); 320 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETTCON, 0x22); 321 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0x3f); 322 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xc6); 323 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETRAMDMY, 0x97); 324 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0x3f); 325 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETPWM, 0x00, 0x1e, 0x13, 0x88, 0x01); 326 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETCLOCK, 0x08, 0x13, 0x07, 0x00, 0x0f, 0x34); 327 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETPANEL, 0x02, 0x03, 0x44); 328 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xc4); 329 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETCASCADE, 0x03); 330 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0x3f); 331 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETPCTRL, 0x07, 0x06, 0x00, 0x02, 0x04, 0x2c, 332 0xff); 333 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGIP0, 0x06, 0x00, 0x00, 0x00, 0x00, 0x08, 334 0x08, 0x08, 0x08, 0x37, 0x07, 0x64, 0x7c, 0x11, 0x11, 0x03, 0x03, 0x32, 335 0x10, 0x0e, 0x00, 0x0e, 0x32, 0x17, 0x97, 0x07, 0x97, 0x32, 0x00, 0x02, 336 0x00, 0x02, 0x00, 0x00); 337 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGIP1, 0x25, 0x24, 0x25, 0x24, 0x18, 0x18, 338 0x18, 0x18, 0x07, 0x06, 0x07, 0x06, 0x05, 0x04, 0x05, 0x04, 0x03, 0x02, 339 0x03, 0x02, 0x01, 0x00, 0x01, 0x00, 0x1e, 0x1e, 0x1e, 0x1e, 0x1f, 0x1f, 340 0x1f, 0x1f, 0x21, 0x20, 0x21, 0x20, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 341 0x18, 0x18); 342 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGIP3, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa0, 343 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 344 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 345 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); 346 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGMA, 0x00, 0x07, 0x10, 0x17, 0x1c, 0x33, 347 0x48, 0x50, 0x57, 0x50, 0x68, 0x6e, 0x71, 0x7f, 0x81, 0x8a, 0x8e, 0x9b, 348 0x9c, 0x4d, 0x56, 0x5d, 0x73, 0x00, 0x07, 0x10, 0x17, 0x1c, 0x33, 0x48, 349 0x50, 0x57, 0x50, 0x68, 0x6e, 0x71, 0x7f, 0x81, 0x8a, 0x8e, 0x9b, 0x9c, 350 0x4d, 0x56, 0x5d, 0x73); 351 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETTP1, 0x07, 0x10, 0x10, 0x1a, 0x26, 0x9e, 352 0x00, 0x4f, 0xa0, 0x14, 0x14, 0x00, 0x00, 0x00, 0x00, 0x12, 0x0a, 0x02, 353 0x02, 0x00, 0x33, 0x02, 0x04, 0x18, 0x01); 354 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETBANK, 0x01); 355 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETPOWER, 0x01, 0x7f, 0x11, 0xfd); 356 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETCLOCK, 0x86); 357 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGIP0, 0x00, 0x00, 0x04, 0x00, 0x00); 358 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGIP3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 359 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa0, 360 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 361 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); 362 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETTP1, 0x02, 0x00, 0x2b, 0x01, 0x7e, 0x0f, 363 0x7e, 0x10, 0xa0, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00); 364 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETBANK, 0x02); 365 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETPTBA, 0xf2); 366 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETCLOCK, 0x03, 0x07, 0x00, 0x10, 0x79); 367 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETGIP3, 0xff, 0xff, 0xff, 0xff, 0xfa, 0xa0, 368 0xff, 0xff, 0xff, 0xff, 0xfa, 0xa0); 369 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETTP1, 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01, 370 0x00, 0x00, 0x00, 0x23, 0x00, 0x23, 0x81, 0x02, 0x40, 0x00, 0x20, 0x6e, 371 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); 372 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETBANK, 0x03); 373 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa0, 374 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa0, 0xff, 0xff, 0xff, 0xff, 0xfa, 0xa0, 375 0xff, 0xff, 0xff, 0xff, 0xfa, 0xa0, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa0, 376 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 377 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); 378 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xc6); 379 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETCYC, 0x03, 0xff, 0xf8); 380 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0x3f); 381 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_UNKNOWN_E1, 0x00); 382 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETBANK, 0x00); 383 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_UNKNOWN_D2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff); 384 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xc4); 385 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETMIPI, 0x96); 386 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0x3f); 387 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETBANK, 0x01); 388 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0xc5); 389 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETMIPI, 0x4f); 390 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETSPCCMD, 0x3f); 391 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83102_SETBANK, 0x00); 392 hx83102_enable_extended_cmds(&dsi_ctx, false); 393 394 mipi_dsi_msleep(&dsi_ctx, 60); 395 396 return dsi_ctx.accum_err; 397 }; 398 399 static const struct drm_display_mode starry_mode = { 400 .clock = 162680, 401 .hdisplay = 1200, 402 .hsync_start = 1200 + 60, 403 .hsync_end = 1200 + 60 + 20, 404 .htotal = 1200 + 60 + 20 + 40, 405 .vdisplay = 1920, 406 .vsync_start = 1920 + 116, 407 .vsync_end = 1920 + 116 + 8, 408 .vtotal = 1920 + 116 + 8 + 12, 409 .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, 410 }; 411 412 static const struct hx83102_panel_desc starry_desc = { 413 .modes = &starry_mode, 414 .size = { 415 .width_mm = 141, 416 .height_mm = 226, 417 }, 418 .init = starry_himax83102_j02_init, 419 }; 420 421 static const struct drm_display_mode boe_tv110wum_default_mode = { 422 .clock = 167700, 423 .hdisplay = 1200, 424 .hsync_start = 1200 + 75, 425 .hsync_end = 1200 + 75 + 20, 426 .htotal = 1200 + 75 + 20 + 65, 427 .vdisplay = 1920, 428 .vsync_start = 1920 + 115, 429 .vsync_end = 1920 + 115 + 8, 430 .vtotal = 1920 + 115 + 8 + 12, 431 .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, 432 }; 433 434 static const struct hx83102_panel_desc boe_nv110wum_desc = { 435 .modes = &boe_tv110wum_default_mode, 436 .size = { 437 .width_mm = 147, 438 .height_mm = 235, 439 }, 440 .init = boe_nv110wum_init, 441 }; 442 443 static const struct drm_display_mode ivo_t109nw41_default_mode = { 444 .clock = 167700, 445 .hdisplay = 1200, 446 .hsync_start = 1200 + 75, 447 .hsync_end = 1200 + 75 + 20, 448 .htotal = 1200 + 75 + 20 + 65, 449 .vdisplay = 1920, 450 .vsync_start = 1920 + 115, 451 .vsync_end = 1920 + 115 + 8, 452 .vtotal = 1920 + 115 + 8 + 12, 453 .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, 454 }; 455 456 static const struct hx83102_panel_desc ivo_t109nw41_desc = { 457 .modes = &ivo_t109nw41_default_mode, 458 .size = { 459 .width_mm = 147, 460 .height_mm = 235, 461 }, 462 .init = ivo_t109nw41_init, 463 }; 464 465 static int hx83102_enable(struct drm_panel *panel) 466 { 467 msleep(130); 468 return 0; 469 } 470 471 static int hx83102_disable(struct drm_panel *panel) 472 { 473 struct hx83102 *ctx = panel_to_hx83102(panel); 474 struct mipi_dsi_device *dsi = ctx->dsi; 475 struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; 476 477 dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; 478 479 mipi_dsi_dcs_set_display_off_multi(&dsi_ctx); 480 mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx); 481 482 mipi_dsi_msleep(&dsi_ctx, 150); 483 484 return dsi_ctx.accum_err; 485 } 486 487 static int hx83102_unprepare(struct drm_panel *panel) 488 { 489 struct hx83102 *ctx = panel_to_hx83102(panel); 490 491 gpiod_set_value(ctx->enable_gpio, 0); 492 usleep_range(1000, 2000); 493 regulator_disable(ctx->avee); 494 regulator_disable(ctx->avdd); 495 usleep_range(5000, 7000); 496 regulator_disable(ctx->pp1800); 497 498 return 0; 499 } 500 501 static int hx83102_prepare(struct drm_panel *panel) 502 { 503 struct hx83102 *ctx = panel_to_hx83102(panel); 504 struct mipi_dsi_device *dsi = ctx->dsi; 505 struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; 506 507 gpiod_set_value(ctx->enable_gpio, 0); 508 usleep_range(1000, 1500); 509 510 dsi_ctx.accum_err = regulator_enable(ctx->pp1800); 511 if (dsi_ctx.accum_err) 512 return dsi_ctx.accum_err; 513 514 usleep_range(3000, 5000); 515 516 dsi_ctx.accum_err = regulator_enable(ctx->avdd); 517 if (dsi_ctx.accum_err) 518 goto poweroff1v8; 519 dsi_ctx.accum_err = regulator_enable(ctx->avee); 520 if (dsi_ctx.accum_err) 521 goto poweroffavdd; 522 523 usleep_range(10000, 11000); 524 525 mipi_dsi_dcs_nop_multi(&dsi_ctx); 526 if (dsi_ctx.accum_err) 527 goto poweroff; 528 529 usleep_range(1000, 2000); 530 531 gpiod_set_value(ctx->enable_gpio, 1); 532 usleep_range(1000, 2000); 533 gpiod_set_value(ctx->enable_gpio, 0); 534 usleep_range(1000, 2000); 535 gpiod_set_value(ctx->enable_gpio, 1); 536 usleep_range(6000, 10000); 537 538 dsi_ctx.accum_err = ctx->desc->init(ctx); 539 540 mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx); 541 mipi_dsi_msleep(&dsi_ctx, 120); 542 mipi_dsi_dcs_set_display_on_multi(&dsi_ctx); 543 if (dsi_ctx.accum_err) 544 goto poweroff; 545 546 return 0; 547 548 poweroff: 549 gpiod_set_value(ctx->enable_gpio, 0); 550 regulator_disable(ctx->avee); 551 poweroffavdd: 552 regulator_disable(ctx->avdd); 553 poweroff1v8: 554 usleep_range(5000, 7000); 555 regulator_disable(ctx->pp1800); 556 557 return dsi_ctx.accum_err; 558 } 559 560 static int hx83102_get_modes(struct drm_panel *panel, 561 struct drm_connector *connector) 562 { 563 struct hx83102 *ctx = panel_to_hx83102(panel); 564 const struct drm_display_mode *m = ctx->desc->modes; 565 struct drm_display_mode *mode; 566 567 mode = drm_mode_duplicate(connector->dev, m); 568 569 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; 570 drm_mode_set_name(mode); 571 drm_mode_probed_add(connector, mode); 572 573 connector->display_info.width_mm = ctx->desc->size.width_mm; 574 connector->display_info.height_mm = ctx->desc->size.height_mm; 575 connector->display_info.bpc = 8; 576 577 return 1; 578 } 579 580 static enum drm_panel_orientation hx83102_get_orientation(struct drm_panel *panel) 581 { 582 struct hx83102 *ctx = panel_to_hx83102(panel); 583 584 return ctx->orientation; 585 } 586 587 static const struct drm_panel_funcs hx83102_drm_funcs = { 588 .disable = hx83102_disable, 589 .unprepare = hx83102_unprepare, 590 .prepare = hx83102_prepare, 591 .enable = hx83102_enable, 592 .get_modes = hx83102_get_modes, 593 .get_orientation = hx83102_get_orientation, 594 }; 595 596 static int hx83102_panel_add(struct hx83102 *ctx) 597 { 598 struct device *dev = &ctx->dsi->dev; 599 int err; 600 601 ctx->avdd = devm_regulator_get(dev, "avdd"); 602 if (IS_ERR(ctx->avdd)) 603 return PTR_ERR(ctx->avdd); 604 605 ctx->avee = devm_regulator_get(dev, "avee"); 606 if (IS_ERR(ctx->avee)) 607 return PTR_ERR(ctx->avee); 608 609 ctx->pp1800 = devm_regulator_get(dev, "pp1800"); 610 if (IS_ERR(ctx->pp1800)) 611 return PTR_ERR(ctx->pp1800); 612 613 ctx->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW); 614 if (IS_ERR(ctx->enable_gpio)) 615 return dev_err_probe(dev, PTR_ERR(ctx->enable_gpio), "Cannot get enable GPIO\n"); 616 617 ctx->base.prepare_prev_first = true; 618 619 drm_panel_init(&ctx->base, dev, &hx83102_drm_funcs, 620 DRM_MODE_CONNECTOR_DSI); 621 err = of_drm_get_panel_orientation(dev->of_node, &ctx->orientation); 622 if (err < 0) 623 return dev_err_probe(dev, err, "failed to get orientation\n"); 624 625 err = drm_panel_of_backlight(&ctx->base); 626 if (err) 627 return err; 628 629 ctx->base.funcs = &hx83102_drm_funcs; 630 ctx->base.dev = &ctx->dsi->dev; 631 632 drm_panel_add(&ctx->base); 633 634 return 0; 635 } 636 637 static int hx83102_probe(struct mipi_dsi_device *dsi) 638 { 639 struct hx83102 *ctx; 640 int ret; 641 const struct hx83102_panel_desc *desc; 642 643 ctx = devm_kzalloc(&dsi->dev, sizeof(*ctx), GFP_KERNEL); 644 if (!ctx) 645 return -ENOMEM; 646 647 desc = of_device_get_match_data(&dsi->dev); 648 dsi->lanes = 4; 649 dsi->format = MIPI_DSI_FMT_RGB888; 650 dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | 651 MIPI_DSI_MODE_LPM; 652 ctx->desc = desc; 653 ctx->dsi = dsi; 654 ret = hx83102_panel_add(ctx); 655 if (ret < 0) 656 return ret; 657 658 mipi_dsi_set_drvdata(dsi, ctx); 659 660 ret = mipi_dsi_attach(dsi); 661 if (ret) 662 drm_panel_remove(&ctx->base); 663 664 return ret; 665 } 666 667 static void hx83102_remove(struct mipi_dsi_device *dsi) 668 { 669 struct hx83102 *ctx = mipi_dsi_get_drvdata(dsi); 670 int ret; 671 672 ret = mipi_dsi_detach(dsi); 673 if (ret < 0) 674 dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret); 675 676 if (ctx->base.dev) 677 drm_panel_remove(&ctx->base); 678 } 679 680 static const struct of_device_id hx83102_of_match[] = { 681 { .compatible = "boe,nv110wum-l60", 682 .data = &boe_nv110wum_desc 683 }, 684 { .compatible = "ivo,t109nw41", 685 .data = &ivo_t109nw41_desc 686 }, 687 { .compatible = "starry,himax83102-j02", 688 .data = &starry_desc 689 }, 690 { /* sentinel */ } 691 }; 692 MODULE_DEVICE_TABLE(of, hx83102_of_match); 693 694 static struct mipi_dsi_driver hx83102_driver = { 695 .probe = hx83102_probe, 696 .remove = hx83102_remove, 697 .driver = { 698 .name = "panel-himax-hx83102", 699 .of_match_table = hx83102_of_match, 700 }, 701 }; 702 module_mipi_dsi_driver(hx83102_driver); 703 704 MODULE_AUTHOR("Cong Yang <yangcong5@huaqin.corp-partner.google.com>"); 705 MODULE_DESCRIPTION("DRM driver for Himax HX83102 based MIPI DSI panels"); 706 MODULE_LICENSE("GPL"); 707