aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/s5c73m3.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/s5c73m3.c')
-rw-r--r--drivers/media/video/s5c73m3.c307
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,