1 /* linux/drivers/video/exynos/s6e8ax0.c
2  *
3  * MIPI-DSI based s6e8ax0 AMOLED lcd 4.65 inch panel driver.
4  *
5  * Inki Dae, <inki.dae@samsung.com>
6  * Donghwa Lee, <dh09.lee@samsung.com>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11 */
12 
13 #include <linux/module.h>
14 #include <linux/kernel.h>
15 #include <linux/errno.h>
16 #include <linux/mutex.h>
17 #include <linux/wait.h>
18 #include <linux/ctype.h>
19 #include <linux/io.h>
20 #include <linux/delay.h>
21 #include <linux/irq.h>
22 #include <linux/interrupt.h>
23 #include <linux/lcd.h>
24 #include <linux/fb.h>
25 #include <linux/backlight.h>
26 #include <linux/regulator/consumer.h>
27 
28 #include <video/mipi_display.h>
29 #include <video/exynos_mipi_dsim.h>
30 
31 #define LDI_MTP_LENGTH		24
32 #define DSIM_PM_STABLE_TIME	10
33 #define MIN_BRIGHTNESS		0
34 #define MAX_BRIGHTNESS		24
35 #define GAMMA_TABLE_COUNT	26
36 
37 #define POWER_IS_ON(pwr)	((pwr) == FB_BLANK_UNBLANK)
38 #define POWER_IS_OFF(pwr)	((pwr) == FB_BLANK_POWERDOWN)
39 #define POWER_IS_NRM(pwr)	((pwr) == FB_BLANK_NORMAL)
40 
41 #define lcd_to_master(a)	(a->dsim_dev->master)
42 #define lcd_to_master_ops(a)	((lcd_to_master(a))->master_ops)
43 
44 enum {
45 	DSIM_NONE_STATE = 0,
46 	DSIM_RESUME_COMPLETE = 1,
47 	DSIM_FRAME_DONE = 2,
48 };
49 
50 struct s6e8ax0 {
51 	struct device	*dev;
52 	unsigned int			power;
53 	unsigned int			id;
54 	unsigned int			gamma;
55 	unsigned int			acl_enable;
56 	unsigned int			cur_acl;
57 
58 	struct lcd_device	*ld;
59 	struct backlight_device	*bd;
60 
61 	struct mipi_dsim_lcd_device	*dsim_dev;
62 	struct lcd_platform_data	*ddi_pd;
63 	struct mutex			lock;
64 	bool  enabled;
65 };
66 
67 
68 static struct regulator_bulk_data supplies[] = {
69 	{ .supply = "vdd3", },
70 	{ .supply = "vci", },
71 };
72 
s6e8ax0_regulator_enable(struct s6e8ax0 * lcd)73 static void s6e8ax0_regulator_enable(struct s6e8ax0 *lcd)
74 {
75 	int ret = 0;
76 	struct lcd_platform_data *pd = NULL;
77 
78 	pd = lcd->ddi_pd;
79 	mutex_lock(&lcd->lock);
80 	if (!lcd->enabled) {
81 		ret = regulator_bulk_enable(ARRAY_SIZE(supplies), supplies);
82 		if (ret)
83 			goto out;
84 
85 		lcd->enabled = true;
86 	}
87 	msleep(pd->power_on_delay);
88 out:
89 	mutex_unlock(&lcd->lock);
90 }
91 
s6e8ax0_regulator_disable(struct s6e8ax0 * lcd)92 static void s6e8ax0_regulator_disable(struct s6e8ax0 *lcd)
93 {
94 	int ret = 0;
95 
96 	mutex_lock(&lcd->lock);
97 	if (lcd->enabled) {
98 		ret = regulator_bulk_disable(ARRAY_SIZE(supplies), supplies);
99 		if (ret)
100 			goto out;
101 
102 		lcd->enabled = false;
103 	}
104 out:
105 	mutex_unlock(&lcd->lock);
106 }
107 
108 static const unsigned char s6e8ax0_22_gamma_30[] = {
109 	0xfa, 0x01, 0x60, 0x10, 0x60, 0xf5, 0x00, 0xff, 0xad, 0xaf,
110 	0xbA, 0xc3, 0xd8, 0xc5, 0x9f, 0xc6, 0x9e, 0xc1, 0xdc, 0xc0,
111 	0x00, 0x61, 0x00, 0x5a, 0x00, 0x74,
112 };
113 
114 static const unsigned char s6e8ax0_22_gamma_50[] = {
115 	0xfa, 0x01, 0x60, 0x10, 0x60, 0xe8, 0x1f, 0xf7, 0xad, 0xc0,
116 	0xb5, 0xc4, 0xdc, 0xc4, 0x9e, 0xc6, 0x9c, 0xbb, 0xd8, 0xbb,
117 	0x00, 0x70, 0x00, 0x68, 0x00, 0x86,
118 };
119 
120 static const unsigned char s6e8ax0_22_gamma_60[] = {
121 	0xfa, 0x01, 0x60, 0x10, 0x60, 0xde, 0x1f, 0xef, 0xad, 0xc4,
122 	0xb3, 0xc3, 0xdd, 0xc4, 0x9e, 0xc6, 0x9c, 0xbc, 0xd6, 0xba,
123 	0x00, 0x75, 0x00, 0x6e, 0x00, 0x8d,
124 };
125 
126 static const unsigned char s6e8ax0_22_gamma_70[] = {
127 	0xfa, 0x01, 0x60, 0x10, 0x60, 0xd8, 0x1f, 0xe7, 0xaf, 0xc8,
128 	0xb4, 0xc4, 0xdd, 0xc3, 0x9d, 0xc6, 0x9c, 0xbb, 0xd6, 0xb9,
129 	0x00, 0x7a, 0x00, 0x72, 0x00, 0x93,
130 };
131 
132 static const unsigned char s6e8ax0_22_gamma_80[] = {
133 	0xfa, 0x01, 0x60, 0x10, 0x60, 0xc9, 0x1f, 0xde, 0xae, 0xc9,
134 	0xb1, 0xc3, 0xdd, 0xc2, 0x9d, 0xc5, 0x9b, 0xbc, 0xd6, 0xbb,
135 	0x00, 0x7f, 0x00, 0x77, 0x00, 0x99,
136 };
137 
138 static const unsigned char s6e8ax0_22_gamma_90[] = {
139 	0xfa, 0x01, 0x60, 0x10, 0x60, 0xc7, 0x1f, 0xd9, 0xb0, 0xcc,
140 	0xb2, 0xc3, 0xdc, 0xc1, 0x9c, 0xc6, 0x9c, 0xbc, 0xd4, 0xb9,
141 	0x00, 0x83, 0x00, 0x7b, 0x00, 0x9e,
142 };
143 
144 static const unsigned char s6e8ax0_22_gamma_100[] = {
145 	0xfa, 0x01, 0x60, 0x10, 0x60, 0xbd, 0x80, 0xcd, 0xba, 0xce,
146 	0xb3, 0xc4, 0xde, 0xc3, 0x9c, 0xc4, 0x9, 0xb8, 0xd3, 0xb6,
147 	0x00, 0x88, 0x00, 0x80, 0x00, 0xa5,
148 };
149 
150 static const unsigned char s6e8ax0_22_gamma_120[] = {
151 	0xfa, 0x01, 0x60, 0x10, 0x60, 0xb9, 0x95, 0xc8, 0xb1, 0xcf,
152 	0xb2, 0xc6, 0xdf, 0xc5, 0x9b, 0xc3, 0x99, 0xb6, 0xd2, 0xb6,
153 	0x00, 0x8f, 0x00, 0x86, 0x00, 0xac,
154 };
155 
156 static const unsigned char s6e8ax0_22_gamma_130[] = {
157 	0xfa, 0x01, 0x60, 0x10, 0x60, 0xb7, 0xa0, 0xc7, 0xb1, 0xd0,
158 	0xb2, 0xc4, 0xdd, 0xc3, 0x9a, 0xc3, 0x98, 0xb6, 0xd0, 0xb4,
159 	0x00, 0x92, 0x00, 0x8a, 0x00, 0xb1,
160 };
161 
162 static const unsigned char s6e8ax0_22_gamma_140[] = {
163 	0xfa, 0x01, 0x60, 0x10, 0x60, 0xb7, 0xa0, 0xc5, 0xb2, 0xd0,
164 	0xb3, 0xc3, 0xde, 0xc3, 0x9b, 0xc2, 0x98, 0xb6, 0xd0, 0xb4,
165 	0x00, 0x95, 0x00, 0x8d, 0x00, 0xb5,
166 };
167 
168 static const unsigned char s6e8ax0_22_gamma_150[] = {
169 	0xfa, 0x01, 0x60, 0x10, 0x60, 0xb3, 0xa0, 0xc2, 0xb2, 0xd0,
170 	0xb2, 0xc1, 0xdd, 0xc2, 0x9b, 0xc2, 0x98, 0xb4, 0xcf, 0xb1,
171 	0x00, 0x99, 0x00, 0x90, 0x00, 0xba,
172 };
173 
174 static const unsigned char s6e8ax0_22_gamma_160[] = {
175 	0xfa, 0x01, 0x60, 0x10, 0x60, 0xaf, 0xa5, 0xbf, 0xb0, 0xd0,
176 	0xb1, 0xc3, 0xde, 0xc2, 0x99, 0xc1, 0x97, 0xb4, 0xce, 0xb1,
177 	0x00, 0x9c, 0x00, 0x93, 0x00, 0xbe,
178 };
179 
180 static const unsigned char s6e8ax0_22_gamma_170[] = {
181 	0xfa, 0x01, 0x60, 0x10, 0x60, 0xaf, 0xb5, 0xbf, 0xb1, 0xd1,
182 	0xb1, 0xc3, 0xde, 0xc3, 0x99, 0xc0, 0x96, 0xb4, 0xce, 0xb1,
183 	0x00, 0x9f, 0x00, 0x96, 0x00, 0xc2,
184 };
185 
186 static const unsigned char s6e8ax0_22_gamma_180[] = {
187 	0xfa, 0x01, 0x60, 0x10, 0x60, 0xaf, 0xb7, 0xbe, 0xb3, 0xd2,
188 	0xb3, 0xc3, 0xde, 0xc2, 0x97, 0xbf, 0x95, 0xb4, 0xcd, 0xb1,
189 	0x00, 0xa2, 0x00, 0x99, 0x00, 0xc5,
190 };
191 
192 static const unsigned char s6e8ax0_22_gamma_190[] = {
193 	0xfa, 0x01, 0x60, 0x10, 0x60, 0xaf, 0xb9, 0xbe, 0xb2, 0xd2,
194 	0xb2, 0xc3, 0xdd, 0xc3, 0x98, 0xbf, 0x95, 0xb2, 0xcc, 0xaf,
195 	0x00, 0xa5, 0x00, 0x9c, 0x00, 0xc9,
196 };
197 
198 static const unsigned char s6e8ax0_22_gamma_200[] = {
199 	0xfa, 0x01, 0x60, 0x10, 0x60, 0xaf, 0xb9, 0xbc, 0xb2, 0xd2,
200 	0xb1, 0xc4, 0xdd, 0xc3, 0x97, 0xbe, 0x95, 0xb1, 0xcb, 0xae,
201 	0x00, 0xa8, 0x00, 0x9f, 0x00, 0xcd,
202 };
203 
204 static const unsigned char s6e8ax0_22_gamma_210[] = {
205 	0xfa, 0x01, 0x60, 0x10, 0x60, 0xb1, 0xc1, 0xbd, 0xb1, 0xd1,
206 	0xb1, 0xc2, 0xde, 0xc2, 0x97, 0xbe, 0x94, 0xB0, 0xc9, 0xad,
207 	0x00, 0xae, 0x00, 0xa4, 0x00, 0xd4,
208 };
209 
210 static const unsigned char s6e8ax0_22_gamma_220[] = {
211 	0xfa, 0x01, 0x60, 0x10, 0x60, 0xb1, 0xc7, 0xbd, 0xb1, 0xd1,
212 	0xb1, 0xc2, 0xdd, 0xc2, 0x97, 0xbd, 0x94, 0xb0, 0xc9, 0xad,
213 	0x00, 0xad, 0x00, 0xa2, 0x00, 0xd3,
214 };
215 
216 static const unsigned char s6e8ax0_22_gamma_230[] = {
217 	0xfa, 0x01, 0x60, 0x10, 0x60, 0xb1, 0xc3, 0xbd, 0xb2, 0xd1,
218 	0xb1, 0xc3, 0xdd, 0xc1, 0x96, 0xbd, 0x94, 0xb0, 0xc9, 0xad,
219 	0x00, 0xb0, 0x00, 0xa7, 0x00, 0xd7,
220 };
221 
222 static const unsigned char s6e8ax0_22_gamma_240[] = {
223 	0xfa, 0x01, 0x60, 0x10, 0x60, 0xb1, 0xcb, 0xbd, 0xb1, 0xd2,
224 	0xb1, 0xc3, 0xdD, 0xc2, 0x95, 0xbd, 0x93, 0xaf, 0xc8, 0xab,
225 	0x00, 0xb3, 0x00, 0xa9, 0x00, 0xdb,
226 };
227 
228 static const unsigned char s6e8ax0_22_gamma_250[] = {
229 	0xfa, 0x01, 0x60, 0x10, 0x60, 0xb3, 0xcc, 0xbe, 0xb0, 0xd2,
230 	0xb0, 0xc3, 0xdD, 0xc2, 0x94, 0xbc, 0x92, 0xae, 0xc8, 0xab,
231 	0x00, 0xb6, 0x00, 0xab, 0x00, 0xde,
232 };
233 
234 static const unsigned char s6e8ax0_22_gamma_260[] = {
235 	0xfa, 0x01, 0x60, 0x10, 0x60, 0xb3, 0xd0, 0xbe, 0xaf, 0xd1,
236 	0xaf, 0xc2, 0xdd, 0xc1, 0x96, 0xbc, 0x93, 0xaf, 0xc8, 0xac,
237 	0x00, 0xb7, 0x00, 0xad, 0x00, 0xe0,
238 };
239 
240 static const unsigned char s6e8ax0_22_gamma_270[] = {
241 	0xfa, 0x01, 0x60, 0x10, 0x60, 0xb2, 0xcF, 0xbd, 0xb0, 0xd2,
242 	0xaf, 0xc2, 0xdc, 0xc1, 0x95, 0xbd, 0x93, 0xae, 0xc6, 0xaa,
243 	0x00, 0xba, 0x00, 0xb0, 0x00, 0xe4,
244 };
245 
246 static const unsigned char s6e8ax0_22_gamma_280[] = {
247 	0xfa, 0x01, 0x60, 0x10, 0x60, 0xb2, 0xd0, 0xbd, 0xaf, 0xd0,
248 	0xad, 0xc4, 0xdd, 0xc3, 0x95, 0xbd, 0x93, 0xac, 0xc5, 0xa9,
249 	0x00, 0xbd, 0x00, 0xb2, 0x00, 0xe7,
250 };
251 
252 static const unsigned char s6e8ax0_22_gamma_300[] = {
253 	0xfa, 0x01, 0x60, 0x10, 0x60, 0xb5, 0xd3, 0xbd, 0xb1, 0xd2,
254 	0xb0, 0xc0, 0xdc, 0xc0, 0x94, 0xba, 0x91, 0xac, 0xc5, 0xa9,
255 	0x00, 0xc2, 0x00, 0xb7, 0x00, 0xed,
256 };
257 
258 static const unsigned char *s6e8ax0_22_gamma_table[] = {
259 	s6e8ax0_22_gamma_30,
260 	s6e8ax0_22_gamma_50,
261 	s6e8ax0_22_gamma_60,
262 	s6e8ax0_22_gamma_70,
263 	s6e8ax0_22_gamma_80,
264 	s6e8ax0_22_gamma_90,
265 	s6e8ax0_22_gamma_100,
266 	s6e8ax0_22_gamma_120,
267 	s6e8ax0_22_gamma_130,
268 	s6e8ax0_22_gamma_140,
269 	s6e8ax0_22_gamma_150,
270 	s6e8ax0_22_gamma_160,
271 	s6e8ax0_22_gamma_170,
272 	s6e8ax0_22_gamma_180,
273 	s6e8ax0_22_gamma_190,
274 	s6e8ax0_22_gamma_200,
275 	s6e8ax0_22_gamma_210,
276 	s6e8ax0_22_gamma_220,
277 	s6e8ax0_22_gamma_230,
278 	s6e8ax0_22_gamma_240,
279 	s6e8ax0_22_gamma_250,
280 	s6e8ax0_22_gamma_260,
281 	s6e8ax0_22_gamma_270,
282 	s6e8ax0_22_gamma_280,
283 	s6e8ax0_22_gamma_300,
284 };
285 
s6e8ax0_panel_cond(struct s6e8ax0 * lcd)286 static void s6e8ax0_panel_cond(struct s6e8ax0 *lcd)
287 {
288 	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
289 
290 	static const unsigned char data_to_send[] = {
291 		0xf8, 0x3d, 0x35, 0x00, 0x00, 0x00, 0x93, 0x00, 0x3c, 0x7d,
292 		0x08, 0x27, 0x7d, 0x3f, 0x00, 0x00, 0x00, 0x20, 0x04, 0x08,
293 		0x6e, 0x00, 0x00, 0x00, 0x02, 0x08, 0x08, 0x23, 0x23, 0xc0,
294 		0xc8, 0x08, 0x48, 0xc1, 0x00, 0xc1, 0xff, 0xff, 0xc8
295 	};
296 	static const unsigned char data_to_send_panel_reverse[] = {
297 		0xf8, 0x19, 0x35, 0x00, 0x00, 0x00, 0x93, 0x00, 0x3c, 0x7d,
298 		0x08, 0x27, 0x7d, 0x3f, 0x00, 0x00, 0x00, 0x20, 0x04, 0x08,
299 		0x6e, 0x00, 0x00, 0x00, 0x02, 0x08, 0x08, 0x23, 0x23, 0xc0,
300 		0xc1, 0x01, 0x41, 0xc1, 0x00, 0xc1, 0xf6, 0xf6, 0xc1
301 	};
302 
303 	if (lcd->dsim_dev->panel_reverse)
304 		ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
305 				data_to_send_panel_reverse,
306 				ARRAY_SIZE(data_to_send_panel_reverse));
307 	else
308 		ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
309 				data_to_send, ARRAY_SIZE(data_to_send));
310 }
311 
s6e8ax0_display_cond(struct s6e8ax0 * lcd)312 static void s6e8ax0_display_cond(struct s6e8ax0 *lcd)
313 {
314 	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
315 	static const unsigned char data_to_send[] = {
316 		0xf2, 0x80, 0x03, 0x0d
317 	};
318 
319 	ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
320 		data_to_send, ARRAY_SIZE(data_to_send));
321 }
322 
323 /* Gamma 2.2 Setting (200cd, 7500K, 10MPCD) */
s6e8ax0_gamma_cond(struct s6e8ax0 * lcd)324 static void s6e8ax0_gamma_cond(struct s6e8ax0 *lcd)
325 {
326 	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
327 	unsigned int gamma = lcd->bd->props.brightness;
328 
329 	ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
330 			s6e8ax0_22_gamma_table[gamma],
331 			GAMMA_TABLE_COUNT);
332 }
333 
s6e8ax0_gamma_update(struct s6e8ax0 * lcd)334 static void s6e8ax0_gamma_update(struct s6e8ax0 *lcd)
335 {
336 	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
337 	static const unsigned char data_to_send[] = {
338 		0xf7, 0x03
339 	};
340 
341 	ops->cmd_write(lcd_to_master(lcd),
342 		MIPI_DSI_DCS_SHORT_WRITE_PARAM, data_to_send,
343 		ARRAY_SIZE(data_to_send));
344 }
345 
s6e8ax0_etc_cond1(struct s6e8ax0 * lcd)346 static void s6e8ax0_etc_cond1(struct s6e8ax0 *lcd)
347 {
348 	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
349 	static const unsigned char data_to_send[] = {
350 		0xd1, 0xfe, 0x80, 0x00, 0x01, 0x0b, 0x00, 0x00, 0x40,
351 		0x0d, 0x00, 0x00
352 	};
353 
354 	ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
355 		data_to_send, ARRAY_SIZE(data_to_send));
356 }
357 
s6e8ax0_etc_cond2(struct s6e8ax0 * lcd)358 static void s6e8ax0_etc_cond2(struct s6e8ax0 *lcd)
359 {
360 	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
361 	static const unsigned char data_to_send[] = {
362 		0xb6, 0x0c, 0x02, 0x03, 0x32, 0xff, 0x44, 0x44, 0xc0,
363 		0x00
364 	};
365 
366 	ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
367 		data_to_send, ARRAY_SIZE(data_to_send));
368 }
369 
s6e8ax0_etc_cond3(struct s6e8ax0 * lcd)370 static void s6e8ax0_etc_cond3(struct s6e8ax0 *lcd)
371 {
372 	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
373 	static const unsigned char data_to_send[] = {
374 		0xe1, 0x10, 0x1c, 0x17, 0x08, 0x1d
375 	};
376 
377 	ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
378 		data_to_send, ARRAY_SIZE(data_to_send));
379 }
380 
s6e8ax0_etc_cond4(struct s6e8ax0 * lcd)381 static void s6e8ax0_etc_cond4(struct s6e8ax0 *lcd)
382 {
383 	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
384 	static const unsigned char data_to_send[] = {
385 		0xe2, 0xed, 0x07, 0xc3, 0x13, 0x0d, 0x03
386 	};
387 
388 	ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
389 		data_to_send, ARRAY_SIZE(data_to_send));
390 }
391 
s6e8ax0_etc_cond5(struct s6e8ax0 * lcd)392 static void s6e8ax0_etc_cond5(struct s6e8ax0 *lcd)
393 {
394 	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
395 	static const unsigned char data_to_send[] = {
396 		0xf4, 0xcf, 0x0a, 0x12, 0x10, 0x19, 0x33, 0x02
397 	};
398 
399 	ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
400 		data_to_send, ARRAY_SIZE(data_to_send));
401 }
s6e8ax0_etc_cond6(struct s6e8ax0 * lcd)402 static void s6e8ax0_etc_cond6(struct s6e8ax0 *lcd)
403 {
404 	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
405 	static const unsigned char data_to_send[] = {
406 		0xe3, 0x40
407 	};
408 
409 	ops->cmd_write(lcd_to_master(lcd),
410 		MIPI_DSI_DCS_SHORT_WRITE_PARAM,
411 		data_to_send, ARRAY_SIZE(data_to_send));
412 }
413 
s6e8ax0_etc_cond7(struct s6e8ax0 * lcd)414 static void s6e8ax0_etc_cond7(struct s6e8ax0 *lcd)
415 {
416 	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
417 	static const unsigned char data_to_send[] = {
418 		0xe4, 0x00, 0x00, 0x14, 0x80, 0x00, 0x00, 0x00
419 	};
420 
421 	ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
422 		data_to_send, ARRAY_SIZE(data_to_send));
423 }
424 
s6e8ax0_elvss_set(struct s6e8ax0 * lcd)425 static void s6e8ax0_elvss_set(struct s6e8ax0 *lcd)
426 {
427 	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
428 	static const unsigned char data_to_send[] = {
429 		0xb1, 0x04, 0x00
430 	};
431 
432 	ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
433 		data_to_send, ARRAY_SIZE(data_to_send));
434 }
435 
s6e8ax0_elvss_nvm_set(struct s6e8ax0 * lcd)436 static void s6e8ax0_elvss_nvm_set(struct s6e8ax0 *lcd)
437 {
438 	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
439 	static const unsigned char data_to_send[] = {
440 		0xd9, 0x5c, 0x20, 0x0c, 0x0f, 0x41, 0x00, 0x10, 0x11,
441 		0x12, 0xd1, 0x00, 0x00, 0x00, 0x00, 0x80, 0xcb, 0xed,
442 		0x64, 0xaf
443 	};
444 
445 	ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
446 		data_to_send, ARRAY_SIZE(data_to_send));
447 }
448 
s6e8ax0_sleep_in(struct s6e8ax0 * lcd)449 static void s6e8ax0_sleep_in(struct s6e8ax0 *lcd)
450 {
451 	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
452 	static const unsigned char data_to_send[] = {
453 		0x10, 0x00
454 	};
455 
456 	ops->cmd_write(lcd_to_master(lcd),
457 		MIPI_DSI_DCS_SHORT_WRITE,
458 		data_to_send, ARRAY_SIZE(data_to_send));
459 }
460 
s6e8ax0_sleep_out(struct s6e8ax0 * lcd)461 static void s6e8ax0_sleep_out(struct s6e8ax0 *lcd)
462 {
463 	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
464 	static const unsigned char data_to_send[] = {
465 		0x11, 0x00
466 	};
467 
468 	ops->cmd_write(lcd_to_master(lcd),
469 		MIPI_DSI_DCS_SHORT_WRITE,
470 		data_to_send, ARRAY_SIZE(data_to_send));
471 }
472 
s6e8ax0_display_on(struct s6e8ax0 * lcd)473 static void s6e8ax0_display_on(struct s6e8ax0 *lcd)
474 {
475 	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
476 	static const unsigned char data_to_send[] = {
477 		0x29, 0x00
478 	};
479 
480 	ops->cmd_write(lcd_to_master(lcd),
481 		MIPI_DSI_DCS_SHORT_WRITE,
482 		data_to_send, ARRAY_SIZE(data_to_send));
483 }
484 
s6e8ax0_display_off(struct s6e8ax0 * lcd)485 static void s6e8ax0_display_off(struct s6e8ax0 *lcd)
486 {
487 	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
488 	static const unsigned char data_to_send[] = {
489 		0x28, 0x00
490 	};
491 
492 	ops->cmd_write(lcd_to_master(lcd),
493 		MIPI_DSI_DCS_SHORT_WRITE,
494 		data_to_send, ARRAY_SIZE(data_to_send));
495 }
496 
s6e8ax0_apply_level2_key(struct s6e8ax0 * lcd)497 static void s6e8ax0_apply_level2_key(struct s6e8ax0 *lcd)
498 {
499 	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
500 	static const unsigned char data_to_send[] = {
501 		0xf0, 0x5a, 0x5a
502 	};
503 
504 	ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
505 		data_to_send, ARRAY_SIZE(data_to_send));
506 }
507 
s6e8ax0_acl_on(struct s6e8ax0 * lcd)508 static void s6e8ax0_acl_on(struct s6e8ax0 *lcd)
509 {
510 	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
511 	static const unsigned char data_to_send[] = {
512 		0xc0, 0x01
513 	};
514 
515 	ops->cmd_write(lcd_to_master(lcd),
516 		MIPI_DSI_DCS_SHORT_WRITE,
517 		data_to_send, ARRAY_SIZE(data_to_send));
518 }
519 
s6e8ax0_acl_off(struct s6e8ax0 * lcd)520 static void s6e8ax0_acl_off(struct s6e8ax0 *lcd)
521 {
522 	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
523 	static const unsigned char data_to_send[] = {
524 		0xc0, 0x00
525 	};
526 
527 	ops->cmd_write(lcd_to_master(lcd),
528 		MIPI_DSI_DCS_SHORT_WRITE,
529 		data_to_send, ARRAY_SIZE(data_to_send));
530 }
531 
532 /* Full white 50% reducing setting */
s6e8ax0_acl_ctrl_set(struct s6e8ax0 * lcd)533 static void s6e8ax0_acl_ctrl_set(struct s6e8ax0 *lcd)
534 {
535 	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
536 	/* Full white 50% reducing setting */
537 	static const unsigned char cutoff_50[] = {
538 		0xc1, 0x47, 0x53, 0x13, 0x53, 0x00, 0x00, 0x02, 0xcf,
539 		0x00, 0x00, 0x04, 0xff,	0x00, 0x00, 0x00, 0x00, 0x00,
540 		0x01, 0x08, 0x0f, 0x16, 0x1d, 0x24, 0x2a, 0x31, 0x38,
541 		0x3f, 0x46
542 	};
543 	/* Full white 45% reducing setting */
544 	static const unsigned char cutoff_45[] = {
545 		0xc1, 0x47, 0x53, 0x13, 0x53, 0x00, 0x00, 0x02, 0xcf,
546 		0x00, 0x00, 0x04, 0xff,	0x00, 0x00, 0x00, 0x00, 0x00,
547 		0x01, 0x07, 0x0d, 0x13, 0x19, 0x1f, 0x25, 0x2b, 0x31,
548 		0x37, 0x3d
549 	};
550 	/* Full white 40% reducing setting */
551 	static const unsigned char cutoff_40[] = {
552 		0xc1, 0x47, 0x53, 0x13, 0x53, 0x00, 0x00, 0x02, 0xcf,
553 		0x00, 0x00, 0x04, 0xff,	0x00, 0x00, 0x00, 0x00, 0x00,
554 		0x01, 0x06, 0x0c, 0x11, 0x16, 0x1c, 0x21, 0x26, 0x2b,
555 		0x31, 0x36
556 	};
557 
558 	if (lcd->acl_enable) {
559 		if (lcd->cur_acl == 0) {
560 			if (lcd->gamma == 0 || lcd->gamma == 1) {
561 				s6e8ax0_acl_off(lcd);
562 				dev_dbg(&lcd->ld->dev,
563 					"cur_acl=%d\n", lcd->cur_acl);
564 			} else
565 				s6e8ax0_acl_on(lcd);
566 		}
567 		switch (lcd->gamma) {
568 		case 0: /* 30cd */
569 			s6e8ax0_acl_off(lcd);
570 			lcd->cur_acl = 0;
571 			break;
572 		case 1 ... 3: /* 50cd ~ 90cd */
573 			ops->cmd_write(lcd_to_master(lcd),
574 				MIPI_DSI_DCS_LONG_WRITE,
575 				cutoff_40,
576 				ARRAY_SIZE(cutoff_40));
577 			lcd->cur_acl = 40;
578 			break;
579 		case 4 ... 7: /* 120cd ~ 210cd */
580 			ops->cmd_write(lcd_to_master(lcd),
581 				MIPI_DSI_DCS_LONG_WRITE,
582 				cutoff_45,
583 				ARRAY_SIZE(cutoff_45));
584 			lcd->cur_acl = 45;
585 			break;
586 		case 8 ... 10: /* 220cd ~ 300cd */
587 			ops->cmd_write(lcd_to_master(lcd),
588 				MIPI_DSI_DCS_LONG_WRITE,
589 				cutoff_50,
590 				ARRAY_SIZE(cutoff_50));
591 			lcd->cur_acl = 50;
592 			break;
593 		default:
594 			break;
595 		}
596 	} else {
597 		s6e8ax0_acl_off(lcd);
598 		lcd->cur_acl = 0;
599 		dev_dbg(&lcd->ld->dev, "cur_acl = %d\n", lcd->cur_acl);
600 	}
601 }
602 
s6e8ax0_read_id(struct s6e8ax0 * lcd,u8 * mtp_id)603 static void s6e8ax0_read_id(struct s6e8ax0 *lcd, u8 *mtp_id)
604 {
605 	unsigned int ret;
606 	unsigned int addr = 0xd1;	/* MTP ID */
607 	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
608 
609 	ret = ops->cmd_read(lcd_to_master(lcd),
610 			MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM,
611 			addr, 3, mtp_id);
612 }
613 
s6e8ax0_panel_init(struct s6e8ax0 * lcd)614 static int s6e8ax0_panel_init(struct s6e8ax0 *lcd)
615 {
616 	s6e8ax0_apply_level2_key(lcd);
617 	s6e8ax0_sleep_out(lcd);
618 	msleep(1);
619 	s6e8ax0_panel_cond(lcd);
620 	s6e8ax0_display_cond(lcd);
621 	s6e8ax0_gamma_cond(lcd);
622 	s6e8ax0_gamma_update(lcd);
623 
624 	s6e8ax0_etc_cond1(lcd);
625 	s6e8ax0_etc_cond2(lcd);
626 	s6e8ax0_etc_cond3(lcd);
627 	s6e8ax0_etc_cond4(lcd);
628 	s6e8ax0_etc_cond5(lcd);
629 	s6e8ax0_etc_cond6(lcd);
630 	s6e8ax0_etc_cond7(lcd);
631 
632 	s6e8ax0_elvss_nvm_set(lcd);
633 	s6e8ax0_elvss_set(lcd);
634 
635 	s6e8ax0_acl_ctrl_set(lcd);
636 	s6e8ax0_acl_on(lcd);
637 
638 	/* if ID3 value is not 33h, branch private elvss mode */
639 	msleep(lcd->ddi_pd->power_on_delay);
640 
641 	return 0;
642 }
643 
s6e8ax0_update_gamma_ctrl(struct s6e8ax0 * lcd,int brightness)644 static int s6e8ax0_update_gamma_ctrl(struct s6e8ax0 *lcd, int brightness)
645 {
646 	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
647 
648 	ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
649 			s6e8ax0_22_gamma_table[brightness],
650 			ARRAY_SIZE(s6e8ax0_22_gamma_table));
651 
652 	/* update gamma table. */
653 	s6e8ax0_gamma_update(lcd);
654 	lcd->gamma = brightness;
655 
656 	return 0;
657 }
658 
s6e8ax0_gamma_ctrl(struct s6e8ax0 * lcd,int gamma)659 static int s6e8ax0_gamma_ctrl(struct s6e8ax0 *lcd, int gamma)
660 {
661 	s6e8ax0_update_gamma_ctrl(lcd, gamma);
662 
663 	return 0;
664 }
665 
s6e8ax0_set_power(struct lcd_device * ld,int power)666 static int s6e8ax0_set_power(struct lcd_device *ld, int power)
667 {
668 	struct s6e8ax0 *lcd = lcd_get_data(ld);
669 	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
670 	int ret = 0;
671 
672 	if (power != FB_BLANK_UNBLANK && power != FB_BLANK_POWERDOWN &&
673 			power != FB_BLANK_NORMAL) {
674 		dev_err(lcd->dev, "power value should be 0, 1 or 4.\n");
675 		return -EINVAL;
676 	}
677 
678 	if ((power == FB_BLANK_UNBLANK) && ops->set_blank_mode) {
679 		/* LCD power on */
680 		if ((POWER_IS_ON(power) && POWER_IS_OFF(lcd->power))
681 			|| (POWER_IS_ON(power) && POWER_IS_NRM(lcd->power))) {
682 			ret = ops->set_blank_mode(lcd_to_master(lcd), power);
683 			if (!ret && lcd->power != power)
684 				lcd->power = power;
685 		}
686 	} else if ((power == FB_BLANK_POWERDOWN) && ops->set_early_blank_mode) {
687 		/* LCD power off */
688 		if ((POWER_IS_OFF(power) && POWER_IS_ON(lcd->power)) ||
689 		(POWER_IS_ON(lcd->power) && POWER_IS_NRM(power))) {
690 			ret = ops->set_early_blank_mode(lcd_to_master(lcd),
691 							power);
692 			if (!ret && lcd->power != power)
693 				lcd->power = power;
694 		}
695 	}
696 
697 	return ret;
698 }
699 
s6e8ax0_get_power(struct lcd_device * ld)700 static int s6e8ax0_get_power(struct lcd_device *ld)
701 {
702 	struct s6e8ax0 *lcd = lcd_get_data(ld);
703 
704 	return lcd->power;
705 }
706 
s6e8ax0_set_brightness(struct backlight_device * bd)707 static int s6e8ax0_set_brightness(struct backlight_device *bd)
708 {
709 	int ret = 0, brightness = bd->props.brightness;
710 	struct s6e8ax0 *lcd = bl_get_data(bd);
711 
712 	if (brightness < MIN_BRIGHTNESS ||
713 		brightness > bd->props.max_brightness) {
714 		dev_err(lcd->dev, "lcd brightness should be %d to %d.\n",
715 			MIN_BRIGHTNESS, MAX_BRIGHTNESS);
716 		return -EINVAL;
717 	}
718 
719 	ret = s6e8ax0_gamma_ctrl(lcd, brightness);
720 	if (ret) {
721 		dev_err(&bd->dev, "lcd brightness setting failed.\n");
722 		return -EIO;
723 	}
724 
725 	return ret;
726 }
727 
728 static struct lcd_ops s6e8ax0_lcd_ops = {
729 	.set_power = s6e8ax0_set_power,
730 	.get_power = s6e8ax0_get_power,
731 };
732 
733 static const struct backlight_ops s6e8ax0_backlight_ops = {
734 	.update_status = s6e8ax0_set_brightness,
735 };
736 
s6e8ax0_power_on(struct mipi_dsim_lcd_device * dsim_dev,int power)737 static void s6e8ax0_power_on(struct mipi_dsim_lcd_device *dsim_dev, int power)
738 {
739 	struct s6e8ax0 *lcd = dev_get_drvdata(&dsim_dev->dev);
740 
741 	msleep(lcd->ddi_pd->power_on_delay);
742 
743 	/* lcd power on */
744 	if (power)
745 		s6e8ax0_regulator_enable(lcd);
746 	else
747 		s6e8ax0_regulator_disable(lcd);
748 
749 	msleep(lcd->ddi_pd->reset_delay);
750 
751 	/* lcd reset */
752 	if (lcd->ddi_pd->reset)
753 		lcd->ddi_pd->reset(lcd->ld);
754 	msleep(5);
755 }
756 
s6e8ax0_set_sequence(struct mipi_dsim_lcd_device * dsim_dev)757 static void s6e8ax0_set_sequence(struct mipi_dsim_lcd_device *dsim_dev)
758 {
759 	struct s6e8ax0 *lcd = dev_get_drvdata(&dsim_dev->dev);
760 
761 	s6e8ax0_panel_init(lcd);
762 	s6e8ax0_display_on(lcd);
763 
764 	lcd->power = FB_BLANK_UNBLANK;
765 }
766 
s6e8ax0_probe(struct mipi_dsim_lcd_device * dsim_dev)767 static int s6e8ax0_probe(struct mipi_dsim_lcd_device *dsim_dev)
768 {
769 	struct s6e8ax0 *lcd;
770 	int ret;
771 	u8 mtp_id[3] = {0, };
772 
773 	lcd = devm_kzalloc(&dsim_dev->dev, sizeof(struct s6e8ax0), GFP_KERNEL);
774 	if (!lcd) {
775 		dev_err(&dsim_dev->dev, "failed to allocate s6e8ax0 structure.\n");
776 		return -ENOMEM;
777 	}
778 
779 	lcd->dsim_dev = dsim_dev;
780 	lcd->ddi_pd = (struct lcd_platform_data *)dsim_dev->platform_data;
781 	lcd->dev = &dsim_dev->dev;
782 
783 	mutex_init(&lcd->lock);
784 
785 	ret = devm_regulator_bulk_get(lcd->dev, ARRAY_SIZE(supplies), supplies);
786 	if (ret) {
787 		dev_err(lcd->dev, "Failed to get regulators: %d\n", ret);
788 		return ret;
789 	}
790 
791 	lcd->ld = devm_lcd_device_register(lcd->dev, "s6e8ax0", lcd->dev, lcd,
792 			&s6e8ax0_lcd_ops);
793 	if (IS_ERR(lcd->ld)) {
794 		dev_err(lcd->dev, "failed to register lcd ops.\n");
795 		return PTR_ERR(lcd->ld);
796 	}
797 
798 	lcd->bd = devm_backlight_device_register(lcd->dev, "s6e8ax0-bl",
799 				lcd->dev, lcd, &s6e8ax0_backlight_ops, NULL);
800 	if (IS_ERR(lcd->bd)) {
801 		dev_err(lcd->dev, "failed to register backlight ops.\n");
802 		return PTR_ERR(lcd->bd);
803 	}
804 
805 	lcd->bd->props.max_brightness = MAX_BRIGHTNESS;
806 	lcd->bd->props.brightness = MAX_BRIGHTNESS;
807 
808 	s6e8ax0_read_id(lcd, mtp_id);
809 	if (mtp_id[0] == 0x00)
810 		dev_err(lcd->dev, "read id failed\n");
811 
812 	dev_info(lcd->dev, "Read ID : %x, %x, %x\n",
813 			mtp_id[0], mtp_id[1], mtp_id[2]);
814 
815 	if (mtp_id[2] == 0x33)
816 		dev_info(lcd->dev,
817 			"ID-3 is 0xff does not support dynamic elvss\n");
818 	else
819 		dev_info(lcd->dev,
820 			"ID-3 is 0x%x support dynamic elvss\n", mtp_id[2]);
821 
822 	lcd->acl_enable = 1;
823 	lcd->cur_acl = 0;
824 
825 	dev_set_drvdata(&dsim_dev->dev, lcd);
826 
827 	dev_dbg(lcd->dev, "probed s6e8ax0 panel driver.\n");
828 
829 	return 0;
830 }
831 
832 #ifdef CONFIG_PM
s6e8ax0_suspend(struct mipi_dsim_lcd_device * dsim_dev)833 static int s6e8ax0_suspend(struct mipi_dsim_lcd_device *dsim_dev)
834 {
835 	struct s6e8ax0 *lcd = dev_get_drvdata(&dsim_dev->dev);
836 
837 	s6e8ax0_sleep_in(lcd);
838 	msleep(lcd->ddi_pd->power_off_delay);
839 	s6e8ax0_display_off(lcd);
840 
841 	s6e8ax0_regulator_disable(lcd);
842 
843 	return 0;
844 }
845 
s6e8ax0_resume(struct mipi_dsim_lcd_device * dsim_dev)846 static int s6e8ax0_resume(struct mipi_dsim_lcd_device *dsim_dev)
847 {
848 	struct s6e8ax0 *lcd = dev_get_drvdata(&dsim_dev->dev);
849 
850 	s6e8ax0_sleep_out(lcd);
851 	msleep(lcd->ddi_pd->power_on_delay);
852 
853 	s6e8ax0_regulator_enable(lcd);
854 	s6e8ax0_set_sequence(dsim_dev);
855 
856 	return 0;
857 }
858 #else
859 #define s6e8ax0_suspend		NULL
860 #define s6e8ax0_resume		NULL
861 #endif
862 
863 static struct mipi_dsim_lcd_driver s6e8ax0_dsim_ddi_driver = {
864 	.name = "s6e8ax0",
865 	.id = -1,
866 
867 	.power_on = s6e8ax0_power_on,
868 	.set_sequence = s6e8ax0_set_sequence,
869 	.probe = s6e8ax0_probe,
870 	.suspend = s6e8ax0_suspend,
871 	.resume = s6e8ax0_resume,
872 };
873 
s6e8ax0_init(void)874 static int s6e8ax0_init(void)
875 {
876 	exynos_mipi_dsi_register_lcd_driver(&s6e8ax0_dsim_ddi_driver);
877 
878 	return 0;
879 }
880 
s6e8ax0_exit(void)881 static void s6e8ax0_exit(void)
882 {
883 	return;
884 }
885 
886 module_init(s6e8ax0_init);
887 module_exit(s6e8ax0_exit);
888 
889 MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>");
890 MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
891 MODULE_DESCRIPTION("MIPI-DSI based s6e8ax0 AMOLED LCD Panel Driver");
892 MODULE_LICENSE("GPL");
893