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