1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * MIPI-DSI based s6e8aa0 AMOLED LCD 5.3 inch panel driver.
4  *
5  * Copyright (c) 2013 Samsung Electronics Co., Ltd
6  *
7  * Inki Dae, <inki.dae@samsung.com>
8  * Donghwa Lee, <dh09.lee@samsung.com>
9  * Joongmock Shin <jmock.shin@samsung.com>
10  * Eunchul Kim <chulspro.kim@samsung.com>
11  * Tomasz Figa <t.figa@samsung.com>
12  * Andrzej Hajda <a.hajda@samsung.com>
13 */
14 
15 #include <drm/drmP.h>
16 #include <drm/drm_mipi_dsi.h>
17 #include <drm/drm_panel.h>
18 
19 #include <linux/gpio/consumer.h>
20 #include <linux/regulator/consumer.h>
21 
22 #include <video/mipi_display.h>
23 #include <video/of_videomode.h>
24 #include <video/videomode.h>
25 
26 #define LDI_MTP_LENGTH			24
27 #define GAMMA_LEVEL_NUM			25
28 #define GAMMA_TABLE_LEN			26
29 
30 #define PANELCTL_SS_MASK		(1 << 5)
31 #define PANELCTL_SS_1_800		(0 << 5)
32 #define PANELCTL_SS_800_1		(1 << 5)
33 #define PANELCTL_GTCON_MASK		(7 << 2)
34 #define PANELCTL_GTCON_110		(6 << 2)
35 #define PANELCTL_GTCON_111		(7 << 2)
36 
37 #define PANELCTL_CLK1_CON_MASK		(7 << 3)
38 #define PANELCTL_CLK1_000		(0 << 3)
39 #define PANELCTL_CLK1_001		(1 << 3)
40 #define PANELCTL_CLK2_CON_MASK		(7 << 0)
41 #define PANELCTL_CLK2_000		(0 << 0)
42 #define PANELCTL_CLK2_001		(1 << 0)
43 
44 #define PANELCTL_INT1_CON_MASK		(7 << 3)
45 #define PANELCTL_INT1_000		(0 << 3)
46 #define PANELCTL_INT1_001		(1 << 3)
47 #define PANELCTL_INT2_CON_MASK		(7 << 0)
48 #define PANELCTL_INT2_000		(0 << 0)
49 #define PANELCTL_INT2_001		(1 << 0)
50 
51 #define PANELCTL_BICTL_CON_MASK		(7 << 3)
52 #define PANELCTL_BICTL_000		(0 << 3)
53 #define PANELCTL_BICTL_001		(1 << 3)
54 #define PANELCTL_BICTLB_CON_MASK	(7 << 0)
55 #define PANELCTL_BICTLB_000		(0 << 0)
56 #define PANELCTL_BICTLB_001		(1 << 0)
57 
58 #define PANELCTL_EM_CLK1_CON_MASK	(7 << 3)
59 #define PANELCTL_EM_CLK1_110		(6 << 3)
60 #define PANELCTL_EM_CLK1_111		(7 << 3)
61 #define PANELCTL_EM_CLK1B_CON_MASK	(7 << 0)
62 #define PANELCTL_EM_CLK1B_110		(6 << 0)
63 #define PANELCTL_EM_CLK1B_111		(7 << 0)
64 
65 #define PANELCTL_EM_CLK2_CON_MASK	(7 << 3)
66 #define PANELCTL_EM_CLK2_110		(6 << 3)
67 #define PANELCTL_EM_CLK2_111		(7 << 3)
68 #define PANELCTL_EM_CLK2B_CON_MASK	(7 << 0)
69 #define PANELCTL_EM_CLK2B_110		(6 << 0)
70 #define PANELCTL_EM_CLK2B_111		(7 << 0)
71 
72 #define PANELCTL_EM_INT1_CON_MASK	(7 << 3)
73 #define PANELCTL_EM_INT1_000		(0 << 3)
74 #define PANELCTL_EM_INT1_001		(1 << 3)
75 #define PANELCTL_EM_INT2_CON_MASK	(7 << 0)
76 #define PANELCTL_EM_INT2_000		(0 << 0)
77 #define PANELCTL_EM_INT2_001		(1 << 0)
78 
79 #define AID_DISABLE			(0x4)
80 #define AID_1				(0x5)
81 #define AID_2				(0x6)
82 #define AID_3				(0x7)
83 
84 typedef u8 s6e8aa0_gamma_table[GAMMA_TABLE_LEN];
85 
86 struct s6e8aa0_variant {
87 	u8 version;
88 	const s6e8aa0_gamma_table *gamma_tables;
89 };
90 
91 struct s6e8aa0 {
92 	struct device *dev;
93 	struct drm_panel panel;
94 
95 	struct regulator_bulk_data supplies[2];
96 	struct gpio_desc *reset_gpio;
97 	u32 power_on_delay;
98 	u32 reset_delay;
99 	u32 init_delay;
100 	bool flip_horizontal;
101 	bool flip_vertical;
102 	struct videomode vm;
103 	u32 width_mm;
104 	u32 height_mm;
105 
106 	u8 version;
107 	u8 id;
108 	const struct s6e8aa0_variant *variant;
109 	int brightness;
110 
111 	/* This field is tested by functions directly accessing DSI bus before
112 	 * transfer, transfer is skipped if it is set. In case of transfer
113 	 * failure or unexpected response the field is set to error value.
114 	 * Such construct allows to eliminate many checks in higher level
115 	 * functions.
116 	 */
117 	int error;
118 };
119 
120 static inline struct s6e8aa0 *panel_to_s6e8aa0(struct drm_panel *panel)
121 {
122 	return container_of(panel, struct s6e8aa0, panel);
123 }
124 
125 static int s6e8aa0_clear_error(struct s6e8aa0 *ctx)
126 {
127 	int ret = ctx->error;
128 
129 	ctx->error = 0;
130 	return ret;
131 }
132 
133 static void s6e8aa0_dcs_write(struct s6e8aa0 *ctx, const void *data, size_t len)
134 {
135 	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
136 	ssize_t ret;
137 
138 	if (ctx->error < 0)
139 		return;
140 
141 	ret = mipi_dsi_dcs_write_buffer(dsi, data, len);
142 	if (ret < 0) {
143 		dev_err(ctx->dev, "error %zd writing dcs seq: %*ph\n", ret,
144 			(int)len, data);
145 		ctx->error = ret;
146 	}
147 }
148 
149 static int s6e8aa0_dcs_read(struct s6e8aa0 *ctx, u8 cmd, void *data, size_t len)
150 {
151 	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
152 	int ret;
153 
154 	if (ctx->error < 0)
155 		return ctx->error;
156 
157 	ret = mipi_dsi_dcs_read(dsi, cmd, data, len);
158 	if (ret < 0) {
159 		dev_err(ctx->dev, "error %d reading dcs seq(%#x)\n", ret, cmd);
160 		ctx->error = ret;
161 	}
162 
163 	return ret;
164 }
165 
166 #define s6e8aa0_dcs_write_seq(ctx, seq...) \
167 ({\
168 	const u8 d[] = { seq };\
169 	BUILD_BUG_ON_MSG(ARRAY_SIZE(d) > 64, "DCS sequence too big for stack");\
170 	s6e8aa0_dcs_write(ctx, d, ARRAY_SIZE(d));\
171 })
172 
173 #define s6e8aa0_dcs_write_seq_static(ctx, seq...) \
174 ({\
175 	static const u8 d[] = { seq };\
176 	s6e8aa0_dcs_write(ctx, d, ARRAY_SIZE(d));\
177 })
178 
179 static void s6e8aa0_apply_level_1_key(struct s6e8aa0 *ctx)
180 {
181 	s6e8aa0_dcs_write_seq_static(ctx, 0xf0, 0x5a, 0x5a);
182 }
183 
184 static void s6e8aa0_panel_cond_set_v142(struct s6e8aa0 *ctx)
185 {
186 	static const u8 aids[] = {
187 		0x04, 0x04, 0x04, 0x04, 0x04, 0x60, 0x80, 0xA0
188 	};
189 	u8 aid = aids[ctx->id >> 5];
190 	u8 cfg = 0x3d;
191 	u8 clk_con = 0xc8;
192 	u8 int_con = 0x08;
193 	u8 bictl_con = 0x48;
194 	u8 em_clk1_con = 0xff;
195 	u8 em_clk2_con = 0xff;
196 	u8 em_int_con = 0xc8;
197 
198 	if (ctx->flip_vertical) {
199 		/* GTCON */
200 		cfg &= ~(PANELCTL_GTCON_MASK);
201 		cfg |= (PANELCTL_GTCON_110);
202 	}
203 
204 	if (ctx->flip_horizontal) {
205 		/* SS */
206 		cfg &= ~(PANELCTL_SS_MASK);
207 		cfg |= (PANELCTL_SS_1_800);
208 	}
209 
210 	if (ctx->flip_horizontal || ctx->flip_vertical) {
211 		/* CLK1,2_CON */
212 		clk_con &= ~(PANELCTL_CLK1_CON_MASK |
213 			PANELCTL_CLK2_CON_MASK);
214 		clk_con |= (PANELCTL_CLK1_000 | PANELCTL_CLK2_001);
215 
216 		/* INT1,2_CON */
217 		int_con &= ~(PANELCTL_INT1_CON_MASK |
218 			PANELCTL_INT2_CON_MASK);
219 		int_con |= (PANELCTL_INT1_000 | PANELCTL_INT2_001);
220 
221 		/* BICTL,B_CON */
222 		bictl_con &= ~(PANELCTL_BICTL_CON_MASK |
223 			PANELCTL_BICTLB_CON_MASK);
224 		bictl_con |= (PANELCTL_BICTL_000 |
225 			PANELCTL_BICTLB_001);
226 
227 		/* EM_CLK1,1B_CON */
228 		em_clk1_con &= ~(PANELCTL_EM_CLK1_CON_MASK |
229 			PANELCTL_EM_CLK1B_CON_MASK);
230 		em_clk1_con |= (PANELCTL_EM_CLK1_110 |
231 			PANELCTL_EM_CLK1B_110);
232 
233 		/* EM_CLK2,2B_CON */
234 		em_clk2_con &= ~(PANELCTL_EM_CLK2_CON_MASK |
235 			PANELCTL_EM_CLK2B_CON_MASK);
236 		em_clk2_con |= (PANELCTL_EM_CLK2_110 |
237 			PANELCTL_EM_CLK2B_110);
238 
239 		/* EM_INT1,2_CON */
240 		em_int_con &= ~(PANELCTL_EM_INT1_CON_MASK |
241 			PANELCTL_EM_INT2_CON_MASK);
242 		em_int_con |= (PANELCTL_EM_INT1_000 |
243 			PANELCTL_EM_INT2_001);
244 	}
245 
246 	s6e8aa0_dcs_write_seq(ctx,
247 		0xf8, cfg, 0x35, 0x00, 0x00, 0x00, 0x93, 0x00,
248 		0x3c, 0x78, 0x08, 0x27, 0x7d, 0x3f, 0x00, 0x00,
249 		0x00, 0x20, aid, 0x08, 0x6e, 0x00, 0x00, 0x00,
250 		0x02, 0x07, 0x07, 0x23, 0x23, 0xc0, clk_con, int_con,
251 		bictl_con, 0xc1, 0x00, 0xc1, em_clk1_con, em_clk2_con,
252 		em_int_con);
253 }
254 
255 static void s6e8aa0_panel_cond_set(struct s6e8aa0 *ctx)
256 {
257 	if (ctx->version < 142)
258 		s6e8aa0_dcs_write_seq_static(ctx,
259 			0xf8, 0x19, 0x35, 0x00, 0x00, 0x00, 0x94, 0x00,
260 			0x3c, 0x78, 0x10, 0x27, 0x08, 0x6e, 0x00, 0x00,
261 			0x00, 0x00, 0x04, 0x08, 0x6e, 0x00, 0x00, 0x00,
262 			0x00, 0x07, 0x07, 0x23, 0x6e, 0xc0, 0xc1, 0x01,
263 			0x81, 0xc1, 0x00, 0xc3, 0xf6, 0xf6, 0xc1
264 		);
265 	else
266 		s6e8aa0_panel_cond_set_v142(ctx);
267 }
268 
269 static void s6e8aa0_display_condition_set(struct s6e8aa0 *ctx)
270 {
271 	s6e8aa0_dcs_write_seq_static(ctx, 0xf2, 0x80, 0x03, 0x0d);
272 }
273 
274 static void s6e8aa0_etc_source_control(struct s6e8aa0 *ctx)
275 {
276 	s6e8aa0_dcs_write_seq_static(ctx, 0xf6, 0x00, 0x02, 0x00);
277 }
278 
279 static void s6e8aa0_etc_pentile_control(struct s6e8aa0 *ctx)
280 {
281 	static const u8 pent32[] = {
282 		0xb6, 0x0c, 0x02, 0x03, 0x32, 0xc0, 0x44, 0x44, 0xc0, 0x00
283 	};
284 
285 	static const u8 pent142[] = {
286 		0xb6, 0x0c, 0x02, 0x03, 0x32, 0xff, 0x44, 0x44, 0xc0, 0x00
287 	};
288 
289 	if (ctx->version < 142)
290 		s6e8aa0_dcs_write(ctx, pent32, ARRAY_SIZE(pent32));
291 	else
292 		s6e8aa0_dcs_write(ctx, pent142, ARRAY_SIZE(pent142));
293 }
294 
295 static void s6e8aa0_etc_power_control(struct s6e8aa0 *ctx)
296 {
297 	static const u8 pwr142[] = {
298 		0xf4, 0xcf, 0x0a, 0x12, 0x10, 0x1e, 0x33, 0x02
299 	};
300 
301 	static const u8 pwr32[] = {
302 		0xf4, 0xcf, 0x0a, 0x15, 0x10, 0x19, 0x33, 0x02
303 	};
304 
305 	if (ctx->version < 142)
306 		s6e8aa0_dcs_write(ctx, pwr32, ARRAY_SIZE(pwr32));
307 	else
308 		s6e8aa0_dcs_write(ctx, pwr142, ARRAY_SIZE(pwr142));
309 }
310 
311 static void s6e8aa0_etc_elvss_control(struct s6e8aa0 *ctx)
312 {
313 	u8 id = ctx->id ? 0 : 0x95;
314 
315 	s6e8aa0_dcs_write_seq(ctx, 0xb1, 0x04, id);
316 }
317 
318 static void s6e8aa0_elvss_nvm_set_v142(struct s6e8aa0 *ctx)
319 {
320 	u8 br;
321 
322 	switch (ctx->brightness) {
323 	case 0 ... 6: /* 30cd ~ 100cd */
324 		br = 0xdf;
325 		break;
326 	case 7 ... 11: /* 120cd ~ 150cd */
327 		br = 0xdd;
328 		break;
329 	case 12 ... 15: /* 180cd ~ 210cd */
330 	default:
331 		br = 0xd9;
332 		break;
333 	case 16 ... 24: /* 240cd ~ 300cd */
334 		br = 0xd0;
335 		break;
336 	}
337 
338 	s6e8aa0_dcs_write_seq(ctx, 0xd9, 0x14, 0x40, 0x0c, 0xcb, 0xce, 0x6e,
339 		0xc4, 0x0f, 0x40, 0x41, br, 0x00, 0x60, 0x19);
340 }
341 
342 static void s6e8aa0_elvss_nvm_set(struct s6e8aa0 *ctx)
343 {
344 	if (ctx->version < 142)
345 		s6e8aa0_dcs_write_seq_static(ctx,
346 			0xd9, 0x14, 0x40, 0x0c, 0xcb, 0xce, 0x6e, 0xc4, 0x07,
347 			0x40, 0x41, 0xc1, 0x00, 0x60, 0x19);
348 	else
349 		s6e8aa0_elvss_nvm_set_v142(ctx);
350 };
351 
352 static void s6e8aa0_apply_level_2_key(struct s6e8aa0 *ctx)
353 {
354 	s6e8aa0_dcs_write_seq_static(ctx, 0xfc, 0x5a, 0x5a);
355 }
356 
357 static const s6e8aa0_gamma_table s6e8aa0_gamma_tables_v142[GAMMA_LEVEL_NUM] = {
358 	{
359 		0xfa, 0x01, 0x71, 0x31, 0x7b, 0x62, 0x55, 0x55,
360 		0xaf, 0xb1, 0xb1, 0xbd, 0xce, 0xb7, 0x9a, 0xb1,
361 		0x90, 0xb2, 0xc4, 0xae, 0x00, 0x60, 0x00, 0x40,
362 		0x00, 0x70,
363 	}, {
364 		0xfa, 0x01, 0x71, 0x31, 0x7b, 0x74, 0x68, 0x69,
365 		0xb8, 0xc1, 0xb7, 0xbd, 0xcd, 0xb8, 0x93, 0xab,
366 		0x88, 0xb4, 0xc4, 0xb1, 0x00, 0x6b, 0x00, 0x4d,
367 		0x00, 0x7d,
368 	}, {
369 		0xfa, 0x01, 0x71, 0x31, 0x7b, 0x95, 0x8a, 0x89,
370 		0xb4, 0xc6, 0xb2, 0xc5, 0xd2, 0xbf, 0x90, 0xa8,
371 		0x85, 0xb5, 0xc4, 0xb3, 0x00, 0x7b, 0x00, 0x5d,
372 		0x00, 0x8f,
373 	}, {
374 		0xfa, 0x01, 0x71, 0x31, 0x7b, 0x9f, 0x98, 0x92,
375 		0xb3, 0xc4, 0xb0, 0xbc, 0xcc, 0xb4, 0x91, 0xa6,
376 		0x87, 0xb5, 0xc5, 0xb4, 0x00, 0x87, 0x00, 0x6a,
377 		0x00, 0x9e,
378 	}, {
379 		0xfa, 0x01, 0x71, 0x31, 0x7b, 0x99, 0x93, 0x8b,
380 		0xb2, 0xc2, 0xb0, 0xbd, 0xce, 0xb4, 0x90, 0xa6,
381 		0x87, 0xb3, 0xc3, 0xb2, 0x00, 0x8d, 0x00, 0x70,
382 		0x00, 0xa4,
383 	}, {
384 		0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa7, 0xa5, 0x99,
385 		0xb2, 0xc2, 0xb0, 0xbb, 0xcd, 0xb1, 0x93, 0xa7,
386 		0x8a, 0xb2, 0xc1, 0xb0, 0x00, 0x92, 0x00, 0x75,
387 		0x00, 0xaa,
388 	}, {
389 		0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa0, 0xa0, 0x93,
390 		0xb6, 0xc4, 0xb4, 0xb5, 0xc8, 0xaa, 0x94, 0xa9,
391 		0x8c, 0xb2, 0xc0, 0xb0, 0x00, 0x97, 0x00, 0x7a,
392 		0x00, 0xaf,
393 	}, {
394 		0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa3, 0xa7, 0x96,
395 		0xb3, 0xc2, 0xb0, 0xba, 0xcb, 0xb0, 0x94, 0xa8,
396 		0x8c, 0xb0, 0xbf, 0xaf, 0x00, 0x9f, 0x00, 0x83,
397 		0x00, 0xb9,
398 	}, {
399 		0xfa, 0x01, 0x71, 0x31, 0x7b, 0x9d, 0xa2, 0x90,
400 		0xb6, 0xc5, 0xb3, 0xb8, 0xc9, 0xae, 0x94, 0xa8,
401 		0x8d, 0xaf, 0xbd, 0xad, 0x00, 0xa4, 0x00, 0x88,
402 		0x00, 0xbf,
403 	}, {
404 		0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa6, 0xac, 0x97,
405 		0xb4, 0xc4, 0xb1, 0xbb, 0xcb, 0xb2, 0x93, 0xa7,
406 		0x8d, 0xae, 0xbc, 0xad, 0x00, 0xa7, 0x00, 0x8c,
407 		0x00, 0xc3,
408 	}, {
409 		0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa2, 0xa9, 0x93,
410 		0xb6, 0xc5, 0xb2, 0xba, 0xc9, 0xb0, 0x93, 0xa7,
411 		0x8d, 0xae, 0xbb, 0xac, 0x00, 0xab, 0x00, 0x90,
412 		0x00, 0xc8,
413 	}, {
414 		0xfa, 0x01, 0x71, 0x31, 0x7b, 0x9e, 0xa6, 0x8f,
415 		0xb7, 0xc6, 0xb3, 0xb8, 0xc8, 0xb0, 0x93, 0xa6,
416 		0x8c, 0xae, 0xbb, 0xad, 0x00, 0xae, 0x00, 0x93,
417 		0x00, 0xcc,
418 	}, {
419 		0xfa, 0x01, 0x71, 0x31, 0x7b, 0xab, 0xb4, 0x9c,
420 		0xb3, 0xc3, 0xaf, 0xb7, 0xc7, 0xaf, 0x93, 0xa6,
421 		0x8c, 0xaf, 0xbc, 0xad, 0x00, 0xb1, 0x00, 0x97,
422 		0x00, 0xcf,
423 	}, {
424 		0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa6, 0xb1, 0x98,
425 		0xb1, 0xc2, 0xab, 0xba, 0xc9, 0xb2, 0x93, 0xa6,
426 		0x8d, 0xae, 0xba, 0xab, 0x00, 0xb5, 0x00, 0x9b,
427 		0x00, 0xd4,
428 	}, {
429 		0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa3, 0xae, 0x94,
430 		0xb2, 0xc3, 0xac, 0xbb, 0xca, 0xb4, 0x91, 0xa4,
431 		0x8a, 0xae, 0xba, 0xac, 0x00, 0xb8, 0x00, 0x9e,
432 		0x00, 0xd8,
433 	}, {
434 		0xfa, 0x01, 0x71, 0x31, 0x7b, 0xab, 0xb7, 0x9c,
435 		0xae, 0xc0, 0xa9, 0xba, 0xc9, 0xb3, 0x92, 0xa5,
436 		0x8b, 0xad, 0xb9, 0xab, 0x00, 0xbb, 0x00, 0xa1,
437 		0x00, 0xdc,
438 	}, {
439 		0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa7, 0xb4, 0x97,
440 		0xb0, 0xc1, 0xaa, 0xb9, 0xc8, 0xb2, 0x92, 0xa5,
441 		0x8c, 0xae, 0xb9, 0xab, 0x00, 0xbe, 0x00, 0xa4,
442 		0x00, 0xdf,
443 	}, {
444 		0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa3, 0xb0, 0x94,
445 		0xb0, 0xc2, 0xab, 0xbb, 0xc9, 0xb3, 0x91, 0xa4,
446 		0x8b, 0xad, 0xb8, 0xaa, 0x00, 0xc1, 0x00, 0xa8,
447 		0x00, 0xe2,
448 	}, {
449 		0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa3, 0xb0, 0x94,
450 		0xae, 0xbf, 0xa8, 0xb9, 0xc8, 0xb3, 0x92, 0xa4,
451 		0x8b, 0xad, 0xb7, 0xa9, 0x00, 0xc4, 0x00, 0xab,
452 		0x00, 0xe6,
453 	}, {
454 		0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa7, 0xb6, 0x98,
455 		0xaf, 0xc0, 0xa8, 0xb8, 0xc7, 0xb2, 0x93, 0xa5,
456 		0x8d, 0xad, 0xb7, 0xa9, 0x00, 0xc7, 0x00, 0xae,
457 		0x00, 0xe9,
458 	}, {
459 		0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa4, 0xb3, 0x95,
460 		0xaf, 0xc1, 0xa9, 0xb9, 0xc8, 0xb3, 0x92, 0xa4,
461 		0x8b, 0xad, 0xb7, 0xaa, 0x00, 0xc9, 0x00, 0xb0,
462 		0x00, 0xec,
463 	}, {
464 		0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa4, 0xb3, 0x95,
465 		0xac, 0xbe, 0xa6, 0xbb, 0xc9, 0xb4, 0x90, 0xa3,
466 		0x8a, 0xad, 0xb7, 0xa9, 0x00, 0xcc, 0x00, 0xb4,
467 		0x00, 0xf0,
468 	}, {
469 		0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa0, 0xb0, 0x91,
470 		0xae, 0xc0, 0xa6, 0xba, 0xc8, 0xb4, 0x91, 0xa4,
471 		0x8b, 0xad, 0xb7, 0xa9, 0x00, 0xcf, 0x00, 0xb7,
472 		0x00, 0xf3,
473 	}, {
474 		0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa7, 0xb8, 0x98,
475 		0xab, 0xbd, 0xa4, 0xbb, 0xc9, 0xb5, 0x91, 0xa3,
476 		0x8b, 0xac, 0xb6, 0xa8, 0x00, 0xd1, 0x00, 0xb9,
477 		0x00, 0xf6,
478 	}, {
479 		0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa4, 0xb5, 0x95,
480 		0xa9, 0xbc, 0xa1, 0xbb, 0xc9, 0xb5, 0x91, 0xa3,
481 		0x8a, 0xad, 0xb6, 0xa8, 0x00, 0xd6, 0x00, 0xbf,
482 		0x00, 0xfc,
483 	},
484 };
485 
486 static const s6e8aa0_gamma_table s6e8aa0_gamma_tables_v96[GAMMA_LEVEL_NUM] = {
487 	{
488 		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x00, 0xff,
489 		0xdf, 0x1f, 0xd7, 0xdc, 0xb7, 0xe1, 0xc0, 0xaf,
490 		0xc4, 0xd2, 0xd0, 0xcf, 0x00, 0x4d, 0x00, 0x40,
491 		0x00, 0x5f,
492 	}, {
493 		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x00, 0xff,
494 		0xd5, 0x35, 0xcf, 0xdc, 0xc1, 0xe1, 0xbf, 0xb3,
495 		0xc1, 0xd2, 0xd1, 0xce,	0x00, 0x53, 0x00, 0x46,
496 		0x00, 0x67,
497 	}, {
498 		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x00, 0xff,
499 		0xd2, 0x64, 0xcf, 0xdb, 0xc6, 0xe1, 0xbd, 0xb3,
500 		0xbd, 0xd2, 0xd2, 0xce,	0x00, 0x59, 0x00, 0x4b,
501 		0x00, 0x6e,
502 	}, {
503 		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x00, 0xff,
504 		0xd0, 0x7c, 0xcf, 0xdb, 0xc9, 0xe0, 0xbc, 0xb4,
505 		0xbb, 0xcf, 0xd1, 0xcc, 0x00, 0x5f, 0x00, 0x50,
506 		0x00, 0x75,
507 	}, {
508 		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x00, 0xff,
509 		0xd0, 0x8e, 0xd1, 0xdb, 0xcc, 0xdf, 0xbb, 0xb6,
510 		0xb9, 0xd0, 0xd1, 0xcd,	0x00, 0x63, 0x00, 0x54,
511 		0x00, 0x7a,
512 	}, {
513 		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x00, 0xff,
514 		0xd1, 0x9e, 0xd5, 0xda, 0xcd, 0xdd, 0xbb, 0xb7,
515 		0xb9, 0xce, 0xce, 0xc9,	0x00, 0x68, 0x00, 0x59,
516 		0x00, 0x81,
517 	}, {
518 		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x00, 0xff,
519 		0xd0, 0xa5, 0xd6, 0xda, 0xcf, 0xdd, 0xbb, 0xb7,
520 		0xb8, 0xcc, 0xcd, 0xc7,	0x00, 0x6c, 0x00, 0x5c,
521 		0x00, 0x86,
522 	}, {
523 		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x1f, 0xfe,
524 		0xd0, 0xae, 0xd7, 0xd9, 0xd0, 0xdb, 0xb9, 0xb6,
525 		0xb5, 0xca, 0xcc, 0xc5,	0x00, 0x74, 0x00, 0x63,
526 		0x00, 0x90,
527 	}, {
528 		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x1f, 0xf9,
529 		0xcf, 0xb0, 0xd6, 0xd9, 0xd1, 0xdb, 0xb9, 0xb6,
530 		0xb4, 0xca, 0xcb, 0xc5,	0x00, 0x77, 0x00, 0x66,
531 		0x00, 0x94,
532 	}, {
533 		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x1f, 0xf7,
534 		0xcf, 0xb3, 0xd7, 0xd8, 0xd1, 0xd9, 0xb7, 0xb6,
535 		0xb3, 0xc9, 0xca, 0xc3,	0x00, 0x7b, 0x00, 0x69,
536 		0x00, 0x99,
537 
538 	}, {
539 		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xfd, 0x2f, 0xf7,
540 		0xdf, 0xb5, 0xd6, 0xd8, 0xd1, 0xd8, 0xb6, 0xb5,
541 		0xb2, 0xca, 0xcb, 0xc4,	0x00, 0x7e, 0x00, 0x6c,
542 		0x00, 0x9d,
543 	}, {
544 		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xfa, 0x2f, 0xf5,
545 		0xce, 0xb6, 0xd5, 0xd7, 0xd2, 0xd8, 0xb6, 0xb4,
546 		0xb0, 0xc7, 0xc9, 0xc1,	0x00, 0x84, 0x00, 0x71,
547 		0x00, 0xa5,
548 	}, {
549 		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xf7, 0x2f, 0xf2,
550 		0xce, 0xb9, 0xd5, 0xd8, 0xd2, 0xd8, 0xb4, 0xb4,
551 		0xaf, 0xc7, 0xc9, 0xc1,	0x00, 0x87, 0x00, 0x73,
552 		0x00, 0xa8,
553 	}, {
554 		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xf5, 0x2f, 0xf0,
555 		0xdf, 0xba, 0xd5, 0xd7, 0xd2, 0xd7, 0xb4, 0xb4,
556 		0xaf, 0xc5, 0xc7, 0xbf,	0x00, 0x8a, 0x00, 0x76,
557 		0x00, 0xac,
558 	}, {
559 		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xf2, 0x2f, 0xed,
560 		0xcE, 0xbb, 0xd4, 0xd6, 0xd2, 0xd6, 0xb5, 0xb4,
561 		0xaF, 0xc5, 0xc7, 0xbf,	0x00, 0x8c, 0x00, 0x78,
562 		0x00, 0xaf,
563 	}, {
564 		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xef, 0x2f, 0xeb,
565 		0xcd, 0xbb, 0xd2, 0xd7, 0xd3, 0xd6, 0xb3, 0xb4,
566 		0xae, 0xc5, 0xc6, 0xbe,	0x00, 0x91, 0x00, 0x7d,
567 		0x00, 0xb6,
568 	}, {
569 		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xee, 0x2f, 0xea,
570 		0xce, 0xbd, 0xd4, 0xd6, 0xd2, 0xd5, 0xb2, 0xb3,
571 		0xad, 0xc3, 0xc4, 0xbb,	0x00, 0x94, 0x00, 0x7f,
572 		0x00, 0xba,
573 	}, {
574 		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xec, 0x2f, 0xe8,
575 		0xce, 0xbe, 0xd3, 0xd6, 0xd3, 0xd5, 0xb2, 0xb2,
576 		0xac, 0xc3, 0xc5, 0xbc,	0x00, 0x96, 0x00, 0x81,
577 		0x00, 0xbd,
578 	}, {
579 		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xeb, 0x2f, 0xe7,
580 		0xce, 0xbf, 0xd3, 0xd6, 0xd2, 0xd5, 0xb1, 0xb2,
581 		0xab, 0xc2, 0xc4, 0xbb,	0x00, 0x99, 0x00, 0x83,
582 		0x00, 0xc0,
583 	}, {
584 		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xef, 0x5f, 0xe9,
585 		0xca, 0xbf, 0xd3, 0xd5, 0xd2, 0xd4, 0xb2, 0xb2,
586 		0xab, 0xc1, 0xc4, 0xba,	0x00, 0x9b, 0x00, 0x85,
587 		0x00, 0xc3,
588 	}, {
589 		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xea, 0x5f, 0xe8,
590 		0xee, 0xbf, 0xd2, 0xd5, 0xd2, 0xd4, 0xb1, 0xb2,
591 		0xab, 0xc1, 0xc2, 0xb9,	0x00, 0x9D, 0x00, 0x87,
592 		0x00, 0xc6,
593 	}, {
594 		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xe9, 0x5f, 0xe7,
595 		0xcd, 0xbf, 0xd2, 0xd6, 0xd2, 0xd4, 0xb1, 0xb2,
596 		0xab, 0xbe, 0xc0, 0xb7,	0x00, 0xa1, 0x00, 0x8a,
597 		0x00, 0xca,
598 	}, {
599 		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xe8, 0x61, 0xe6,
600 		0xcd, 0xbf, 0xd1, 0xd6, 0xd3, 0xd4, 0xaf, 0xb0,
601 		0xa9, 0xbe, 0xc1, 0xb7,	0x00, 0xa3, 0x00, 0x8b,
602 		0x00, 0xce,
603 	}, {
604 		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xe8, 0x62, 0xe5,
605 		0xcc, 0xc0, 0xd0, 0xd6, 0xd2, 0xd4, 0xaf, 0xb1,
606 		0xa9, 0xbd, 0xc0, 0xb6,	0x00, 0xa5, 0x00, 0x8d,
607 		0x00, 0xd0,
608 	}, {
609 		0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xe7, 0x7f, 0xe3,
610 		0xcc, 0xc1, 0xd0, 0xd5, 0xd3, 0xd3, 0xae, 0xaf,
611 		0xa8, 0xbe, 0xc0, 0xb7,	0x00, 0xa8, 0x00, 0x90,
612 		0x00, 0xd3,
613 	}
614 };
615 
616 static const s6e8aa0_gamma_table s6e8aa0_gamma_tables_v32[GAMMA_LEVEL_NUM] = {
617 	{
618 		0xfa, 0x01, 0x43, 0x14, 0x45, 0x72, 0x5e, 0x6b,
619 		0xa1, 0xa7, 0x9a, 0xb4, 0xcb, 0xb8, 0x92, 0xac,
620 		0x97, 0xb4, 0xc3, 0xb5, 0x00, 0x4e, 0x00, 0x37,
621 		0x00, 0x58,
622 	}, {
623 		0xfa, 0x01, 0x43, 0x14, 0x45, 0x85, 0x71, 0x7d,
624 		0xa6, 0xb6, 0xa1, 0xb5, 0xca, 0xba, 0x93, 0xac,
625 		0x98, 0xb2, 0xc0, 0xaf, 0x00, 0x59, 0x00, 0x43,
626 		0x00, 0x64,
627 	}, {
628 		0xfa, 0x01, 0x43, 0x14, 0x45, 0xa4, 0x94, 0x9e,
629 		0xa0, 0xbb, 0x9c, 0xc3, 0xd2, 0xc6, 0x93, 0xaa,
630 		0x95, 0xb7, 0xc2, 0xb4, 0x00, 0x65, 0x00, 0x50,
631 		0x00, 0x74,
632 	}, {
633 		0xfa, 0x01, 0x43, 0x14, 0x45, 0xad, 0xa1, 0xa6,
634 		0xa0, 0xb9, 0x9b, 0xc3, 0xd1, 0xc8, 0x90, 0xa6,
635 		0x90, 0xbb, 0xc3, 0xb7, 0x00, 0x6f, 0x00, 0x5b,
636 		0x00, 0x80,
637 	}, {
638 		0xfa, 0x01, 0x43, 0x14, 0x45, 0xa6, 0x9d, 0x9f,
639 		0x9f, 0xb8, 0x9a, 0xc7, 0xd5, 0xcc, 0x90, 0xa5,
640 		0x8f, 0xb8, 0xc1, 0xb6, 0x00, 0x74, 0x00, 0x60,
641 		0x00, 0x85,
642 	}, {
643 		0xfa, 0x01, 0x43, 0x14, 0x45, 0xb3, 0xae, 0xae,
644 		0x9e, 0xb7, 0x9a, 0xc8, 0xd6, 0xce, 0x91, 0xa6,
645 		0x90, 0xb6, 0xc0, 0xb3, 0x00, 0x78, 0x00, 0x65,
646 		0x00, 0x8a,
647 	}, {
648 		0xfa, 0x01, 0x43, 0x14, 0x45, 0xad, 0xa9, 0xa8,
649 		0xa3, 0xb9, 0x9e, 0xc4, 0xd3, 0xcb, 0x94, 0xa6,
650 		0x90, 0xb6, 0xbf, 0xb3, 0x00, 0x7c, 0x00, 0x69,
651 		0x00, 0x8e,
652 	}, {
653 		0xfa, 0x01, 0x43, 0x14, 0x45, 0xaf, 0xaf, 0xa9,
654 		0xa5, 0xbc, 0xa2, 0xc7, 0xd5, 0xcd, 0x93, 0xa5,
655 		0x8f, 0xb4, 0xbd, 0xb1, 0x00, 0x83, 0x00, 0x70,
656 		0x00, 0x96,
657 	}, {
658 		0xfa, 0x01, 0x43, 0x14, 0x45, 0xa9, 0xab, 0xa3,
659 		0xaa, 0xbf, 0xa7, 0xc5, 0xd3, 0xcb, 0x93, 0xa5,
660 		0x8f, 0xb2, 0xbb, 0xb0, 0x00, 0x86, 0x00, 0x74,
661 		0x00, 0x9b,
662 	}, {
663 		0xfa, 0x01, 0x43, 0x14, 0x45, 0xb1, 0xb5, 0xab,
664 		0xab, 0xc0, 0xa9, 0xc7, 0xd4, 0xcc, 0x94, 0xa4,
665 		0x8f, 0xb1, 0xbb, 0xaf, 0x00, 0x8a, 0x00, 0x77,
666 		0x00, 0x9e,
667 	}, {
668 		0xfa, 0x01, 0x43, 0x14, 0x45, 0xad, 0xb2, 0xa7,
669 		0xae, 0xc2, 0xab, 0xc5, 0xd3, 0xca, 0x93, 0xa4,
670 		0x8f, 0xb1, 0xba, 0xae, 0x00, 0x8d, 0x00, 0x7b,
671 		0x00, 0xa2,
672 	}, {
673 		0xfa, 0x01, 0x43, 0x14, 0x45, 0xa9, 0xaf, 0xa3,
674 		0xb0, 0xc3, 0xae, 0xc4, 0xd1, 0xc8, 0x93, 0xa4,
675 		0x8f, 0xb1, 0xba, 0xaf, 0x00, 0x8f, 0x00, 0x7d,
676 		0x00, 0xa5,
677 	}, {
678 		0xfa, 0x01, 0x43, 0x14, 0x45, 0xb4, 0xbd, 0xaf,
679 		0xae, 0xc1, 0xab, 0xc2, 0xd0, 0xc6, 0x94, 0xa4,
680 		0x8f, 0xb1, 0xba, 0xaf, 0x00, 0x92, 0x00, 0x80,
681 		0x00, 0xa8,
682 	}, {
683 		0xfa, 0x01, 0x43, 0x14, 0x45, 0xb0, 0xb9, 0xac,
684 		0xad, 0xc1, 0xab, 0xc4, 0xd1, 0xc7, 0x95, 0xa4,
685 		0x90, 0xb0, 0xb9, 0xad, 0x00, 0x95, 0x00, 0x84,
686 		0x00, 0xac,
687 	}, {
688 		0xfa, 0x01, 0x43, 0x14, 0x45, 0xad, 0xb6, 0xa7,
689 		0xaf, 0xc2, 0xae, 0xc5, 0xd1, 0xc7, 0x93, 0xa3,
690 		0x8e, 0xb0, 0xb9, 0xad, 0x00, 0x98, 0x00, 0x86,
691 		0x00, 0xaf,
692 	}, {
693 		0xfa, 0x01, 0x43, 0x14, 0x45, 0xb4, 0xbf, 0xaf,
694 		0xad, 0xc1, 0xab, 0xc3, 0xd0, 0xc6, 0x94, 0xa3,
695 		0x8f, 0xaf, 0xb8, 0xac, 0x00, 0x9a, 0x00, 0x89,
696 		0x00, 0xb2,
697 	}, {
698 		0xfa, 0x01, 0x43, 0x14, 0x45, 0xb0, 0xbc, 0xac,
699 		0xaf, 0xc2, 0xad, 0xc2, 0xcf, 0xc4, 0x94, 0xa3,
700 		0x90, 0xaf, 0xb8, 0xad, 0x00, 0x9c, 0x00, 0x8b,
701 		0x00, 0xb5,
702 	}, {
703 		0xfa, 0x01, 0x43, 0x14, 0x45, 0xad, 0xb9, 0xa7,
704 		0xb1, 0xc4, 0xaf, 0xc3, 0xcf, 0xc5, 0x94, 0xa3,
705 		0x8f, 0xae, 0xb7, 0xac, 0x00, 0x9f, 0x00, 0x8e,
706 		0x00, 0xb8,
707 	}, {
708 		0xfa, 0x01, 0x43, 0x14, 0x45, 0xad, 0xb9, 0xa7,
709 		0xaf, 0xc2, 0xad, 0xc1, 0xce, 0xc3, 0x95, 0xa3,
710 		0x90, 0xad, 0xb6, 0xab, 0x00, 0xa2, 0x00, 0x91,
711 		0x00, 0xbb,
712 	}, {
713 		0xfa, 0x01, 0x43, 0x14, 0x45, 0xb1, 0xbe, 0xac,
714 		0xb1, 0xc4, 0xaf, 0xc1, 0xcd, 0xc1, 0x95, 0xa4,
715 		0x91, 0xad, 0xb6, 0xab, 0x00, 0xa4, 0x00, 0x93,
716 		0x00, 0xbd,
717 	}, {
718 		0xfa, 0x01, 0x43, 0x14, 0x45, 0xad, 0xbb, 0xa8,
719 		0xb3, 0xc5, 0xb2, 0xc1, 0xcd, 0xc2, 0x95, 0xa3,
720 		0x90, 0xad, 0xb6, 0xab, 0x00, 0xa6, 0x00, 0x95,
721 		0x00, 0xc0,
722 	}, {
723 		0xfa, 0x01, 0x43, 0x14, 0x45, 0xad, 0xbb, 0xa8,
724 		0xb0, 0xc3, 0xaf, 0xc2, 0xce, 0xc2, 0x94, 0xa2,
725 		0x90, 0xac, 0xb6, 0xab, 0x00, 0xa8, 0x00, 0x98,
726 		0x00, 0xc3,
727 	}, {
728 		0xfa, 0x01, 0x43, 0x14, 0x45, 0xa9, 0xb8, 0xa5,
729 		0xb3, 0xc5, 0xb2, 0xc1, 0xcc, 0xc0, 0x95, 0xa2,
730 		0x90, 0xad, 0xb6, 0xab, 0x00, 0xaa, 0x00, 0x9a,
731 		0x00, 0xc5,
732 	}, {
733 		0xfa, 0x01, 0x43, 0x14, 0x45, 0xb0, 0xc0, 0xac,
734 		0xb0, 0xc3, 0xaf, 0xc1, 0xcd, 0xc1, 0x95, 0xa2,
735 		0x90, 0xac, 0xb5, 0xa9, 0x00, 0xac, 0x00, 0x9c,
736 		0x00, 0xc8,
737 	}, {
738 		0xfa, 0x01, 0x43, 0x14, 0x45, 0xad, 0xbd, 0xa8,
739 		0xaf, 0xc2, 0xaf, 0xc1, 0xcc, 0xc0, 0x95, 0xa2,
740 		0x90, 0xac, 0xb5, 0xaa, 0x00, 0xb1, 0x00, 0xa1,
741 		0x00, 0xcc,
742 	},
743 };
744 
745 static const struct s6e8aa0_variant s6e8aa0_variants[] = {
746 	{
747 		.version = 32,
748 		.gamma_tables = s6e8aa0_gamma_tables_v32,
749 	}, {
750 		.version = 96,
751 		.gamma_tables = s6e8aa0_gamma_tables_v96,
752 	}, {
753 		.version = 142,
754 		.gamma_tables = s6e8aa0_gamma_tables_v142,
755 	}, {
756 		.version = 210,
757 		.gamma_tables = s6e8aa0_gamma_tables_v142,
758 	}
759 };
760 
761 static void s6e8aa0_brightness_set(struct s6e8aa0 *ctx)
762 {
763 	const u8 *gamma;
764 
765 	if (ctx->error)
766 		return;
767 
768 	gamma = ctx->variant->gamma_tables[ctx->brightness];
769 
770 	if (ctx->version >= 142)
771 		s6e8aa0_elvss_nvm_set(ctx);
772 
773 	s6e8aa0_dcs_write(ctx, gamma, GAMMA_TABLE_LEN);
774 
775 	/* update gamma table. */
776 	s6e8aa0_dcs_write_seq_static(ctx, 0xf7, 0x03);
777 }
778 
779 static void s6e8aa0_panel_init(struct s6e8aa0 *ctx)
780 {
781 	s6e8aa0_apply_level_1_key(ctx);
782 	s6e8aa0_apply_level_2_key(ctx);
783 	msleep(20);
784 
785 	s6e8aa0_dcs_write_seq_static(ctx, MIPI_DCS_EXIT_SLEEP_MODE);
786 	msleep(40);
787 
788 	s6e8aa0_panel_cond_set(ctx);
789 	s6e8aa0_display_condition_set(ctx);
790 	s6e8aa0_brightness_set(ctx);
791 	s6e8aa0_etc_source_control(ctx);
792 	s6e8aa0_etc_pentile_control(ctx);
793 	s6e8aa0_elvss_nvm_set(ctx);
794 	s6e8aa0_etc_power_control(ctx);
795 	s6e8aa0_etc_elvss_control(ctx);
796 	msleep(ctx->init_delay);
797 }
798 
799 static void s6e8aa0_set_maximum_return_packet_size(struct s6e8aa0 *ctx,
800 						   u16 size)
801 {
802 	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
803 	int ret;
804 
805 	if (ctx->error < 0)
806 		return;
807 
808 	ret = mipi_dsi_set_maximum_return_packet_size(dsi, size);
809 	if (ret < 0) {
810 		dev_err(ctx->dev,
811 			"error %d setting maximum return packet size to %d\n",
812 			ret, size);
813 		ctx->error = ret;
814 	}
815 }
816 
817 static void s6e8aa0_read_mtp_id(struct s6e8aa0 *ctx)
818 {
819 	u8 id[3];
820 	int ret, i;
821 
822 	ret = s6e8aa0_dcs_read(ctx, 0xd1, id, ARRAY_SIZE(id));
823 	if (ret < 0 || ret < ARRAY_SIZE(id) || id[0] == 0x00) {
824 		dev_err(ctx->dev, "read id failed\n");
825 		ctx->error = -EIO;
826 		return;
827 	}
828 
829 	dev_info(ctx->dev, "ID: 0x%2x, 0x%2x, 0x%2x\n", id[0], id[1], id[2]);
830 
831 	for (i = 0; i < ARRAY_SIZE(s6e8aa0_variants); ++i) {
832 		if (id[1] == s6e8aa0_variants[i].version)
833 			break;
834 	}
835 	if (i >= ARRAY_SIZE(s6e8aa0_variants)) {
836 		dev_err(ctx->dev, "unsupported display version %d\n", id[1]);
837 		ctx->error = -EINVAL;
838 		return;
839 	}
840 
841 	ctx->variant = &s6e8aa0_variants[i];
842 	ctx->version = id[1];
843 	ctx->id = id[2];
844 }
845 
846 static void s6e8aa0_set_sequence(struct s6e8aa0 *ctx)
847 {
848 	s6e8aa0_set_maximum_return_packet_size(ctx, 3);
849 	s6e8aa0_read_mtp_id(ctx);
850 	s6e8aa0_panel_init(ctx);
851 	s6e8aa0_dcs_write_seq_static(ctx, MIPI_DCS_SET_DISPLAY_ON);
852 }
853 
854 static int s6e8aa0_power_on(struct s6e8aa0 *ctx)
855 {
856 	int ret;
857 
858 	ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
859 	if (ret < 0)
860 		return ret;
861 
862 	msleep(ctx->power_on_delay);
863 
864 	gpiod_set_value(ctx->reset_gpio, 0);
865 	usleep_range(10000, 11000);
866 	gpiod_set_value(ctx->reset_gpio, 1);
867 
868 	msleep(ctx->reset_delay);
869 
870 	return 0;
871 }
872 
873 static int s6e8aa0_power_off(struct s6e8aa0 *ctx)
874 {
875 	return regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
876 }
877 
878 static int s6e8aa0_disable(struct drm_panel *panel)
879 {
880 	return 0;
881 }
882 
883 static int s6e8aa0_unprepare(struct drm_panel *panel)
884 {
885 	struct s6e8aa0 *ctx = panel_to_s6e8aa0(panel);
886 
887 	s6e8aa0_dcs_write_seq_static(ctx, MIPI_DCS_ENTER_SLEEP_MODE);
888 	s6e8aa0_dcs_write_seq_static(ctx, MIPI_DCS_SET_DISPLAY_OFF);
889 	msleep(40);
890 
891 	s6e8aa0_clear_error(ctx);
892 
893 	return s6e8aa0_power_off(ctx);
894 }
895 
896 static int s6e8aa0_prepare(struct drm_panel *panel)
897 {
898 	struct s6e8aa0 *ctx = panel_to_s6e8aa0(panel);
899 	int ret;
900 
901 	ret = s6e8aa0_power_on(ctx);
902 	if (ret < 0)
903 		return ret;
904 
905 	s6e8aa0_set_sequence(ctx);
906 	ret = ctx->error;
907 
908 	if (ret < 0)
909 		s6e8aa0_unprepare(panel);
910 
911 	return ret;
912 }
913 
914 static int s6e8aa0_enable(struct drm_panel *panel)
915 {
916 	return 0;
917 }
918 
919 static int s6e8aa0_get_modes(struct drm_panel *panel)
920 {
921 	struct drm_connector *connector = panel->connector;
922 	struct s6e8aa0 *ctx = panel_to_s6e8aa0(panel);
923 	struct drm_display_mode *mode;
924 
925 	mode = drm_mode_create(connector->dev);
926 	if (!mode) {
927 		DRM_ERROR("failed to create a new display mode\n");
928 		return 0;
929 	}
930 
931 	drm_display_mode_from_videomode(&ctx->vm, mode);
932 	mode->width_mm = ctx->width_mm;
933 	mode->height_mm = ctx->height_mm;
934 	connector->display_info.width_mm = mode->width_mm;
935 	connector->display_info.height_mm = mode->height_mm;
936 
937 	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
938 	drm_mode_probed_add(connector, mode);
939 
940 	return 1;
941 }
942 
943 static const struct drm_panel_funcs s6e8aa0_drm_funcs = {
944 	.disable = s6e8aa0_disable,
945 	.unprepare = s6e8aa0_unprepare,
946 	.prepare = s6e8aa0_prepare,
947 	.enable = s6e8aa0_enable,
948 	.get_modes = s6e8aa0_get_modes,
949 };
950 
951 static int s6e8aa0_parse_dt(struct s6e8aa0 *ctx)
952 {
953 	struct device *dev = ctx->dev;
954 	struct device_node *np = dev->of_node;
955 	int ret;
956 
957 	ret = of_get_videomode(np, &ctx->vm, 0);
958 	if (ret < 0)
959 		return ret;
960 
961 	of_property_read_u32(np, "power-on-delay", &ctx->power_on_delay);
962 	of_property_read_u32(np, "reset-delay", &ctx->reset_delay);
963 	of_property_read_u32(np, "init-delay", &ctx->init_delay);
964 	of_property_read_u32(np, "panel-width-mm", &ctx->width_mm);
965 	of_property_read_u32(np, "panel-height-mm", &ctx->height_mm);
966 
967 	ctx->flip_horizontal = of_property_read_bool(np, "flip-horizontal");
968 	ctx->flip_vertical = of_property_read_bool(np, "flip-vertical");
969 
970 	return 0;
971 }
972 
973 static int s6e8aa0_probe(struct mipi_dsi_device *dsi)
974 {
975 	struct device *dev = &dsi->dev;
976 	struct s6e8aa0 *ctx;
977 	int ret;
978 
979 	ctx = devm_kzalloc(dev, sizeof(struct s6e8aa0), GFP_KERNEL);
980 	if (!ctx)
981 		return -ENOMEM;
982 
983 	mipi_dsi_set_drvdata(dsi, ctx);
984 
985 	ctx->dev = dev;
986 
987 	dsi->lanes = 4;
988 	dsi->format = MIPI_DSI_FMT_RGB888;
989 	dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST
990 		| MIPI_DSI_MODE_VIDEO_HFP | MIPI_DSI_MODE_VIDEO_HBP
991 		| MIPI_DSI_MODE_VIDEO_HSA | MIPI_DSI_MODE_EOT_PACKET
992 		| MIPI_DSI_MODE_VSYNC_FLUSH | MIPI_DSI_MODE_VIDEO_AUTO_VERT;
993 
994 	ret = s6e8aa0_parse_dt(ctx);
995 	if (ret < 0)
996 		return ret;
997 
998 	ctx->supplies[0].supply = "vdd3";
999 	ctx->supplies[1].supply = "vci";
1000 	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies),
1001 				      ctx->supplies);
1002 	if (ret < 0) {
1003 		dev_err(dev, "failed to get regulators: %d\n", ret);
1004 		return ret;
1005 	}
1006 
1007 	ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
1008 	if (IS_ERR(ctx->reset_gpio)) {
1009 		dev_err(dev, "cannot get reset-gpios %ld\n",
1010 			PTR_ERR(ctx->reset_gpio));
1011 		return PTR_ERR(ctx->reset_gpio);
1012 	}
1013 
1014 	ctx->brightness = GAMMA_LEVEL_NUM - 1;
1015 
1016 	drm_panel_init(&ctx->panel);
1017 	ctx->panel.dev = dev;
1018 	ctx->panel.funcs = &s6e8aa0_drm_funcs;
1019 
1020 	ret = drm_panel_add(&ctx->panel);
1021 	if (ret < 0)
1022 		return ret;
1023 
1024 	ret = mipi_dsi_attach(dsi);
1025 	if (ret < 0)
1026 		drm_panel_remove(&ctx->panel);
1027 
1028 	return ret;
1029 }
1030 
1031 static int s6e8aa0_remove(struct mipi_dsi_device *dsi)
1032 {
1033 	struct s6e8aa0 *ctx = mipi_dsi_get_drvdata(dsi);
1034 
1035 	mipi_dsi_detach(dsi);
1036 	drm_panel_remove(&ctx->panel);
1037 
1038 	return 0;
1039 }
1040 
1041 static const struct of_device_id s6e8aa0_of_match[] = {
1042 	{ .compatible = "samsung,s6e8aa0" },
1043 	{ }
1044 };
1045 MODULE_DEVICE_TABLE(of, s6e8aa0_of_match);
1046 
1047 static struct mipi_dsi_driver s6e8aa0_driver = {
1048 	.probe = s6e8aa0_probe,
1049 	.remove = s6e8aa0_remove,
1050 	.driver = {
1051 		.name = "panel-samsung-s6e8aa0",
1052 		.of_match_table = s6e8aa0_of_match,
1053 	},
1054 };
1055 module_mipi_dsi_driver(s6e8aa0_driver);
1056 
1057 MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>");
1058 MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
1059 MODULE_AUTHOR("Joongmock Shin <jmock.shin@samsung.com>");
1060 MODULE_AUTHOR("Eunchul Kim <chulspro.kim@samsung.com>");
1061 MODULE_AUTHOR("Tomasz Figa <t.figa@samsung.com>");
1062 MODULE_AUTHOR("Andrzej Hajda <a.hajda@samsung.com>");
1063 MODULE_DESCRIPTION("MIPI-DSI based s6e8aa0 AMOLED LCD Panel Driver");
1064 MODULE_LICENSE("GPL v2");
1065