1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Driver for panels based on Himax HX8394 controller, such as: 4 * 5 * - HannStar HSD060BHW4 5.99" MIPI-DSI panel 6 * 7 * Copyright (C) 2021 Kamil Trzciński 8 * 9 * Based on drivers/gpu/drm/panel/panel-sitronix-st7703.c 10 * Copyright (C) Purism SPC 2019 11 */ 12 13 #include <linux/delay.h> 14 #include <linux/gpio/consumer.h> 15 #include <linux/media-bus-format.h> 16 #include <linux/mod_devicetable.h> 17 #include <linux/module.h> 18 #include <linux/of.h> 19 #include <linux/regulator/consumer.h> 20 21 #include <video/mipi_display.h> 22 23 #include <drm/drm_mipi_dsi.h> 24 #include <drm/drm_modes.h> 25 #include <drm/drm_panel.h> 26 27 #define DRV_NAME "panel-himax-hx8394" 28 29 /* Manufacturer specific commands sent via DSI, listed in HX8394-F datasheet */ 30 #define HX8394_CMD_SETSEQUENCE 0xb0 31 #define HX8394_CMD_SETPOWER 0xb1 32 #define HX8394_CMD_SETDISP 0xb2 33 #define HX8394_CMD_SETCYC 0xb4 34 #define HX8394_CMD_SETVCOM 0xb6 35 #define HX8394_CMD_SETTE 0xb7 36 #define HX8394_CMD_SETSENSOR 0xb8 37 #define HX8394_CMD_SETEXTC 0xb9 38 #define HX8394_CMD_SETMIPI 0xba 39 #define HX8394_CMD_SETOTP 0xbb 40 #define HX8394_CMD_SETREGBANK 0xbd 41 #define HX8394_CMD_UNKNOWN5 0xbf 42 #define HX8394_CMD_UNKNOWN1 0xc0 43 #define HX8394_CMD_SETDGCLUT 0xc1 44 #define HX8394_CMD_SETID 0xc3 45 #define HX8394_CMD_SETDDB 0xc4 46 #define HX8394_CMD_UNKNOWN2 0xc6 47 #define HX8394_CMD_SETCABC 0xc9 48 #define HX8394_CMD_SETCABCGAIN 0xca 49 #define HX8394_CMD_SETPANEL 0xcc 50 #define HX8394_CMD_SETOFFSET 0xd2 51 #define HX8394_CMD_SETGIP0 0xd3 52 #define HX8394_CMD_UNKNOWN3 0xd4 53 #define HX8394_CMD_SETGIP1 0xd5 54 #define HX8394_CMD_SETGIP2 0xd6 55 #define HX8394_CMD_SETGPO 0xd6 56 #define HX8394_CMD_UNKNOWN4 0xd8 57 #define HX8394_CMD_SETSCALING 0xdd 58 #define HX8394_CMD_SETIDLE 0xdf 59 #define HX8394_CMD_SETGAMMA 0xe0 60 #define HX8394_CMD_SETCHEMODE_DYN 0xe4 61 #define HX8394_CMD_SETCHE 0xe5 62 #define HX8394_CMD_SETCESEL 0xe6 63 #define HX8394_CMD_SET_SP_CMD 0xe9 64 #define HX8394_CMD_SETREADINDEX 0xfe 65 #define HX8394_CMD_GETSPIREAD 0xff 66 67 struct hx8394 { 68 struct device *dev; 69 struct drm_panel panel; 70 struct gpio_desc *reset_gpio; 71 struct regulator *vcc; 72 struct regulator *iovcc; 73 enum drm_panel_orientation orientation; 74 75 const struct hx8394_panel_desc *desc; 76 }; 77 78 struct hx8394_panel_desc { 79 const struct drm_display_mode *mode; 80 unsigned int lanes; 81 unsigned long mode_flags; 82 enum mipi_dsi_pixel_format format; 83 int (*init_sequence)(struct hx8394 *ctx); 84 }; 85 86 static inline struct hx8394 *panel_to_hx8394(struct drm_panel *panel) 87 { 88 return container_of(panel, struct hx8394, panel); 89 } 90 91 static int hsd060bhw4_init_sequence(struct hx8394 *ctx) 92 { 93 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); 94 95 /* 5.19.8 SETEXTC: Set extension command (B9h) */ 96 mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETEXTC, 97 0xff, 0x83, 0x94); 98 99 /* 5.19.2 SETPOWER: Set power (B1h) */ 100 mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETPOWER, 101 0x48, 0x11, 0x71, 0x09, 0x32, 0x24, 0x71, 0x31, 0x55, 0x30); 102 103 /* 5.19.9 SETMIPI: Set MIPI control (BAh) */ 104 mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETMIPI, 105 0x63, 0x03, 0x68, 0x6b, 0xb2, 0xc0); 106 107 /* 5.19.3 SETDISP: Set display related register (B2h) */ 108 mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETDISP, 109 0x00, 0x80, 0x78, 0x0c, 0x07); 110 111 /* 5.19.4 SETCYC: Set display waveform cycles (B4h) */ 112 mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETCYC, 113 0x12, 0x63, 0x12, 0x63, 0x12, 0x63, 0x01, 0x0c, 0x7c, 0x55, 114 0x00, 0x3f, 0x12, 0x6b, 0x12, 0x6b, 0x12, 0x6b, 0x01, 0x0c, 115 0x7c); 116 117 /* 5.19.19 SETGIP0: Set GIP Option0 (D3h) */ 118 mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETGIP0, 119 0x00, 0x00, 0x00, 0x00, 0x3c, 0x1c, 0x00, 0x00, 0x32, 0x10, 120 0x09, 0x00, 0x09, 0x32, 0x15, 0xad, 0x05, 0xad, 0x32, 0x00, 121 0x00, 0x00, 0x00, 0x37, 0x03, 0x0b, 0x0b, 0x37, 0x00, 0x00, 122 0x00, 0x0c, 0x40); 123 124 /* 5.19.20 Set GIP Option1 (D5h) */ 125 mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETGIP1, 126 0x19, 0x19, 0x18, 0x18, 0x1b, 0x1b, 0x1a, 0x1a, 0x00, 0x01, 127 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x20, 0x21, 0x18, 0x18, 128 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 129 0x24, 0x25, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 130 0x18, 0x18, 0x18, 0x18, 0x18, 0x18); 131 132 /* 5.19.21 Set GIP Option2 (D6h) */ 133 mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETGIP2, 134 0x18, 0x18, 0x19, 0x19, 0x1b, 0x1b, 0x1a, 0x1a, 0x07, 0x06, 135 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x25, 0x24, 0x18, 0x18, 136 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 137 0x21, 0x20, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 138 0x18, 0x18, 0x18, 0x18, 0x18, 0x18); 139 140 /* 5.19.25 SETGAMMA: Set gamma curve related setting (E0h) */ 141 mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETGAMMA, 142 0x00, 0x04, 0x0c, 0x12, 0x14, 0x18, 0x1a, 0x18, 0x31, 0x3f, 143 0x4d, 0x4c, 0x54, 0x65, 0x6b, 0x70, 0x7f, 0x82, 0x7e, 0x8a, 144 0x99, 0x4a, 0x48, 0x49, 0x4b, 0x4a, 0x4c, 0x4b, 0x7f, 0x00, 145 0x04, 0x0c, 0x11, 0x13, 0x17, 0x1a, 0x18, 0x31, 146 0x3f, 0x4d, 0x4c, 0x54, 0x65, 0x6b, 0x70, 0x7f, 147 0x82, 0x7e, 0x8a, 0x99, 0x4a, 0x48, 0x49, 0x4b, 148 0x4a, 0x4c, 0x4b, 0x7f); 149 150 /* 5.19.17 SETPANEL (CCh) */ 151 mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETPANEL, 152 0x0b); 153 154 /* Unknown command, not listed in the HX8394-F datasheet */ 155 mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_UNKNOWN1, 156 0x1f, 0x31); 157 158 /* 5.19.5 SETVCOM: Set VCOM voltage (B6h) */ 159 mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETVCOM, 160 0x7d, 0x7d); 161 162 /* Unknown command, not listed in the HX8394-F datasheet */ 163 mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_UNKNOWN3, 164 0x02); 165 166 /* 5.19.11 Set register bank (BDh) */ 167 mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETREGBANK, 168 0x01); 169 170 /* 5.19.2 SETPOWER: Set power (B1h) */ 171 mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETPOWER, 172 0x00); 173 174 /* 5.19.11 Set register bank (BDh) */ 175 mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETREGBANK, 176 0x00); 177 178 /* Unknown command, not listed in the HX8394-F datasheet */ 179 mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_UNKNOWN3, 180 0xed); 181 182 return 0; 183 } 184 185 static const struct drm_display_mode hsd060bhw4_mode = { 186 .hdisplay = 720, 187 .hsync_start = 720 + 40, 188 .hsync_end = 720 + 40 + 46, 189 .htotal = 720 + 40 + 46 + 40, 190 .vdisplay = 1440, 191 .vsync_start = 1440 + 9, 192 .vsync_end = 1440 + 9 + 7, 193 .vtotal = 1440 + 9 + 7 + 7, 194 .clock = 74250, 195 .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, 196 .width_mm = 68, 197 .height_mm = 136, 198 }; 199 200 static const struct hx8394_panel_desc hsd060bhw4_desc = { 201 .mode = &hsd060bhw4_mode, 202 .lanes = 4, 203 .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST, 204 .format = MIPI_DSI_FMT_RGB888, 205 .init_sequence = hsd060bhw4_init_sequence, 206 }; 207 208 static int powkiddy_x55_init_sequence(struct hx8394 *ctx) 209 { 210 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); 211 212 /* 5.19.8 SETEXTC: Set extension command (B9h) */ 213 mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETEXTC, 214 0xff, 0x83, 0x94); 215 216 /* 5.19.9 SETMIPI: Set MIPI control (BAh) */ 217 mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETMIPI, 218 0x63, 0x03, 0x68, 0x6b, 0xb2, 0xc0); 219 220 /* 5.19.2 SETPOWER: Set power (B1h) */ 221 mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETPOWER, 222 0x48, 0x12, 0x72, 0x09, 0x32, 0x54, 0x71, 0x71, 0x57, 0x47); 223 224 /* 5.19.3 SETDISP: Set display related register (B2h) */ 225 mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETDISP, 226 0x00, 0x80, 0x64, 0x2c, 0x16, 0x2f); 227 228 /* 5.19.4 SETCYC: Set display waveform cycles (B4h) */ 229 mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETCYC, 230 0x73, 0x74, 0x73, 0x74, 0x73, 0x74, 0x01, 0x0c, 0x86, 0x75, 231 0x00, 0x3f, 0x73, 0x74, 0x73, 0x74, 0x73, 0x74, 0x01, 0x0c, 232 0x86); 233 234 /* 5.19.5 SETVCOM: Set VCOM voltage (B6h) */ 235 mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETVCOM, 236 0x6e, 0x6e); 237 238 /* 5.19.19 SETGIP0: Set GIP Option0 (D3h) */ 239 mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETGIP0, 240 0x00, 0x00, 0x07, 0x07, 0x40, 0x07, 0x0c, 0x00, 0x08, 0x10, 241 0x08, 0x00, 0x08, 0x54, 0x15, 0x0a, 0x05, 0x0a, 0x02, 0x15, 242 0x06, 0x05, 0x06, 0x47, 0x44, 0x0a, 0x0a, 0x4b, 0x10, 0x07, 243 0x07, 0x0c, 0x40); 244 245 /* 5.19.20 Set GIP Option1 (D5h) */ 246 mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETGIP1, 247 0x1c, 0x1c, 0x1d, 0x1d, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 248 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x24, 0x25, 0x18, 0x18, 249 0x26, 0x27, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 250 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x20, 0x21, 251 0x18, 0x18, 0x18, 0x18); 252 253 /* 5.19.21 Set GIP Option2 (D6h) */ 254 mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETGIP2, 255 0x1c, 0x1c, 0x1d, 0x1d, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 256 0x01, 0x00, 0x0b, 0x0a, 0x09, 0x08, 0x21, 0x20, 0x18, 0x18, 257 0x27, 0x26, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 258 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x25, 0x24, 259 0x18, 0x18, 0x18, 0x18); 260 261 /* 5.19.25 SETGAMMA: Set gamma curve related setting (E0h) */ 262 mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETGAMMA, 263 0x00, 0x0a, 0x15, 0x1b, 0x1e, 0x21, 0x24, 0x22, 0x47, 0x56, 264 0x65, 0x66, 0x6e, 0x82, 0x88, 0x8b, 0x9a, 0x9d, 0x98, 0xa8, 265 0xb9, 0x5d, 0x5c, 0x61, 0x66, 0x6a, 0x6f, 0x7f, 0x7f, 0x00, 266 0x0a, 0x15, 0x1b, 0x1e, 0x21, 0x24, 0x22, 0x47, 0x56, 0x65, 267 0x65, 0x6e, 0x81, 0x87, 0x8b, 0x98, 0x9d, 0x99, 0xa8, 0xba, 268 0x5d, 0x5d, 0x62, 0x67, 0x6b, 0x72, 0x7f, 0x7f); 269 270 /* Unknown command, not listed in the HX8394-F datasheet */ 271 mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_UNKNOWN1, 272 0x1f, 0x31); 273 274 /* 5.19.17 SETPANEL (CCh) */ 275 mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETPANEL, 276 0x0b); 277 278 /* Unknown command, not listed in the HX8394-F datasheet */ 279 mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_UNKNOWN3, 280 0x02); 281 282 /* 5.19.11 Set register bank (BDh) */ 283 mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETREGBANK, 284 0x02); 285 286 /* Unknown command, not listed in the HX8394-F datasheet */ 287 mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_UNKNOWN4, 288 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 289 0xff, 0xff); 290 291 /* 5.19.11 Set register bank (BDh) */ 292 mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETREGBANK, 293 0x00); 294 295 /* 5.19.11 Set register bank (BDh) */ 296 mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETREGBANK, 297 0x01); 298 299 /* 5.19.2 SETPOWER: Set power (B1h) */ 300 mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETPOWER, 301 0x00); 302 303 /* 5.19.11 Set register bank (BDh) */ 304 mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETREGBANK, 305 0x00); 306 307 /* Unknown command, not listed in the HX8394-F datasheet */ 308 mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_UNKNOWN5, 309 0x40, 0x81, 0x50, 0x00, 0x1a, 0xfc, 0x01); 310 311 /* Unknown command, not listed in the HX8394-F datasheet */ 312 mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_UNKNOWN2, 313 0xed); 314 315 return 0; 316 } 317 318 static const struct drm_display_mode powkiddy_x55_mode = { 319 .hdisplay = 720, 320 .hsync_start = 720 + 44, 321 .hsync_end = 720 + 44 + 20, 322 .htotal = 720 + 44 + 20 + 20, 323 .vdisplay = 1280, 324 .vsync_start = 1280 + 12, 325 .vsync_end = 1280 + 12 + 10, 326 .vtotal = 1280 + 12 + 10 + 10, 327 .clock = 63290, 328 .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, 329 .width_mm = 67, 330 .height_mm = 121, 331 }; 332 333 static const struct hx8394_panel_desc powkiddy_x55_desc = { 334 .mode = &powkiddy_x55_mode, 335 .lanes = 4, 336 .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | 337 MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET, 338 .format = MIPI_DSI_FMT_RGB888, 339 .init_sequence = powkiddy_x55_init_sequence, 340 }; 341 342 static int hx8394_enable(struct drm_panel *panel) 343 { 344 struct hx8394 *ctx = panel_to_hx8394(panel); 345 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); 346 int ret; 347 348 ret = ctx->desc->init_sequence(ctx); 349 if (ret) { 350 dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret); 351 return ret; 352 } 353 354 ret = mipi_dsi_dcs_exit_sleep_mode(dsi); 355 if (ret) { 356 dev_err(ctx->dev, "Failed to exit sleep mode: %d\n", ret); 357 return ret; 358 } 359 360 /* Panel is operational 120 msec after reset */ 361 msleep(120); 362 363 ret = mipi_dsi_dcs_set_display_on(dsi); 364 if (ret) { 365 dev_err(ctx->dev, "Failed to turn on the display: %d\n", ret); 366 goto sleep_in; 367 } 368 369 return 0; 370 371 sleep_in: 372 /* This will probably fail, but let's try orderly power off anyway. */ 373 if (!mipi_dsi_dcs_enter_sleep_mode(dsi)) 374 msleep(50); 375 376 return ret; 377 } 378 379 static int hx8394_disable(struct drm_panel *panel) 380 { 381 struct hx8394 *ctx = panel_to_hx8394(panel); 382 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); 383 int ret; 384 385 ret = mipi_dsi_dcs_enter_sleep_mode(dsi); 386 if (ret) { 387 dev_err(ctx->dev, "Failed to enter sleep mode: %d\n", ret); 388 return ret; 389 } 390 391 msleep(50); /* about 3 frames */ 392 393 return 0; 394 } 395 396 static int hx8394_unprepare(struct drm_panel *panel) 397 { 398 struct hx8394 *ctx = panel_to_hx8394(panel); 399 400 gpiod_set_value_cansleep(ctx->reset_gpio, 1); 401 402 regulator_disable(ctx->iovcc); 403 regulator_disable(ctx->vcc); 404 405 return 0; 406 } 407 408 static int hx8394_prepare(struct drm_panel *panel) 409 { 410 struct hx8394 *ctx = panel_to_hx8394(panel); 411 int ret; 412 413 gpiod_set_value_cansleep(ctx->reset_gpio, 1); 414 415 ret = regulator_enable(ctx->vcc); 416 if (ret) { 417 dev_err(ctx->dev, "Failed to enable vcc supply: %d\n", ret); 418 return ret; 419 } 420 421 ret = regulator_enable(ctx->iovcc); 422 if (ret) { 423 dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret); 424 goto disable_vcc; 425 } 426 427 gpiod_set_value_cansleep(ctx->reset_gpio, 0); 428 429 msleep(180); 430 431 return 0; 432 433 disable_vcc: 434 gpiod_set_value_cansleep(ctx->reset_gpio, 1); 435 regulator_disable(ctx->vcc); 436 return ret; 437 } 438 439 static int hx8394_get_modes(struct drm_panel *panel, 440 struct drm_connector *connector) 441 { 442 struct hx8394 *ctx = panel_to_hx8394(panel); 443 struct drm_display_mode *mode; 444 445 mode = drm_mode_duplicate(connector->dev, ctx->desc->mode); 446 if (!mode) { 447 dev_err(ctx->dev, "Failed to add mode %ux%u@%u\n", 448 ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay, 449 drm_mode_vrefresh(ctx->desc->mode)); 450 return -ENOMEM; 451 } 452 453 drm_mode_set_name(mode); 454 455 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; 456 connector->display_info.width_mm = mode->width_mm; 457 connector->display_info.height_mm = mode->height_mm; 458 drm_mode_probed_add(connector, mode); 459 460 return 1; 461 } 462 463 static enum drm_panel_orientation hx8394_get_orientation(struct drm_panel *panel) 464 { 465 struct hx8394 *ctx = panel_to_hx8394(panel); 466 467 return ctx->orientation; 468 } 469 470 static const struct drm_panel_funcs hx8394_drm_funcs = { 471 .disable = hx8394_disable, 472 .unprepare = hx8394_unprepare, 473 .prepare = hx8394_prepare, 474 .enable = hx8394_enable, 475 .get_modes = hx8394_get_modes, 476 .get_orientation = hx8394_get_orientation, 477 }; 478 479 static int hx8394_probe(struct mipi_dsi_device *dsi) 480 { 481 struct device *dev = &dsi->dev; 482 struct hx8394 *ctx; 483 int ret; 484 485 ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); 486 if (!ctx) 487 return -ENOMEM; 488 489 ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); 490 if (IS_ERR(ctx->reset_gpio)) 491 return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), 492 "Failed to get reset gpio\n"); 493 494 ret = of_drm_get_panel_orientation(dev->of_node, &ctx->orientation); 495 if (ret < 0) { 496 dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, ret); 497 return ret; 498 } 499 500 mipi_dsi_set_drvdata(dsi, ctx); 501 502 ctx->dev = dev; 503 ctx->desc = of_device_get_match_data(dev); 504 505 dsi->mode_flags = ctx->desc->mode_flags; 506 dsi->format = ctx->desc->format; 507 dsi->lanes = ctx->desc->lanes; 508 509 ctx->vcc = devm_regulator_get(dev, "vcc"); 510 if (IS_ERR(ctx->vcc)) 511 return dev_err_probe(dev, PTR_ERR(ctx->vcc), 512 "Failed to request vcc regulator\n"); 513 514 ctx->iovcc = devm_regulator_get(dev, "iovcc"); 515 if (IS_ERR(ctx->iovcc)) 516 return dev_err_probe(dev, PTR_ERR(ctx->iovcc), 517 "Failed to request iovcc regulator\n"); 518 519 drm_panel_init(&ctx->panel, dev, &hx8394_drm_funcs, 520 DRM_MODE_CONNECTOR_DSI); 521 522 ret = drm_panel_of_backlight(&ctx->panel); 523 if (ret) 524 return ret; 525 526 drm_panel_add(&ctx->panel); 527 528 ret = mipi_dsi_attach(dsi); 529 if (ret < 0) { 530 dev_err_probe(dev, ret, "mipi_dsi_attach failed\n"); 531 drm_panel_remove(&ctx->panel); 532 return ret; 533 } 534 535 dev_dbg(dev, "%ux%u@%u %ubpp dsi %udl - ready\n", 536 ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay, 537 drm_mode_vrefresh(ctx->desc->mode), 538 mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes); 539 540 return 0; 541 } 542 543 static void hx8394_remove(struct mipi_dsi_device *dsi) 544 { 545 struct hx8394 *ctx = mipi_dsi_get_drvdata(dsi); 546 int ret; 547 548 ret = mipi_dsi_detach(dsi); 549 if (ret < 0) 550 dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); 551 552 drm_panel_remove(&ctx->panel); 553 } 554 555 static const struct of_device_id hx8394_of_match[] = { 556 { .compatible = "hannstar,hsd060bhw4", .data = &hsd060bhw4_desc }, 557 { .compatible = "powkiddy,x55-panel", .data = &powkiddy_x55_desc }, 558 { /* sentinel */ } 559 }; 560 MODULE_DEVICE_TABLE(of, hx8394_of_match); 561 562 static struct mipi_dsi_driver hx8394_driver = { 563 .probe = hx8394_probe, 564 .remove = hx8394_remove, 565 .driver = { 566 .name = DRV_NAME, 567 .of_match_table = hx8394_of_match, 568 }, 569 }; 570 module_mipi_dsi_driver(hx8394_driver); 571 572 MODULE_AUTHOR("Kamil Trzciński <ayufan@ayufan.eu>"); 573 MODULE_DESCRIPTION("DRM driver for Himax HX8394 based MIPI DSI panels"); 574 MODULE_LICENSE("GPL"); 575