diff options
Diffstat (limited to 'drivers/media/video/s5c73m3.c')
-rw-r--r-- | drivers/media/video/s5c73m3.c | 307 |
1 files changed, 223 insertions, 84 deletions
diff --git a/drivers/media/video/s5c73m3.c b/drivers/media/video/s5c73m3.c index ea07a34..5db5f7f 100644 --- a/drivers/media/video/s5c73m3.c +++ b/drivers/media/video/s5c73m3.c @@ -37,6 +37,7 @@ #endif #include <linux/regulator/machine.h> +#include <linux/leds-aat1290a.h> #include <media/s5c73m3_platform.h> #include "s5c73m3.h" @@ -163,6 +164,8 @@ static u8 sysfs_phone_fw[10] = {0,}; static u8 sysfs_sensor_type[15] = {0,}; static u8 sysfs_isp_core[10] = {0,}; static u8 data_memory[500000] = {0,}; +static u32 crc_table[256] = {0,}; +static int copied_fw_binary; static u16 isp_chip_info1; static u16 isp_chip_info2; @@ -312,6 +315,48 @@ static int s5c73m3_read(struct v4l2_subdev *sd, return err; } +static int s5c73m3_i2c_check_status_with_CRC(struct v4l2_subdev *sd) +{ + int err = 0; + int index = 0; + u16 status = 0; + u16 i2c_status = 0; + u16 i2c_seq_status = 0; + + do { + err = s5c73m3_read(sd, 0x0009, S5C73M3_STATUS, &status); + err = s5c73m3_read(sd, 0x0009, + S5C73M3_I2C_ERR_STATUS, &i2c_status); + if (i2c_status & ERROR_STATUS_CHECK_BIN_CRC) { + cam_dbg("failed to check CRC value of ISP Ram\n"); + err = -1; + break; + } + + if (status == 0xffff) + break; + + index++; + udelay(500); + } while (index < 2000); /* 1 sec */ + + if (index >= 2000) { + err = s5c73m3_read(sd, 0x0009, + S5C73M3_I2C_ERR_STATUS, &i2c_status); + err = s5c73m3_read(sd, 0x0009, + S5C73M3_I2C_SEQ_STATUS, &i2c_seq_status); + cam_dbg("TimeOut!! index:%d,status:%#x,i2c_stauts:%#x,i2c_seq_status:%#x\n", + index, + status, + i2c_status, + i2c_seq_status); + + err = -1; + } + + return err; +} + static int s5c73m3_i2c_check_status(struct v4l2_subdev *sd) { int err = 0; @@ -346,6 +391,46 @@ static int s5c73m3_i2c_check_status(struct v4l2_subdev *sd) return err; } +void s5c73m3_make_CRC_table(u32 *table, u32 id) +{ + u32 i, j, k; + + for(i = 0; i < 256; ++i) { + k = i; + for(j = 0; j < 8; ++j) { + if(k & 1) + k = (k >> 1) ^ id; + else + k >>= 1; + } + table[i] = k; + } +} + +static int s5c73m3_reset_module(struct v4l2_subdev *sd, bool powerReset) +{ + struct s5c73m3_state *state = to_state(sd); + int err = 0; + + cam_trace("E\n"); + + if (powerReset) { + err = state->pdata->power_on_off(0); + CHECK_ERR(err); + err = state->pdata->power_on_off(1); + CHECK_ERR(err); + } else { + err = state->pdata->is_isp_reset(); + CHECK_ERR(err); + } + err = s5c73m3_set_timing_register_for_vdd(sd); + CHECK_ERR(err); + + cam_trace("X\n"); + + return err; +} + static int s5c73m3_writeb(struct v4l2_subdev *sd, unsigned short addr, unsigned short data) { @@ -487,6 +572,27 @@ static int s5c73m3_get_sensor_fw_binary(struct v4l2_subdev *sd) mm_segment_t old_fs; long ret = 0; char fw_path[25] = {0,}; + u8 mem0 =0, mem1 = 0; + u32 CRC = 0; + u32 DataCRC = 0; + u32 IntOriginalCRC = 0; + u32 crc_index = 0; + int retryCnt = 2; + + if (state->sensor_fw[0] == 'O') { + sprintf(fw_path, "/data/cfw/SlimISP_G%c.bin", + state->sensor_fw[1]); + } else if (state->sensor_fw[0] == 'S') { + sprintf(fw_path, "/data/cfw/SlimISP_Z%c.bin", + state->sensor_fw[1]); + } else { + sprintf(fw_path, "/data/cfw/SlimISP_%c%c.bin", + state->sensor_fw[0], + state->sensor_fw[1]); + } + + /* Make CRC Table */ + s5c73m3_make_CRC_table((u32 *)&crc_table, 0xEDB88320); /*ARM go*/ err = s5c73m3_write(sd, 0x3000, 0x0004, 0xFFFF); @@ -554,32 +660,18 @@ static int s5c73m3_get_sensor_fw_binary(struct v4l2_subdev *sd) mdelay(200); - old_fs = get_fs(); - set_fs(KERNEL_DS); - - if (state->sensor_fw[0] == 'O') { - sprintf(fw_path, "/data/cfw/SlimISP_G%c.bin", - state->sensor_fw[1]); - } else if (state->sensor_fw[0] == 'S') { - sprintf(fw_path, "/data/cfw/SlimISP_Z%c.bin", - state->sensor_fw[1]); - } else { - sprintf(fw_path, "/data/cfw/SlimISP_%c%c.bin", - state->sensor_fw[0], - state->sensor_fw[1]); - } - - fp = filp_open(fw_path, O_WRONLY|O_CREAT, 0644); - if (IS_ERR(fp) || fp == NULL) { - cam_err("failed to open %s, err %ld\n", - fw_path, PTR_ERR(fp)); - err = -EINVAL; - goto out; - } +retry: + memset(data_memory, 0, sizeof(data_memory)); + mem0 =0, mem1 = 0; + CRC = 0; + DataCRC = 0; + IntOriginalCRC = 0; + crc_index = 0; /* SPI Copy mode ready I2C CMD */ err = s5c73m3_writeb(sd, 0x0924, 0x0000); CHECK_ERR(err); + cam_dbg("sent SPI ready CMD\n"); rxSize = 64*1024; mdelay(10); @@ -589,19 +681,72 @@ static int s5c73m3_get_sensor_fw_binary(struct v4l2_subdev *sd) state->sensor_size, rxSize); CHECK_ERR(err); - ret = vfs_write(fp, (char __user *)data_memory, - state->sensor_size, &fp->f_pos); + CRC = ~CRC; + for(crc_index = 0;crc_index < (state->sensor_size-4)/2;crc_index++) { + /*low byte*/ + mem0 = (unsigned char)(data_memory[crc_index*2] & 0x00ff); + /*high byte*/ + mem1 = (unsigned char)(data_memory[crc_index*2+1] & 0x00ff); + CRC = crc_table[(CRC ^ (mem0)) & 0xFF] ^ (CRC >> 8); + CRC = crc_table[(CRC ^ (mem1)) & 0xFF] ^ (CRC >> 8); + } + CRC = ~CRC; + + DataCRC = (CRC&0x000000ff)<<24; + DataCRC += (CRC&0x0000ff00)<<8; + DataCRC += (CRC&0x00ff0000)>>8; + DataCRC += (CRC&0xff000000)>>24; + cam_err("made CSC value by S/W = 0x%x\n", DataCRC); + + IntOriginalCRC = (data_memory[state->sensor_size-4]&0x00ff)<<24; + IntOriginalCRC += (data_memory[state->sensor_size-3]&0x00ff)<<16; + IntOriginalCRC += (data_memory[state->sensor_size-2]&0x00ff)<<8; + IntOriginalCRC += (data_memory[state->sensor_size-1]&0x00ff); + cam_err("Original CRC Int = 0x%x\n", IntOriginalCRC); + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + if (IntOriginalCRC == DataCRC) { + fp = filp_open(fw_path, O_WRONLY|O_CREAT|O_TRUNC, 0644); + if (IS_ERR(fp) || fp == NULL) { + cam_err("failed to open %s, err %ld\n", + fw_path, PTR_ERR(fp)); + err = -EINVAL; + goto out; + } + + ret = vfs_write(fp, (char __user *)data_memory, + state->sensor_size, &fp->f_pos); + + if (camfw_info[S5C73M3_SD_CARD].opened == 0) { + memcpy(state->phone_fw, + state->sensor_fw, + S5C73M3_FW_VER_LEN); + state->phone_fw[S5C73M3_FW_VER_LEN+1] = ' '; + + memcpy(sysfs_phone_fw, + state->phone_fw, + sizeof(state->phone_fw)); + cam_dbg("Changed to Phone_version = %s\n", + state->phone_fw); + } + } else { + if (retryCnt > 0) { + set_fs(old_fs); + retryCnt--; + goto retry; + } + } if (fp != NULL) filp_close(fp, current->files); out: set_fs(old_fs); - return err; } - static int s5c73m3_get_sensor_fw_version(struct v4l2_subdev *sd) { struct s5c73m3_state *state = to_state(sd); @@ -802,7 +947,6 @@ static int s5c73m3_get_phone_fw_version(struct v4l2_subdev *sd) int err = 0; int retVal = 0; int fw_requested = 1; - int copied_fw_binary = 0; if (state->sensor_fw[0] == 'O') { sprintf(fw_path, "SlimISP_G%c.bin", @@ -885,14 +1029,12 @@ request_fw: state->fw_index = S5C73M3_IN_DATA; } } else { - cam_dbg("get new fw to F-ROM : %s Version\n", + cam_dbg("can't open %s Ver. Firmware. so, download from F-ROM\n", state->sensor_fw); if (fw != NULL) release_firmware(fw); - retVal = state->pdata->is_isp_reset(); - CHECK_ERR(retVal); - retVal = s5c73m3_set_timing_register_for_vdd(sd); + retVal = s5c73m3_reset_module(sd, true); CHECK_ERR(retVal); retVal = s5c73m3_get_sensor_fw_binary(sd); CHECK_ERR(retVal); @@ -901,17 +1043,13 @@ request_fw: } } - if (copied_fw_binary) { + if (!copied_fw_binary) { memcpy(state->phone_fw, - state->sensor_fw, + camfw_info[state->fw_index].ver, S5C73M3_FW_VER_LEN); state->phone_fw[S5C73M3_FW_VER_LEN+1] = ' '; - } else { - memcpy(state->phone_fw, - camfw_info[state->fw_index].ver, - S5C73M3_FW_VER_LEN); - state->phone_fw[S5C73M3_FW_VER_LEN+1] = ' '; } + memcpy(sysfs_phone_fw, state->phone_fw, sizeof(state->phone_fw)); @@ -1049,10 +1187,11 @@ static int s5c73m3_check_fw_date(struct v4l2_subdev *sd) static int s5c73m3_check_fw(struct v4l2_subdev *sd, int download) { - struct s5c73m3_state *state = to_state(sd); int err, i; int retVal; + copied_fw_binary = 0; + if (!download) { for (i = 0; i < S5C73M3_PATH_MAX; i++) camfw_info[i].opened = 0; @@ -1065,16 +1204,22 @@ static int s5c73m3_check_fw(struct v4l2_subdev *sd, int download) } retVal = s5c73m3_check_fw_date(sd); - err = state->pdata->is_isp_reset(); - CHECK_ERR(err); - err = s5c73m3_set_timing_register_for_vdd(sd); - CHECK_ERR(err); /* retVal = 0 : Same Version - retVal < 0 : Phone Version is latest Version than sensorFW. - retVal > 0 : Sensor Version is latest version than phoenFW. */ - if (retVal <= 0 || download) { + retVal < 0 : Phone Version is latest Version than sensorFW. + retVal > 0 : Sensor Version is latest version than phoenFW. */ + if (retVal <= 0||download) { cam_dbg("Loading From PhoneFW......\n"); + + /* In case that there is no FW in phone and FW needs to be + downloaded from F-ROM, ISP power reset is required before + loading FW to ISP for F-ROM to work properly.*/ + if (copied_fw_binary) + err = s5c73m3_reset_module(sd, true); + else + err = s5c73m3_reset_module(sd, false); + CHECK_ERR(err); + err = s5c73m3_SPI_booting(sd); CHECK_ERR(err); @@ -1084,26 +1229,13 @@ static int s5c73m3_check_fw(struct v4l2_subdev *sd, int download) } } else { cam_dbg("Loading From SensorFW......\n"); -#if 0 - err = s5c73m3_SPI_booting_by_ISP(sd); + err = s5c73m3_reset_module(sd, true); CHECK_ERR(err); -#else err = s5c73m3_get_sensor_fw_binary(sd); CHECK_ERR(err); - - memcpy(state->phone_fw, - state->sensor_fw, - S5C73M3_FW_VER_LEN); - state->phone_fw[S5C73M3_FW_VER_LEN+1] = ' '; - - memcpy(sysfs_phone_fw, - state->phone_fw, - sizeof(state->phone_fw)); - cam_dbg("Changed to Phone_version = %s\n", - state->phone_fw); -#endif } + return 0; } @@ -1927,6 +2059,27 @@ static int s5c73m3_aeawb_lock_unlock(struct v4l2_subdev *sd, int val) return 0; } +static void s5c73m3_wait_for_preflash_fire(struct v4l2_subdev *sd) +{ + u16 pre_flash = false; + u16 timeout_cnt = 0; + + do { + s5c73m3_read(sd, 0x0009, + S5C73M3_STILL_PRE_FLASH | 0x5000, &pre_flash); + if (pre_flash || timeout_cnt > 20) { + if (!pre_flash) { + cam_dbg("pre_Flash = %d, timeout_cnt = %d\n", + pre_flash, timeout_cnt); + } + break; + } else + timeout_cnt++; + + mdelay(15); + } while (1); +} + static int s5c73m3_start_capture(struct v4l2_subdev *sd, int val) { struct s5c73m3_state *state = to_state(sd); @@ -1940,7 +2093,7 @@ static int s5c73m3_start_capture(struct v4l2_subdev *sd, int val) if (!pre_flash) { err = s5c73m3_writeb(sd, S5C73M3_STILL_PRE_FLASH , S5C73M3_STILL_PRE_FLASH_FIRE); - msleep(100); + s5c73m3_wait_for_preflash_fire(sd); } err = s5c73m3_writeb(sd, S5C73M3_STILL_MAIN_FLASH , S5C73M3_STILL_MAIN_FLASH_FIRE); @@ -1954,7 +2107,7 @@ static int s5c73m3_start_capture(struct v4l2_subdev *sd, int val) if (isneed_flash) { err = s5c73m3_writeb(sd, S5C73M3_STILL_PRE_FLASH , S5C73M3_STILL_PRE_FLASH_FIRE); - msleep(100); + s5c73m3_wait_for_preflash_fire(sd); err = s5c73m3_writeb(sd, S5C73M3_STILL_MAIN_FLASH, S5C73M3_STILL_MAIN_FLASH_FIRE); @@ -3109,7 +3262,7 @@ static int s5c73m3_read_vdd_core(struct v4l2_subdev *sd) set_fs(KERNEL_DS); fp = filp_open(S5C73M3_CORE_VDD, - O_WRONLY|O_CREAT, 0666); + O_WRONLY|O_CREAT|O_TRUNC, 0644); if (IS_ERR(fp)) goto out; @@ -3197,34 +3350,31 @@ static int s5c73m3_init(struct v4l2_subdev *sd, u32 val) #endif CHECK_ERR(err); - err = s5c73m3_i2c_check_status(sd); + err = s5c73m3_i2c_check_status_with_CRC(sd); if (err < 0) { cam_err("ISP is not ready. retry loading fw!!\n"); /* retry */ retVal = s5c73m3_check_fw_date(sd); - err = state->pdata->is_isp_reset(); - CHECK_ERR(err); - err = s5c73m3_set_timing_register_for_vdd(sd); - CHECK_ERR(err); - /* retVal = 0 : Same Version retVal < 0 : Phone Version is latest Version than sensorFW. retVal > 0 : Sensor Version is latest version than phoenFW. */ if (retVal <= 0) { cam_dbg("Loading From PhoneFW......\n"); + err = s5c73m3_reset_module(sd, false); + CHECK_ERR(err); err = s5c73m3_SPI_booting(sd); CHECK_ERR(err); } else { cam_dbg("Loading From SensorFW......\n"); + err = s5c73m3_reset_module(sd, true); + CHECK_ERR(err); err = s5c73m3_get_sensor_fw_binary(sd); CHECK_ERR(err); } - } state->isp.bad_fw = 0; - s5c73m3_init_param(sd); return 0; @@ -3271,18 +3421,7 @@ static ssize_t s5c73m3_camera_rear_flash(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - int err; - - if (buf[0] == '0') - err = s5c73m3_writeb(sd_internal, S5C73M3_FLASH_TORCH, - S5C73M3_FLASH_TORCH_OFF); - else - err = s5c73m3_writeb(sd_internal, S5C73M3_FLASH_TORCH, - S5C73M3_FLASH_TORCH_ON); - - CHECK_ERR(err); - - return count; + return aat1290a_power(dev, attr, buf, count); } static ssize_t s5c73m3_camera_isp_core_show(struct device *dev, |