1 /* linux/drivers/video/backlight/smart_dimming.c
3 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com
6 * Samsung Smart Dimming for OCTA
8 * Minwoo Kim, <minwoo7945.kim@samsung.com>
11 #include "smart_dimming.h"
12 #include "s6e8aa0_voltage_table.h"
14 const unsigned char v1_offset_table[14] = {
22 const unsigned char v15_offset_table[20] = {
31 const unsigned char range_table_count[IV_TABLE_MAX] = {
32 1, 14, 20, 24, 28, 84, 84, 1
36 const unsigned int table_radio[IV_TABLE_MAX] = {
37 0, 630, 468, 1365, 1170, 390, 390, 0
40 const unsigned int dv_value[IV_MAX] = {
41 0, 15, 35, 59, 87, 171, 255
44 const char color_name[3] = {'R', 'G', 'B'};
47 const unsigned char *offset_table[IV_TABLE_MAX] = {
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,
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,
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,
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,
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,
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,
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,
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
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,
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,
129 const unsigned char *gamma_300cd_list[GAMMA_300CD_MAX] = {
142 const unsigned char gamma_id_list[GAMMA_300CD_MAX] = {
143 0x23, 0x29, 0x33, 0x43, 0x53, 0x63, 0x73, 0x83, 0x8e, 0xae
146 static s16 s9_to_s16(s16 v)
148 return (s16)(v << 7) >> 7;
151 static unsigned int calc_v1_volt(s16 gamma, int rgb_index,
152 unsigned int adjust_volt[CI_MAX][AD_IVMAX])
154 unsigned int ret = 0;
156 ret = volt_table_v1[gamma] >> 10;
161 static unsigned int calc_v15_volt(s16 gamma, int rgb_index,
162 unsigned int adjust_volt[CI_MAX][AD_IVMAX])
164 /* for CV : 20, DV :320 */
166 unsigned int v1, v35;
167 unsigned int ratio = 0;
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];
173 ret = (v1 << 10) - ((v1 - v35) * ratio);
179 static unsigned int calc_v35_volt(s16 gamma, int rgb_index,
180 unsigned int adjust_volt[CI_MAX][AD_IVMAX])
182 /* for CV : 65, DV :320 */
184 unsigned int v1, v59;
185 unsigned int ratio = 0;
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];
191 ret = (v1 << 10) - ((v1 - v59) * ratio);
197 static unsigned int calc_v50_volt(s16 gamma, int rgb_index,
198 unsigned int adjust_volt[CI_MAX][AD_IVMAX])
200 /* for CV : 65, DV :320 */
202 unsigned int v1, v87;
203 unsigned int ratio = 0;
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];
209 ret = (v1 << 10) - ((v1 - v87) * ratio);
215 static unsigned int calc_v87_volt(s16 gamma, int rgb_index,
216 unsigned int adjust_volt[CI_MAX][AD_IVMAX])
218 /* for CV : 65, DV :320 */
220 unsigned int v1, v171;
221 unsigned int ratio = 0;
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];
227 ret = (v1 << 10) - ((v1 - v171) * ratio);
233 static unsigned int calc_v171_volt(s16 gamma, int rgb_index,
234 unsigned int adjust_volt[CI_MAX][AD_IVMAX])
236 /* for CV : 65, DV :320 */
238 unsigned int v1, v255;
239 unsigned int ratio = 0;
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];
245 ret = (v1 << 10) - ((v1 - v255) * ratio);
251 static unsigned int calc_v255_volt(s16 gamma, int rgb_index,
252 unsigned int adjust_volt[CI_MAX][AD_IVMAX])
254 unsigned int ret = 0;
256 ret = volt_table_v255[gamma] >> 10;
261 #define MTP_REVERSE 1
263 unsigned char calc_voltage_table(struct smart_dimming *smart,
264 const unsigned char *mtp)
267 #if defined(MTP_REVERSE)
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;
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]) = {
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};
296 memset(adjust_mtp, 0, sizeof(adjust_mtp));
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]));
304 t1 = s9_to_s16((mtp[offset] << 8) | (mtp[offset + 1]));
306 t2 = s9_to_s16((smart->default_gamma[offset] << 8) |
307 (smart->default_gamma[offset + 1])) + t1;
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);
314 /* for V0 All RGB Voltage Value is Reference Voltage */
315 smart->adjust_volt[c][AD_IV0] = 4600;
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)];
323 t1 = (s8)mtp[CI_MAX * calc_seq[i] + c];
325 t2 = smart->default_gamma[CI_MAX * calc_seq[i] + c] + t1;
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);
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];
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;
345 ratio = (range_table_count[i] -
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);
362 int init_table_info(struct smart_dimming *smart_dim)
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];
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]);;
379 for (i = 0; i < GAMMA_300CD_MAX; i++) {
380 if (smart_dim->panel_id[1] == gamma_id_list[i])
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];
390 smart_dim->default_gamma = gamma_300cd_list[i];
395 #define VALUE_DIM_1000 1000
397 static unsigned int lookup_voltage_table_idx(struct smart_dimming *smart_dim,
400 unsigned int lookup_index;
401 u16 table_count, table_index;
403 unsigned int minimum = smart_dim->g300_gra_tbl[255];
404 unsigned int candidate = 0;
405 unsigned int offset = 0;
407 lookup_index = (gamma / VALUE_DIM_1000) + 1;
408 if (lookup_index > MAX_GRADATION) {
409 printk("ERROR Wrong input value ..\n");
413 /* printk("lookup index : %d\n",lookup_index); */
415 if (smart_dim->flooktbl[lookup_index].count) {
416 if (smart_dim->flooktbl[lookup_index - 1].count) {
418 smart_dim->flooktbl[lookup_index - 1].entry;
420 smart_dim->flooktbl[lookup_index].count +
421 smart_dim->flooktbl[lookup_index - 1].count;
423 table_index = smart_dim->flooktbl[lookup_index].entry;
424 table_count = smart_dim->flooktbl[lookup_index].count;
428 while (!(smart_dim->flooktbl[lookup_index + offset].count ||
429 smart_dim->flooktbl[lookup_index - offset].count))
432 if (smart_dim->flooktbl[lookup_index - offset].count)
434 smart_dim->flooktbl[lookup_index - offset].entry;
437 smart_dim->flooktbl[lookup_index + offset].entry;
439 smart_dim->flooktbl[lookup_index + offset].count +
440 smart_dim->flooktbl[lookup_index - offset].count;
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];
448 gap = smart_dim->g300_gra_tbl[table_index] - gamma;
451 candidate = table_index;
457 candidate = table_index;
466 static unsigned int calc_v1_reg(int ci, unsigned int dv[CI_MAX][IV_MAX])
472 ret = (595 * 1000) - (130 * v1);
479 static unsigned int calc_v15_reg(int ci, unsigned int dv[CI_MAX][IV_MAX])
482 unsigned int v1, v15, v35;
489 t1 = (v1 - v15) << 10;
490 t2 = (v1 - v35) ? (v1 - v35) : (v1) ? v1 : 1;
491 ret = (320 * (t1 / t2)) - (20 << 10);
497 static unsigned int calc_v35_reg(int ci, unsigned int dv[CI_MAX][IV_MAX])
500 unsigned int v1, v35, v57;
507 t1 = (v1 - v35) << 10;
508 t2 = (v1 - v57) ? (v1 - v57) : (v1) ? v1 : 1;
509 ret = (320 * (t1 / t2)) - (65 << 10);
516 static unsigned int calc_v50_reg(int ci, unsigned int dv[CI_MAX][IV_MAX])
519 unsigned int v1, v57, v87;
526 t1 = (v1 - v57) << 10;
527 t2 = (v1 - v87) ? (v1 - v87) : (v1) ? v1 : 1;
528 ret = (320 * (t1 / t2)) - (65 << 10);
534 static unsigned int calc_v87_reg(int ci, unsigned int dv[CI_MAX][IV_MAX])
537 unsigned int v1, v87, v171;
542 v171 = dv[ci][IV_171];
544 t1 = (v1 - v87) << 10;
545 t2 = (v1 - v171) ? (v1 - v171) : (v1) ? v1 : 1;
546 ret = (320 * (t1 / t2)) - (65 << 10);
553 static unsigned int calc_v171_reg(int ci, unsigned int dv[CI_MAX][IV_MAX])
556 unsigned int v1, v171, v255;
560 v171 = dv[ci][IV_171];
561 v255 = dv[ci][IV_255];
563 t1 = (v1 - v171) << 10;
564 t2 = (v1 - v255) ? (v1 - v255) : (v1) ? v1 : 1;
565 ret = (320 * (t1 / t2)) - (65 << 10);
573 static unsigned int calc_v255_reg(int ci, unsigned int dv[CI_MAX][IV_MAX])
578 v255 = dv[ci][IV_255];
580 ret = (500 * 1000) - (130 * v255);
587 unsigned int calc_gamma_table(struct smart_dimming *smart_dim,
588 unsigned int gamma_val, unsigned char gamma_set[])
593 unsigned int dv[CI_MAX][IV_MAX];
594 s16 gamma[CI_MAX][IV_MAX];
596 unsigned int(*calc_reg[IV_MAX])
597 (int ci, unsigned int dv[CI_MAX][IV_MAX]) = {
607 memset(gamma, 0, sizeof(gamma));
609 for (c = CI_RED; c < CI_MAX; c++)
610 dv[c][0] = smart_dim->adjust_volt[c][AD_IV1];
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];
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];
625 for (i = IV_15; i < IV_MAX; i++) {
626 for (c = CI_RED; c < CI_MAX; c++)
628 (s16)calc_reg[i](c, dv) - smart_dim->mtp[c][i];
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];
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];