From cbb8377ca8d75cc2a412c6a238c2c38675fe8700 Mon Sep 17 00:00:00 2001 From: ddl Date: Fri, 16 Nov 2012 16:01:22 +0800 Subject: [PATCH] camera: ov5640 add support touch focus --- drivers/media/video/ov5640.c | 142 ++++++++++++++++++++++++----------- 1 file changed, 99 insertions(+), 43 deletions(-) diff --git a/drivers/media/video/ov5640.c b/drivers/media/video/ov5640.c index ab996b01caad..8bdbac5314a7 100755 --- a/drivers/media/video/ov5640.c +++ b/drivers/media/video/ov5640.c @@ -68,6 +68,7 @@ module_param(debug, int, S_IRUGO|S_IWUSR); #define CONFIG_SENSOR_Flip 0 #ifdef CONFIG_OV5640_AUTOFOCUS #define CONFIG_SENSOR_Focus 1 +#define CONFIG_SENSOR_FocusCenterInCapture 0 #include "ov5640_af_firmware.c" #else #define CONFIG_SENSOR_Focus 0 @@ -128,9 +129,7 @@ module_param(debug, int, S_IRUGO|S_IWUSR); #define STA_FOCUS_Reg 0x3029 /* ov5640 VCM Command */ -#define OverlayEn_Cmd 0x01 -#define OverlayDis_Cmd 0x02 -#define SingleFocus_Cmd 0x03 + #define ConstFocus_Cmd 0x04 #define StepMode_Cmd 0x05 #define PauseFocus_Cmd 0x06 @@ -138,12 +137,15 @@ module_param(debug, int, S_IRUGO|S_IWUSR); #define SetZone_Cmd 0x10 #define UpdateZone_Cmd 0x12 #define SetMotor_Cmd 0x20 +#define SingleFocus_Cmd 0x03 +#define GetFocusResult_Cmd 0x07 +#define ReleaseFocus_Cmd 0x08 +#define ZoneRelaunch_Cmd 0x12 +#define DefaultZoneConfig_Cmd 0x80 +#define TouchZoneConfig_Cmd 0x81 +#define CustomZoneConfig_Cmd 0x8f -#define Zone_configuration_Cmd 0x12 -#define Trig_autofocus_Cmd 0x03 -#define Get_focus_result_Cmd 0x07 - /* ov5640 Focus State */ //#define S_FIRWRE 0xFF /*Firmware is downloaded and not run*/ #define S_STARTUP 0x7e /*Firmware is initializing*/ @@ -1423,6 +1425,14 @@ static struct v4l2_queryctrl sensor_controls[] = .default_value = 125, },*/ { + .id = V4L2_CID_FOCUSZONE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "FocusZone Control", + .minimum = -1, + .maximum = 1, + .step = 1, + .default_value = 0, + },{ .id = V4L2_CID_FOCUS_AUTO, .type = V4L2_CTRL_TYPE_BOOLEAN, .name = "Focus Control", @@ -1529,6 +1539,7 @@ struct sensor_work enum sensor_wq_result result; bool wait; int var; + int zone_center_pos[2]; }; typedef struct sensor_info_priv_s @@ -1876,22 +1887,24 @@ static int sensor_af_cmdset(struct i2c_client *client, int cmd_main, struct af_c char read_tag=0xff,cnt; if (cmdinfo) { - if (cmdinfo->validate_bit & 0x80) { - if (sensor_write(client, CMD_ACK_Reg, cmdinfo->cmd_tag)) { - SENSOR_TR("%s write CMD_ACK_Reg(main:0x%x tag:0x%x) error!\n",SENSOR_NAME_STRING(),cmd_main,cmdinfo->cmd_tag); - goto sensor_af_cmdset_err; - } - SENSOR_DG("%s write CMD_ACK_Reg(main:0x%x tag:0x%x) success!\n",SENSOR_NAME_STRING(),cmd_main,cmdinfo->cmd_tag); - } - for (i=0; i<4; i++) { + for (i=0; i<4; i++) { if (cmdinfo->validate_bit & (1<cmd_para[i])) { + if (sensor_write(client, CMD_PARA0_Reg+i, cmdinfo->cmd_para[i])) { SENSOR_TR("%s write CMD_PARA_Reg(main:0x%x para%d:0x%x) error!\n",SENSOR_NAME_STRING(),cmd_main,i,cmdinfo->cmd_para[i]); goto sensor_af_cmdset_err; } SENSOR_DG("%s write CMD_PARA_Reg(main:0x%x para%d:0x%x) success!\n",SENSOR_NAME_STRING(),cmd_main,i,cmdinfo->cmd_para[i]); } } + + if (cmdinfo->validate_bit & 0x80) { + if (sensor_write(client, CMD_ACK_Reg, cmdinfo->cmd_tag)) { + SENSOR_TR("%s write CMD_ACK_Reg(main:0x%x tag:0x%x) error!\n",SENSOR_NAME_STRING(),cmd_main,cmdinfo->cmd_tag); + goto sensor_af_cmdset_err; + } + SENSOR_DG("%s write CMD_ACK_Reg(main:0x%x tag:0x%x) success!\n",SENSOR_NAME_STRING(),cmd_main,cmdinfo->cmd_tag); + } + } else { if (sensor_write(client, CMD_ACK_Reg, 0xff)) { SENSOR_TR("%s write CMD_ACK_Reg(main:0x%x no tag) error!\n",SENSOR_NAME_STRING(),cmd_main); @@ -1952,13 +1965,42 @@ static int sensor_af_idlechk(struct i2c_client *client) sensor_af_idlechk_end: return ret; } +static int sensor_af_touch_zone(struct i2c_client *client, int *zone_center_pos) +{ + int ret = 0; + struct af_cmdinfo cmdinfo; + cmdinfo.cmd_tag = 0x01; + cmdinfo.validate_bit = 0x83; + if (zone_center_pos[0]<=8) + cmdinfo.cmd_para[0] = 0; + else if ((zone_center_pos[0]>8) && (zone_center_pos[0]<64)) + cmdinfo.cmd_para[0] = zone_center_pos[0]-8; + else + cmdinfo.cmd_para[0] = 64; + + if (zone_center_pos[1]<=6) + cmdinfo.cmd_para[1] = 0; + else if ((zone_center_pos[1]>6) && (zone_center_pos[1]<48)) + cmdinfo.cmd_para[1] = zone_center_pos[1]-6; + else + cmdinfo.cmd_para[1] = 48; + + ret = sensor_af_cmdset(client, TouchZoneConfig_Cmd, &cmdinfo); + if(0 != ret) { + SENSOR_TR("%s touch zone config error!\n",SENSOR_NAME_STRING()); + ret = -1; + goto sensor_af_zone_end; + } +sensor_af_zone_end: + return ret; +} static int sensor_af_single(struct i2c_client *client) { int ret = 0; char state,cnt; struct af_cmdinfo cmdinfo; - + cmdinfo.cmd_tag = 0x01; cmdinfo.validate_bit = 0x80; ret = sensor_af_cmdset(client, SingleFocus_Cmd, &cmdinfo); @@ -2109,7 +2151,10 @@ static void sensor_af_workqueue(struct work_struct *work) break; } case WqCmd_af_single: - { + { + if ((sensor_work->zone_center_pos[0] >=0) && (sensor_work->zone_center_pos[1]>=0)) + sensor_af_touch_zone(client,sensor_work->zone_center_pos); + if (sensor_af_single(client) < 0) { SENSOR_TR("%s Sensor_af_single is failed in sensor_af_workqueue!\n",SENSOR_NAME_STRING()); sensor_work->result = WqRet_fail; @@ -2183,7 +2228,7 @@ set_end: return; } -static int sensor_af_workqueue_set(struct soc_camera_device *icd, enum sensor_wq_cmd cmd, int var, bool wait) +static int sensor_af_workqueue_set(struct soc_camera_device *icd, enum sensor_wq_cmd cmd, int var, bool wait, int *zone_pos) { struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); struct sensor *sensor = to_sensor(client); @@ -2211,6 +2256,26 @@ static int sensor_af_workqueue_set(struct soc_camera_device *icd, enum sensor_wq wk->result = WqRet_inval; wk->wait = wait; wk->var = var; + + if (zone_pos) { + if (*zone_pos || *(zone_pos+1) || *(zone_pos+2) || *(zone_pos+3)) { + *zone_pos += 1000; + *(zone_pos+1) += 1000; + *(zone_pos+2) += 1000; + *(zone_pos+3) += 1000; + wk->zone_center_pos[0] = ((*zone_pos + *(zone_pos+2))>>1)*80/2000; + wk->zone_center_pos[1] = ((*(zone_pos+1) + *(zone_pos+3))>>1)*60/2000; + } else { + #if CONFIG_SENSOR_FocusCenterInCapture + wk->zone_center_pos[0] = 32; + wk->zone_center_pos[1] = 24; + #else + wk->zone_center_pos[0] = -1; + wk->zone_center_pos[1] = -1; + #endif + } + } + init_waitqueue_head(&wk->done); queue_delayed_work(sensor->sensor_wq,&(wk->dwork),0); @@ -2261,11 +2326,11 @@ static int sensor_parameter_record(struct i2c_client *client) sensor->parameter.preview_exposure = ((tp_h<<12) & 0xF000) | ((tp_m<<4) & 0x0FF0) | ((tp_l>>4) & 0x0F); //Read back AGC Gain for preview - sensor_read(client,0x350b, &tp_l); - sensor->parameter.preview_gain = tp_l; + sensor_read(client,0x350b, &ret_l); + sensor->parameter.preview_gain = ret_l; SENSOR_DG(" %s Read 0x350b=0x%02x PreviewExposure:%d 0x3500=0x%02x 0x3501=0x%02x 0x3502=0x%02x \n", - SENSOR_NAME_STRING(), tp_l,sensor->parameter.preview_exposure,ret_h, ret_m, ret_l); + SENSOR_NAME_STRING(), tp_l,sensor->parameter.preview_exposure,tp_h, tp_m, tp_l); return 0; } #define OV5640_FULL_PERIOD_PIXEL_NUMS_HTS (2844) @@ -2278,14 +2343,8 @@ static int sensor_ae_transfer(struct i2c_client *client) u8 ExposureMid; u8 ExposureHigh; u16 ulCapture_Exposure; - u32 ulCapture_Exposure_Gain; - u16 iCapture_Gain; - u8 Lines_10ms; - bool m_60Hz = 0; - u8 reg_l = 0,reg_h =0; u16 Preview_Maxlines; u8 Gain; - u32 Capture_MaxLines; u16 OV5640_g_iExtra_ExpLines; struct sensor *sensor = to_sensor(client); @@ -2299,9 +2358,7 @@ static int sensor_ae_transfer(struct i2c_client *client) SENSOR_DG("cap shutter calutaed = %d, 0x%x\n", ulCapture_Exposure,ulCapture_Exposure); // write the gain and exposure to 0x350* registers - sensor_write(client,0x350b, Gain); - //Gain = (Gain >> 8) & 0x01; - //sensor_write(client,0x350a, Gain); + sensor_write(client,0x350b, Gain); if (ulCapture_Exposure <= 1940) { OV5640_g_iExtra_ExpLines = 0; @@ -2392,7 +2449,7 @@ static int sensor_init(struct v4l2_subdev *sd, u32 val) struct sensor *sensor = to_sensor(client); const struct v4l2_queryctrl *qctrl; const struct sensor_datafmt *fmt; - char value,ret_h,ret_l; + char value; int ret,pid = 0; SENSOR_DG("\n%s..%s.. \n",SENSOR_NAME_STRING(),__FUNCTION__); @@ -2656,7 +2713,6 @@ static int sensor_s_fmt(struct v4l2_subdev *sd,struct v4l2_mbus_framefmt *mf) struct soc_camera_device *icd = client->dev.platform_data; struct reginfo *winseqe_set_addr=NULL; int ret = 0, set_w,set_h; - char ret_h,ret_l; fmt = sensor_find_datafmt(mf->code, sensor_colour_fmts, ARRAY_SIZE(sensor_colour_fmts)); @@ -2848,7 +2904,7 @@ static int sensor_s_fmt(struct v4l2_subdev *sd,struct v4l2_mbus_framefmt *mf) } #if CONFIG_SENSOR_Focus if (sensor->info_priv.auto_focus == SENSOR_AF_MODE_AUTO) { - sensor_af_workqueue_set(icd,WqCmd_af_return_idle,0,true); + sensor_af_workqueue_set(icd,WqCmd_af_return_idle,0,true,NULL); msleep(200); } else { msleep(500); @@ -3252,7 +3308,7 @@ static int sensor_set_focus_absolute(struct soc_camera_device *icd, const struct if ((sensor->info_priv.funmodule_state & SENSOR_AF_IS_OK) && (sensor->info_priv.affm_reinit == 0)) { if ((value >= qctrl_info->minimum) && (value <= qctrl_info->maximum)) { - ret = sensor_af_workqueue_set(icd, WqCmd_af_special_pos, value, true); + ret = sensor_af_workqueue_set(icd, WqCmd_af_special_pos, value, true,NULL); SENSOR_DG("%s..%s : %d ret:0x%x\n",SENSOR_NAME_STRING(),__FUNCTION__, value,ret); } else { ret = -EINVAL; @@ -3280,9 +3336,9 @@ static int sensor_set_focus_relative(struct soc_camera_device *icd, const struct if ((sensor->info_priv.funmodule_state & SENSOR_AF_IS_OK) && (sensor->info_priv.affm_reinit == 0)) { if ((value >= qctrl_info->minimum) && (value <= qctrl_info->maximum)) { if (value > 0) { - ret = sensor_af_workqueue_set(icd, WqCmd_af_near_pos, 0, true); + ret = sensor_af_workqueue_set(icd, WqCmd_af_near_pos, 0, true,NULL); } else { - ret = sensor_af_workqueue_set(icd, WqCmd_af_far_pos, 0, true); + ret = sensor_af_workqueue_set(icd, WqCmd_af_far_pos, 0, true,NULL); } SENSOR_DG("%s..%s : %d ret:0x%x\n",SENSOR_NAME_STRING(),__FUNCTION__, value,ret); } else { @@ -3297,7 +3353,7 @@ static int sensor_set_focus_relative(struct soc_camera_device *icd, const struct return ret; } -static int sensor_set_focus_mode(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value) +static int sensor_set_focus_mode(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value, int *zone_pos) { struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); struct sensor *sensor = to_sensor(client); @@ -3308,7 +3364,7 @@ static int sensor_set_focus_mode(struct soc_camera_device *icd, const struct v4l { case SENSOR_AF_MODE_AUTO: { - ret = sensor_af_workqueue_set(icd, WqCmd_af_single, 0, true); + ret = sensor_af_workqueue_set(icd, WqCmd_af_single, 0, true, zone_pos); break; } @@ -3326,7 +3382,7 @@ static int sensor_set_focus_mode(struct soc_camera_device *icd, const struct v4l case SENSOR_AF_MODE_CONTINUOUS: { - ret = sensor_af_workqueue_set(icd, WqCmd_af_continues, 0, true); + ret = sensor_af_workqueue_set(icd, WqCmd_af_continues, 0, true,NULL); break; }*/ default: @@ -3597,7 +3653,7 @@ static int sensor_s_ext_control(struct soc_camera_device *icd, struct v4l2_ext_c const struct v4l2_queryctrl *qctrl; struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); struct sensor *sensor = to_sensor(client); - int val_offset,ret; + int val_offset; qctrl = soc_camera_find_qctrl(&sensor_ops, ext_ctrl->id); @@ -3685,7 +3741,7 @@ static int sensor_s_ext_control(struct soc_camera_device *icd, struct v4l2_ext_c case V4L2_CID_FOCUS_AUTO: { if (ext_ctrl->value == 1) { - if (sensor_set_focus_mode(icd, qctrl,SENSOR_AF_MODE_AUTO) != 0) { + if (sensor_set_focus_mode(icd, qctrl,SENSOR_AF_MODE_AUTO,ext_ctrl->rect) != 0) { if(0 == (sensor->info_priv.funmodule_state & SENSOR_AF_IS_OK)) { sensor->info_priv.auto_focus = SENSOR_AF_MODE_AUTO; } @@ -3800,7 +3856,7 @@ static int sensor_s_stream(struct v4l2_subdev *sd, int enable) /* If auto focus firmware haven't download success, must download firmware again when in video or preview stream on */ if (sensor_fmt_capturechk(sd, &mf) == false) { if ((sensor->info_priv.affm_reinit == 1) || ((sensor->info_priv.funmodule_state & SENSOR_AF_IS_OK)==0)) { - sensor_af_workqueue_set(icd, WqCmd_af_init, 0, false); + sensor_af_workqueue_set(icd, WqCmd_af_init, 0, false,NULL); sensor->info_priv.affm_reinit = 0; } } -- 2.34.1