xref: /linux/drivers/gpu/drm/panel/panel-boe-tv101wum-ll2.c (revision d53b8e36925256097a08d7cb749198d85cbf9b2b)
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