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