Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / drivers / video / fbdev / exynos / s6e8ax0.c
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
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
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
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
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) */
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
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
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
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
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
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
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 }
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
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
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
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
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
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
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
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
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
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
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 */
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
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
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
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
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
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
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
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
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
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
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
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
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
874 static int s6e8ax0_init(void)
875 {
876         exynos_mipi_dsi_register_lcd_driver(&s6e8ax0_dsim_ddi_driver);
877
878         return 0;
879 }
880
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");