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) 2024 Luca Weiss <luca.weiss@fairphone.com> 5 */ 6 7 #include <linux/delay.h> 8 #include <linux/gpio/consumer.h> 9 #include <linux/module.h> 10 #include <linux/of.h> 11 #include <linux/regulator/consumer.h> 12 13 #include <drm/drm_mipi_dsi.h> 14 #include <drm/drm_modes.h> 15 #include <drm/drm_panel.h> 16 #include <drm/drm_probe_helper.h> 17 18 /* Manufacturer specific DSI commands */ 19 #define HX83112A_SETPOWER1 0xb1 20 #define HX83112A_SETDISP 0xb2 21 #define HX83112A_SETDRV 0xb4 22 #define HX83112A_SETEXTC 0xb9 23 #define HX83112A_SETBANK 0xbd 24 #define HX83112A_SETPTBA 0xbf 25 #define HX83112A_SETDGCLUT 0xc1 26 #define HX83112A_SETTCON 0xc7 27 #define HX83112A_SETCLOCK 0xcb 28 #define HX83112A_SETPANEL 0xcc 29 #define HX83112A_SETPOWER2 0xd2 30 #define HX83112A_SETGIP0 0xd3 31 #define HX83112A_SETGIP1 0xd5 32 #define HX83112A_SETGIP2 0xd6 33 #define HX83112A_SETGIP3 0xd8 34 #define HX83112A_SETTP1 0xe7 35 #define HX83112A_UNKNOWN1 0xe9 36 37 struct hx83112a_panel { 38 struct drm_panel panel; 39 struct mipi_dsi_device *dsi; 40 struct regulator_bulk_data supplies[3]; 41 struct gpio_desc *reset_gpio; 42 }; 43 44 static inline struct hx83112a_panel *to_hx83112a_panel(struct drm_panel *panel) 45 { 46 return container_of(panel, struct hx83112a_panel, panel); 47 } 48 49 static void hx83112a_reset(struct hx83112a_panel *ctx) 50 { 51 gpiod_set_value_cansleep(ctx->reset_gpio, 0); 52 msleep(20); 53 gpiod_set_value_cansleep(ctx->reset_gpio, 1); 54 msleep(20); 55 gpiod_set_value_cansleep(ctx->reset_gpio, 0); 56 msleep(50); 57 } 58 59 static int hx83112a_on(struct hx83112a_panel *ctx) 60 { 61 struct mipi_dsi_device *dsi = ctx->dsi; 62 struct device *dev = &dsi->dev; 63 int ret; 64 65 dsi->mode_flags |= MIPI_DSI_MODE_LPM; 66 67 mipi_dsi_dcs_write_seq(dsi, HX83112A_SETEXTC, 0x83, 0x11, 0x2a); 68 mipi_dsi_dcs_write_seq(dsi, HX83112A_SETPOWER1, 69 0x08, 0x28, 0x28, 0x83, 0x83, 0x4c, 0x4f, 0x33); 70 mipi_dsi_dcs_write_seq(dsi, HX83112A_SETDISP, 71 0x00, 0x02, 0x00, 0x90, 0x24, 0x00, 0x08, 0x19, 72 0xea, 0x11, 0x11, 0x00, 0x11, 0xa3); 73 mipi_dsi_dcs_write_seq(dsi, HX83112A_SETDRV, 74 0x58, 0x68, 0x58, 0x68, 0x0f, 0xef, 0x0b, 0xc0, 75 0x0b, 0xc0, 0x0b, 0xc0, 0x00, 0xff, 0x00, 0xff, 76 0x00, 0x00, 0x14, 0x15, 0x00, 0x29, 0x11, 0x07, 77 0x12, 0x00, 0x29); 78 mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x02); 79 mipi_dsi_dcs_write_seq(dsi, HX83112A_SETDRV, 80 0x00, 0x12, 0x12, 0x11, 0x88, 0x12, 0x12, 0x00, 81 0x53); 82 mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x00); 83 mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x03); 84 mipi_dsi_dcs_write_seq(dsi, HX83112A_SETDGCLUT, 85 0xff, 0xfe, 0xfb, 0xf8, 0xf4, 0xf1, 0xed, 0xe6, 86 0xe2, 0xde, 0xdb, 0xd6, 0xd3, 0xcf, 0xca, 0xc6, 87 0xc2, 0xbe, 0xb9, 0xb0, 0xa7, 0x9e, 0x96, 0x8d, 88 0x84, 0x7c, 0x74, 0x6b, 0x62, 0x5a, 0x51, 0x49, 89 0x41, 0x39, 0x31, 0x29, 0x21, 0x19, 0x12, 0x0a, 90 0x06, 0x05, 0x02, 0x01, 0x00, 0x00, 0xc9, 0xb3, 91 0x08, 0x0e, 0xf2, 0xe1, 0x59, 0xf4, 0x22, 0xad, 92 0x40); 93 mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x02); 94 mipi_dsi_dcs_write_seq(dsi, HX83112A_SETDGCLUT, 95 0xff, 0xfe, 0xfb, 0xf8, 0xf4, 0xf1, 0xed, 0xe6, 96 0xe2, 0xde, 0xdb, 0xd6, 0xd3, 0xcf, 0xca, 0xc6, 97 0xc2, 0xbe, 0xb9, 0xb0, 0xa7, 0x9e, 0x96, 0x8d, 98 0x84, 0x7c, 0x74, 0x6b, 0x62, 0x5a, 0x51, 0x49, 99 0x41, 0x39, 0x31, 0x29, 0x21, 0x19, 0x12, 0x0a, 100 0x06, 0x05, 0x02, 0x01, 0x00, 0x00, 0xc9, 0xb3, 101 0x08, 0x0e, 0xf2, 0xe1, 0x59, 0xf4, 0x22, 0xad, 102 0x40); 103 mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x01); 104 mipi_dsi_dcs_write_seq(dsi, HX83112A_SETDGCLUT, 105 0xff, 0xfe, 0xfb, 0xf8, 0xf4, 0xf1, 0xed, 0xe6, 106 0xe2, 0xde, 0xdb, 0xd6, 0xd3, 0xcf, 0xca, 0xc6, 107 0xc2, 0xbe, 0xb9, 0xb0, 0xa7, 0x9e, 0x96, 0x8d, 108 0x84, 0x7c, 0x74, 0x6b, 0x62, 0x5a, 0x51, 0x49, 109 0x41, 0x39, 0x31, 0x29, 0x21, 0x19, 0x12, 0x0a, 110 0x06, 0x05, 0x02, 0x01, 0x00, 0x00, 0xc9, 0xb3, 111 0x08, 0x0e, 0xf2, 0xe1, 0x59, 0xf4, 0x22, 0xad, 112 0x40); 113 mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x00); 114 mipi_dsi_dcs_write_seq(dsi, HX83112A_SETDGCLUT, 0x01); 115 mipi_dsi_dcs_write_seq(dsi, HX83112A_SETTCON, 116 0x70, 0x00, 0x04, 0xe0, 0x33, 0x00); 117 mipi_dsi_dcs_write_seq(dsi, HX83112A_SETPANEL, 0x08); 118 mipi_dsi_dcs_write_seq(dsi, HX83112A_SETPOWER2, 0x2b, 0x2b); 119 mipi_dsi_dcs_write_seq(dsi, HX83112A_SETGIP0, 120 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 121 0x08, 0x03, 0x03, 0x22, 0x18, 0x07, 0x07, 0x07, 122 0x07, 0x32, 0x10, 0x06, 0x00, 0x06, 0x32, 0x10, 123 0x07, 0x00, 0x07, 0x32, 0x19, 0x31, 0x09, 0x31, 124 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x08, 125 0x09, 0x30, 0x00, 0x00, 0x00, 0x06, 0x0d, 0x00, 126 0x0f); 127 mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x01); 128 mipi_dsi_dcs_write_seq(dsi, HX83112A_SETGIP0, 129 0x00, 0x00, 0x19, 0x10, 0x00, 0x0a, 0x00, 0x81); 130 mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x00); 131 mipi_dsi_dcs_write_seq(dsi, HX83112A_SETGIP1, 132 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 133 0xc0, 0xc0, 0x18, 0x18, 0x19, 0x19, 0x18, 0x18, 134 0x40, 0x40, 0x18, 0x18, 0x18, 0x18, 0x3f, 0x3f, 135 0x28, 0x28, 0x24, 0x24, 0x02, 0x03, 0x02, 0x03, 136 0x00, 0x01, 0x00, 0x01, 0x31, 0x31, 0x31, 0x31, 137 0x30, 0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f); 138 mipi_dsi_dcs_write_seq(dsi, HX83112A_SETGIP2, 139 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 140 0x40, 0x40, 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 141 0x40, 0x40, 0x18, 0x18, 0x18, 0x18, 0x3f, 0x3f, 142 0x24, 0x24, 0x28, 0x28, 0x01, 0x00, 0x01, 0x00, 143 0x03, 0x02, 0x03, 0x02, 0x31, 0x31, 0x31, 0x31, 144 0x30, 0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f); 145 mipi_dsi_dcs_write_seq(dsi, HX83112A_SETGIP3, 146 0xaa, 0xea, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea, 147 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xea, 0xab, 0xaa, 148 0xaa, 0xaa, 0xaa, 0xea, 0xab, 0xaa, 0xaa, 0xaa); 149 mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x01); 150 mipi_dsi_dcs_write_seq(dsi, HX83112A_SETGIP3, 151 0xaa, 0x2e, 0x28, 0x00, 0x00, 0x00, 0xaa, 0x2e, 152 0x28, 0x00, 0x00, 0x00, 0xaa, 0xee, 0xaa, 0xaa, 153 0xaa, 0xaa, 0xaa, 0xee, 0xaa, 0xaa, 0xaa, 0xaa); 154 mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x02); 155 mipi_dsi_dcs_write_seq(dsi, HX83112A_SETGIP3, 156 0xaa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xaa, 0xff, 157 0xff, 0xff, 0xff, 0xff); 158 mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x03); 159 mipi_dsi_dcs_write_seq(dsi, HX83112A_SETGIP3, 160 0xaa, 0xaa, 0xea, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 161 0xea, 0xaa, 0xaa, 0xaa, 0xaa, 0xff, 0xff, 0xff, 162 0xff, 0xff, 0xaa, 0xff, 0xff, 0xff, 0xff, 0xff); 163 mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x00); 164 mipi_dsi_dcs_write_seq(dsi, HX83112A_SETTP1, 165 0x0e, 0x0e, 0x1e, 0x65, 0x1c, 0x65, 0x00, 0x50, 166 0x20, 0x20, 0x00, 0x00, 0x02, 0x02, 0x02, 0x05, 167 0x14, 0x14, 0x32, 0xb9, 0x23, 0xb9, 0x08); 168 mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x01); 169 mipi_dsi_dcs_write_seq(dsi, HX83112A_SETTP1, 170 0x02, 0x00, 0xa8, 0x01, 0xa8, 0x0d, 0xa4, 0x0e); 171 mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x02); 172 mipi_dsi_dcs_write_seq(dsi, HX83112A_SETTP1, 173 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 174 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 175 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 176 0x00, 0x00, 0x00, 0x02, 0x00); 177 mipi_dsi_dcs_write_seq(dsi, HX83112A_SETBANK, 0x00); 178 mipi_dsi_dcs_write_seq(dsi, HX83112A_UNKNOWN1, 0xc3); 179 mipi_dsi_dcs_write_seq(dsi, HX83112A_SETCLOCK, 0xd1, 0xd6); 180 mipi_dsi_dcs_write_seq(dsi, HX83112A_UNKNOWN1, 0x3f); 181 mipi_dsi_dcs_write_seq(dsi, HX83112A_UNKNOWN1, 0xc6); 182 mipi_dsi_dcs_write_seq(dsi, HX83112A_SETPTBA, 0x37); 183 mipi_dsi_dcs_write_seq(dsi, HX83112A_UNKNOWN1, 0x3f); 184 185 ret = mipi_dsi_dcs_exit_sleep_mode(dsi); 186 if (ret < 0) { 187 dev_err(dev, "Failed to exit sleep mode: %d\n", ret); 188 return ret; 189 } 190 msleep(150); 191 192 ret = mipi_dsi_dcs_set_display_on(dsi); 193 if (ret < 0) { 194 dev_err(dev, "Failed to set display on: %d\n", ret); 195 return ret; 196 } 197 msleep(50); 198 199 return 0; 200 } 201 202 static int hx83112a_disable(struct drm_panel *panel) 203 { 204 struct hx83112a_panel *ctx = to_hx83112a_panel(panel); 205 struct mipi_dsi_device *dsi = ctx->dsi; 206 struct device *dev = &dsi->dev; 207 int ret; 208 209 dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; 210 211 ret = mipi_dsi_dcs_set_display_off(dsi); 212 if (ret < 0) { 213 dev_err(dev, "Failed to set display off: %d\n", ret); 214 return ret; 215 } 216 msleep(20); 217 218 ret = mipi_dsi_dcs_enter_sleep_mode(dsi); 219 if (ret < 0) { 220 dev_err(dev, "Failed to enter sleep mode: %d\n", ret); 221 return ret; 222 } 223 msleep(120); 224 225 return 0; 226 } 227 228 static int hx83112a_prepare(struct drm_panel *panel) 229 { 230 struct hx83112a_panel *ctx = to_hx83112a_panel(panel); 231 struct device *dev = &ctx->dsi->dev; 232 int ret; 233 234 ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies); 235 if (ret < 0) { 236 dev_err(dev, "Failed to enable regulators: %d\n", ret); 237 return ret; 238 } 239 240 hx83112a_reset(ctx); 241 242 ret = hx83112a_on(ctx); 243 if (ret < 0) { 244 dev_err(dev, "Failed to initialize panel: %d\n", ret); 245 gpiod_set_value_cansleep(ctx->reset_gpio, 1); 246 regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); 247 return ret; 248 } 249 250 return 0; 251 } 252 253 static int hx83112a_unprepare(struct drm_panel *panel) 254 { 255 struct hx83112a_panel *ctx = to_hx83112a_panel(panel); 256 257 gpiod_set_value_cansleep(ctx->reset_gpio, 1); 258 regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); 259 260 return 0; 261 } 262 263 static const struct drm_display_mode hx83112a_mode = { 264 .clock = (1080 + 28 + 8 + 8) * (2340 + 27 + 5 + 5) * 60 / 1000, 265 .hdisplay = 1080, 266 .hsync_start = 1080 + 28, 267 .hsync_end = 1080 + 28 + 8, 268 .htotal = 1080 + 28 + 8 + 8, 269 .vdisplay = 2340, 270 .vsync_start = 2340 + 27, 271 .vsync_end = 2340 + 27 + 5, 272 .vtotal = 2340 + 27 + 5 + 5, 273 .width_mm = 67, 274 .height_mm = 145, 275 .type = DRM_MODE_TYPE_DRIVER, 276 }; 277 278 static int hx83112a_get_modes(struct drm_panel *panel, 279 struct drm_connector *connector) 280 { 281 return drm_connector_helper_get_modes_fixed(connector, &hx83112a_mode); 282 } 283 284 static const struct drm_panel_funcs hx83112a_panel_funcs = { 285 .prepare = hx83112a_prepare, 286 .unprepare = hx83112a_unprepare, 287 .disable = hx83112a_disable, 288 .get_modes = hx83112a_get_modes, 289 }; 290 291 static int hx83112a_probe(struct mipi_dsi_device *dsi) 292 { 293 struct device *dev = &dsi->dev; 294 struct hx83112a_panel *ctx; 295 int ret; 296 297 ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); 298 if (!ctx) 299 return -ENOMEM; 300 301 ctx->supplies[0].supply = "vdd1"; 302 ctx->supplies[1].supply = "vsn"; 303 ctx->supplies[2].supply = "vsp"; 304 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies), 305 ctx->supplies); 306 if (ret < 0) 307 return dev_err_probe(dev, ret, "Failed to get regulators\n"); 308 309 ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); 310 if (IS_ERR(ctx->reset_gpio)) 311 return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), 312 "Failed to get reset-gpios\n"); 313 314 ctx->dsi = dsi; 315 mipi_dsi_set_drvdata(dsi, ctx); 316 317 dsi->lanes = 4; 318 dsi->format = MIPI_DSI_FMT_RGB888; 319 dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | 320 MIPI_DSI_MODE_VIDEO_HSE | 321 MIPI_DSI_CLOCK_NON_CONTINUOUS; 322 323 drm_panel_init(&ctx->panel, dev, &hx83112a_panel_funcs, 324 DRM_MODE_CONNECTOR_DSI); 325 ctx->panel.prepare_prev_first = true; 326 327 ret = drm_panel_of_backlight(&ctx->panel); 328 if (ret) 329 return dev_err_probe(dev, ret, "Failed to get backlight\n"); 330 331 drm_panel_add(&ctx->panel); 332 333 ret = mipi_dsi_attach(dsi); 334 if (ret < 0) { 335 dev_err_probe(dev, ret, "Failed to attach to DSI host\n"); 336 drm_panel_remove(&ctx->panel); 337 return ret; 338 } 339 340 return 0; 341 } 342 343 static void hx83112a_remove(struct mipi_dsi_device *dsi) 344 { 345 struct hx83112a_panel *ctx = mipi_dsi_get_drvdata(dsi); 346 int ret; 347 348 ret = mipi_dsi_detach(dsi); 349 if (ret < 0) 350 dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); 351 352 drm_panel_remove(&ctx->panel); 353 } 354 355 static const struct of_device_id hx83112a_of_match[] = { 356 { .compatible = "djn,9a-3r063-1102b" }, 357 { /* sentinel */ } 358 }; 359 MODULE_DEVICE_TABLE(of, hx83112a_of_match); 360 361 static struct mipi_dsi_driver hx83112a_driver = { 362 .probe = hx83112a_probe, 363 .remove = hx83112a_remove, 364 .driver = { 365 .name = "panel-himax-hx83112a", 366 .of_match_table = hx83112a_of_match, 367 }, 368 }; 369 module_mipi_dsi_driver(hx83112a_driver); 370 371 MODULE_DESCRIPTION("DRM driver for hx83112a-equipped DSI panels"); 372 MODULE_LICENSE("GPL"); 373