Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
s6e8ax0.c
Go to the documentation of this file.
1 /* linux/drivers/video/exynos/s6e8ax0.c
2  *
3  * MIPI-DSI based s6e8ax0 AMOLED lcd 4.65 inch panel driver.
4  *
5  * Inki Dae, <[email protected]>
6  * Donghwa Lee, <[email protected]>
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>
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 {
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;
60 
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  }
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 {
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)
305  data_to_send_panel_reverse,
306  ARRAY_SIZE(data_to_send_panel_reverse));
307  else
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 
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 
330  s6e8ax0_22_gamma_table[gamma],
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 
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 
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 
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 
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 
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),
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 
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 
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 
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),
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),
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),
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),
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 
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),
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),
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),
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),
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),
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),
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 
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_get_brightness(struct backlight_device *bd)
708 {
709  return bd->props.brightness;
710 }
711 
712 static int s6e8ax0_set_brightness(struct backlight_device *bd)
713 {
714  int ret = 0, brightness = bd->props.brightness;
715  struct s6e8ax0 *lcd = bl_get_data(bd);
716 
717  if (brightness < MIN_BRIGHTNESS ||
718  brightness > bd->props.max_brightness) {
719  dev_err(lcd->dev, "lcd brightness should be %d to %d.\n",
721  return -EINVAL;
722  }
723 
724  ret = s6e8ax0_gamma_ctrl(lcd, brightness);
725  if (ret) {
726  dev_err(&bd->dev, "lcd brightness setting failed.\n");
727  return -EIO;
728  }
729 
730  return ret;
731 }
732 
733 static struct lcd_ops s6e8ax0_lcd_ops = {
734  .set_power = s6e8ax0_set_power,
735  .get_power = s6e8ax0_get_power,
736 };
737 
738 static const struct backlight_ops s6e8ax0_backlight_ops = {
739  .get_brightness = s6e8ax0_get_brightness,
740  .update_status = s6e8ax0_set_brightness,
741 };
742 
743 static void s6e8ax0_power_on(struct mipi_dsim_lcd_device *dsim_dev, int power)
744 {
745  struct s6e8ax0 *lcd = dev_get_drvdata(&dsim_dev->dev);
746 
747  msleep(lcd->ddi_pd->power_on_delay);
748 
749  /* lcd power on */
750  if (power)
751  s6e8ax0_regulator_enable(lcd);
752  else
753  s6e8ax0_regulator_disable(lcd);
754 
755  msleep(lcd->ddi_pd->reset_delay);
756 
757  /* lcd reset */
758  if (lcd->ddi_pd->reset)
759  lcd->ddi_pd->reset(lcd->ld);
760  msleep(5);
761 }
762 
763 static void s6e8ax0_set_sequence(struct mipi_dsim_lcd_device *dsim_dev)
764 {
765  struct s6e8ax0 *lcd = dev_get_drvdata(&dsim_dev->dev);
766 
767  s6e8ax0_panel_init(lcd);
768  s6e8ax0_display_on(lcd);
769 
770  lcd->power = FB_BLANK_UNBLANK;
771 }
772 
773 static int s6e8ax0_probe(struct mipi_dsim_lcd_device *dsim_dev)
774 {
775  struct s6e8ax0 *lcd;
776  int ret;
777  u8 mtp_id[3] = {0, };
778 
779  lcd = kzalloc(sizeof(struct s6e8ax0), GFP_KERNEL);
780  if (!lcd) {
781  dev_err(&dsim_dev->dev, "failed to allocate s6e8ax0 structure.\n");
782  return -ENOMEM;
783  }
784 
785  lcd->dsim_dev = dsim_dev;
786  lcd->ddi_pd = (struct lcd_platform_data *)dsim_dev->platform_data;
787  lcd->dev = &dsim_dev->dev;
788 
789  mutex_init(&lcd->lock);
790 
791  ret = regulator_bulk_get(lcd->dev, ARRAY_SIZE(supplies), supplies);
792  if (ret) {
793  dev_err(lcd->dev, "Failed to get regulators: %d\n", ret);
794  goto err_lcd_register;
795  }
796 
797  lcd->ld = lcd_device_register("s6e8ax0", lcd->dev, lcd,
798  &s6e8ax0_lcd_ops);
799  if (IS_ERR(lcd->ld)) {
800  dev_err(lcd->dev, "failed to register lcd ops.\n");
801  ret = PTR_ERR(lcd->ld);
802  goto err_lcd_register;
803  }
804 
805  lcd->bd = backlight_device_register("s6e8ax0-bl", lcd->dev, lcd,
806  &s6e8ax0_backlight_ops, NULL);
807  if (IS_ERR(lcd->bd)) {
808  dev_err(lcd->dev, "failed to register backlight ops.\n");
809  ret = PTR_ERR(lcd->bd);
810  goto err_backlight_register;
811  }
812 
813  lcd->bd->props.max_brightness = MAX_BRIGHTNESS;
814  lcd->bd->props.brightness = MAX_BRIGHTNESS;
815 
816  s6e8ax0_read_id(lcd, mtp_id);
817  if (mtp_id[0] == 0x00)
818  dev_err(lcd->dev, "read id failed\n");
819 
820  dev_info(lcd->dev, "Read ID : %x, %x, %x\n",
821  mtp_id[0], mtp_id[1], mtp_id[2]);
822 
823  if (mtp_id[2] == 0x33)
824  dev_info(lcd->dev,
825  "ID-3 is 0xff does not support dynamic elvss\n");
826  else
827  dev_info(lcd->dev,
828  "ID-3 is 0x%x support dynamic elvss\n", mtp_id[2]);
829 
830  lcd->acl_enable = 1;
831  lcd->cur_acl = 0;
832 
833  dev_set_drvdata(&dsim_dev->dev, lcd);
834 
835  dev_dbg(lcd->dev, "probed s6e8ax0 panel driver.\n");
836 
837  return 0;
838 
839 err_backlight_register:
841 
842 err_lcd_register:
843  regulator_bulk_free(ARRAY_SIZE(supplies), supplies);
844  kfree(lcd);
845 
846  return ret;
847 }
848 
849 #ifdef CONFIG_PM
850 static int s6e8ax0_suspend(struct mipi_dsim_lcd_device *dsim_dev)
851 {
852  struct s6e8ax0 *lcd = dev_get_drvdata(&dsim_dev->dev);
853 
854  s6e8ax0_sleep_in(lcd);
855  msleep(lcd->ddi_pd->power_off_delay);
856  s6e8ax0_display_off(lcd);
857 
858  s6e8ax0_regulator_disable(lcd);
859 
860  return 0;
861 }
862 
863 static int s6e8ax0_resume(struct mipi_dsim_lcd_device *dsim_dev)
864 {
865  struct s6e8ax0 *lcd = dev_get_drvdata(&dsim_dev->dev);
866 
867  s6e8ax0_sleep_out(lcd);
868  msleep(lcd->ddi_pd->power_on_delay);
869 
870  s6e8ax0_regulator_enable(lcd);
871  s6e8ax0_set_sequence(dsim_dev);
872 
873  return 0;
874 }
875 #else
876 #define s6e8ax0_suspend NULL
877 #define s6e8ax0_resume NULL
878 #endif
879 
880 static struct mipi_dsim_lcd_driver s6e8ax0_dsim_ddi_driver = {
881  .name = "s6e8ax0",
882  .id = -1,
883 
884  .power_on = s6e8ax0_power_on,
885  .set_sequence = s6e8ax0_set_sequence,
886  .probe = s6e8ax0_probe,
887  .suspend = s6e8ax0_suspend,
888  .resume = s6e8ax0_resume,
889 };
890 
891 static int s6e8ax0_init(void)
892 {
893  exynos_mipi_dsi_register_lcd_driver(&s6e8ax0_dsim_ddi_driver);
894 
895  return 0;
896 }
897 
898 static void s6e8ax0_exit(void)
899 {
900  return;
901 }
902 
903 module_init(s6e8ax0_init);
904 module_exit(s6e8ax0_exit);
905 
906 MODULE_AUTHOR("Donghwa Lee <[email protected]>");
907 MODULE_AUTHOR("Inki Dae <[email protected]>");
908 MODULE_DESCRIPTION("MIPI-DSI based s6e8ax0 AMOLED LCD Panel Driver");
909 MODULE_LICENSE("GPL");