1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2019, The Linux Foundation. All rights reserved.
4  */
5 
6 #include <linux/delay.h>
7 #include <linux/module.h>
8 #include <linux/of_device.h>
9 #include <linux/gpio/consumer.h>
10 #include <linux/regulator/consumer.h>
11 
12 #include <video/mipi_display.h>
13 
14 #include <drm/drm_mipi_dsi.h>
15 #include <drm/drm_modes.h>
16 #include <drm/drm_panel.h>
17 #include <drm/drm_print.h>
18 
19 struct visionox_rm69299 {
20 	struct drm_panel panel;
21 	struct regulator_bulk_data supplies[2];
22 	struct gpio_desc *reset_gpio;
23 	struct mipi_dsi_device *dsi;
24 	bool prepared;
25 	bool enabled;
26 };
27 
28 static inline struct visionox_rm69299 *panel_to_ctx(struct drm_panel *panel)
29 {
30 	return container_of(panel, struct visionox_rm69299, panel);
31 }
32 
33 static int visionox_rm69299_power_on(struct visionox_rm69299 *ctx)
34 {
35 	int ret;
36 
37 	ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
38 	if (ret < 0)
39 		return ret;
40 
41 	/*
42 	 * Reset sequence of visionox panel requires the panel to be
43 	 * out of reset for 10ms, followed by being held in reset
44 	 * for 10ms and then out again
45 	 */
46 	gpiod_set_value(ctx->reset_gpio, 1);
47 	usleep_range(10000, 20000);
48 	gpiod_set_value(ctx->reset_gpio, 0);
49 	usleep_range(10000, 20000);
50 	gpiod_set_value(ctx->reset_gpio, 1);
51 	usleep_range(10000, 20000);
52 
53 	return 0;
54 }
55 
56 static int visionox_rm69299_power_off(struct visionox_rm69299 *ctx)
57 {
58 	gpiod_set_value(ctx->reset_gpio, 0);
59 
60 	return regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
61 }
62 
63 static int visionox_rm69299_unprepare(struct drm_panel *panel)
64 {
65 	struct visionox_rm69299 *ctx = panel_to_ctx(panel);
66 	int ret;
67 
68 	ctx->dsi->mode_flags = 0;
69 
70 	ret = mipi_dsi_dcs_write(ctx->dsi, MIPI_DCS_SET_DISPLAY_OFF, NULL, 0);
71 	if (ret < 0)
72 		DRM_DEV_ERROR(ctx->panel.dev,
73 			      "set_display_off cmd failed ret = %d\n", ret);
74 
75 	/* 120ms delay required here as per DCS spec */
76 	msleep(120);
77 
78 	ret = mipi_dsi_dcs_write(ctx->dsi, MIPI_DCS_ENTER_SLEEP_MODE, NULL, 0);
79 	if (ret < 0) {
80 		DRM_DEV_ERROR(ctx->panel.dev,
81 			      "enter_sleep cmd failed ret = %d\n", ret);
82 	}
83 
84 	ret = visionox_rm69299_power_off(ctx);
85 
86 	ctx->prepared = false;
87 	return ret;
88 }
89 
90 static int visionox_rm69299_prepare(struct drm_panel *panel)
91 {
92 	struct visionox_rm69299 *ctx = panel_to_ctx(panel);
93 	int ret;
94 
95 	if (ctx->prepared)
96 		return 0;
97 
98 	ret = visionox_rm69299_power_on(ctx);
99 	if (ret < 0)
100 		return ret;
101 
102 	ctx->dsi->mode_flags |= MIPI_DSI_MODE_LPM;
103 
104 	ret = mipi_dsi_dcs_write_buffer(ctx->dsi, (u8[]) { 0xfe, 0x00 }, 2);
105 	if (ret < 0) {
106 		DRM_DEV_ERROR(ctx->panel.dev,
107 			      "cmd set tx 0 failed, ret = %d\n", ret);
108 		goto power_off;
109 	}
110 
111 	ret = mipi_dsi_dcs_write_buffer(ctx->dsi, (u8[]) { 0xc2, 0x08 }, 2);
112 	if (ret < 0) {
113 		DRM_DEV_ERROR(ctx->panel.dev,
114 			      "cmd set tx 1 failed, ret = %d\n", ret);
115 		goto power_off;
116 	}
117 
118 	ret = mipi_dsi_dcs_write_buffer(ctx->dsi, (u8[]) { 0x35, 0x00 }, 2);
119 	if (ret < 0) {
120 		DRM_DEV_ERROR(ctx->panel.dev,
121 			      "cmd set tx 2 failed, ret = %d\n", ret);
122 		goto power_off;
123 	}
124 
125 	ret = mipi_dsi_dcs_write_buffer(ctx->dsi, (u8[]) { 0x51, 0xff }, 2);
126 	if (ret < 0) {
127 		DRM_DEV_ERROR(ctx->panel.dev,
128 			      "cmd set tx 3 failed, ret = %d\n", ret);
129 		goto power_off;
130 	}
131 
132 	ret = mipi_dsi_dcs_write(ctx->dsi, MIPI_DCS_EXIT_SLEEP_MODE, NULL, 0);
133 	if (ret < 0) {
134 		DRM_DEV_ERROR(ctx->panel.dev,
135 			      "exit_sleep_mode cmd failed ret = %d\n", ret);
136 		goto power_off;
137 	}
138 
139 	/* Per DSI spec wait 120ms after sending exit sleep DCS command */
140 	msleep(120);
141 
142 	ret = mipi_dsi_dcs_write(ctx->dsi, MIPI_DCS_SET_DISPLAY_ON, NULL, 0);
143 	if (ret < 0) {
144 		DRM_DEV_ERROR(ctx->panel.dev,
145 			      "set_display_on cmd failed ret = %d\n", ret);
146 		goto power_off;
147 	}
148 
149 	/* Per DSI spec wait 120ms after sending set_display_on DCS command */
150 	msleep(120);
151 
152 	ctx->prepared = true;
153 
154 	return 0;
155 
156 power_off:
157 	return ret;
158 }
159 
160 static const struct drm_display_mode visionox_rm69299_1080x2248_60hz = {
161 	.name = "1080x2248",
162 	.clock = 158695,
163 	.hdisplay = 1080,
164 	.hsync_start = 1080 + 26,
165 	.hsync_end = 1080 + 26 + 2,
166 	.htotal = 1080 + 26 + 2 + 36,
167 	.vdisplay = 2248,
168 	.vsync_start = 2248 + 56,
169 	.vsync_end = 2248 + 56 + 4,
170 	.vtotal = 2248 + 56 + 4 + 4,
171 	.vrefresh = 60,
172 	.flags = 0,
173 };
174 
175 static int visionox_rm69299_get_modes(struct drm_panel *panel,
176 				      struct drm_connector *connector)
177 {
178 	struct visionox_rm69299 *ctx = panel_to_ctx(panel);
179 	struct drm_display_mode *mode;
180 
181 	mode = drm_mode_create(connector->dev);
182 	if (!mode) {
183 		DRM_DEV_ERROR(ctx->panel.dev,
184 			      "failed to create a new display mode\n");
185 		return 0;
186 	}
187 
188 	connector->display_info.width_mm = 74;
189 	connector->display_info.height_mm = 131;
190 	drm_mode_copy(mode, &visionox_rm69299_1080x2248_60hz);
191 	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
192 	drm_mode_probed_add(connector, mode);
193 
194 	return 1;
195 }
196 
197 static const struct drm_panel_funcs visionox_rm69299_drm_funcs = {
198 	.unprepare = visionox_rm69299_unprepare,
199 	.prepare = visionox_rm69299_prepare,
200 	.get_modes = visionox_rm69299_get_modes,
201 };
202 
203 static int visionox_rm69299_probe(struct mipi_dsi_device *dsi)
204 {
205 	struct device *dev = &dsi->dev;
206 	struct visionox_rm69299 *ctx;
207 	int ret;
208 
209 	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
210 	if (!ctx)
211 		return -ENOMEM;
212 
213 	mipi_dsi_set_drvdata(dsi, ctx);
214 
215 	ctx->panel.dev = dev;
216 	ctx->dsi = dsi;
217 
218 	ctx->supplies[0].supply = "vdda";
219 	ctx->supplies[1].supply = "vdd3p3";
220 
221 	ret = devm_regulator_bulk_get(ctx->panel.dev, ARRAY_SIZE(ctx->supplies),
222 				      ctx->supplies);
223 	if (ret < 0)
224 		return ret;
225 
226 	ctx->reset_gpio = devm_gpiod_get(ctx->panel.dev,
227 					 "reset", GPIOD_OUT_LOW);
228 	if (IS_ERR(ctx->reset_gpio)) {
229 		DRM_DEV_ERROR(dev, "cannot get reset gpio %ld\n",
230 			      PTR_ERR(ctx->reset_gpio));
231 		return PTR_ERR(ctx->reset_gpio);
232 	}
233 
234 	drm_panel_init(&ctx->panel, dev, &visionox_rm69299_drm_funcs,
235 		       DRM_MODE_CONNECTOR_DSI);
236 	ctx->panel.dev = dev;
237 	ctx->panel.funcs = &visionox_rm69299_drm_funcs;
238 	drm_panel_add(&ctx->panel);
239 
240 	dsi->lanes = 4;
241 	dsi->format = MIPI_DSI_FMT_RGB888;
242 	dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_LPM |
243 			  MIPI_DSI_CLOCK_NON_CONTINUOUS;
244 	ret = mipi_dsi_attach(dsi);
245 	if (ret < 0) {
246 		DRM_DEV_ERROR(dev, "dsi attach failed ret = %d\n", ret);
247 		goto err_dsi_attach;
248 	}
249 
250 	ret = regulator_set_load(ctx->supplies[0].consumer, 32000);
251 	if (ret) {
252 		DRM_DEV_ERROR(dev,
253 			      "regulator set load failed for vdda supply ret = %d\n",
254 			      ret);
255 		goto err_set_load;
256 	}
257 
258 	ret = regulator_set_load(ctx->supplies[1].consumer, 13200);
259 	if (ret) {
260 		DRM_DEV_ERROR(dev,
261 			      "regulator set load failed for vdd3p3 supply ret = %d\n",
262 			      ret);
263 		goto err_set_load;
264 	}
265 
266 	return 0;
267 
268 err_set_load:
269 	mipi_dsi_detach(dsi);
270 err_dsi_attach:
271 	drm_panel_remove(&ctx->panel);
272 	return ret;
273 }
274 
275 static int visionox_rm69299_remove(struct mipi_dsi_device *dsi)
276 {
277 	struct visionox_rm69299 *ctx = mipi_dsi_get_drvdata(dsi);
278 
279 	mipi_dsi_detach(ctx->dsi);
280 	mipi_dsi_device_unregister(ctx->dsi);
281 
282 	drm_panel_remove(&ctx->panel);
283 	return 0;
284 }
285 
286 static const struct of_device_id visionox_rm69299_of_match[] = {
287 	{ .compatible = "visionox,rm69299-1080p-display", },
288 	{ /* sentinel */ }
289 };
290 MODULE_DEVICE_TABLE(of, visionox_rm69299_of_match);
291 
292 static struct mipi_dsi_driver visionox_rm69299_driver = {
293 	.driver = {
294 		.name = "panel-visionox-rm69299",
295 		.of_match_table = visionox_rm69299_of_match,
296 	},
297 	.probe = visionox_rm69299_probe,
298 	.remove = visionox_rm69299_remove,
299 };
300 module_mipi_dsi_driver(visionox_rm69299_driver);
301 
302 MODULE_DESCRIPTION("Visionox RM69299 DSI Panel Driver");
303 MODULE_LICENSE("GPL v2");
304