1 // SPDX-License-Identifier: GPL-2.0-only 2 // Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree: 3 // Copyright (c) 2013, The Linux Foundation. All rights reserved. 4 // Copyright (c) 2024, Neil Armstrong <neil.armstrong@linaro.org> 5 6 #include <linux/delay.h> 7 #include <linux/gpio/consumer.h> 8 #include <linux/module.h> 9 #include <linux/of.h> 10 #include <linux/regulator/consumer.h> 11 12 #include <drm/drm_mipi_dsi.h> 13 #include <drm/drm_modes.h> 14 #include <drm/drm_panel.h> 15 #include <drm/drm_probe_helper.h> 16 17 struct boe_tv101wum_ll2 { 18 struct drm_panel panel; 19 struct mipi_dsi_device *dsi; 20 struct gpio_desc *reset_gpio; 21 struct regulator_bulk_data *supplies; 22 }; 23 24 static const struct regulator_bulk_data boe_tv101wum_ll2_supplies[] = { 25 { .supply = "vsp" }, 26 { .supply = "vsn" }, 27 }; 28 29 static inline struct boe_tv101wum_ll2 *to_boe_tv101wum_ll2(struct drm_panel *panel) 30 { 31 return container_of(panel, struct boe_tv101wum_ll2, panel); 32 } 33 34 static void boe_tv101wum_ll2_reset(struct boe_tv101wum_ll2 *ctx) 35 { 36 gpiod_set_value_cansleep(ctx->reset_gpio, 0); 37 usleep_range(5000, 6000); 38 gpiod_set_value_cansleep(ctx->reset_gpio, 1); 39 usleep_range(5000, 6000); 40 gpiod_set_value_cansleep(ctx->reset_gpio, 0); 41 42 msleep(120); 43 } 44 45 static int boe_tv101wum_ll2_on(struct boe_tv101wum_ll2 *ctx) 46 { 47 struct mipi_dsi_device *dsi = ctx->dsi; 48 struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; 49 50 dsi->mode_flags |= MIPI_DSI_MODE_LPM; 51 52 mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx); 53 54 mipi_dsi_msleep(&dsi_ctx, 120); 55 56 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x50, 0x5a, 0x0e); 57 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x80, 0xff, 0x81, 0x68, 0x6c, 0x22, 58 0x6d, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00); 59 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x50, 0x5a, 0x23); 60 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x90, 0x00, 0x00); 61 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x94, 0x2c, 0x00); 62 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x50, 0x5a, 0x19); 63 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xa2, 0x38); 64 65 mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x50, 0x5a, 0x0c); 66 mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x80, 0xfd); 67 mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x50, 0x00); 68 69 mipi_dsi_dcs_set_display_on_multi(&dsi_ctx); 70 71 mipi_dsi_msleep(&dsi_ctx, 20); 72 73 return dsi_ctx.accum_err; 74 } 75 76 static void boe_tv101wum_ll2_off(struct boe_tv101wum_ll2 *ctx) 77 { 78 struct mipi_dsi_device *dsi = ctx->dsi; 79 struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; 80 81 dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; 82 83 mipi_dsi_dcs_set_display_off_multi(&dsi_ctx); 84 85 mipi_dsi_msleep(&dsi_ctx, 70); 86 87 mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx); 88 89 mipi_dsi_msleep(&dsi_ctx, 20); 90 91 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x04, 0x5a); 92 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x05, 0x5a); 93 94 mipi_dsi_msleep(&dsi_ctx, 150); 95 } 96 97 static int boe_tv101wum_ll2_prepare(struct drm_panel *panel) 98 { 99 struct boe_tv101wum_ll2 *ctx = to_boe_tv101wum_ll2(panel); 100 int ret; 101 102 ret = regulator_bulk_enable(ARRAY_SIZE(boe_tv101wum_ll2_supplies), 103 ctx->supplies); 104 if (ret < 0) 105 return ret; 106 107 boe_tv101wum_ll2_reset(ctx); 108 109 ret = boe_tv101wum_ll2_on(ctx); 110 if (ret < 0) { 111 gpiod_set_value_cansleep(ctx->reset_gpio, 1); 112 regulator_bulk_disable(ARRAY_SIZE(boe_tv101wum_ll2_supplies), 113 ctx->supplies); 114 return ret; 115 } 116 117 return 0; 118 } 119 120 static int boe_tv101wum_ll2_unprepare(struct drm_panel *panel) 121 { 122 struct boe_tv101wum_ll2 *ctx = to_boe_tv101wum_ll2(panel); 123 124 /* Ignore errors on failure, in any case set gpio and disable regulators */ 125 boe_tv101wum_ll2_off(ctx); 126 127 gpiod_set_value_cansleep(ctx->reset_gpio, 1); 128 129 regulator_bulk_disable(ARRAY_SIZE(boe_tv101wum_ll2_supplies), 130 ctx->supplies); 131 132 return 0; 133 } 134 135 static const struct drm_display_mode boe_tv101wum_ll2_mode = { 136 .clock = (1200 + 27 + 8 + 12) * (1920 + 155 + 8 + 32) * 60 / 1000, 137 .hdisplay = 1200, 138 .hsync_start = 1200 + 27, 139 .hsync_end = 1200 + 27 + 8, 140 .htotal = 1200 + 27 + 8 + 12, 141 .vdisplay = 1920, 142 .vsync_start = 1920 + 155, 143 .vsync_end = 1920 + 155 + 8, 144 .vtotal = 1920 + 155 + 8 + 32, 145 .width_mm = 136, 146 .height_mm = 217, 147 .type = DRM_MODE_TYPE_DRIVER, 148 }; 149 150 static int boe_tv101wum_ll2_get_modes(struct drm_panel *panel, 151 struct drm_connector *connector) 152 { 153 /* We do not set display_info.bpc since unset value is bpc=8 by default */ 154 return drm_connector_helper_get_modes_fixed(connector, &boe_tv101wum_ll2_mode); 155 } 156 157 static const struct drm_panel_funcs boe_tv101wum_ll2_panel_funcs = { 158 .prepare = boe_tv101wum_ll2_prepare, 159 .unprepare = boe_tv101wum_ll2_unprepare, 160 .get_modes = boe_tv101wum_ll2_get_modes, 161 }; 162 163 static int boe_tv101wum_ll2_probe(struct mipi_dsi_device *dsi) 164 { 165 struct device *dev = &dsi->dev; 166 struct boe_tv101wum_ll2 *ctx; 167 int ret; 168 169 ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); 170 if (!ctx) 171 return -ENOMEM; 172 173 ret = devm_regulator_bulk_get_const(&dsi->dev, 174 ARRAY_SIZE(boe_tv101wum_ll2_supplies), 175 boe_tv101wum_ll2_supplies, 176 &ctx->supplies); 177 if (ret < 0) 178 return ret; 179 180 ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); 181 if (IS_ERR(ctx->reset_gpio)) 182 return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), 183 "Failed to get reset-gpios\n"); 184 185 ctx->dsi = dsi; 186 mipi_dsi_set_drvdata(dsi, ctx); 187 188 dsi->lanes = 4; 189 dsi->format = MIPI_DSI_FMT_RGB888; 190 dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | 191 MIPI_DSI_MODE_VIDEO_HSE; 192 193 drm_panel_init(&ctx->panel, dev, &boe_tv101wum_ll2_panel_funcs, 194 DRM_MODE_CONNECTOR_DSI); 195 ctx->panel.prepare_prev_first = true; 196 197 ret = drm_panel_of_backlight(&ctx->panel); 198 if (ret) 199 return dev_err_probe(dev, ret, "Failed to get backlight\n"); 200 201 drm_panel_add(&ctx->panel); 202 203 ret = mipi_dsi_attach(dsi); 204 if (ret < 0) { 205 drm_panel_remove(&ctx->panel); 206 return dev_err_probe(dev, ret, "Failed to attach to DSI host\n"); 207 } 208 209 return 0; 210 } 211 212 static void boe_tv101wum_ll2_remove(struct mipi_dsi_device *dsi) 213 { 214 struct boe_tv101wum_ll2 *ctx = mipi_dsi_get_drvdata(dsi); 215 int ret; 216 217 ret = mipi_dsi_detach(dsi); 218 if (ret < 0) 219 dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); 220 221 drm_panel_remove(&ctx->panel); 222 } 223 224 static const struct of_device_id boe_tv101wum_ll2_of_match[] = { 225 { .compatible = "boe,tv101wum-ll2" }, 226 { /* sentinel */ } 227 }; 228 MODULE_DEVICE_TABLE(of, boe_tv101wum_ll2_of_match); 229 230 static struct mipi_dsi_driver boe_tv101wum_ll2_driver = { 231 .probe = boe_tv101wum_ll2_probe, 232 .remove = boe_tv101wum_ll2_remove, 233 .driver = { 234 .name = "panel-boe-tv101wum_ll2", 235 .of_match_table = boe_tv101wum_ll2_of_match, 236 }, 237 }; 238 module_mipi_dsi_driver(boe_tv101wum_ll2_driver); 239 240 MODULE_DESCRIPTION("DRM driver for BOE TV101WUM-LL2 Panel"); 241 MODULE_LICENSE("GPL"); 242