[COMMON] fimc-is2: add OTP cal read for 5E9
authorWooyeon Kim <wooy88.kim@samsung.com>
Tue, 26 Feb 2019 10:19:39 +0000 (19:19 +0900)
committerlingsen1 <lingsen1@lenovo.com>
Mon, 10 Jun 2019 03:24:42 +0000 (11:24 +0800)
 - cal read and check in 5E9

 PR JIRA ID: CPR-773

Change-Id: I68a23e5b44c9c2ad2e8ede02d643013dfb860b4e
Signed-off-by: Wooyeon Kim <wooy88.kim@samsung.com>
drivers/media/platform/exynos/fimc-is2/sensor/module_framework/cis/fimc-is-cis-5e9.c
drivers/media/platform/exynos/fimc-is2/sensor/module_framework/cis/fimc-is-cis-5e9.h

index 2a0c26b028872698139eb50ff2758fc618055fad..8f45861bf8a05303537c55b6900241360023abb7 100644 (file)
@@ -193,11 +193,244 @@ int sensor_5e9_cis_check_rev(struct v4l2_subdev *subdev)
        return ret;
 }
 
+int sensor_5e9_cis_otp_check_awb_ratio(char *unit, char *golden, char *limit)
+{
+       int ret = 0;
+
+       float r_g_min = (float)(limit[0]) / 1000;
+       float r_g_max = (float)(limit[1]) / 1000;
+       float b_g_min = (float)(limit[2]) / 1000;
+       float b_g_max = (float)(limit[3]) / 1000;
+
+       /* read by little endian */
+       float rg = (float) ((unit[1] << 8) | (unit[0])) / 16384;
+       float bg = (float) ((unit[3] << 8) | (unit[2])) / 16384;
+
+       float golden_rg = (float) ((golden[1] << 8) | (golden[0])) / 16384;
+       float golden_bg = (float) ((golden[3] << 8) | (golden[2])) / 16384;
+
+       if (rg < (golden_rg - r_g_min) || rg > (golden_rg + r_g_max)) {
+               err("%s(): Final RG calibration factors out of range! rg=0x%x golden_rg=0x%x",
+                       __func__, (unit[1] << 8 | unit[0]), (golden[1] << 8 | golden[0]));
+               ret = 1;
+       }
+
+       if (bg < (golden_bg - b_g_min) || bg > (golden_bg + b_g_max)) {
+               err("%s(): Final BG calibration factors out of range! bg=0x%x, golden_bg=0x%x",
+                       __func__, (unit[3] << 8 | unit[2]), (golden[3] << 8 | golden[2]));
+               ret = 1;
+       }
+
+       return ret;
+}
+
+int sensor_5e9_cis_otp_check_crc(struct v4l2_subdev *subdev,
+               struct fimc_is_device_sensor *device, int grp_offset)
+{
+       int ret = 0;
+       u16 crc_value = 0;
+       u16 crc16 = 0;
+       char *check_buf = (char *)&device->otp_cal_buf[0][0];
+       int group = (grp_offset == 0) ? 1 : 2;
+
+       /* ADDR CRC check */
+       crc_value = ((check_buf[grp_offset + OTP_GRP_ADDR_CHKSUM + 1] << 8)
+                       | (check_buf[grp_offset + OTP_GRP_ADDR_CHKSUM]));
+       crc16 = sensor_cis_otp_get_crc16(&check_buf[grp_offset + OTP_GRP_ADDR_CRC_START],
+                                               OTP_GRP_ADDR_CRC_SIZE);
+       if (crc_value != crc16) {
+               err("GR%d: Error to ADDR CRC16 : 0x%x, cal buffer CRC: 0x%x", group, crc16, crc_value);
+               ret = -EINVAL;
+       } else
+               info("GR%d: ADDR CRC16 : 0x%x, cal buffer CRC: 0x%x\n", group, crc16, crc_value);
+
+       /* INFO CRC check */
+       crc_value = ((check_buf[grp_offset + OTP_GRP_INFO_CHKSUM + 1] << 8)
+                       | (check_buf[grp_offset + OTP_GRP_INFO_CHKSUM]));
+       crc16 = sensor_cis_otp_get_crc16(&check_buf[grp_offset + OTP_GRP_INFO_CRC_START],
+                                               OTP_GRP_INFO_CRC_SIZE);
+       if (crc_value != crc16) {
+               err("GR%d: Error to INFO CRC16 : 0x%x, cal buffer CRC: 0x%x", group, crc16, crc_value);
+               ret = -EINVAL;
+       } else
+               info("GR%d: INFO CRC16 : 0x%x, cal buffer CRC: 0x%x\n", group, crc16, crc_value);
+
+       /* AWB CRC check */
+       crc_value = ((check_buf[grp_offset + OTP_GRP_AWB_CHKSUM + 1] << 8)
+                       | (check_buf[grp_offset + OTP_GRP_AWB_CHKSUM]));
+       crc16 = sensor_cis_otp_get_crc16(&check_buf[grp_offset + OTP_GRP_AWB_CRC_START],
+                                               OTP_GRP_AWB_CRC_SIZE);
+       if (crc_value != crc16) {
+               err("GR%d: Error to AWB CRC16 : 0x%x, cal buffer CRC: 0x%x", group, crc16, crc_value);
+               ret = -EINVAL;
+       } else
+               info("GR%d: AWB CRC16 : 0x%x, cal buffer CRC: 0x%x\n", group, crc16, crc_value);
+
+       /* LSC_XTC CRC check */
+       crc_value = ((check_buf[grp_offset + OTP_GRP_LSC_XTC_CHKSUM + 1] << 8)
+                       | (check_buf[grp_offset + OTP_GRP_LSC_XTC_CHKSUM]));
+       crc16 = sensor_cis_otp_get_crc16(&check_buf[grp_offset + OTP_GRP_LSC_XTC_CRC_START],
+                                               OTP_GRP_LSC_XTC_CRC_SIZE);
+       if (crc_value != crc16) {
+               err("GR%d: Error to LSC_XTC CRC16 : 0x%x, cal buffer CRC: 0x%x", group, crc16, crc_value);
+               ret = -EINVAL;
+       } else
+               info("GR%d: LSC_XTC CRC16 : 0x%x, cal buffer CRC: 0x%x\n", group, crc16, crc_value);
+
+       /* LSC_XTC CRC check */
+       crc_value = ((check_buf[grp_offset + OTP_GRP_AE_SYNC_CHKSUM + 1] << 8)
+                       | (check_buf[grp_offset + OTP_GRP_AE_SYNC_CHKSUM]));
+       crc16 = sensor_cis_otp_get_crc16(&check_buf[grp_offset + OTP_GRP_AE_SYNC_CRC_START],
+                                               OTP_GRP_AE_SYNC_CRC_SIZE);
+       if (crc_value != crc16) {
+               err("GR%d: Error to AE_SYNC CRC16 : 0x%x, cal buffer CRC: 0x%x", group, crc16, crc_value);
+               ret = -EINVAL;
+       } else
+               info("GR%d: AE_SYNC CRC16 : 0x%x, cal buffer CRC: 0x%x\n", group, crc16, crc_value);
+
+       return ret;
+}
+
+int sensor_5e9_cis_otp_read(struct v4l2_subdev *subdev, struct fimc_is_device_sensor *device)
+{
+       int ret = 0;
+       struct fimc_is_cis *cis;
+       struct i2c_client *client;
+       u8 val, page;
+       int i;
+       int retry = 200;
+
+       FIMC_BUG(!subdev);
+
+       cis = (struct fimc_is_cis *)v4l2_get_subdevdata(subdev);
+       if (!cis) {
+               err("cis is NULL");
+               return -EINVAL;
+       }
+
+       client = cis->client;
+       if (unlikely(!client)) {
+               err("client is NULL");
+               return -ENODEV;
+       }
+
+       dbg_sensor(1, "%s, 1. sensor initial setting", __func__);
+       CALL_CISOPS(cis, cis_set_global_setting, subdev);
+       CALL_CISOPS(cis, cis_mode_change, subdev, 0);
+
+       I2C_MUTEX_LOCK(cis->i2c_lock);
+
+       dbg_sensor(1, "%s, 2. sensor stream on", __func__);
+       fimc_is_sensor_write8(client, 0x0100, 0x01);
+
+       /* wait 50ms */
+       msleep(50);
+
+       dbg_sensor(1, "%s, 3. page select & read cal", __func__);
+       for (page = OTP_PAGE_START; page <= OTP_PAGE_END; page++) {
+               /* page select & read start */
+               fimc_is_sensor_write8(client, OTP_PAGE_SELECT, page);
+               fimc_is_sensor_write8(client, OTP_PAGE_CTRL, 0x01);
+               usleep_range(1000, 1001);
+
+               /* wait 0x0A01 == 1 [0]: read completed with no errors */
+               while (retry--) {
+                       fimc_is_sensor_read8(client, OTP_PAGE_ERRCHK, &val);
+                       if (val == 1)
+                               break;
+
+                       usleep_range(100, 100);
+               }
+
+               for (i = 0; i < OTP_PAGE_SIZE; i++) {
+                       fimc_is_sensor_read8(client, OTP_PAGE_BASE + i, &device->otp_cal_buf[page][i]);
+                       dbg_sensor(2, "cal: [%d][0x%x]: %x\n", page, OTP_PAGE_BASE + i, device->otp_cal_buf[page][i]);
+               }
+
+               /* make initial state */
+               fimc_is_sensor_write8(client, OTP_PAGE_CTRL, 0x04);
+               fimc_is_sensor_write8(client, OTP_PAGE_CTRL, 0x00);
+       }
+
+       fimc_is_sensor_write8(client, 0x0100, 0x00);
+       msleep(20);
+       info("OTP end!!!!!\n");
+
+       I2C_MUTEX_UNLOCK(cis->i2c_lock);
+
+       return ret;
+}
+
+int sensor_5e9_cis_otp(struct v4l2_subdev *subdev, struct fimc_is_device_sensor *device)
+{
+       int ret = 0;
+       int otp_group = 0x0;
+       int offset = 0;
+       char *otp_buf = (char *)&device->otp_cal_buf[0][0];
+       char file_str[60];
+
+       snprintf(file_str, sizeof(file_str), "%s%s", OTP_DATA_PATH, device->otp_filename);
+       ret = sensor_cis_otp_read_file(file_str, (void *)device->otp_cal_buf, OTP_PAGE_SIZE * 64);
+       if (ret) {
+               /* OTP data read */
+               ret = sensor_5e9_cis_otp_read(subdev, device);
+               if (ret < 0) {
+                       err("Don't read to 5E9 OTP data");
+                       goto p_err;
+               }
+
+               /* Write to OTP data at file */
+               ret = sensor_cis_otp_write_file(file_str, (void *)device->otp_cal_buf, OTP_PAGE_SIZE * 64);
+               if (ret < 0) {
+                       err("5E9 OTP data don't file write");
+                       goto p_err;
+               }
+       }
+
+       /* Need to first check GROUP2 */
+       if (otp_buf[OTP_GRP_FLAG + OTP_GRP2_OFFSET * OTP_PAGE_SIZE] == OTP_DATA_VALID) {
+               otp_group = OTP_GROUP_TWO;
+               offset = OTP_GRP2_OFFSET * OTP_PAGE_SIZE;
+       } else if (otp_buf[OTP_GRP_FLAG] == OTP_DATA_VALID) {
+               otp_group = OTP_GROUP_ONE;
+               offset = 0;
+       } else {
+               err("All OTP data are invalid, check module");
+               goto p_err;
+       }
+
+       /* OTP CRC check */
+       ret = sensor_5e9_cis_otp_check_crc(subdev, device, offset);
+       if (ret < 0) {
+               err("All OTP data CRC check fail, check module");
+
+               device->cal_status[CAMERA_CRC_INDEX_AWB] = CRC_ERROR;
+               goto p_err;
+       } else {
+               u8 *awb_base = &otp_buf[offset + OTP_GRP_AWB_CHKSUM];
+
+               device->cal_status[CAMERA_CRC_INDEX_AWB] = CRC_NO_ERROR;
+               ret = sensor_5e9_cis_otp_check_awb_ratio(&awb_base[CURRENT_RG_RATIO_OFFSET],
+                               &awb_base[MASTER_RG_RATIO_OFFSET],
+                               &awb_base[RG_MIN_LIMIT_OFFSET]);
+               if (ret) {
+                       err("%s(): 5E9 OTP AWB Group%d ratio out of limit(%d)", __func__, otp_group, ret);
+                       device->cal_status[CAMERA_CRC_INDEX_AWB] = LIMIT_FAILURE;
+                       ret = -1;
+               }
+       }
+
+p_err:
+       return ret;
+}
+
 /* CIS OPS */
 int sensor_5e9_cis_init(struct v4l2_subdev *subdev)
 {
        int ret = 0;
        struct fimc_is_cis *cis;
+       struct fimc_is_module_enum *module;
+       struct fimc_is_device_sensor *device = NULL;
        u32 setfile_index = 0;
        cis_setting_info setinfo;
 
@@ -214,6 +447,15 @@ int sensor_5e9_cis_init(struct v4l2_subdev *subdev)
 
        FIMC_BUG(!subdev);
 
+       module = (struct fimc_is_module_enum *)v4l2_get_subdev_hostdata(subdev);
+
+       device = (struct fimc_is_device_sensor *)v4l2_get_subdev_hostdata(module->subdev);
+       if (!device) {
+               err("device sensor is NULL");
+               ret = -ENODEV;
+               goto p_err;
+       }
+
        cis = (struct fimc_is_cis *)v4l2_get_subdevdata(subdev);
        if (!cis) {
                err("cis is NULL");
@@ -368,6 +610,14 @@ int sensor_5e9_cis_init(struct v4l2_subdev *subdev)
        dbg_sensor(1, "[%s] time %lu us\n", __func__, (end.tv_sec - st.tv_sec)*1000000 + (end.tv_usec - st.tv_usec));
 #endif
 
+       if (device->use_otp_cal) {
+               ret = sensor_5e9_cis_otp(subdev, device);
+               if (ret < 0) {
+                       err("5E9 OTP data have problem, check module");
+                       ret = 0;
+               }
+       }
+
 p_err:
        return ret;
 }
@@ -1925,6 +2175,7 @@ static int cis_5e9_probe(struct i2c_client *client,
        const struct i2c_device_id *id)
 {
        int ret = 0;
+       int i;
        struct fimc_is_core *core = NULL;
        struct v4l2_subdev *subdev_cis = NULL;
        struct fimc_is_cis *cis = NULL;
@@ -2073,6 +2324,20 @@ static int cis_5e9_probe(struct i2c_client *client,
        cis->use_initial_ae = of_property_read_bool(dnode, "use_initial_ae");
        probe_info("%s use initial_ae(%d)\n", __func__, cis->use_initial_ae);
 
+       device->use_otp_cal = of_property_read_bool(dnode, "use_otp_cal");
+       probe_info("%s use otp_cal(%d)\n", __func__, device->use_otp_cal);
+       if (device->use_otp_cal) {
+               ret = of_property_read_string(dnode, "otp_filename", &device->otp_filename);
+               if (ret) {
+                       err("OTP filename read fail(%d), take default name", ret);
+                       device->otp_filename = "5e9_otp_cal_data.bin";
+               }
+               probe_info("%s otp_filename(%s)\n", __func__, device->otp_filename);
+       }
+
+       for (i = 0; i < CAMERA_CRC_INDEX_MAX; i++)
+               device->cal_status[i] = CRC_NO_ERROR;
+
        v4l2_i2c_subdev_init(subdev_cis, client, &subdev_ops);
        v4l2_set_subdevdata(subdev_cis, cis);
        v4l2_set_subdev_hostdata(subdev_cis, device);
index 4655b0f86ca3c00c337479027c16d32c2ad29b64..295c2e69a95e6e72b74cd2cfbec3bc22ec704d41 100644 (file)
 #define USE_OTP_AWB_CAL_DATA   (0)
 #endif
 
+/* OTP valies */
+#define OTP_DATA_PATH                  "/data/vendor/camera/"
+#define OTP_PAGE_CTRL                  0x0A00
+#define OTP_PAGE_ERRCHK                        0x0A01
+#define OTP_PAGE_SELECT                        0x0A02
+#define OTP_PAGE_BASE                  0x0A04
+#define OTP_PAGE_START                 0
+#define OTP_PAGE_END                   63
+#define OTP_PAGE_SIZE                  64
+
+#define OTP_GRP_FLAG                   (17 * OTP_PAGE_SIZE)
+
+#define OTP_GRP_ADDR_CHKSUM            (17 * OTP_PAGE_SIZE + 0x4)
+#define OTP_GRP_ADDR_CRC_START         (17 * OTP_PAGE_SIZE + 0x8)
+#define OTP_GRP_ADDR_CRC_SIZE          (72)
+#define OTP_GRP_INFO_CHKSUM            (18 * OTP_PAGE_SIZE + 0x20)
+#define OTP_GRP_INFO_CRC_START         (18 * OTP_PAGE_SIZE + 0x24)
+#define OTP_GRP_INFO_CRC_SIZE          (54)
+#define OTP_GRP_AWB_CHKSUM             (19 * OTP_PAGE_SIZE + 0x30)
+#define OTP_GRP_AWB_CRC_START          (19 * OTP_PAGE_SIZE + 0x34)
+#define OTP_GRP_AWB_CRC_SIZE           (80)
+#define OTP_GRP_LSC_XTC_CHKSUM         (21 * OTP_PAGE_SIZE + 0x20)
+#define OTP_GRP_LSC_XTC_CRC_START      (21 * OTP_PAGE_SIZE + 0x24)
+#define OTP_GRP_LSC_XTC_CRC_SIZE       (888)
+#define OTP_GRP_AE_SYNC_CHKSUM         (35 * OTP_PAGE_SIZE + 0x30)
+#define OTP_GRP_AE_SYNC_CRC_START      (35 * OTP_PAGE_SIZE + 0x34)
+#define OTP_GRP_AE_SYNC_CRC_SIZE       (4)
+
+#define OTP_GRP2_OFFSET                        (20)
+
+/* AWB ratio check */
+#define RG_MIN_LIMIT_OFFSET            0x28
+#define RG_MAX_LIMIT_OFFSET            0x29
+#define BG_MIN_LIMIT_OFFSET            0x2A
+#define BG_MAX_LIMIT_OFFSET            0x2B
+
+#define MASTER_RG_RATIO_OFFSET         0x2C
+#define MASTER_BG_RATIO_OFFSET         0x2E
+#define MASTER_GR_GB_RATIO_OFFSET      0x30
+#define CURRENT_RG_RATIO_OFFSET                0x32
+#define CURRENT_BG_RATIO_OFFSET                0x34
+#define CURRENT_GR_GB_RATIO_OFFSET     0x36
+
+enum otp_group {
+       OTP_GROUP_ONE = 0x1,
+       OTP_GROUP_TWO = 0x2,
+       OTP_GROUP_MAX,
+};
+
+enum valid_check {
+       OTP_DATA_EMPTY = 0x0,
+       OTP_DATA_VALID = 0x40,
+       OTP_DATA_INVALID = 0xC0,
+};
+
 #endif