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