static int ana38401_read_offset(struct lcd_info *lcd, u8 addr, u8 *buf, u32 len, u32 offset) { int ret, i, remain, limit; unsigned char wbuf[] = {0xB0, 0}; limit = LDI_MAX_READ_LENGTH; remain = len; again: wbuf[1] = offset + (len - remain); ana38401_write(lcd, wbuf, ARRAY_SIZE(wbuf)); ret = ana38401_read(lcd, addr, &buf[(len - remain)], remain > limit ? limit : remain); remain -= limit; if (remain > 0) goto again; if (ret < 1) dev_err(&lcd->ld->dev, "%s failed\n", __func__); smtd_dbg("%s: %02xh\n", __func__, addr); for (i = 0; i < len; i++) smtd_dbg("%03dth value is %02x\n", i + offset, (int)buf[i]); return ret; }
static int init_gamma_table(struct lcd_info *lcd , const u8 *mtp_data) { int i, j, ret = 0; lcd->gamma_table = kzalloc(GAMMA_MAX * sizeof(u8 *), GFP_KERNEL); if (IS_ERR_OR_NULL(lcd->gamma_table)) { pr_err("failed to allocate gamma table\n"); ret = -ENOMEM; goto err_alloc_gamma_table; } for (i = 0; i < GAMMA_MAX; i++) { lcd->gamma_table[i] = kzalloc(GAMMA_PARAM_SIZE * sizeof(u8), GFP_KERNEL); if (IS_ERR_OR_NULL(lcd->gamma_table[i])) { pr_err("failed to allocate gamma\n"); ret = -ENOMEM; goto err_alloc_gamma; } lcd->gamma_table[i][0] = 0xCA; } if ((lcd->id[2] == 0x00) || (lcd->id[2] == 0x01)) { lcd->aid = aid_setting_table_VT888; for (i = 0; i < ARRAY_SIZE(aid_setting_table_VT888); i++) calc_gamma_table(&lcd->smart, lcd->aid, &lcd->gamma_table[i][1], mtp_data, i); } if (lcd->id[2] == 0x02) { lcd->aid = aid_setting_table_VT232; for (i = 0; i < ARRAY_SIZE(aid_setting_table_VT232); i++) calc_gamma_table(&lcd->smart, lcd->aid, &lcd->gamma_table[i][1], mtp_data, i); } for (i = 0; i < GAMMA_MAX; i++) { for (j = 0; j < GAMMA_PARAM_SIZE; j++) smtd_dbg("%d,", lcd->gamma_table[i][j]); smtd_dbg("\n"); } smtd_dbg("\n"); return 0; err_alloc_gamma: while (i > 0) { kfree(lcd->gamma_table[i-1]); i--; } kfree(lcd->gamma_table); err_alloc_gamma_table: return ret; }
static int init_elvss_table(struct lcd_info *lcd) { int i, j, ret = 0; lcd->elvss_table = kzalloc(ELVSS_STATUS_MAX * sizeof(u8 *), GFP_KERNEL); if (IS_ERR_OR_NULL(lcd->elvss_table)) { pr_err("failed to allocate elvss table\n"); ret = -ENOMEM; goto err_alloc_elvss_table; } for (i = 0; i < ELVSS_STATUS_MAX; i++) { lcd->elvss_table[i] = kzalloc(ELVSS_PARAM_SIZE * sizeof(u8), GFP_KERNEL); if (IS_ERR_OR_NULL(lcd->elvss_table[i])) { pr_err("failed to allocate elvss\n"); ret = -ENOMEM; goto err_alloc_elvss; } lcd->elvss_table[i][0] = 0xB6; lcd->elvss_table[i][1] = 0x28; if ((lcd->elvss_ref + ELVSS_CONTROL_TABLE[i][2]) > 0x29) lcd->elvss_table[i][2] = 0x29; else lcd->elvss_table[i][2] = lcd->elvss_ref + ELVSS_CONTROL_TABLE[i][2]; } for (i = 0; i < ELVSS_STATUS_MAX; i++) { for (j = 0; j < ELVSS_PARAM_SIZE; j++) smtd_dbg("0x%02x, ", lcd->elvss_table[i][j]); smtd_dbg("\n"); } return 0; err_alloc_elvss: while (i > 0) { kfree(lcd->elvss_table[i-1]); i--; } kfree(lcd->elvss_table); err_alloc_elvss_table: return ret; }
static void init_mtp_data(struct lcd_info *lcd, u8 *mtp_data) { int i, c, j; int *mtp; int mtp_v0[3]; mtp = lcd->daid.mtp; for (c = 0; c < CI_MAX; c++) { for (i = IV_11, j = 0; i < IV_MAX; i++, j++) mtp[i * CI_MAX + c] = mtp_data[MTP_VMAX * c + j]; mtp[IV_3 * CI_MAX + c] = mtp_data[MTP_VMAX * c + j++]; mtp_v0[c] = mtp_data[MTP_VMAX*c + j++]; mtp[IV_VT * CI_MAX + c] = mtp_data[MTP_VMAX * c + j++]; } for (c = 0; c < CI_MAX; c++) { for (i = IV_3, j = 0; i <= IV_203; i++, j++) { if (mtp[i * CI_MAX + c] & 0x80) { mtp[i * CI_MAX + c] = mtp[i * CI_MAX + c] & 0x7f; mtp[i * CI_MAX + c] *= (-1); } } if (mtp_v0[c] & 0x80) mtp[IV_255*CI_MAX + c] *= (-1); } for (i = 0, j = 0; i <= IV_MAX; i++) for (c = 0; c < CI_MAX; c++, j++) smtd_dbg("mtp_data[%02d] = %d\n", j, mtp_data[j]); for (i = 0, j = 0; i < IV_MAX; i++) for (c = 0; c < CI_MAX; c++, j++) smtd_dbg("mtp[%02d] = %d\n", j, mtp[j]); smtd_dbg("MTP_Offset_Value\n"); for (i = 0; i < IV_MAX; i++) { for (c = 0; c < CI_MAX; c++) smtd_dbg("%4d ", lcd->daid.mtp[i*CI_MAX+c]); smtd_dbg("\n"); } }
static int ana38401_read_hbm(struct lcd_info *lcd, u8 *buf) { int ret; smtd_dbg("%s: %02xh\n", __func__, LDI_HBM_GAMMA_REG); ret = ana38401_read_offset(lcd, LDI_HBM_GAMMA_REG, buf, LDI_HBM_GAMMA_LEN, LDI_HBM_GAMMA_OFFSET); if (ret < 1) dev_err(&lcd->ld->dev, "%s failed\n", __func__); return ret; }
/* re-order function. same as init_mtp_data */ static void init_hbm_data(struct lcd_info *lcd, u8 *hbm_data, int *result) { int i, c, j; int *hbm; int hbm_v0[3]; hbm = result; for (c = 0; c < CI_MAX; c++) { for (i = IV_11, j = 0; i < IV_MAX; i++, j++) hbm[i * CI_MAX + c] = hbm_data[MTP_VMAX * c + j]; hbm[IV_3 * CI_MAX + c] = hbm_data[MTP_VMAX * c + j++]; hbm_v0[c] = hbm_data[MTP_VMAX*c + j++]; hbm[IV_VT * CI_MAX + c] = hbm_data[MTP_VMAX * c + j++]; } for (c = 0; c < CI_MAX; c++) { if (hbm_v0[c] & 0x80) hbm[IV_255*CI_MAX + c] |= BIT(8); } for (i = 0, j = 0; i <= IV_MAX; i++) for (c = 0; c < CI_MAX; c++, j++) smtd_dbg("hbm_data[%02d] = %d\n", j, hbm_data[j]); for (i = 0, j = 0; i < IV_MAX; i++) for (c = 0; c < CI_MAX; c++, j++) smtd_dbg("hbm[%02d] = %d\n", j, hbm[j]); smtd_dbg("HBM_Offset_Value\n"); for (i = 0; i < IV_MAX; i++) { for (c = 0; c < CI_MAX; c++) smtd_dbg("%4d ", hbm[i*CI_MAX+c]); smtd_dbg("\n"); } }
static int ana38401_read_coordinate(struct lcd_info *lcd) { int ret; unsigned char buf[LDI_COORDINATE_LEN] = {0,}; smtd_dbg("%s: %02xh\n", __func__, LDI_COORDINATE_REG); ret = ana38401_read_offset(lcd, LDI_COORDINATE_REG, buf, LDI_COORDINATE_LEN, LDI_COORDINATE_OFFSET); if (ret < 1) dev_err(&lcd->ld->dev, "%s failed\n", __func__); lcd->coordinate[0] = buf[0] << 8 | buf[1]; /* X */ lcd->coordinate[1] = buf[2] << 8 | buf[3]; /* Y */ return ret; }
static int ana38401_read_date(struct lcd_info *lcd) { int ret; unsigned char buf[LDI_DATE_LEN] = {0,}; smtd_dbg("%s: %02xh\n", __func__, LDI_DATE_REG); ret = ana38401_read_offset(lcd, LDI_DATE_REG, buf, LDI_DATE_LEN, LDI_DATE_OFFSET); if (ret < 1) dev_err(&lcd->ld->dev, "%s failed\n", __func__); else dev_info(&lcd->ld->dev, "%s: %02x %02x\n", __func__, buf[0], buf[1]); /* manufacture date */ if (!lcd->date[0] && !lcd->date[1]) { lcd->date[0] = buf[0]; /* 127th */ lcd->date[1] = buf[1]; /* 128th */ } return ret; }
static int init_gamma_table(struct lcd_info *lcd, u8 *mtp_data, u8 *hbm_data) { int i, c, j, v, new_gamma; int ret = 0; int *pgamma; int **gamma; unsigned char value; /* allocate memory for local gamma table */ gamma = kzalloc(IBRIGHTNESS_MAX * sizeof(int *), GFP_KERNEL); if (!gamma) { pr_err("failed to allocate gamma table\n"); ret = -ENOMEM; goto err_alloc_gamma_table; } for (i = 0; i < IBRIGHTNESS_MAX; i++) { gamma[i] = kzalloc(IV_MAX*CI_MAX * sizeof(int), GFP_KERNEL); if (!gamma[i]) { pr_err("failed to allocate gamma\n"); ret = -ENOMEM; goto err_alloc_gamma; } } /* allocate memory for gamma table */ lcd->gamma_table = kzalloc(IBRIGHTNESS_MAX * sizeof(u8 *), GFP_KERNEL); if (!lcd->gamma_table) { pr_err("failed to allocate gamma table 2\n"); ret = -ENOMEM; goto err_alloc_gamma_table2; } for (i = 0; i < IBRIGHTNESS_MAX; i++) { lcd->gamma_table[i] = kzalloc(GAMMA_PARAM_SIZE * sizeof(u8), GFP_KERNEL); if (!lcd->gamma_table[i]) { pr_err("failed to allocate gamma 2\n"); ret = -ENOMEM; goto err_alloc_gamma2; } lcd->gamma_table[i][0] = LDI_GAMMA_REG; } /* calculate gamma table */ init_mtp_data(lcd, mtp_data); dynamic_aid(lcd->daid, gamma); /* to support hbm with Gamma_Offset_Index[4] read hbm gamma parameter from panel relocate order, add mtp offset in all brightness level loop and re-relocate */ init_hbm_data(lcd, hbm_data, gamma[IBRIGHTNESS_500NT]); smtd_dbg("MTP_Offset_Value\n"); for (j = 0; j < IV_MAX; j++) { for (c = 0; c < CI_MAX; c++) smtd_dbg("%04d ", lcd->daid.mtp[j*CI_MAX+c]); smtd_dbg("\n"); } smtd_dbg("Gamma_Offset_Index[0]\n"); for (i = 0; i < IBRIGHTNESS_MAX; i++) { smtd_dbg("Gamma [%03d] = ", index_brightness_table[i]); for (j = 0; j < IV_MAX; j++) { for (c = 0; c < CI_MAX; c++) smtd_dbg("%04d ", gamma[i][j*CI_MAX+c]); } smtd_dbg("\n"); } for (i = 0; i < IBRIGHTNESS_MAX; i++) { for (j = 0; j < IV_MAX; j++) { for (c = 0; c < CI_MAX; c++) { new_gamma = gamma[i][j*CI_MAX+c] + lcd->daid.mtp[j*CI_MAX+c]; new_gamma = (new_gamma < 0) ? 0 : new_gamma; if (j != IV_MAX - 1) new_gamma = (new_gamma > 255) ? 0 : new_gamma; gamma[i][j*CI_MAX+c] = new_gamma; } } } smtd_dbg("Gamma_Offset_Index[4]\n"); for (i = 0; i < IBRIGHTNESS_MAX; i++) { smtd_dbg("Gamma [%03d] = ", index_brightness_table[i]); for (j = 0; j < IV_MAX; j++) { for (c = 0; c < CI_MAX; c++) smtd_dbg("%04d ", gamma[i][j*CI_MAX+c]); } smtd_dbg("\n"); } /* relocate gamma order */ for (i = 0; i < IBRIGHTNESS_MAX; i++) { /* Brightness table */ for (c = 0, j = 1; c < CI_MAX; c++, pgamma++) { for (v = IV_11; v < IV_MAX; v++) { pgamma = &gamma[i][v * CI_MAX + c]; value = (char)((*pgamma) & 0xff); lcd->gamma_table[i][j++] = value; } pgamma = &gamma[i][IV_3 * CI_MAX + c]; value = (char)((*pgamma) & 0xff); lcd->gamma_table[i][j++] = value; pgamma = &gamma[i][IV_255 * CI_MAX + c]; value = (*pgamma & 0x100) ? 0x80 : 0x00; lcd->gamma_table[i][j++] = value; pgamma = &gamma[i][IV_VT * CI_MAX + c]; value = (char)((*pgamma) & 0xff); lcd->gamma_table[i][j++] = value; } for (v = 0; v < GAMMA_PARAM_SIZE; v++) smtd_dbg("%d ", lcd->gamma_table[i][v]); smtd_dbg("\n"); } /* free local gamma table */ for (i = 0; i < IBRIGHTNESS_MAX; i++) kfree(gamma[i]); kfree(gamma); return 0; err_alloc_gamma2: while (i > 0) { kfree(lcd->gamma_table[i-1]); i--; } kfree(lcd->gamma_table); err_alloc_gamma_table2: i = IBRIGHTNESS_MAX; err_alloc_gamma: while (i > 0) { kfree(gamma[i-1]); i--; } kfree(gamma); err_alloc_gamma_table: return ret; }
static void show_lcd_table(struct lcd_info *lcd) { int i, j, temp, acl; for (i = 0; i < IBRIGHTNESS_MAX; i++) { smtd_dbg("%03d: ", index_brightness_table[i]); for (j = 0; j < GAMMA_PARAM_SIZE; j++) smtd_dbg("%02X ", lcd->gamma_table[i][j]); smtd_dbg("\n"); } smtd_dbg("\n"); for (i = 0; i < IBRIGHTNESS_MAX; i++) { smtd_dbg("%03d: ", index_brightness_table[i]); for (j = 0; j < GAMMA_PARAM_SIZE; j++) smtd_dbg("%03d ", lcd->gamma_table[i][j]); smtd_dbg("\n"); } smtd_dbg("\n"); for (i = 0; i < IBRIGHTNESS_MAX; i++) { smtd_dbg("%03d: ", index_brightness_table[i]); for (j = 0; j < AID_PARAM_SIZE; j++) smtd_dbg("%02X ", lcd->aor[i][j]); smtd_dbg("\n"); } smtd_dbg("\n"); for (temp = 0; temp < TEMP_MAX; temp++) { smtd_dbg("temp: %d\n", temp); for (acl = 0; acl < ACL_STATUS_MAX; acl++) { smtd_dbg("acl: %d\n", acl); for (i = 0; i < ELVSS_STATUS_MAX; i++) { smtd_dbg("%03d: ", ELVSS_DIM_TABLE[i]); for (j = 0; j < DEFAULT_PARAM_SIZE; j++) smtd_dbg("%02X ", lcd->elvss_table[temp][acl][i][j]); smtd_dbg("\n"); } smtd_dbg("\n"); } smtd_dbg("\n"); } smtd_dbg("\n"); }
static int init_aid_dimming_table(struct lcd_info *lcd, const u8 *mtp_data) { unsigned int i, j, c; u16 reverse_seq[] = { 0, 28, 29, 30, 31, 32, 33, 25, 26, 27, 22, 23, 24, 19, 20, 21, 16, 17, 18, 13, 14, 15, 10, 11, 12, 7, 8, 9, 4, 5, 6, 1, 2, 3}; u16 temp[GAMMA_PARAM_SIZE]; for (i = 0; i < ARRAY_SIZE(aid_rgb_fix_table_VT232); i++) { if (aid_rgb_fix_table_VT232[i].gray == IV_255) j = (aid_rgb_fix_table_VT232[i].gray * 3 + aid_rgb_fix_table_VT232[i].rgb*2) + 2; else j = (aid_rgb_fix_table_VT232[i].gray * 3 + aid_rgb_fix_table_VT232[i].rgb) + 1; c = lcd->gamma_table[aid_rgb_fix_table_VT232[i].candela_idx][j] + aid_rgb_fix_table_VT232[i].offset; if (c > 0xff) lcd->gamma_table[aid_rgb_fix_table_VT232[i].candela_idx][j] = 0xff; else lcd->gamma_table[aid_rgb_fix_table_VT232[i].candela_idx][j] += aid_rgb_fix_table_VT232[i].offset; } for (i = 0; i < GAMMA_MAX; i++) { memcpy(lcd->aor[i], SEQ_AOR_CONTROL, AID_PARAM_SIZE); lcd->aor[i][0x01] = aid_setting_table_VT232[i].aor_cmd[0]; lcd->aor[i][0x06] = aid_setting_table_VT232[i].aor_cmd[1]; lcd->aor[i][0x07] = aid_setting_table_VT232[i].aor_cmd[2]; } for (i = 0; i < GAMMA_MAX; i++) { for (j = 0; j < GAMMA_PARAM_SIZE; j++) smtd_dbg("%d,", lcd->gamma_table[i][j]); smtd_dbg("\n"); } smtd_dbg("\n"); for (i = 0; i < GAMMA_MAX; i++) { for (j = 0; j < GAMMA_PARAM_SIZE; j++) temp[j] = lcd->gamma_table[i][reverse_seq[j]]; for (j = 0; j < GAMMA_PARAM_SIZE; j++) lcd->gamma_table[i][j] = temp[j]; for (c = CI_RED; c < CI_MAX ; c++) lcd->gamma_table[i][31+c] = lcd->smart.default_gamma[30+c]; } #ifdef PSRE_HBM for (i = 0; i < GAMMA_PARAM_SIZE; i++) lcd->hbm_gamma_table[i] = lcd->gamma_table[GAMMA_300CD][i]; for (i = 0; i < HBM_READ_LEN; i++) lcd->hbm_gamma_table[1+i] = mtp_data[33+i]; #endif for (i = 0; i < GAMMA_MAX; i++) { for (j = 0; j < GAMMA_PARAM_SIZE; j++) smtd_dbg("%d,", lcd->gamma_table[i][j]); smtd_dbg("\n"); } return 0; }
static int s6e8fa0_probe(struct mipi_dsim_device *dsim) { int ret = 0, i; struct lcd_info *lcd; #ifdef SMART_DIMMING u8 mtp_data[LDI_MTP_LENGTH] = {0,}; u8 elvss_data[LDI_ELVSS_LENGTH] = {0,}; #endif lcd = kzalloc(sizeof(struct lcd_info), GFP_KERNEL); if (!lcd) { pr_err("failed to allocate for lcd\n"); ret = -ENOMEM; goto err_alloc; } g_lcd = lcd; lcd->ld = lcd_device_register("panel", dsim->dev, lcd, &s6e8fa0_lcd_ops); if (IS_ERR(lcd->ld)) { pr_err("failed to register lcd device\n"); ret = PTR_ERR(lcd->ld); goto out_free_lcd; } lcd->bd = backlight_device_register("panel", dsim->dev, lcd, &s6e8fa0_backlight_ops, NULL); if (IS_ERR(lcd->bd)) { pr_err("failed to register backlight device\n"); ret = PTR_ERR(lcd->bd); goto out_free_backlight; } lcd->dev = dsim->dev; lcd->dsim = dsim; lcd->bd->props.max_brightness = MAX_BRIGHTNESS; lcd->bd->props.brightness = DEFAULT_BRIGHTNESS; lcd->bl = DEFAULT_GAMMA_LEVEL; lcd->current_bl = lcd->bl; lcd->acl_enable = 0; lcd->current_acl = 0; lcd->power = FB_BLANK_UNBLANK; lcd->ldi_enable = 1; lcd->auto_brightness = 0; lcd->connected = 1; lcd->siop_enable = 0; ret = device_create_file(&lcd->ld->dev, &dev_attr_power_reduce); if (ret < 0) dev_err(&lcd->ld->dev, "failed to add sysfs entries, %d\n", __LINE__); ret = device_create_file(&lcd->ld->dev, &dev_attr_lcd_type); if (ret < 0) dev_err(&lcd->ld->dev, "failed to add sysfs entries, %d\n", __LINE__); ret = device_create_file(&lcd->ld->dev, &dev_attr_window_type); if (ret < 0) dev_err(&lcd->ld->dev, "failed to add sysfs entries, %d\n", __LINE__); ret = device_create_file(&lcd->ld->dev, &dev_attr_gamma_table); if (ret < 0) dev_err(&lcd->ld->dev, "failed to add sysfs entries, %d\n", __LINE__); ret = device_create_file(&lcd->bd->dev, &dev_attr_auto_brightness); if (ret < 0) dev_err(&lcd->ld->dev, "failed to add sysfs entries, %d\n", __LINE__); ret = device_create_file(&lcd->ld->dev, &dev_attr_siop_enable); if (ret < 0) dev_err(&lcd->ld->dev, "failed to add sysfs entries, %d\n", __LINE__); /* dev_set_drvdata(dsim->dev, lcd); */ mutex_init(&lcd->lock); mutex_init(&lcd->bl_lock); s6e8fa0_read_id(lcd, lcd->id); dev_info(&lcd->ld->dev, "ID: %x, %x, %x\n", lcd->id[0], lcd->id[1], lcd->id[2]); dev_info(&lcd->ld->dev, "%s lcd panel driver has been probed.\n", dev_name(dsim->dev)); #ifdef SMART_DIMMING for (i = 0; i < LDI_ID_LEN; i++) lcd->smart.panelid[i] = lcd->id[i]; init_table_info_6P(&lcd->smart); ret = s6e8fa0_read_mtp(lcd, mtp_data); for (i = 0; i < LDI_MTP_LENGTH ; i++) smtd_dbg("%dth mtp value is %d\n", i, mtp_data[i]); if (ret < 1) printk(KERN_ERR "[LCD:ERROR] : %s read mtp failed\n", __func__); /*return -EPERM;*/ calc_voltage_table_6P(&lcd->smart, mtp_data); ret = s6e8fa0_read_elvss(lcd, elvss_data); for (i = 0; i < LDI_ELVSS_LENGTH ; i++) smtd_dbg("%dth ELVSS_volt_level %x\n", i, elvss_data[i]); lcd->elvss_ref = elvss_data[1]; #ifdef PSRE_HBM lcd->elvss_cal_origin = elvss_data[16]; lcd->elvss_cal_hbm = mtp_data[39]; #endif ret = init_elvss_table(lcd); ret += init_gamma_table(lcd, mtp_data); ret += init_aid_dimming_table(lcd, mtp_data); if (ret) printk(KERN_ERR "gamma table generation is failed\n"); update_brightness(lcd, 1); #endif return 0; out_free_backlight: lcd_device_unregister(lcd->ld); kfree(lcd); return ret; out_free_lcd: kfree(lcd); return ret; err_alloc: return ret; }