xref: /linux/drivers/gpu/drm/panel/panel-elida-kd35t133.c (revision 3286f88f31da060ac2789cee247153961ba57e49)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Elida kd35t133 5.5" MIPI-DSI panel driver
4  * Copyright (C) 2020 Theobroma Systems Design und Consulting GmbH
5  *
6  * based on
7  *
8  * Rockteck jh057n00900 5.5" MIPI-DSI panel driver
9  * Copyright (C) Purism SPC 2019
10  */
11 
12 #include <linux/delay.h>
13 #include <linux/gpio/consumer.h>
14 #include <linux/media-bus-format.h>
15 #include <linux/module.h>
16 #include <linux/of.h>
17 #include <linux/regulator/consumer.h>
18 
19 #include <video/display_timing.h>
20 #include <video/mipi_display.h>
21 
22 #include <drm/drm_mipi_dsi.h>
23 #include <drm/drm_modes.h>
24 #include <drm/drm_panel.h>
25 
26 /* Manufacturer specific Commands send via DSI */
27 #define KD35T133_CMD_INTERFACEMODECTRL		0xb0
28 #define KD35T133_CMD_FRAMERATECTRL		0xb1
29 #define KD35T133_CMD_DISPLAYINVERSIONCTRL	0xb4
30 #define KD35T133_CMD_DISPLAYFUNCTIONCTRL	0xb6
31 #define KD35T133_CMD_POWERCONTROL1		0xc0
32 #define KD35T133_CMD_POWERCONTROL2		0xc1
33 #define KD35T133_CMD_VCOMCONTROL		0xc5
34 #define KD35T133_CMD_POSITIVEGAMMA		0xe0
35 #define KD35T133_CMD_NEGATIVEGAMMA		0xe1
36 #define KD35T133_CMD_SETIMAGEFUNCTION		0xe9
37 #define KD35T133_CMD_ADJUSTCONTROL3		0xf7
38 
39 struct kd35t133 {
40 	struct device *dev;
41 	struct drm_panel panel;
42 	struct gpio_desc *reset_gpio;
43 	struct regulator *vdd;
44 	struct regulator *iovcc;
45 	enum drm_panel_orientation orientation;
46 	bool prepared;
47 };
48 
49 static inline struct kd35t133 *panel_to_kd35t133(struct drm_panel *panel)
50 {
51 	return container_of(panel, struct kd35t133, panel);
52 }
53 
54 static int kd35t133_init_sequence(struct kd35t133 *ctx)
55 {
56 	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
57 	struct device *dev = ctx->dev;
58 
59 	/*
60 	 * Init sequence was supplied by the panel vendor with minimal
61 	 * documentation.
62 	 */
63 	mipi_dsi_dcs_write_seq(dsi, KD35T133_CMD_POSITIVEGAMMA,
64 			       0x00, 0x13, 0x18, 0x04, 0x0f, 0x06, 0x3a, 0x56,
65 			       0x4d, 0x03, 0x0a, 0x06, 0x30, 0x3e, 0x0f);
66 	mipi_dsi_dcs_write_seq(dsi, KD35T133_CMD_NEGATIVEGAMMA,
67 			       0x00, 0x13, 0x18, 0x01, 0x11, 0x06, 0x38, 0x34,
68 			       0x4d, 0x06, 0x0d, 0x0b, 0x31, 0x37, 0x0f);
69 	mipi_dsi_dcs_write_seq(dsi, KD35T133_CMD_POWERCONTROL1, 0x18, 0x17);
70 	mipi_dsi_dcs_write_seq(dsi, KD35T133_CMD_POWERCONTROL2, 0x41);
71 	mipi_dsi_dcs_write_seq(dsi, KD35T133_CMD_VCOMCONTROL, 0x00, 0x1a, 0x80);
72 	mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_ADDRESS_MODE, 0x48);
73 	mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_PIXEL_FORMAT, 0x55);
74 	mipi_dsi_dcs_write_seq(dsi, KD35T133_CMD_INTERFACEMODECTRL, 0x00);
75 	mipi_dsi_dcs_write_seq(dsi, KD35T133_CMD_FRAMERATECTRL, 0xa0);
76 	mipi_dsi_dcs_write_seq(dsi, KD35T133_CMD_DISPLAYINVERSIONCTRL, 0x02);
77 	mipi_dsi_dcs_write_seq(dsi, KD35T133_CMD_DISPLAYFUNCTIONCTRL,
78 			       0x20, 0x02);
79 	mipi_dsi_dcs_write_seq(dsi, KD35T133_CMD_SETIMAGEFUNCTION, 0x00);
80 	mipi_dsi_dcs_write_seq(dsi, KD35T133_CMD_ADJUSTCONTROL3,
81 			       0xa9, 0x51, 0x2c, 0x82);
82 	mipi_dsi_dcs_write(dsi, MIPI_DCS_ENTER_INVERT_MODE, NULL, 0);
83 
84 	dev_dbg(dev, "Panel init sequence done\n");
85 	return 0;
86 }
87 
88 static int kd35t133_unprepare(struct drm_panel *panel)
89 {
90 	struct kd35t133 *ctx = panel_to_kd35t133(panel);
91 	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
92 	int ret;
93 
94 	if (!ctx->prepared)
95 		return 0;
96 
97 	ret = mipi_dsi_dcs_set_display_off(dsi);
98 	if (ret < 0)
99 		dev_err(ctx->dev, "failed to set display off: %d\n", ret);
100 
101 	ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
102 	if (ret < 0) {
103 		dev_err(ctx->dev, "failed to enter sleep mode: %d\n", ret);
104 		return ret;
105 	}
106 
107 	regulator_disable(ctx->iovcc);
108 	regulator_disable(ctx->vdd);
109 
110 	ctx->prepared = false;
111 
112 	return 0;
113 }
114 
115 static int kd35t133_prepare(struct drm_panel *panel)
116 {
117 	struct kd35t133 *ctx = panel_to_kd35t133(panel);
118 	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
119 	int ret;
120 
121 	if (ctx->prepared)
122 		return 0;
123 
124 	dev_dbg(ctx->dev, "Resetting the panel\n");
125 	ret = regulator_enable(ctx->vdd);
126 	if (ret < 0) {
127 		dev_err(ctx->dev, "Failed to enable vdd supply: %d\n", ret);
128 		return ret;
129 	}
130 
131 	ret = regulator_enable(ctx->iovcc);
132 	if (ret < 0) {
133 		dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret);
134 		goto disable_vdd;
135 	}
136 
137 	msleep(20);
138 
139 	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
140 	usleep_range(10, 20);
141 	gpiod_set_value_cansleep(ctx->reset_gpio, 0);
142 
143 	msleep(20);
144 
145 	ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
146 	if (ret < 0) {
147 		dev_err(ctx->dev, "Failed to exit sleep mode: %d\n", ret);
148 		goto disable_iovcc;
149 	}
150 
151 	msleep(250);
152 
153 	ret = kd35t133_init_sequence(ctx);
154 	if (ret < 0) {
155 		dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret);
156 		goto disable_iovcc;
157 	}
158 
159 	ret = mipi_dsi_dcs_set_display_on(dsi);
160 	if (ret < 0) {
161 		dev_err(ctx->dev, "Failed to set display on: %d\n", ret);
162 		goto disable_iovcc;
163 	}
164 
165 	msleep(50);
166 
167 	ctx->prepared = true;
168 
169 	return 0;
170 
171 disable_iovcc:
172 	regulator_disable(ctx->iovcc);
173 disable_vdd:
174 	regulator_disable(ctx->vdd);
175 	return ret;
176 }
177 
178 static const struct drm_display_mode default_mode = {
179 	.hdisplay	= 320,
180 	.hsync_start	= 320 + 130,
181 	.hsync_end	= 320 + 130 + 4,
182 	.htotal		= 320 + 130 + 4 + 130,
183 	.vdisplay	= 480,
184 	.vsync_start	= 480 + 2,
185 	.vsync_end	= 480 + 2 + 1,
186 	.vtotal		= 480 + 2 + 1 + 2,
187 	.clock		= 17000,
188 	.width_mm	= 42,
189 	.height_mm	= 82,
190 };
191 
192 static int kd35t133_get_modes(struct drm_panel *panel,
193 				struct drm_connector *connector)
194 {
195 	struct kd35t133 *ctx = panel_to_kd35t133(panel);
196 	struct drm_display_mode *mode;
197 
198 	mode = drm_mode_duplicate(connector->dev, &default_mode);
199 	if (!mode) {
200 		dev_err(ctx->dev, "Failed to add mode %ux%u@%u\n",
201 			default_mode.hdisplay, default_mode.vdisplay,
202 			drm_mode_vrefresh(&default_mode));
203 		return -ENOMEM;
204 	}
205 
206 	drm_mode_set_name(mode);
207 
208 	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
209 	connector->display_info.width_mm = mode->width_mm;
210 	connector->display_info.height_mm = mode->height_mm;
211 	drm_mode_probed_add(connector, mode);
212 	/*
213 	 * TODO: Remove once all drm drivers call
214 	 * drm_connector_set_orientation_from_panel()
215 	 */
216 	drm_connector_set_panel_orientation(connector, ctx->orientation);
217 
218 	return 1;
219 }
220 
221 static enum drm_panel_orientation kd35t133_get_orientation(struct drm_panel *panel)
222 {
223 	struct kd35t133 *ctx = panel_to_kd35t133(panel);
224 
225 	return ctx->orientation;
226 }
227 
228 static const struct drm_panel_funcs kd35t133_funcs = {
229 	.unprepare	= kd35t133_unprepare,
230 	.prepare	= kd35t133_prepare,
231 	.get_modes	= kd35t133_get_modes,
232 	.get_orientation = kd35t133_get_orientation,
233 };
234 
235 static int kd35t133_probe(struct mipi_dsi_device *dsi)
236 {
237 	struct device *dev = &dsi->dev;
238 	struct kd35t133 *ctx;
239 	int ret;
240 
241 	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
242 	if (!ctx)
243 		return -ENOMEM;
244 
245 	ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
246 	if (IS_ERR(ctx->reset_gpio)) {
247 		dev_err(dev, "cannot get reset gpio\n");
248 		return PTR_ERR(ctx->reset_gpio);
249 	}
250 
251 	ctx->vdd = devm_regulator_get(dev, "vdd");
252 	if (IS_ERR(ctx->vdd)) {
253 		ret = PTR_ERR(ctx->vdd);
254 		if (ret != -EPROBE_DEFER)
255 			dev_err(dev, "Failed to request vdd regulator: %d\n", ret);
256 		return ret;
257 	}
258 
259 	ctx->iovcc = devm_regulator_get(dev, "iovcc");
260 	if (IS_ERR(ctx->iovcc)) {
261 		ret = PTR_ERR(ctx->iovcc);
262 		if (ret != -EPROBE_DEFER)
263 			dev_err(dev, "Failed to request iovcc regulator: %d\n", ret);
264 		return ret;
265 	}
266 
267 	ret = of_drm_get_panel_orientation(dev->of_node, &ctx->orientation);
268 	if (ret < 0) {
269 		dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, ret);
270 		return ret;
271 	}
272 
273 	mipi_dsi_set_drvdata(dsi, ctx);
274 
275 	ctx->dev = dev;
276 
277 	dsi->lanes = 1;
278 	dsi->format = MIPI_DSI_FMT_RGB888;
279 	dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
280 			  MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET |
281 			  MIPI_DSI_CLOCK_NON_CONTINUOUS;
282 
283 	drm_panel_init(&ctx->panel, &dsi->dev, &kd35t133_funcs,
284 		       DRM_MODE_CONNECTOR_DSI);
285 
286 	ret = drm_panel_of_backlight(&ctx->panel);
287 	if (ret)
288 		return ret;
289 
290 	drm_panel_add(&ctx->panel);
291 
292 	ret = mipi_dsi_attach(dsi);
293 	if (ret < 0) {
294 		dev_err(dev, "mipi_dsi_attach failed: %d\n", ret);
295 		drm_panel_remove(&ctx->panel);
296 		return ret;
297 	}
298 
299 	return 0;
300 }
301 
302 static void kd35t133_shutdown(struct mipi_dsi_device *dsi)
303 {
304 	struct kd35t133 *ctx = mipi_dsi_get_drvdata(dsi);
305 	int ret;
306 
307 	ret = drm_panel_unprepare(&ctx->panel);
308 	if (ret < 0)
309 		dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret);
310 
311 	ret = drm_panel_disable(&ctx->panel);
312 	if (ret < 0)
313 		dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret);
314 }
315 
316 static void kd35t133_remove(struct mipi_dsi_device *dsi)
317 {
318 	struct kd35t133 *ctx = mipi_dsi_get_drvdata(dsi);
319 	int ret;
320 
321 	kd35t133_shutdown(dsi);
322 
323 	ret = mipi_dsi_detach(dsi);
324 	if (ret < 0)
325 		dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
326 
327 	drm_panel_remove(&ctx->panel);
328 }
329 
330 static const struct of_device_id kd35t133_of_match[] = {
331 	{ .compatible = "elida,kd35t133" },
332 	{ /* sentinel */ }
333 };
334 MODULE_DEVICE_TABLE(of, kd35t133_of_match);
335 
336 static struct mipi_dsi_driver kd35t133_driver = {
337 	.driver = {
338 		.name = "panel-elida-kd35t133",
339 		.of_match_table = kd35t133_of_match,
340 	},
341 	.probe	= kd35t133_probe,
342 	.remove = kd35t133_remove,
343 	.shutdown = kd35t133_shutdown,
344 };
345 module_mipi_dsi_driver(kd35t133_driver);
346 
347 MODULE_AUTHOR("Heiko Stuebner <heiko.stuebner@theobroma-systems.com>");
348 MODULE_DESCRIPTION("DRM driver for Elida kd35t133 MIPI DSI panel");
349 MODULE_LICENSE("GPL v2");
350