• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
297 	ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
298 		data_to_send, ARRAY_SIZE(data_to_send));
299 }
300 
s6e8ax0_display_cond(struct s6e8ax0 * lcd)301 static void s6e8ax0_display_cond(struct s6e8ax0 *lcd)
302 {
303 	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
304 	static const unsigned char data_to_send[] = {
305 		0xf2, 0x80, 0x03, 0x0d
306 	};
307 
308 	ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
309 		data_to_send, ARRAY_SIZE(data_to_send));
310 }
311 
312 /* Gamma 2.2 Setting (200cd, 7500K, 10MPCD) */
s6e8ax0_gamma_cond(struct s6e8ax0 * lcd)313 static void s6e8ax0_gamma_cond(struct s6e8ax0 *lcd)
314 {
315 	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
316 	unsigned int gamma = lcd->bd->props.brightness;
317 
318 	ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
319 			s6e8ax0_22_gamma_table[gamma],
320 			GAMMA_TABLE_COUNT);
321 }
322 
s6e8ax0_gamma_update(struct s6e8ax0 * lcd)323 static void s6e8ax0_gamma_update(struct s6e8ax0 *lcd)
324 {
325 	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
326 	static const unsigned char data_to_send[] = {
327 		0xf7, 0x03
328 	};
329 
330 	ops->cmd_write(lcd_to_master(lcd),
331 		MIPI_DSI_DCS_SHORT_WRITE_PARAM, data_to_send,
332 		ARRAY_SIZE(data_to_send));
333 }
334 
s6e8ax0_etc_cond1(struct s6e8ax0 * lcd)335 static void s6e8ax0_etc_cond1(struct s6e8ax0 *lcd)
336 {
337 	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
338 	static const unsigned char data_to_send[] = {
339 		0xd1, 0xfe, 0x80, 0x00, 0x01, 0x0b, 0x00, 0x00, 0x40,
340 		0x0d, 0x00, 0x00
341 	};
342 
343 	ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
344 		data_to_send, ARRAY_SIZE(data_to_send));
345 }
346 
s6e8ax0_etc_cond2(struct s6e8ax0 * lcd)347 static void s6e8ax0_etc_cond2(struct s6e8ax0 *lcd)
348 {
349 	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
350 	static const unsigned char data_to_send[] = {
351 		0xb6, 0x0c, 0x02, 0x03, 0x32, 0xff, 0x44, 0x44, 0xc0,
352 		0x00
353 	};
354 
355 	ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
356 		data_to_send, ARRAY_SIZE(data_to_send));
357 }
358 
s6e8ax0_etc_cond3(struct s6e8ax0 * lcd)359 static void s6e8ax0_etc_cond3(struct s6e8ax0 *lcd)
360 {
361 	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
362 	static const unsigned char data_to_send[] = {
363 		0xe1, 0x10, 0x1c, 0x17, 0x08, 0x1d
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_cond4(struct s6e8ax0 * lcd)370 static void s6e8ax0_etc_cond4(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 		0xe2, 0xed, 0x07, 0xc3, 0x13, 0x0d, 0x03
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_cond5(struct s6e8ax0 * lcd)381 static void s6e8ax0_etc_cond5(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 		0xf4, 0xcf, 0x0a, 0x12, 0x10, 0x19, 0x33, 0x02
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 }
s6e8ax0_etc_cond6(struct s6e8ax0 * lcd)391 static void s6e8ax0_etc_cond6(struct s6e8ax0 *lcd)
392 {
393 	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
394 	static const unsigned char data_to_send[] = {
395 		0xe3, 0x40
396 	};
397 
398 	ops->cmd_write(lcd_to_master(lcd),
399 		MIPI_DSI_DCS_SHORT_WRITE_PARAM,
400 		data_to_send, ARRAY_SIZE(data_to_send));
401 }
402 
s6e8ax0_etc_cond7(struct s6e8ax0 * lcd)403 static void s6e8ax0_etc_cond7(struct s6e8ax0 *lcd)
404 {
405 	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
406 	static const unsigned char data_to_send[] = {
407 		0xe4, 0x00, 0x00, 0x14, 0x80, 0x00, 0x00, 0x00
408 	};
409 
410 	ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
411 		data_to_send, ARRAY_SIZE(data_to_send));
412 }
413 
s6e8ax0_elvss_set(struct s6e8ax0 * lcd)414 static void s6e8ax0_elvss_set(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 		0xb1, 0x04, 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_nvm_set(struct s6e8ax0 * lcd)425 static void s6e8ax0_elvss_nvm_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 		0xd9, 0x5c, 0x20, 0x0c, 0x0f, 0x41, 0x00, 0x10, 0x11,
430 		0x12, 0xd1, 0x00, 0x00, 0x00, 0x00, 0x80, 0xcb, 0xed,
431 		0x64, 0xaf
432 	};
433 
434 	ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
435 		data_to_send, ARRAY_SIZE(data_to_send));
436 }
437 
s6e8ax0_sleep_in(struct s6e8ax0 * lcd)438 static void s6e8ax0_sleep_in(struct s6e8ax0 *lcd)
439 {
440 	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
441 	static const unsigned char data_to_send[] = {
442 		0x10, 0x00
443 	};
444 
445 	ops->cmd_write(lcd_to_master(lcd),
446 		MIPI_DSI_DCS_SHORT_WRITE,
447 		data_to_send, ARRAY_SIZE(data_to_send));
448 }
449 
s6e8ax0_sleep_out(struct s6e8ax0 * lcd)450 static void s6e8ax0_sleep_out(struct s6e8ax0 *lcd)
451 {
452 	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
453 	static const unsigned char data_to_send[] = {
454 		0x11, 0x00
455 	};
456 
457 	ops->cmd_write(lcd_to_master(lcd),
458 		MIPI_DSI_DCS_SHORT_WRITE,
459 		data_to_send, ARRAY_SIZE(data_to_send));
460 }
461 
s6e8ax0_display_on(struct s6e8ax0 * lcd)462 static void s6e8ax0_display_on(struct s6e8ax0 *lcd)
463 {
464 	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
465 	static const unsigned char data_to_send[] = {
466 		0x29, 0x00
467 	};
468 
469 	ops->cmd_write(lcd_to_master(lcd),
470 		MIPI_DSI_DCS_SHORT_WRITE,
471 		data_to_send, ARRAY_SIZE(data_to_send));
472 }
473 
s6e8ax0_display_off(struct s6e8ax0 * lcd)474 static void s6e8ax0_display_off(struct s6e8ax0 *lcd)
475 {
476 	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
477 	static const unsigned char data_to_send[] = {
478 		0x28, 0x00
479 	};
480 
481 	ops->cmd_write(lcd_to_master(lcd),
482 		MIPI_DSI_DCS_SHORT_WRITE,
483 		data_to_send, ARRAY_SIZE(data_to_send));
484 }
485 
s6e8ax0_apply_level2_key(struct s6e8ax0 * lcd)486 static void s6e8ax0_apply_level2_key(struct s6e8ax0 *lcd)
487 {
488 	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
489 	static const unsigned char data_to_send[] = {
490 		0xf0, 0x5a, 0x5a
491 	};
492 
493 	ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
494 		data_to_send, ARRAY_SIZE(data_to_send));
495 }
496 
s6e8ax0_acl_on(struct s6e8ax0 * lcd)497 static void s6e8ax0_acl_on(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 		0xc0, 0x01
502 	};
503 
504 	ops->cmd_write(lcd_to_master(lcd),
505 		MIPI_DSI_DCS_SHORT_WRITE,
506 		data_to_send, ARRAY_SIZE(data_to_send));
507 }
508 
s6e8ax0_acl_off(struct s6e8ax0 * lcd)509 static void s6e8ax0_acl_off(struct s6e8ax0 *lcd)
510 {
511 	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
512 	static const unsigned char data_to_send[] = {
513 		0xc0, 0x00
514 	};
515 
516 	ops->cmd_write(lcd_to_master(lcd),
517 		MIPI_DSI_DCS_SHORT_WRITE,
518 		data_to_send, ARRAY_SIZE(data_to_send));
519 }
520 
521 /* Full white 50% reducing setting */
s6e8ax0_acl_ctrl_set(struct s6e8ax0 * lcd)522 static void s6e8ax0_acl_ctrl_set(struct s6e8ax0 *lcd)
523 {
524 	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
525 	/* Full white 50% reducing setting */
526 	static const unsigned char cutoff_50[] = {
527 		0xc1, 0x47, 0x53, 0x13, 0x53, 0x00, 0x00, 0x02, 0xcf,
528 		0x00, 0x00, 0x04, 0xff,	0x00, 0x00, 0x00, 0x00, 0x00,
529 		0x01, 0x08, 0x0f, 0x16, 0x1d, 0x24, 0x2a, 0x31, 0x38,
530 		0x3f, 0x46
531 	};
532 	/* Full white 45% reducing setting */
533 	static const unsigned char cutoff_45[] = {
534 		0xc1, 0x47, 0x53, 0x13, 0x53, 0x00, 0x00, 0x02, 0xcf,
535 		0x00, 0x00, 0x04, 0xff,	0x00, 0x00, 0x00, 0x00, 0x00,
536 		0x01, 0x07, 0x0d, 0x13, 0x19, 0x1f, 0x25, 0x2b, 0x31,
537 		0x37, 0x3d
538 	};
539 	/* Full white 40% reducing setting */
540 	static const unsigned char cutoff_40[] = {
541 		0xc1, 0x47, 0x53, 0x13, 0x53, 0x00, 0x00, 0x02, 0xcf,
542 		0x00, 0x00, 0x04, 0xff,	0x00, 0x00, 0x00, 0x00, 0x00,
543 		0x01, 0x06, 0x0c, 0x11, 0x16, 0x1c, 0x21, 0x26, 0x2b,
544 		0x31, 0x36
545 	};
546 
547 	if (lcd->acl_enable) {
548 		if (lcd->cur_acl == 0) {
549 			if (lcd->gamma == 0 || lcd->gamma == 1) {
550 				s6e8ax0_acl_off(lcd);
551 				dev_dbg(&lcd->ld->dev,
552 					"cur_acl=%d\n", lcd->cur_acl);
553 			} else
554 				s6e8ax0_acl_on(lcd);
555 		}
556 		switch (lcd->gamma) {
557 		case 0: /* 30cd */
558 			s6e8ax0_acl_off(lcd);
559 			lcd->cur_acl = 0;
560 			break;
561 		case 1 ... 3: /* 50cd ~ 90cd */
562 			ops->cmd_write(lcd_to_master(lcd),
563 				MIPI_DSI_DCS_LONG_WRITE,
564 				cutoff_40,
565 				ARRAY_SIZE(cutoff_40));
566 			lcd->cur_acl = 40;
567 			break;
568 		case 4 ... 7: /* 120cd ~ 210cd */
569 			ops->cmd_write(lcd_to_master(lcd),
570 				MIPI_DSI_DCS_LONG_WRITE,
571 				cutoff_45,
572 				ARRAY_SIZE(cutoff_45));
573 			lcd->cur_acl = 45;
574 			break;
575 		case 8 ... 10: /* 220cd ~ 300cd */
576 			ops->cmd_write(lcd_to_master(lcd),
577 				MIPI_DSI_DCS_LONG_WRITE,
578 				cutoff_50,
579 				ARRAY_SIZE(cutoff_50));
580 			lcd->cur_acl = 50;
581 			break;
582 		default:
583 			break;
584 		}
585 	} else {
586 		s6e8ax0_acl_off(lcd);
587 		lcd->cur_acl = 0;
588 		dev_dbg(&lcd->ld->dev, "cur_acl = %d\n", lcd->cur_acl);
589 	}
590 }
591 
s6e8ax0_read_id(struct s6e8ax0 * lcd,u8 * mtp_id)592 static void s6e8ax0_read_id(struct s6e8ax0 *lcd, u8 *mtp_id)
593 {
594 	unsigned int ret;
595 	unsigned int addr = 0xd1;	/* MTP ID */
596 	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
597 
598 	ret = ops->cmd_read(lcd_to_master(lcd),
599 			MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM,
600 			addr, 3, mtp_id);
601 }
602 
s6e8ax0_panel_init(struct s6e8ax0 * lcd)603 static int s6e8ax0_panel_init(struct s6e8ax0 *lcd)
604 {
605 	s6e8ax0_apply_level2_key(lcd);
606 	s6e8ax0_sleep_out(lcd);
607 	msleep(1);
608 	s6e8ax0_panel_cond(lcd);
609 	s6e8ax0_display_cond(lcd);
610 	s6e8ax0_gamma_cond(lcd);
611 	s6e8ax0_gamma_update(lcd);
612 
613 	s6e8ax0_etc_cond1(lcd);
614 	s6e8ax0_etc_cond2(lcd);
615 	s6e8ax0_etc_cond3(lcd);
616 	s6e8ax0_etc_cond4(lcd);
617 	s6e8ax0_etc_cond5(lcd);
618 	s6e8ax0_etc_cond6(lcd);
619 	s6e8ax0_etc_cond7(lcd);
620 
621 	s6e8ax0_elvss_nvm_set(lcd);
622 	s6e8ax0_elvss_set(lcd);
623 
624 	s6e8ax0_acl_ctrl_set(lcd);
625 	s6e8ax0_acl_on(lcd);
626 
627 	/* if ID3 value is not 33h, branch private elvss mode */
628 	msleep(lcd->ddi_pd->power_on_delay);
629 
630 	return 0;
631 }
632 
s6e8ax0_update_gamma_ctrl(struct s6e8ax0 * lcd,int brightness)633 static int s6e8ax0_update_gamma_ctrl(struct s6e8ax0 *lcd, int brightness)
634 {
635 	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
636 
637 	ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
638 			s6e8ax0_22_gamma_table[brightness],
639 			ARRAY_SIZE(s6e8ax0_22_gamma_table));
640 
641 	/* update gamma table. */
642 	s6e8ax0_gamma_update(lcd);
643 	lcd->gamma = brightness;
644 
645 	return 0;
646 }
647 
s6e8ax0_gamma_ctrl(struct s6e8ax0 * lcd,int gamma)648 static int s6e8ax0_gamma_ctrl(struct s6e8ax0 *lcd, int gamma)
649 {
650 	s6e8ax0_update_gamma_ctrl(lcd, gamma);
651 
652 	return 0;
653 }
654 
s6e8ax0_set_power(struct lcd_device * ld,int power)655 static int s6e8ax0_set_power(struct lcd_device *ld, int power)
656 {
657 	struct s6e8ax0 *lcd = lcd_get_data(ld);
658 	struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
659 	int ret = 0;
660 
661 	if (power != FB_BLANK_UNBLANK && power != FB_BLANK_POWERDOWN &&
662 			power != FB_BLANK_NORMAL) {
663 		dev_err(lcd->dev, "power value should be 0, 1 or 4.\n");
664 		return -EINVAL;
665 	}
666 
667 	if ((power == FB_BLANK_UNBLANK) && ops->set_blank_mode) {
668 		/* LCD power on */
669 		if ((POWER_IS_ON(power) && POWER_IS_OFF(lcd->power))
670 			|| (POWER_IS_ON(power) && POWER_IS_NRM(lcd->power))) {
671 			ret = ops->set_blank_mode(lcd_to_master(lcd), power);
672 			if (!ret && lcd->power != power)
673 				lcd->power = power;
674 		}
675 	} else if ((power == FB_BLANK_POWERDOWN) && ops->set_early_blank_mode) {
676 		/* LCD power off */
677 		if ((POWER_IS_OFF(power) && POWER_IS_ON(lcd->power)) ||
678 		(POWER_IS_ON(lcd->power) && POWER_IS_NRM(power))) {
679 			ret = ops->set_early_blank_mode(lcd_to_master(lcd),
680 							power);
681 			if (!ret && lcd->power != power)
682 				lcd->power = power;
683 		}
684 	}
685 
686 	return ret;
687 }
688 
s6e8ax0_get_power(struct lcd_device * ld)689 static int s6e8ax0_get_power(struct lcd_device *ld)
690 {
691 	struct s6e8ax0 *lcd = lcd_get_data(ld);
692 
693 	return lcd->power;
694 }
695 
s6e8ax0_get_brightness(struct backlight_device * bd)696 static int s6e8ax0_get_brightness(struct backlight_device *bd)
697 {
698 	return bd->props.brightness;
699 }
700 
s6e8ax0_set_brightness(struct backlight_device * bd)701 static int s6e8ax0_set_brightness(struct backlight_device *bd)
702 {
703 	int ret = 0, brightness = bd->props.brightness;
704 	struct s6e8ax0 *lcd = bl_get_data(bd);
705 
706 	if (brightness < MIN_BRIGHTNESS ||
707 		brightness > bd->props.max_brightness) {
708 		dev_err(lcd->dev, "lcd brightness should be %d to %d.\n",
709 			MIN_BRIGHTNESS, MAX_BRIGHTNESS);
710 		return -EINVAL;
711 	}
712 
713 	ret = s6e8ax0_gamma_ctrl(lcd, brightness);
714 	if (ret) {
715 		dev_err(&bd->dev, "lcd brightness setting failed.\n");
716 		return -EIO;
717 	}
718 
719 	return ret;
720 }
721 
722 static struct lcd_ops s6e8ax0_lcd_ops = {
723 	.set_power = s6e8ax0_set_power,
724 	.get_power = s6e8ax0_get_power,
725 };
726 
727 static const struct backlight_ops s6e8ax0_backlight_ops = {
728 	.get_brightness = s6e8ax0_get_brightness,
729 	.update_status = s6e8ax0_set_brightness,
730 };
731 
s6e8ax0_power_on(struct mipi_dsim_lcd_device * dsim_dev,int power)732 static void s6e8ax0_power_on(struct mipi_dsim_lcd_device *dsim_dev, int power)
733 {
734 	struct s6e8ax0 *lcd = dev_get_drvdata(&dsim_dev->dev);
735 
736 	msleep(lcd->ddi_pd->power_on_delay);
737 
738 	/* lcd power on */
739 	if (power)
740 		s6e8ax0_regulator_enable(lcd);
741 	else
742 		s6e8ax0_regulator_disable(lcd);
743 
744 	msleep(lcd->ddi_pd->reset_delay);
745 
746 	/* lcd reset */
747 	if (lcd->ddi_pd->reset)
748 		lcd->ddi_pd->reset(lcd->ld);
749 	msleep(5);
750 }
751 
s6e8ax0_set_sequence(struct mipi_dsim_lcd_device * dsim_dev)752 static void s6e8ax0_set_sequence(struct mipi_dsim_lcd_device *dsim_dev)
753 {
754 	struct s6e8ax0 *lcd = dev_get_drvdata(&dsim_dev->dev);
755 
756 	s6e8ax0_panel_init(lcd);
757 	s6e8ax0_display_on(lcd);
758 
759 	lcd->power = FB_BLANK_UNBLANK;
760 }
761 
s6e8ax0_probe(struct mipi_dsim_lcd_device * dsim_dev)762 static int s6e8ax0_probe(struct mipi_dsim_lcd_device *dsim_dev)
763 {
764 	struct s6e8ax0 *lcd;
765 	int ret;
766 	u8 mtp_id[3] = {0, };
767 
768 	lcd = kzalloc(sizeof(struct s6e8ax0), GFP_KERNEL);
769 	if (!lcd) {
770 		dev_err(&dsim_dev->dev, "failed to allocate s6e8ax0 structure.\n");
771 		return -ENOMEM;
772 	}
773 
774 	lcd->dsim_dev = dsim_dev;
775 	lcd->ddi_pd = (struct lcd_platform_data *)dsim_dev->platform_data;
776 	lcd->dev = &dsim_dev->dev;
777 
778 	mutex_init(&lcd->lock);
779 
780 	ret = regulator_bulk_get(lcd->dev, ARRAY_SIZE(supplies), supplies);
781 	if (ret) {
782 		dev_err(lcd->dev, "Failed to get regulators: %d\n", ret);
783 		goto err_lcd_register;
784 	}
785 
786 	lcd->ld = lcd_device_register("s6e8ax0", lcd->dev, lcd,
787 			&s6e8ax0_lcd_ops);
788 	if (IS_ERR(lcd->ld)) {
789 		dev_err(lcd->dev, "failed to register lcd ops.\n");
790 		ret = PTR_ERR(lcd->ld);
791 		goto err_lcd_register;
792 	}
793 
794 	lcd->bd = backlight_device_register("s6e8ax0-bl", lcd->dev, lcd,
795 			&s6e8ax0_backlight_ops, NULL);
796 	if (IS_ERR(lcd->bd)) {
797 		dev_err(lcd->dev, "failed to register backlight ops.\n");
798 		ret = PTR_ERR(lcd->bd);
799 		goto err_backlight_register;
800 	}
801 
802 	lcd->bd->props.max_brightness = MAX_BRIGHTNESS;
803 	lcd->bd->props.brightness = MAX_BRIGHTNESS;
804 
805 	s6e8ax0_read_id(lcd, mtp_id);
806 	if (mtp_id[0] == 0x00)
807 		dev_err(lcd->dev, "read id failed\n");
808 
809 	dev_info(lcd->dev, "Read ID : %x, %x, %x\n",
810 			mtp_id[0], mtp_id[1], mtp_id[2]);
811 
812 	if (mtp_id[2] == 0x33)
813 		dev_info(lcd->dev,
814 			"ID-3 is 0xff does not support dynamic elvss\n");
815 	else
816 		dev_info(lcd->dev,
817 			"ID-3 is 0x%x support dynamic elvss\n", mtp_id[2]);
818 
819 	lcd->acl_enable = 1;
820 	lcd->cur_acl = 0;
821 
822 	dev_set_drvdata(&dsim_dev->dev, lcd);
823 
824 	dev_dbg(lcd->dev, "probed s6e8ax0 panel driver.\n");
825 
826 	return 0;
827 
828 err_backlight_register:
829 	lcd_device_unregister(lcd->ld);
830 
831 err_lcd_register:
832 	regulator_bulk_free(ARRAY_SIZE(supplies), supplies);
833 	kfree(lcd);
834 
835 	return ret;
836 }
837 
838 #ifdef CONFIG_PM
s6e8ax0_suspend(struct mipi_dsim_lcd_device * dsim_dev)839 static int s6e8ax0_suspend(struct mipi_dsim_lcd_device *dsim_dev)
840 {
841 	struct s6e8ax0 *lcd = dev_get_drvdata(&dsim_dev->dev);
842 
843 	s6e8ax0_sleep_in(lcd);
844 	msleep(lcd->ddi_pd->power_off_delay);
845 	s6e8ax0_display_off(lcd);
846 
847 	s6e8ax0_regulator_disable(lcd);
848 
849 	return 0;
850 }
851 
s6e8ax0_resume(struct mipi_dsim_lcd_device * dsim_dev)852 static int s6e8ax0_resume(struct mipi_dsim_lcd_device *dsim_dev)
853 {
854 	struct s6e8ax0 *lcd = dev_get_drvdata(&dsim_dev->dev);
855 
856 	s6e8ax0_sleep_out(lcd);
857 	msleep(lcd->ddi_pd->power_on_delay);
858 
859 	s6e8ax0_regulator_enable(lcd);
860 	s6e8ax0_set_sequence(dsim_dev);
861 
862 	return 0;
863 }
864 #else
865 #define s6e8ax0_suspend		NULL
866 #define s6e8ax0_resume		NULL
867 #endif
868 
869 static struct mipi_dsim_lcd_driver s6e8ax0_dsim_ddi_driver = {
870 	.name = "s6e8ax0",
871 	.id = -1,
872 
873 	.power_on = s6e8ax0_power_on,
874 	.set_sequence = s6e8ax0_set_sequence,
875 	.probe = s6e8ax0_probe,
876 	.suspend = s6e8ax0_suspend,
877 	.resume = s6e8ax0_resume,
878 };
879 
s6e8ax0_init(void)880 static int s6e8ax0_init(void)
881 {
882 	exynos_mipi_dsi_register_lcd_driver(&s6e8ax0_dsim_ddi_driver);
883 
884 	return 0;
885 }
886 
s6e8ax0_exit(void)887 static void s6e8ax0_exit(void)
888 {
889 	return;
890 }
891 
892 module_init(s6e8ax0_init);
893 module_exit(s6e8ax0_exit);
894 
895 MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>");
896 MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
897 MODULE_DESCRIPTION("MIPI-DSI based s6e8ax0 AMOLED LCD Panel Driver");
898 MODULE_LICENSE("GPL");
899