1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree. 4 * Copyright (c) 2025 Luca Weiss <luca@lucaweiss.eu> 5 */ 6 7 #include <linux/backlight.h> 8 #include <linux/delay.h> 9 #include <linux/gpio/consumer.h> 10 #include <linux/mod_devicetable.h> 11 #include <linux/module.h> 12 #include <linux/regulator/consumer.h> 13 14 #include <video/mipi_display.h> 15 16 #include <drm/drm_mipi_dsi.h> 17 #include <drm/drm_modes.h> 18 #include <drm/drm_panel.h> 19 #include <drm/drm_probe_helper.h> 20 21 /* Manufacturer specific DSI commands */ 22 #define HX83112B_SETPOWER1 0xb1 23 #define HX83112B_SETDISP 0xb2 24 #define HX83112B_SETDRV 0xb4 25 #define HX83112B_SETEXTC 0xb9 26 #define HX83112B_SETBANK 0xbd 27 #define HX83112B_SETDGCLUT 0xc1 28 #define HX83112B_SETDISMO 0xc2 29 #define HX83112B_UNKNOWN1 0xc6 30 #define HX83112B_SETPANEL 0xcc 31 #define HX83112B_UNKNOWN2 0xd1 32 #define HX83112B_SETPOWER2 0xd2 33 #define HX83112B_SETGIP0 0xd3 34 #define HX83112B_SETGIP1 0xd5 35 #define HX83112B_SETGIP2 0xd6 36 #define HX83112B_SETGIP3 0xd8 37 #define HX83112B_SETIDLE 0xdd 38 #define HX83112B_UNKNOWN3 0xe7 39 #define HX83112B_UNKNOWN4 0xe9 40 41 struct hx83112b_panel { 42 struct drm_panel panel; 43 struct mipi_dsi_device *dsi; 44 struct regulator_bulk_data *supplies; 45 struct gpio_desc *reset_gpio; 46 }; 47 48 static const struct regulator_bulk_data hx83112b_supplies[] = { 49 { .supply = "iovcc" }, 50 { .supply = "vsn" }, 51 { .supply = "vsp" }, 52 }; 53 54 static inline struct hx83112b_panel *to_hx83112b_panel(struct drm_panel *panel) 55 { 56 return container_of(panel, struct hx83112b_panel, panel); 57 } 58 59 static void hx83112b_reset(struct hx83112b_panel *ctx) 60 { 61 gpiod_set_value_cansleep(ctx->reset_gpio, 0); 62 usleep_range(10000, 11000); 63 gpiod_set_value_cansleep(ctx->reset_gpio, 1); 64 usleep_range(10000, 11000); 65 gpiod_set_value_cansleep(ctx->reset_gpio, 0); 66 usleep_range(10000, 11000); 67 } 68 69 static int hx83112b_on(struct hx83112b_panel *ctx) 70 { 71 struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi }; 72 73 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETEXTC, 0x83, 0x11, 0x2b); 74 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x01); 75 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDISMO, 0x08, 0x70); 76 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x03); 77 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDISP, 0x04, 0x38, 0x08, 0x70); 78 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x00); 79 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETPOWER1, 80 0xf8, 0x27, 0x27, 0x00, 0x00, 0x0b, 0x0e, 81 0x0b, 0x0e, 0x33); 82 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETPOWER2, 0x2d, 0x2d); 83 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDISP, 84 0x80, 0x02, 0x18, 0x80, 0x70, 0x00, 0x08, 85 0x1c, 0x08, 0x11, 0x05); 86 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0xd1); 87 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDISP, 0x00, 0x08); 88 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0x00); 89 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x02); 90 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDISP, 0xb5, 0x0a); 91 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x00); 92 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETIDLE, 93 0x00, 0x00, 0x08, 0x1c, 0x08, 0x34, 0x34, 94 0x88); 95 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDRV, 96 0x65, 0x6b, 0x00, 0x00, 0xd0, 0xd4, 0x36, 97 0xcf, 0x06, 0xce, 0x00, 0xce, 0x00, 0x00, 98 0x00, 0x07, 0x00, 0x2a, 0x07, 0x01, 0x07, 99 0x00, 0x00, 0x2a); 100 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x03); 101 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0xc3); 102 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDRV, 0x01, 0x67, 0x2a); 103 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0x00); 104 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x00); 105 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDGCLUT, 0x01); 106 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x01); 107 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDGCLUT, 108 0xff, 0xfb, 0xf9, 0xf6, 0xf4, 0xf1, 0xef, 109 0xea, 0xe7, 0xe5, 0xe2, 0xdf, 0xdd, 0xda, 110 0xd8, 0xd5, 0xd2, 0xcf, 0xcc, 0xc5, 0xbe, 111 0xb7, 0xb0, 0xa8, 0xa0, 0x98, 0x8e, 0x85, 112 0x7b, 0x72, 0x69, 0x5e, 0x53, 0x48, 0x3e, 113 0x35, 0x2b, 0x22, 0x17, 0x0d, 0x09, 0x07, 114 0x05, 0x01, 0x00, 0x26, 0xf0, 0x86, 0x25, 115 0x6e, 0xb6, 0xdd, 0xf3, 0xd8, 0xcc, 0x9b, 116 0x00); 117 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x02); 118 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDGCLUT, 119 0xff, 0xfb, 0xf9, 0xf6, 0xf4, 0xf1, 0xef, 120 0xea, 0xe7, 0xe5, 0xe2, 0xdf, 0xdd, 0xda, 121 0xd8, 0xd5, 0xd2, 0xcf, 0xcc, 0xc5, 0xbe, 122 0xb7, 0xb0, 0xa8, 0xa0, 0x98, 0x8e, 0x85, 123 0x7b, 0x72, 0x69, 0x5e, 0x53, 0x48, 0x3e, 124 0x35, 0x2b, 0x22, 0x17, 0x0d, 0x09, 0x07, 125 0x05, 0x01, 0x00, 0x26, 0xf0, 0x86, 0x25, 126 0x6e, 0xb6, 0xdd, 0xf3, 0xd8, 0xcc, 0x9b, 127 0x00); 128 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x03); 129 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDGCLUT, 130 0xff, 0xfb, 0xf9, 0xf6, 0xf4, 0xf1, 0xef, 131 0xea, 0xe7, 0xe5, 0xe2, 0xdf, 0xdd, 0xda, 132 0xd8, 0xd5, 0xd2, 0xcf, 0xcc, 0xc5, 0xbe, 133 0xb7, 0xb0, 0xa8, 0xa0, 0x98, 0x8e, 0x85, 134 0x7b, 0x72, 0x69, 0x5e, 0x53, 0x48, 0x3e, 135 0x35, 0x2b, 0x22, 0x17, 0x0d, 0x09, 0x07, 136 0x05, 0x01, 0x00, 0x26, 0xf0, 0x86, 0x25, 137 0x6e, 0xb6, 0xdd, 0xf3, 0xd8, 0xcc, 0x9b, 138 0x00); 139 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x00); 140 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETDISMO, 0xc8); 141 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETPANEL, 0x08); 142 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETGIP0, 143 0x81, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 144 0x04, 0x00, 0x01, 0x13, 0x40, 0x04, 0x09, 145 0x09, 0x0b, 0x0b, 0x32, 0x10, 0x08, 0x00, 146 0x08, 0x32, 0x10, 0x08, 0x00, 0x08, 0x32, 147 0x10, 0x08, 0x00, 0x08, 0x00, 0x00, 0x0a, 148 0x08, 0x7b); 149 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0xc5); 150 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN1, 0xf7); 151 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0x00); 152 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0xd4); 153 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN1, 0x6e); 154 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0x00); 155 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0xef); 156 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETGIP0, 0x0c); 157 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0x00); 158 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x01); 159 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0xc8); 160 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETGIP0, 0xa1); 161 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0x00); 162 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x00); 163 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETGIP1, 164 0x18, 0x18, 0x19, 0x18, 0x18, 0x20, 0x18, 165 0x18, 0x18, 0x10, 0x10, 0x18, 0x18, 0x00, 166 0x00, 0x18, 0x18, 0x01, 0x01, 0x18, 0x18, 167 0x28, 0x28, 0x18, 0x18, 0x18, 0x18, 0x18, 168 0x2f, 0x2f, 0x30, 0x30, 0x31, 0x31, 0x35, 169 0x35, 0x36, 0x36, 0x37, 0x37, 0x18, 0x18, 170 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xfc, 171 0xfc, 0x00, 0x00, 0xfc, 0xfc, 0x00, 0x00); 172 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETGIP2, 173 0x18, 0x18, 0x19, 0x18, 0x18, 0x20, 0x19, 174 0x18, 0x18, 0x10, 0x10, 0x18, 0x18, 0x00, 175 0x00, 0x18, 0x18, 0x01, 0x01, 0x18, 0x18, 176 0x28, 0x28, 0x18, 0x18, 0x18, 0x18, 0x18, 177 0x2f, 0x2f, 0x30, 0x30, 0x31, 0x31, 0x35, 178 0x35, 0x36, 0x36, 0x37, 0x37, 0x18, 0x18, 179 0x18, 0x18, 0x18, 0x18, 0x18, 0x18); 180 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETGIP3, 181 0xaa, 0xaa, 0xaa, 0xaf, 0xea, 0xaa, 0xaa, 182 0xaa, 0xaa, 0xaf, 0xea, 0xaa, 0xaa, 0xaa, 183 0xab, 0xaf, 0xef, 0xaa, 0xaa, 0xaa, 0xaa, 184 0xaf, 0xea, 0xaa); 185 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x01); 186 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETGIP3, 187 0xaa, 0xaa, 0xab, 0xaf, 0xea, 0xaa, 0xaa, 188 0xaa, 0xae, 0xaf, 0xea, 0xaa); 189 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x02); 190 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETGIP3, 191 0xaa, 0xaa, 0xaa, 0xaf, 0xea, 0xaa, 0xaa, 192 0xaa, 0xaa, 0xaf, 0xea, 0xaa); 193 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x03); 194 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETGIP3, 195 0xba, 0xaa, 0xaa, 0xaf, 0xea, 0xaa, 0xaa, 196 0xaa, 0xaa, 0xaf, 0xea, 0xaa, 0xba, 0xaa, 197 0xaa, 0xaf, 0xea, 0xaa, 0xaa, 0xaa, 0xaa, 198 0xaf, 0xea, 0xaa); 199 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x00); 200 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0xe4); 201 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN3, 0x17, 0x69); 202 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0x00); 203 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN3, 204 0x09, 0x09, 0x00, 0x07, 0xe8, 0x00, 0x26, 205 0x00, 0x07, 0x00, 0x00, 0xe8, 0x32, 0x00, 206 0xe9, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x01, 207 0x01, 0x00, 0x12, 0x04); 208 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x01); 209 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN3, 210 0x02, 0x00, 0x01, 0x20, 0x01, 0x18, 0x08, 211 0xa8, 0x09); 212 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x02); 213 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN3, 0x20, 0x20, 0x00); 214 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x03); 215 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN3, 216 0x00, 0xdc, 0x11, 0x70, 0x00, 0x20); 217 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0xc9); 218 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN3, 219 0x2a, 0xce, 0x02, 0x70, 0x01, 0x04); 220 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN4, 0x00); 221 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_SETBANK, 0x00); 222 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, HX83112B_UNKNOWN2, 0x27); 223 mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx); 224 mipi_dsi_msleep(&dsi_ctx, 120); 225 mipi_dsi_dcs_set_display_on_multi(&dsi_ctx); 226 mipi_dsi_msleep(&dsi_ctx, 20); 227 mipi_dsi_dcs_set_display_brightness_multi(&dsi_ctx, 0x0000); 228 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, 229 0x24); 230 mipi_dsi_dcs_set_tear_on_multi(&dsi_ctx, MIPI_DSI_DCS_TEAR_MODE_VBLANK); 231 232 return dsi_ctx.accum_err; 233 } 234 235 static int hx83112b_off(struct hx83112b_panel *ctx) 236 { 237 struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi }; 238 239 mipi_dsi_dcs_set_display_off_multi(&dsi_ctx); 240 mipi_dsi_msleep(&dsi_ctx, 20); 241 mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx); 242 mipi_dsi_msleep(&dsi_ctx, 120); 243 244 return dsi_ctx.accum_err; 245 } 246 247 static int hx83112b_prepare(struct drm_panel *panel) 248 { 249 struct hx83112b_panel *ctx = to_hx83112b_panel(panel); 250 struct device *dev = &ctx->dsi->dev; 251 int ret; 252 253 ret = regulator_bulk_enable(ARRAY_SIZE(hx83112b_supplies), ctx->supplies); 254 if (ret < 0) { 255 dev_err(dev, "Failed to enable regulators: %d\n", ret); 256 return ret; 257 } 258 259 hx83112b_reset(ctx); 260 261 ret = hx83112b_on(ctx); 262 if (ret < 0) { 263 dev_err(dev, "Failed to initialize panel: %d\n", ret); 264 gpiod_set_value_cansleep(ctx->reset_gpio, 1); 265 regulator_bulk_disable(ARRAY_SIZE(hx83112b_supplies), ctx->supplies); 266 return ret; 267 } 268 269 return 0; 270 } 271 272 static int hx83112b_unprepare(struct drm_panel *panel) 273 { 274 struct hx83112b_panel *ctx = to_hx83112b_panel(panel); 275 struct device *dev = &ctx->dsi->dev; 276 int ret; 277 278 ret = hx83112b_off(ctx); 279 if (ret < 0) 280 dev_err(dev, "Failed to un-initialize panel: %d\n", ret); 281 282 gpiod_set_value_cansleep(ctx->reset_gpio, 1); 283 regulator_bulk_disable(ARRAY_SIZE(hx83112b_supplies), ctx->supplies); 284 285 return 0; 286 } 287 288 static const struct drm_display_mode hx83112b_mode = { 289 .clock = (1080 + 40 + 4 + 12) * (2160 + 32 + 2 + 2) * 60 / 1000, 290 .hdisplay = 1080, 291 .hsync_start = 1080 + 40, 292 .hsync_end = 1080 + 40 + 4, 293 .htotal = 1080 + 40 + 4 + 12, 294 .vdisplay = 2160, 295 .vsync_start = 2160 + 32, 296 .vsync_end = 2160 + 32 + 2, 297 .vtotal = 2160 + 32 + 2 + 2, 298 .width_mm = 65, 299 .height_mm = 128, 300 .type = DRM_MODE_TYPE_DRIVER, 301 }; 302 303 static int hx83112b_get_modes(struct drm_panel *panel, 304 struct drm_connector *connector) 305 { 306 return drm_connector_helper_get_modes_fixed(connector, &hx83112b_mode); 307 } 308 309 static const struct drm_panel_funcs hx83112b_panel_funcs = { 310 .prepare = hx83112b_prepare, 311 .unprepare = hx83112b_unprepare, 312 .get_modes = hx83112b_get_modes, 313 }; 314 315 static int hx83112b_bl_update_status(struct backlight_device *bl) 316 { 317 struct mipi_dsi_device *dsi = bl_get_data(bl); 318 u16 brightness = backlight_get_brightness(bl); 319 int ret; 320 321 dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; 322 323 ret = mipi_dsi_dcs_set_display_brightness_large(dsi, brightness); 324 if (ret < 0) 325 return ret; 326 327 dsi->mode_flags |= MIPI_DSI_MODE_LPM; 328 329 return 0; 330 } 331 332 static const struct backlight_ops hx83112b_bl_ops = { 333 .update_status = hx83112b_bl_update_status, 334 }; 335 336 static struct backlight_device * 337 hx83112b_create_backlight(struct mipi_dsi_device *dsi) 338 { 339 struct device *dev = &dsi->dev; 340 const struct backlight_properties props = { 341 .type = BACKLIGHT_RAW, 342 .brightness = 4095, 343 .max_brightness = 4095, 344 }; 345 346 return devm_backlight_device_register(dev, dev_name(dev), dev, dsi, 347 &hx83112b_bl_ops, &props); 348 } 349 350 static int hx83112b_probe(struct mipi_dsi_device *dsi) 351 { 352 struct device *dev = &dsi->dev; 353 struct hx83112b_panel *ctx; 354 int ret; 355 356 ctx = devm_drm_panel_alloc(dev, struct hx83112b_panel, panel, 357 &hx83112b_panel_funcs, 358 DRM_MODE_CONNECTOR_DSI); 359 if (IS_ERR(ctx)) 360 return PTR_ERR(ctx); 361 362 ret = devm_regulator_bulk_get_const(dev, 363 ARRAY_SIZE(hx83112b_supplies), 364 hx83112b_supplies, 365 &ctx->supplies); 366 if (ret < 0) 367 return ret; 368 369 ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); 370 if (IS_ERR(ctx->reset_gpio)) 371 return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), 372 "Failed to get reset-gpios\n"); 373 374 ctx->dsi = dsi; 375 mipi_dsi_set_drvdata(dsi, ctx); 376 377 dsi->lanes = 4; 378 dsi->format = MIPI_DSI_FMT_RGB888; 379 dsi->mode_flags = MIPI_DSI_MODE_VIDEO_BURST | 380 MIPI_DSI_CLOCK_NON_CONTINUOUS | 381 MIPI_DSI_MODE_VIDEO_NO_HSA | MIPI_DSI_MODE_LPM; 382 383 ctx->panel.prepare_prev_first = true; 384 385 ctx->panel.backlight = hx83112b_create_backlight(dsi); 386 if (IS_ERR(ctx->panel.backlight)) 387 return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight), 388 "Failed to create backlight\n"); 389 390 drm_panel_add(&ctx->panel); 391 392 ret = mipi_dsi_attach(dsi); 393 if (ret < 0) { 394 drm_panel_remove(&ctx->panel); 395 return dev_err_probe(dev, ret, "Failed to attach to DSI host\n"); 396 } 397 398 return 0; 399 } 400 401 static void hx83112b_remove(struct mipi_dsi_device *dsi) 402 { 403 struct hx83112b_panel *ctx = mipi_dsi_get_drvdata(dsi); 404 int ret; 405 406 ret = mipi_dsi_detach(dsi); 407 if (ret < 0) 408 dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); 409 410 drm_panel_remove(&ctx->panel); 411 } 412 413 static const struct of_device_id hx83112b_of_match[] = { 414 { .compatible = "djn,98-03057-6598b-i" }, 415 { /* sentinel */ } 416 }; 417 MODULE_DEVICE_TABLE(of, hx83112b_of_match); 418 419 static struct mipi_dsi_driver hx83112b_driver = { 420 .probe = hx83112b_probe, 421 .remove = hx83112b_remove, 422 .driver = { 423 .name = "panel-himax-hx83112b", 424 .of_match_table = hx83112b_of_match, 425 }, 426 }; 427 module_mipi_dsi_driver(hx83112b_driver); 428 429 MODULE_DESCRIPTION("DRM driver for hx83112b-equipped DSI panels"); 430 MODULE_LICENSE("GPL"); 431