gpio/tca6424: merge I2C transactions, remove cast
[linux-2.6-block.git] / drivers / video / 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
297         ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
298                 data_to_send, ARRAY_SIZE(data_to_send));
299 }
300
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) */
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
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
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
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
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
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
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 }
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
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
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
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
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
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
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
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
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
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
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 */
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
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
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
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
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
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
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
696 static int s6e8ax0_get_brightness(struct backlight_device *bd)
697 {
698         return bd->props.brightness;
699 }
700
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
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
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
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
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
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
880 static int s6e8ax0_init(void)
881 {
882         exynos_mipi_dsi_register_lcd_driver(&s6e8ax0_dsim_ddi_driver);
883
884         return 0;
885 }
886
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");