upload tizen1.0 source
[kernel/linux-2.6.36.git] / drivers / video / backlight / smart_dimming.c
1 /* linux/drivers/video/backlight/smart_dimming.c
2  *
3  * Copyright (c) 2011 Samsung Electronics Co., Ltd.
4  *              http://www.samsung.com
5
6  * Samsung Smart Dimming for OCTA
7  *
8  * Minwoo Kim, <minwoo7945.kim@samsung.com>
9 */
10
11 #include "smart_dimming.h"
12 #include "s6e8aa0_voltage_table.h"
13
14 const unsigned char v1_offset_table[14] = {
15         47, 42, 37, 32,
16         27, 23, 19, 15,
17         12,  9,  6,  4,
18         2,  0
19 };
20
21
22 const unsigned char v15_offset_table[20] = {
23         66, 62, 58, 54,
24         50, 46, 43, 38,
25         34, 30, 27, 24,
26         21, 18, 15, 12,
27         9,  6,  3, 0,
28 };
29
30
31 const unsigned char range_table_count[IV_TABLE_MAX] = {
32         1, 14, 20, 24, 28, 84, 84, 1
33 };
34
35
36 const unsigned int table_radio[IV_TABLE_MAX] = {
37         0, 630, 468, 1365, 1170, 390, 390, 0
38 };
39
40 const unsigned int dv_value[IV_MAX] = {
41         0, 15, 35, 59, 87, 171, 255
42 };
43
44 const char color_name[3] = {'R', 'G', 'B'};
45
46
47 const unsigned char *offset_table[IV_TABLE_MAX] = {
48         NULL,
49         v1_offset_table,
50         v15_offset_table,
51         NULL,
52         NULL,
53         NULL,
54         NULL,
55         NULL
56 };
57
58 const unsigned char gamma_300cd_23[] = {
59         0x4A, 0x01, 0x4D, 0xBC, 0xF1, 0xC6,
60         0xB1, 0xD6, 0xB3, 0xC2, 0xDD, 0xC2,
61         0x96, 0xBD, 0x96, 0xAF, 0xC9, 0xAE,
62         0x00, 0xA5, 0x00, 0x91, 0x00, 0xC8,
63 };
64
65 const unsigned char gamma_300cd_29[] = {
66         0x4A, 0x01, 0x4D, 0xBC, 0xF1, 0xC6,
67         0xB1, 0xD6, 0xB3, 0xC2, 0xDD, 0xC2,
68         0x96, 0xBD, 0x96, 0xAF, 0xC9, 0xAE,
69         0x00, 0xA5, 0x00, 0x91, 0x00, 0xC8,
70 };
71
72 const unsigned char gamma_300cd_33[] = {
73         0x0f, 0x00, 0x0f, 0xda, 0xc0, 0xe4,
74         0xc8, 0xc8, 0xc6, 0xd3, 0xd6, 0xd0,
75         0xab, 0xb2, 0xa6, 0xbf, 0xc2, 0xb9,
76         0x00, 0x93, 0x00, 0x86, 0x00, 0xd1,
77 };
78
79 const unsigned char gamma_300cd_43[] = {
80         0x1f, 0x1f, 0x1f, 0xe3, 0x69, 0xe0,
81         0xcc, 0xc1, 0xce, 0xd4, 0xd2, 0xd2,
82         0xae, 0xae, 0xa6, 0xbf, 0xc0, 0xb6,
83         0x00, 0xa3, 0x00, 0x90, 0x00, 0xd7,
84 };
85
86 const unsigned char gamma_300cd_53[] = {
87         0x1f, 0x1f, 0x1f, 0xe7, 0x7f, 0xe3,
88         0xcc, 0xc1, 0xd0, 0xd5, 0xd3, 0xd3,
89         0xae, 0xaf, 0xa8, 0xbe, 0xc0, 0xb7,
90         0x00, 0xa8, 0x00, 0x90, 0x00, 0xd3,
91 };
92
93 const unsigned char gamma_300cd_63[] = {
94         0x60, 0x10, 0x60, 0xb5, 0xd3, 0xbd,
95         0xb1, 0xd2, 0xb0, 0xc0, 0xdc, 0xc0,
96         0x94, 0xba, 0x91, 0xac, 0xc5, 0xa9,
97         0x00, 0xc2, 0x00, 0xb7, 0x00, 0xed,
98 };
99
100 const unsigned char gamma_300cd_73[] = {
101         0x1f, 0x1f, 0x1f, 0xed, 0xe6, 0xe7,
102         0xd1, 0xd3, 0xd4, 0xda, 0xd8, 0xd7,
103         0xb1, 0xaf, 0xab, 0xbd, 0xbb, 0xb8,
104         0x00, 0xd6, 0x00, 0xda, 0x00, 0xfa,
105 };
106
107 const unsigned char gamma_300cd_83[] = {
108         0x69, 0x5A, 0x6C, 0xA1, 0xB7, 0x9D,
109         0xAB, 0xB6, 0xAF, 0xB8, 0xC1, 0xB9,
110         0x8E, 0x96, 0x8B, 0xA6, 0xAC, 0xA4,
111         0x00, 0xD2, 0x00, 0xD3, 0x00, 0xF1
112 };
113
114 const unsigned char gamma_300cd_8e[] = {
115         0x58, 0x1F, 0x63, 0xAC, 0xB4, 0x99,
116         0xAD, 0xBA, 0xA3, 0xC0, 0xCB, 0xBB,
117         0x93, 0x9F, 0x8B, 0xAD, 0xB4, 0xA7,
118         0x00, 0xBE, 0x00, 0xAB, 0x00, 0xE7,
119 };
120
121 /* SM2, C1/M0 Cellox Panel */
122 const unsigned char gamma_300cd_ae[] = {
123         0x5F, 0x2E, 0x67, 0xAA, 0xC6, 0xAC,
124         0xB0, 0xC8, 0xBB, 0xBE, 0xCB, 0xBD,
125         0x97, 0xA5, 0x91, 0xAF, 0xB8, 0xAB,
126         0x00, 0xC2, 0x00, 0xBA, 0x00, 0xE2,
127 };
128
129 const unsigned char *gamma_300cd_list[GAMMA_300CD_MAX] = {
130         gamma_300cd_23,
131         gamma_300cd_29,
132         gamma_300cd_33,
133         gamma_300cd_43,
134         gamma_300cd_53,
135         gamma_300cd_63,
136         gamma_300cd_73,
137         gamma_300cd_83,
138         gamma_300cd_8e,
139         gamma_300cd_ae,
140 };
141
142 const unsigned char gamma_id_list[GAMMA_300CD_MAX] = {
143         0x23, 0x29, 0x33, 0x43, 0x53, 0x63, 0x73, 0x83, 0x8e, 0xae
144 };
145
146 static s16 s9_to_s16(s16 v)
147 {
148         return (s16)(v << 7) >> 7;
149 }
150
151 static unsigned int calc_v1_volt(s16 gamma, int rgb_index,
152                 unsigned int adjust_volt[CI_MAX][AD_IVMAX])
153 {
154         unsigned int ret = 0;
155
156         ret = volt_table_v1[gamma] >> 10;
157
158         return ret;
159 }
160
161 static unsigned int calc_v15_volt(s16 gamma, int rgb_index,
162                 unsigned int adjust_volt[CI_MAX][AD_IVMAX])
163 {
164         /* for CV : 20, DV :320 */
165         int ret = 0;
166         unsigned int v1, v35;
167         unsigned int ratio = 0;
168
169         v1 = adjust_volt[rgb_index][AD_IV1];
170         v35 = adjust_volt[rgb_index][AD_IV35];
171         ratio = volt_table_cv_20_dv_320[gamma];
172
173         ret = (v1 << 10) - ((v1 - v35) * ratio);
174         ret = ret >> 10;
175
176         return ret;
177 }
178
179 static unsigned int calc_v35_volt(s16 gamma, int rgb_index,
180                 unsigned int adjust_volt[CI_MAX][AD_IVMAX])
181 {
182         /* for CV : 65, DV :320 */
183         int ret = 0;
184         unsigned int v1, v59;
185         unsigned int ratio = 0;
186
187         v1 = adjust_volt[rgb_index][AD_IV1];
188         v59 = adjust_volt[rgb_index][AD_IV59];
189         ratio = volt_table_cv_65_dv_320[gamma];
190
191         ret = (v1 << 10) - ((v1 - v59) * ratio);
192         ret = ret >> 10;
193
194         return ret;
195 }
196
197 static unsigned int calc_v50_volt(s16 gamma, int rgb_index,
198                 unsigned int adjust_volt[CI_MAX][AD_IVMAX])
199 {
200         /* for CV : 65, DV :320 */
201         int ret = 0;
202         unsigned int v1, v87;
203         unsigned int ratio = 0;
204
205         v1 = adjust_volt[rgb_index][AD_IV1];
206         v87 = adjust_volt[rgb_index][AD_IV87];
207         ratio = volt_table_cv_65_dv_320[gamma];
208
209         ret = (v1 << 10) - ((v1 - v87) * ratio);
210         ret = ret >> 10;
211
212         return ret;
213 }
214
215 static unsigned int calc_v87_volt(s16 gamma, int rgb_index,
216                 unsigned int adjust_volt[CI_MAX][AD_IVMAX])
217 {
218         /* for CV : 65, DV :320 */
219         int ret = 0;
220         unsigned int v1, v171;
221         unsigned int ratio = 0;
222
223         v1 = adjust_volt[rgb_index][AD_IV1];
224         v171 = adjust_volt[rgb_index][AD_IV171];
225         ratio = volt_table_cv_65_dv_320[gamma];
226
227         ret = (v1 << 10) - ((v1 - v171) * ratio);
228         ret = ret >> 10;
229
230         return ret;
231 }
232
233 static unsigned int calc_v171_volt(s16 gamma, int rgb_index,
234                 unsigned int adjust_volt[CI_MAX][AD_IVMAX])
235 {
236         /* for CV : 65, DV :320 */
237         int ret = 0;
238         unsigned int v1, v255;
239         unsigned int ratio = 0;
240
241         v1 = adjust_volt[rgb_index][AD_IV1];
242         v255 = adjust_volt[rgb_index][AD_IV255];
243         ratio = volt_table_cv_65_dv_320[gamma];
244
245         ret = (v1 << 10) - ((v1 - v255) * ratio);
246         ret = ret >> 10;
247
248         return ret;
249 }
250
251 static unsigned int calc_v255_volt(s16 gamma, int rgb_index,
252                 unsigned int adjust_volt[CI_MAX][AD_IVMAX])
253 {
254         unsigned int ret = 0;
255
256         ret = volt_table_v255[gamma] >> 10;
257
258         return ret;
259 }
260
261 #define MTP_REVERSE 1
262
263 unsigned char calc_voltage_table(struct smart_dimming *smart,
264                 const unsigned char *mtp)
265 {
266         int c, i, j;
267 #if defined(MTP_REVERSE)
268         int offset1 = 0;
269 #endif
270         int offset = 0;
271         s16 t1, t2;
272         s16 adjust_mtp[CI_MAX][IV_MAX];
273         /* unsigned int adjust_volt[CI_MAX][AD_IVMAX] = {0, }; */
274         unsigned char range_index;
275         unsigned char table_index = 0;
276
277         unsigned int v1, v2;
278         unsigned int ratio;
279
280         /* adjust_volt[][]: result from calc output voltage V1 ~ V255 */
281         unsigned int(*calc_volt[IV_MAX])(s16 gamma, int rgb_index,
282                         unsigned int adjust_volt[CI_MAX][AD_IVMAX]) = {
283                 calc_v1_volt,
284                 calc_v15_volt,
285                 calc_v35_volt,
286                 calc_v50_volt,
287                 calc_v87_volt,
288                 calc_v171_volt,
289                 calc_v255_volt,
290         };
291
292         unsigned char calc_seq[6] = {IV_1, IV_171, IV_87, IV_59, IV_35, IV_15};
293         unsigned char ad_seq[6] =
294                         {AD_IV1, AD_IV171, AD_IV87, AD_IV59, AD_IV35, AD_IV15};
295
296         memset(adjust_mtp, 0, sizeof(adjust_mtp));
297
298         for (c = CI_RED; c < CI_MAX; c++) {
299                 offset = IV_255 * CI_MAX + c * 2;
300 #if defined(MTP_REVERSE)
301                 offset1 = IV_255 * (c + 1) + (c * 2);
302                 t1 = s9_to_s16((mtp[offset1] << 8) | (mtp[offset1 + 1]));
303 #else
304                 t1 = s9_to_s16((mtp[offset] << 8) | (mtp[offset + 1]));
305 #endif
306                 t2 = s9_to_s16((smart->default_gamma[offset] << 8) |
307                                 (smart->default_gamma[offset + 1])) + t1;
308
309                 smart->mtp[c][IV_255] = t1;
310                 adjust_mtp[c][IV_255] = t2;
311                 smart->adjust_volt[c][AD_IV255] =
312                                 calc_volt[IV_255](t2, c, smart->adjust_volt);
313
314                 /* for V0 All RGB Voltage Value is Reference Voltage */
315                 smart->adjust_volt[c][AD_IV0] = 4600;
316         }
317
318         for (c = CI_RED; c < CI_MAX; c++) {
319                 for (i = IV_1; i < IV_255; i++) {
320 #if defined(MTP_REVERSE)
321                         t1 = (s8)mtp[(calc_seq[i]) + (c * 8)];
322 #else
323                         t1 = (s8)mtp[CI_MAX * calc_seq[i] + c];
324 #endif
325                         t2 = smart->default_gamma[CI_MAX * calc_seq[i] + c] + t1;
326
327                         smart->mtp[c][calc_seq[i]] = t1;
328                         adjust_mtp[c][calc_seq[i]] = t2;
329                         smart->adjust_volt[c][ad_seq[i]] =
330                         calc_volt[calc_seq[i]](t2, c, smart->adjust_volt);
331                 }
332         }
333
334         for (i = 0; i < AD_IVMAX; i++) {
335                 for (c = CI_RED; c < CI_MAX; c++)
336                         smart->ve[table_index].v[c] = smart->adjust_volt[c][i];
337
338                 range_index = 0;
339                 for (j = table_index+1; j < table_index + range_table_count[i]; j++) {
340                         for (c = CI_RED; c < CI_MAX; c++) {
341                                 if (smart->t_info[i].offset_table != NULL)
342                                         ratio = smart->t_info[i].offset_table[range_index]
343                                                 * smart->t_info[i].rv;
344                                 else
345                                         ratio = (range_table_count[i] -
346                                                 (range_index+1)) *
347                                                 smart->t_info[i].rv;
348
349                                 v1 = smart->adjust_volt[c][i + 1] << 15;
350                                 v2 = (smart->adjust_volt[c][i] -
351                                         smart->adjust_volt[c][i + 1]) * ratio;
352                                 smart->ve[j].v[c] = ((v1 + v2) >> 15);
353                         }
354                         range_index++;
355                 }
356                 table_index = j;
357         }
358         return 0;
359 }
360
361
362 int init_table_info(struct smart_dimming *smart_dim)
363 {
364         int i;
365         int offset = 0;
366
367         for (i = 0; i < IV_TABLE_MAX; i++) {
368                 smart_dim->t_info[i].count =
369                         (unsigned char)range_table_count[i];
370                 smart_dim->t_info[i].offset_table = offset_table[i];
371                 smart_dim->t_info[i].rv = table_radio[i];
372                 offset += range_table_count[i];
373         }
374         smart_dim->flooktbl = flookup_table;
375         smart_dim->g300_gra_tbl = gamma_300_gra_table;
376         smart_dim->gamma_22_tbl = gamma_22_table;
377         printk("Panel 2nd ID : %x\n", smart_dim->panel_id[1]);;
378
379         for (i = 0; i < GAMMA_300CD_MAX; i++) {
380                 if (smart_dim->panel_id[1] == gamma_id_list[i])
381                         break;
382         }
383         printk("%s : Default Gamma Table\n", __func__);
384         if (i >= GAMMA_300CD_MAX) {
385                 printk("[SMART DIMMING-WARNING] %s \
386                         Can't found default gamma table\n", __func__);
387                 smart_dim->default_gamma =
388                         gamma_300cd_list[GAMMA_300CD_MAX - 1];
389         } else
390                 smart_dim->default_gamma = gamma_300cd_list[i];
391
392         return 0;
393 }
394
395 #define VALUE_DIM_1000 1000
396
397 static unsigned int lookup_voltage_table_idx(struct smart_dimming *smart_dim,
398                                         unsigned int gamma)
399 {
400         unsigned int lookup_index;
401         u16 table_count, table_index;
402         unsigned int gap, i;
403         unsigned int minimum = smart_dim->g300_gra_tbl[255];
404         unsigned int candidate = 0;
405         unsigned int offset = 0;
406
407         lookup_index = (gamma / VALUE_DIM_1000) + 1;
408         if (lookup_index > MAX_GRADATION) {
409                 printk("ERROR Wrong input value ..\n");
410                 return 0;
411         }
412
413         /* printk("lookup index : %d\n",lookup_index); */
414
415         if (smart_dim->flooktbl[lookup_index].count) {
416                 if (smart_dim->flooktbl[lookup_index - 1].count) {
417                         table_index =
418                                 smart_dim->flooktbl[lookup_index - 1].entry;
419                         table_count =
420                                 smart_dim->flooktbl[lookup_index].count +
421                                 smart_dim->flooktbl[lookup_index - 1].count;
422                 } else {
423                         table_index = smart_dim->flooktbl[lookup_index].entry;
424                         table_count = smart_dim->flooktbl[lookup_index].count;
425                 }
426         } else {
427                 offset += 1;
428                 while (!(smart_dim->flooktbl[lookup_index + offset].count ||
429                         smart_dim->flooktbl[lookup_index - offset].count))
430                         offset++;
431
432                 if (smart_dim->flooktbl[lookup_index - offset].count)
433                         table_index =
434                                 smart_dim->flooktbl[lookup_index - offset].entry;
435                 else
436                         table_index =
437                                 smart_dim->flooktbl[lookup_index + offset].entry;
438                 table_count =
439                         smart_dim->flooktbl[lookup_index + offset].count +
440                         smart_dim->flooktbl[lookup_index - offset].count;
441         }
442
443
444         for (i = 0; i < table_count; i++) {
445                 if (gamma > smart_dim->g300_gra_tbl[table_index])
446                         gap = gamma - smart_dim->g300_gra_tbl[table_index];
447                 else
448                         gap = smart_dim->g300_gra_tbl[table_index] - gamma;
449
450                 if (gap == 0) {
451                         candidate = table_index;
452                         break;
453                 }
454
455                 if (gap < minimum) {
456                         minimum = gap;
457                         candidate = table_index;
458                 }
459                 table_index++;
460         }
461
462         return candidate;
463 }
464
465
466 static unsigned int calc_v1_reg(int ci, unsigned int dv[CI_MAX][IV_MAX])
467 {
468         unsigned int ret;
469         unsigned int v1;
470
471         v1 = dv[ci][IV_1];
472         ret = (595 * 1000) - (130 * v1);
473         ret = ret / 1000;
474
475         return ret;
476
477
478 }
479 static unsigned int calc_v15_reg(int ci, unsigned int dv[CI_MAX][IV_MAX])
480 {
481         unsigned int t1, t2;
482         unsigned int v1, v15, v35;
483         unsigned int ret;
484
485         v1 = dv[ci][IV_1];
486         v15 = dv[ci][IV_15];
487         v35 = dv[ci][IV_35];
488
489         t1 = (v1 - v15) << 10;
490         t2 = (v1 - v35) ? (v1 - v35) : (v1) ? v1 : 1;
491         ret = (320 * (t1 / t2)) - (20 << 10);
492         ret >>= 10;
493
494         return ret;
495
496 }
497 static unsigned int calc_v35_reg(int ci, unsigned int dv[CI_MAX][IV_MAX])
498 {
499         unsigned int t1, t2;
500         unsigned int v1, v35, v57;
501         unsigned int ret;
502
503         v1 = dv[ci][IV_1];
504         v35 = dv[ci][IV_35];
505         v57 = dv[ci][IV_59];
506
507         t1 = (v1 - v35) << 10;
508         t2 = (v1 - v57) ? (v1 - v57) : (v1) ? v1 : 1;
509         ret = (320 * (t1 / t2)) - (65 << 10);
510
511         ret >>= 10;
512
513         return ret;
514 }
515
516 static unsigned int calc_v50_reg(int ci, unsigned int dv[CI_MAX][IV_MAX])
517 {
518         unsigned int t1, t2;
519         unsigned int v1, v57, v87;
520         unsigned int ret;
521
522         v1 = dv[ci][IV_1];
523         v57 = dv[ci][IV_59];
524         v87 = dv[ci][IV_87];
525
526         t1 = (v1 - v57) << 10;
527         t2 = (v1 - v87) ? (v1 - v87) : (v1) ? v1 : 1;
528         ret = (320 * (t1 / t2)) - (65 << 10);
529         ret >>= 10;
530
531         return ret;
532 }
533
534 static unsigned int calc_v87_reg(int ci, unsigned int dv[CI_MAX][IV_MAX])
535 {
536         unsigned int t1, t2;
537         unsigned int v1, v87, v171;
538         unsigned int ret;
539
540         v1 = dv[ci][IV_1];
541         v87 = dv[ci][IV_87];
542         v171 = dv[ci][IV_171];
543
544         t1 = (v1 - v87) << 10;
545         t2 = (v1 - v171) ? (v1 - v171) : (v1) ? v1 : 1;
546         ret = (320 * (t1 / t2)) - (65 << 10);
547         ret >>= 10;
548
549         return ret;
550 }
551
552
553 static unsigned int calc_v171_reg(int ci, unsigned int dv[CI_MAX][IV_MAX])
554 {
555         unsigned int t1, t2;
556         unsigned int v1, v171, v255;
557         unsigned int ret;
558
559         v1 = dv[ci][IV_1];
560         v171 = dv[ci][IV_171];
561         v255 = dv[ci][IV_255];
562
563         t1 = (v1 - v171) << 10;
564         t2 = (v1 - v255) ? (v1 - v255) : (v1) ? v1 : 1;
565         ret = (320 * (t1 / t2)) - (65 << 10);
566         ret >>= 10;
567
568         return ret;
569 }
570
571
572
573 static unsigned int calc_v255_reg(int ci, unsigned int dv[CI_MAX][IV_MAX])
574 {
575         unsigned int ret;
576         unsigned int v255;
577
578         v255 = dv[ci][IV_255];
579
580         ret = (500 * 1000) - (130 * v255);
581         ret = ret / 1000;
582
583         return ret;
584 }
585
586
587 unsigned int calc_gamma_table(struct smart_dimming *smart_dim,
588                 unsigned int gamma_val, unsigned char gamma_set[])
589 {
590         unsigned int i, c;
591         unsigned int temp;
592         unsigned int lidx;
593         unsigned int dv[CI_MAX][IV_MAX];
594         s16 gamma[CI_MAX][IV_MAX];
595         u16 offset;
596         unsigned int(*calc_reg[IV_MAX])
597                 (int ci, unsigned int dv[CI_MAX][IV_MAX]) = {
598                 calc_v1_reg,
599                 calc_v15_reg,
600                 calc_v35_reg,
601                 calc_v50_reg,
602                 calc_v87_reg,
603                 calc_v171_reg,
604                 calc_v255_reg,
605         };
606
607         memset(gamma, 0, sizeof(gamma));
608
609         for (c = CI_RED; c < CI_MAX; c++)
610                 dv[c][0] = smart_dim->adjust_volt[c][AD_IV1];
611
612
613         for (i = IV_15; i < IV_MAX; i++) {
614                 temp = smart_dim->gamma_22_tbl[dv_value[i]] * gamma_val;
615                 lidx = lookup_voltage_table_idx(smart_dim, temp);
616                 for (c = CI_RED; c < CI_MAX; c++)
617                         dv[c][i] = smart_dim->ve[lidx].v[c];
618         }
619
620         /* for IV1 does not calculate value */
621         /* just use default gamma value (IV1) */
622         for (c = CI_RED; c < CI_MAX; c++)
623                 gamma[c][IV_1] = smart_dim->default_gamma[c];
624
625         for (i = IV_15; i < IV_MAX; i++) {
626                 for (c = CI_RED; c < CI_MAX; c++)
627                         gamma[c][i] =
628                                 (s16)calc_reg[i](c, dv) - smart_dim->mtp[c][i];
629         }
630
631         for (c = CI_RED; c < CI_MAX; c++) {
632                 offset = IV_255 * CI_MAX+c*2;
633                 gamma_set[offset + 1] = gamma[c][IV_255];
634         }
635
636         for (c = CI_RED; c < CI_MAX; c++) {
637                 for (i = IV_1; i < IV_255; i++)
638                         gamma_set[(CI_MAX * i) + c] = gamma[c][i];
639         }
640
641         return 0;
642 }