camera: ov5642 and ov5640 support auto focus in background kernel thread, qbuf and...
authorddl <ddl@rock-chips.com>
Tue, 15 Nov 2011 11:53:59 +0000 (19:53 +0800)
committerddl <ddl@rock-chips.com>
Tue, 15 Nov 2011 11:53:59 +0000 (19:53 +0800)
drivers/media/video/ov5640.c
drivers/media/video/ov5642.c
drivers/media/video/rk29_camera_oneframe.c

index 1d59a8eee4f847a2fd949fab05de9870e9593a8c..055ab274d045aa503cca05530efce7d35f8ee703 100755 (executable)
@@ -1343,6 +1343,8 @@ static unsigned long sensor_query_bus_param(struct soc_camera_device *icd);
 static int sensor_set_effect(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value);
 static int sensor_set_whiteBalance(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value);
 static int sensor_deactivate(struct i2c_client *client);
+static bool sensor_fmt_capturechk(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf);
+static bool sensor_fmt_videochk(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf);
 
 static struct soc_camera_ops sensor_ops =
 {
@@ -1378,16 +1380,31 @@ static const struct sensor_datafmt sensor_colour_fmts[] = {
     {V4L2_MBUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_JPEG},
     {V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG}    
 };
-enum sensor_work_state
+enum sensor_wq_cmd
 {
-       sensor_work_ready = 0,
-       sensor_working,
+    WqCmd_af_init,
+    WqCmd_af_single,
+    WqCmd_af_special_pos,
+    WqCmd_af_far_pos,
+    WqCmd_af_near_pos,
+    WqCmd_af_continues,
+    WqCmd_af_return_idle,
+};
+enum sensor_wq_result
+{
+    WqRet_success = 0,
+    WqRet_fail = -1,
+    WqRet_inval = -2
 };
 struct sensor_work
 {
        struct i2c_client *client;
        struct delayed_work dwork;
-       enum sensor_work_state state;
+       enum sensor_wq_cmd cmd;
+    wait_queue_head_t done;
+    enum sensor_wq_result result;
+    bool wait;
+    int var;    
 };
 
 typedef struct sensor_info_priv_s
@@ -1435,7 +1452,6 @@ struct sensor
     sensor_info_priv_t info_priv;
        struct sensor_parameter parameter;
        struct workqueue_struct *sensor_wq;
-       struct sensor_work sensor_wk;
        struct mutex wq_lock;
     int model; /* V4L2_IDENT_OV* codes from v4l2-chip-ident.h */
 #if CONFIG_SENSOR_I2C_NOSCHED
@@ -1900,19 +1916,30 @@ sensor_af_init_end:
        return ret;
 }
 
-static int sensor_af_wq_function(struct i2c_client *client)
+static int sensor_af_downfirmware(struct i2c_client *client)
 {
        struct sensor *sensor = to_sensor(client);
-       int ret=0;
-
+       struct af_cmdinfo cmdinfo;
+       int ret=0, focus_pos = 0xfe;
+    struct soc_camera_device *icd = client->dev.platform_data;
+    struct v4l2_mbus_framefmt mf;
+               
        SENSOR_DG("%s %s Enter\n",SENSOR_NAME_STRING(), __FUNCTION__);
-
-       mutex_lock(&sensor->wq_lock);
+    
        if (sensor_af_init(client)) {
                sensor->info_priv.funmodule_state &= (~SENSOR_AF_IS_OK);
                ret = -1;
        } else {
                sensor->info_priv.funmodule_state |= SENSOR_AF_IS_OK;
+        
+        mf.width = icd->user_width;
+               mf.height = icd->user_height;
+        mf.code = sensor->info_priv.fmt.code;
+        mf.colorspace = sensor->info_priv.fmt.colorspace;
+        mf.field       = V4L2_FIELD_NONE;
+        if (sensor_fmt_videochk(NULL, &mf) == true) {    /* ddl@rock-chips.com: focus mode fix const auto focus in video */
+            ret = sensor_af_const(client);
+        } else {
                switch (sensor->info_priv.auto_focus)
                {
                        /*case SENSOR_AF_MODE_INFINITY:
@@ -1941,34 +1968,165 @@ static int sensor_af_wq_function(struct i2c_client *client)
                                ret = sensor_af_const(client);
                                break;
                        }*/
-                       case SENSOR_AF_MODE_CLOSE:
-                       {
-                               ret = 0;
-                               break;
-                       }
-                       default:
-            {
-                               SENSOR_DG("%s focus mode(0x%x) is unkonwn\n",SENSOR_NAME_STRING(),sensor->info_priv.auto_focus);
-                goto sensor_af_wq_function_end;
-                       }
-               }
-
-               SENSOR_DG("%s sensor_af_wq_function set focus mode(0x%x) ret:0x%x\n",SENSOR_NAME_STRING(), sensor->info_priv.auto_focus,ret);
+                       case SENSOR_AF_MODE_CLOSE:
+                       {
+                               ret = 0;
+                               break;
+                       }
+                       default:
+                {
+                               SENSOR_DG("%s focus mode(0x%x) is unkonwn\n",SENSOR_NAME_STRING(),sensor->info_priv.auto_focus);
+                    goto sensor_af_downfirmware_end;
+                       }
+               }
+        }
+               SENSOR_DG("%s sensor_af_downfirmware set focus mode(0x%x) ret:0x%x\n",SENSOR_NAME_STRING(), sensor->info_priv.auto_focus,ret);
        }
 
-sensor_af_wq_function_end:
-       sensor->sensor_wk.state = sensor_work_ready;
-       mutex_unlock(&sensor->wq_lock);
+sensor_af_downfirmware_end:
+       
        return ret;
 }
 static void sensor_af_workqueue(struct work_struct *work)
 {
        struct sensor_work *sensor_work = container_of(work, struct sensor_work, dwork.work);
        struct i2c_client *client = sensor_work->client;
+    struct sensor *sensor = to_sensor(client);
+    struct af_cmdinfo cmdinfo;
+    
+    SENSOR_DG("%s %s Enter, cmd:0x%x \n",SENSOR_NAME_STRING(), __FUNCTION__,sensor_work->cmd);
+    
+    mutex_lock(&sensor->wq_lock);
+    switch (sensor_work->cmd) 
+    {
+        case WqCmd_af_init:
+        {
+               if (sensor_af_downfirmware(client) < 0) {
+                       SENSOR_TR("%s Sensor_af_init is failed in sensor_af_workqueue!\n",SENSOR_NAME_STRING());
+               }            
+            break;
+        }
+        case WqCmd_af_single:
+        {
+            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;
+               } else {
+                sensor_work->result = WqRet_success;
+               }
+            break;
+        }
+        case WqCmd_af_special_pos:
+        {
+            sensor_af_idlechk(client);
+
+                       cmdinfo.cmd_tag = StepFocus_Spec_Tag;
+                       cmdinfo.cmd_para[0] = sensor_work->var;
+                       cmdinfo.validate_bit = 0x81;
+                       if (sensor_af_cmdset(client, StepMode_Cmd, &cmdinfo) < 0)
+               sensor_work->result = WqRet_fail;
+            else 
+               sensor_work->result = WqRet_success;
+            break;
+        }
+        case WqCmd_af_near_pos:
+        {            
+            sensor_af_idlechk(client);
+            cmdinfo.cmd_tag = StepFocus_Near_Tag;
+            cmdinfo.validate_bit = 0x80;
+                       if (sensor_af_cmdset(client, StepMode_Cmd, &cmdinfo) < 0)
+               sensor_work->result = WqRet_fail;
+            else 
+               sensor_work->result = WqRet_success;
+            break;
+        }
+        case WqCmd_af_far_pos:
+        {
+            sensor_af_idlechk(client);
+                       cmdinfo.cmd_tag = StepFocus_Far_Tag;
+                       cmdinfo.validate_bit = 0x80;
+                       if (sensor_af_cmdset(client, StepMode_Cmd, &cmdinfo) < 0)
+               sensor_work->result = WqRet_fail;
+            else 
+               sensor_work->result = WqRet_success;
+            break;
+        }
+        case WqCmd_af_continues:
+        {
+            if (sensor_af_const(client) < 0)
+               sensor_work->result = WqRet_fail;
+            else 
+               sensor_work->result = WqRet_success;
+            break;
+        }
+        case WqCmd_af_return_idle:
+        {
+            if (sensor_af_idlechk(client) < 0)
+               sensor_work->result = WqRet_fail;
+            else 
+               sensor_work->result = WqRet_success;
+            break;
+        }  
+        default:
+            SENSOR_TR("Unknow command(%d) in %s af workqueue!",sensor_work->cmd,SENSOR_NAME_STRING());
+            break;
+    } 
 
-       if (sensor_af_wq_function(client) < 0) {
-               SENSOR_TR("%s af workqueue return false\n",SENSOR_NAME_STRING());
-       }
+    if (sensor_work->wait == false) {
+        kfree((void*)sensor_work);
+    } else {
+        wake_up(&sensor_work->done); 
+    }
+    mutex_unlock(&sensor->wq_lock); 
+    return;
+}
+
+static int sensor_af_workqueue_set(struct soc_camera_device *icd, enum sensor_wq_cmd cmd, int var, bool wait)
+{
+    struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+       struct sensor *sensor = to_sensor(client); 
+    struct sensor_work *wk;
+    int ret=0;
+
+    if (sensor->sensor_wq == NULL) { 
+        ret = -EINVAL;
+        goto sensor_af_workqueue_set_end;
+    }
+    
+    wk = kzalloc(sizeof(struct sensor_work), GFP_KERNEL);
+    if (wk) {
+           wk->client = client;
+           INIT_WORK(&(wk->dwork.work), sensor_af_workqueue);
+        wk->cmd = cmd;
+        wk->result = WqRet_inval;
+        wk->wait = wait;
+        wk->var = var;
+        init_waitqueue_head(&wk->done);
+        
+           queue_delayed_work(sensor->sensor_wq,&(wk->dwork),0);
+        
+        /* ddl@rock-chips.com: 
+        * video_lock is been locked in v4l2_ioctl function, but auto focus may slow,
+        * As a result any other ioctl calls will proceed very, very slowly since each call
+        * will have to wait for the AF to finish. Camera preview is pause,because VIDIOC_QBUF 
+        * and VIDIOC_DQBUF is sched. so unlock video_lock here.
+        */
+        if (wait == true) {
+            mutex_unlock(&icd->video_lock);                     
+            if (wait_event_timeout(wk->done, (wk->result != WqRet_inval), msecs_to_jiffies(2500)) == 0) {
+                SENSOR_TR("%s %s cmd(%d) is timeout!",SENSOR_NAME_STRING(),__FUNCTION__,cmd);                        
+            }
+            ret = wk->result;
+            kfree((void*)wk);
+            mutex_lock(&icd->video_lock);  
+        }
+        
+    } else {
+        SENSOR_TR("%s %s cmd(%d) ingore,because struct sensor_work malloc failed!",SENSOR_NAME_STRING(),__FUNCTION__,cmd);
+        ret = -1;
+    }
+sensor_af_workqueue_set_end:
+    return ret;
 }
 #endif
 static int sensor_parameter_record(struct i2c_client *client)
@@ -2207,7 +2365,7 @@ sensor_power_end:
 }
 static int sensor_init(struct v4l2_subdev *sd, u32 val)
 {
-    struct i2c_client *client = sd->priv;
+    struct i2c_client *client = v4l2_get_subdevdata(sd);
     struct soc_camera_device *icd = client->dev.platform_data;
     struct sensor *sensor = to_sensor(client);
        const struct v4l2_queryctrl *qctrl;
@@ -2262,8 +2420,7 @@ static int sensor_init(struct v4l2_subdev *sd, u32 val)
     }
 
     ret = sensor_write_array(client, sensor_init_data);
-    if (ret != 0)
-    {
+    if (ret != 0) {
         SENSOR_TR("error: %s initial failed\n",SENSOR_NAME_STRING());
         goto sensor_INIT_ERR;
     }
@@ -2322,7 +2479,7 @@ static int sensor_init(struct v4l2_subdev *sd, u32 val)
     #endif
     SENSOR_DG("\n%s..%s.. icd->width = %d.. icd->height %d\n",SENSOR_NAME_STRING(),((val == 0)?__FUNCTION__:"sensor_reinit"),icd->user_width,icd->user_height);
 
-    sensor->info_priv.funmodule_state |= SENSOR_INIT_IS_OK;
+    sensor->info_priv.funmodule_state = SENSOR_INIT_IS_OK;
         
     return 0;
 sensor_INIT_ERR:
@@ -2417,7 +2574,7 @@ static unsigned long sensor_query_bus_param(struct soc_camera_device *icd)
 
 static int sensor_g_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
 {
-    struct i2c_client *client = sd->priv;
+    struct i2c_client *client = v4l2_get_subdevdata(sd);
     struct soc_camera_device *icd = client->dev.platform_data;
     struct sensor *sensor = to_sensor(client);
 
@@ -2466,7 +2623,7 @@ static bool sensor_fmt_videochk(struct v4l2_subdev *sd, struct v4l2_mbus_framefm
 }
 static int sensor_s_fmt(struct v4l2_subdev *sd,struct v4l2_mbus_framefmt *mf)
 {
-    struct i2c_client *client = sd->priv;
+    struct i2c_client *client = v4l2_get_subdevdata(sd);
     const struct sensor_datafmt *fmt;
     struct sensor *sensor = to_sensor(client);
        const struct v4l2_queryctrl *qctrl;
@@ -2658,7 +2815,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_idlechk(client);
+                sensor_af_workqueue_set(icd,WqCmd_af_return_idle,0,true);
                 msleep(200);
             } else {
                 msleep(500);
@@ -2683,7 +2840,7 @@ sensor_s_fmt_end:
 
 static int sensor_try_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
 {
-    struct i2c_client *client = sd->priv;
+    struct i2c_client *client = v4l2_get_subdevdata(sd);
     struct sensor *sensor = to_sensor(client);
     const struct sensor_datafmt *fmt;
     int ret = 0;
@@ -2712,7 +2869,7 @@ static int sensor_try_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
 
  static int sensor_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *id)
 {
-    struct i2c_client *client = sd->priv;
+    struct i2c_client *client = v4l2_get_subdevdata(sd);
 
     if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
         return -EINVAL;
@@ -2985,13 +3142,12 @@ static int sensor_set_focus_absolute(struct soc_camera_device *icd, const struct
        int ret = 0;
 
        qctrl_info = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_FOCUS_ABSOLUTE);
-       if (!qctrl_info) {
-               ret = -EINVAL;
-        goto sensor_set_focus_absolute_end;
-       }
-
+       if (!qctrl_info)
+               return -EINVAL;
+    
        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 >= qctrl_info->minimum) && (value <= qctrl_info->maximum)) {
+            ret = sensor_af_workqueue_set(icd, WqCmd_af_special_pos, value, true);
                        SENSOR_DG("%s..%s : %d  ret:0x%x\n",SENSOR_NAME_STRING(),__FUNCTION__, value,ret);
                } else {
                        ret = -EINVAL;
@@ -3003,7 +3159,6 @@ static int sensor_set_focus_absolute(struct soc_camera_device *icd, const struct
                        sensor->info_priv.funmodule_state,sensor->info_priv.affm_reinit);
        }
 
-sensor_set_focus_absolute_end:
        return ret;
 }
 static int sensor_set_focus_relative(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value)
@@ -3014,13 +3169,16 @@ static int sensor_set_focus_relative(struct soc_camera_device *icd, const struct
        int ret = 0;
 
        qctrl_info = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_FOCUS_RELATIVE);
-       if (!qctrl_info) {
-               ret = -EINVAL;
-        goto sensor_set_focus_relative_end;
-       }
+       if (!qctrl_info)
+               return -EINVAL;    
 
        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 >= qctrl_info->minimum) && (value <= qctrl_info->maximum)) {            
+            if (value > 0) {
+                ret = sensor_af_workqueue_set(icd, WqCmd_af_near_pos, 0, true);
+            } else {
+                ret = sensor_af_workqueue_set(icd, WqCmd_af_far_pos, 0, true);
+            }
                        SENSOR_DG("%s..%s : %d  ret:0x%x\n",SENSOR_NAME_STRING(),__FUNCTION__, value,ret);
                } else {
                        ret = -EINVAL;
@@ -3031,7 +3189,6 @@ static int sensor_set_focus_relative(struct soc_camera_device *icd, const struct
                SENSOR_TR("\n %s..%s AF module state(0x%x, 0x%x) is error!\n",SENSOR_NAME_STRING(),__FUNCTION__,
                        sensor->info_priv.funmodule_state,sensor->info_priv.affm_reinit);
        }
-sensor_set_focus_relative_end:
        return ret;
 }
 
@@ -3046,7 +3203,7 @@ static int sensor_set_focus_mode(struct soc_camera_device *icd, const struct v4l
                {
                        case SENSOR_AF_MODE_AUTO:
                        {
-                               ret = sensor_af_single(client);
+                               ret = sensor_af_workqueue_set(icd, WqCmd_af_single, 0, true);
                                break;
                        }
 
@@ -3064,7 +3221,7 @@ static int sensor_set_focus_mode(struct soc_camera_device *icd, const struct v4l
                        
                        case SENSOR_AF_MODE_CONTINUOUS:
                        {
-                               ret = sensor_af_const(client);
+                               ret = sensor_af_workqueue_set(icd, WqCmd_af_continues, 0, true);
                                break;
                        }*/
                        default:
@@ -3102,7 +3259,7 @@ static int sensor_set_flash(struct soc_camera_device *icd, const struct v4l2_que
 #endif
 static int sensor_g_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
-    struct i2c_client *client = sd->priv;
+    struct i2c_client *client = v4l2_get_subdevdata(sd);
     struct sensor *sensor = to_sensor(client);
     const struct v4l2_queryctrl *qctrl;
 
@@ -3161,7 +3318,7 @@ static int sensor_g_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 
 static int sensor_s_control(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 {
-    struct i2c_client *client = sd->priv;
+    struct i2c_client *client = v4l2_get_subdevdata(sd);
     struct sensor *sensor = to_sensor(client);
     struct soc_camera_device *icd = client->dev.platform_data;
     const struct v4l2_queryctrl *qctrl;
@@ -3335,7 +3492,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;
+    int val_offset,ret;
 
     qctrl = soc_camera_find_qctrl(&sensor_ops, ext_ctrl->id);
 
@@ -3423,8 +3580,12 @@ 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) != 0) {
+                                               if(0 == (sensor->info_priv.funmodule_state & SENSOR_AF_IS_OK)) {
+                                                       sensor->info_priv.auto_focus = SENSOR_AF_MODE_AUTO;
+                                               }
                                                return -EINVAL;
+                                       }
                                        sensor->info_priv.auto_focus = SENSOR_AF_MODE_AUTO;
                                } else if (SENSOR_AF_MODE_AUTO == sensor->info_priv.auto_focus){
                                        if (ext_ctrl->value == 0)
@@ -3467,7 +3628,7 @@ static int sensor_s_ext_control(struct soc_camera_device *icd, struct v4l2_ext_c
 
 static int sensor_g_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl)
 {
-    struct i2c_client *client = sd->priv;
+    struct i2c_client *client = v4l2_get_subdevdata(sd);
     struct soc_camera_device *icd = client->dev.platform_data;
     int i, error_cnt=0, error_idx=-1;
 
@@ -3492,7 +3653,7 @@ static int sensor_g_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_control
 
 static int sensor_s_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ext_ctrl)
 {
-    struct i2c_client *client = sd->priv;
+    struct i2c_client *client = v4l2_get_subdevdata(sd);
     struct soc_camera_device *icd = client->dev.platform_data;
     int i, error_cnt=0, error_idx=-1;
 
@@ -3516,7 +3677,7 @@ static int sensor_s_ext_controls(struct v4l2_subdev *sd, struct v4l2_ext_control
 
 static int sensor_s_stream(struct v4l2_subdev *sd, int enable)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
     struct sensor *sensor = to_sensor(client);
        #if CONFIG_SENSOR_Focus
        struct soc_camera_device *icd = client->dev.platform_data;
@@ -3534,34 +3695,17 @@ 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)) {
-                               if (sensor->sensor_wq != NULL) {
-                                       mutex_lock(&sensor->wq_lock);
-                                       if (sensor->sensor_wk.state == sensor_working) {
-                                               SENSOR_DG("%s sensor af firmware thread is runing, Ingore current work",SENSOR_NAME_STRING());
-                                               mutex_unlock(&sensor->wq_lock);
-                                               goto sensor_s_stream_end;
-                                       }
-                                       sensor->sensor_wk.state = sensor_working;
-                                       mutex_unlock(&sensor->wq_lock);
-                                       sensor->sensor_wk.client = client;
-                                       INIT_WORK(&(sensor->sensor_wk.dwork.work), sensor_af_workqueue);
-                                       queue_delayed_work(sensor->sensor_wq,&(sensor->sensor_wk.dwork), 0);
-                               }
+                sensor_af_workqueue_set(icd, WqCmd_af_init, 0, false);
                                sensor->info_priv.affm_reinit = 0;
                        }
                }
                #endif
        } else if (enable == 0) {
                sensor->info_priv.enable = 0;
-               #if CONFIG_SENSOR_Focus
-               flush_work(&(sensor->sensor_wk.dwork.work));
-               mutex_lock(&sensor->wq_lock);
-               sensor->sensor_wk.state = sensor_work_ready;
-               mutex_unlock(&sensor->wq_lock);
+               #if CONFIG_SENSOR_Focus 
+        flush_workqueue(sensor->sensor_wq);
                #endif
        }
-
-sensor_s_stream_end:
        return 0;
 }
 
@@ -3627,7 +3771,7 @@ sensor_video_probe_err:
 }
 static long sensor_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
 {
-       struct i2c_client *client = sd->priv;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
     struct soc_camera_device *icd = client->dev.platform_data;
     struct sensor *sensor = to_sensor(client);
     int ret = 0;
@@ -3659,7 +3803,6 @@ static long sensor_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
             /* ddl@rock-chips.com : if gpio_flash havn't been set in board-xxx.c, sensor driver must notify is not support flash control 
                for this project */
             #if CONFIG_SENSOR_Flash    
-            int i;
                if (sensor->sensor_gpio_res) {
                 printk("flash io:%d\n",sensor->sensor_gpio_res->gpio_flash);
                 if (sensor->sensor_gpio_res->gpio_flash == INVALID_GPIO) {
@@ -3766,11 +3909,10 @@ static int sensor_probe(struct i2c_client *client,
                sensor = NULL;
     } else {
                #if CONFIG_SENSOR_Focus
-               sensor->sensor_wq = create_workqueue(SENSOR_NAME_STRING( wq));
+               sensor->sensor_wq = create_workqueue(SENSOR_NAME_STRING(_af_workqueue));
                if (sensor->sensor_wq == NULL)
-                       SENSOR_TR("%s workqueue create fail!", SENSOR_NAME_STRING( wq));
+                       SENSOR_TR("%s create fail!", SENSOR_NAME_STRING(_af_workqueue));
                mutex_init(&sensor->wq_lock);
-               sensor->sensor_wk.state = sensor_work_ready;
                #endif
     }
 
index 9b0b2f98cd6aaec5a6651f8fe19e1dd7bebec706..98816754ee17943f901d815ff6b3baa6d064d3bf 100755 (executable)
@@ -3299,19 +3299,32 @@ static const struct sensor_datafmt sensor_colour_fmts[] = {
     {V4L2_MBUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_JPEG},
     {V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG}    
 };
-
-enum sensor_work_state
+enum sensor_wq_cmd
+{
+    WqCmd_af_init,
+    WqCmd_af_single,
+    WqCmd_af_special_pos,
+    WqCmd_af_far_pos,
+    WqCmd_af_near_pos,
+    WqCmd_af_continues,
+    WqCmd_af_update_zone
+};
+enum sensor_wq_result
 {
-       sensor_work_ready = 0,
-       sensor_working,
+    WqRet_success = 0,
+    WqRet_fail = -1,
+    WqRet_inval = -2
 };
 struct sensor_work
 {
        struct i2c_client *client;
        struct delayed_work dwork;
-       enum sensor_work_state state;
+       enum sensor_wq_cmd cmd;
+    wait_queue_head_t done;
+    enum sensor_wq_result result;
+    bool wait;
+    int var;    
 };
-
 typedef struct sensor_info_priv_s
 {
     int whiteBalance;
@@ -3356,7 +3369,6 @@ struct sensor
     sensor_info_priv_t info_priv;
        struct sensor_parameter parameter;
        struct workqueue_struct *sensor_wq;
-       struct sensor_work sensor_wk;
        struct mutex wq_lock;
     int model; /* V4L2_IDENT_OV* codes from v4l2-chip-ident.h */
 #if CONFIG_SENSOR_I2C_NOSCHED
@@ -3832,7 +3844,7 @@ sensor_af_init_end:
        return ret;
 }
 
-static int sensor_af_wq_function(struct i2c_client *client)
+static int sensor_af_downfirmware(struct i2c_client *client)
 {
        struct sensor *sensor = to_sensor(client);
        struct af_cmdinfo cmdinfo;
@@ -3841,8 +3853,7 @@ static int sensor_af_wq_function(struct i2c_client *client)
     struct v4l2_mbus_framefmt mf;
                
        SENSOR_DG("%s %s Enter\n",SENSOR_NAME_STRING(), __FUNCTION__);
-
-       mutex_lock(&sensor->wq_lock);
+    
        if (sensor_af_init(client)) {
                sensor->info_priv.funmodule_state &= (~SENSOR_AF_IS_OK);
                ret = -1;
@@ -3893,26 +3904,157 @@ static int sensor_af_wq_function(struct i2c_client *client)
                        default:
                 {
                                SENSOR_DG("%s focus mode(0x%x) is unkonwn\n",SENSOR_NAME_STRING(),sensor->info_priv.auto_focus);
-                    goto sensor_af_wq_function_end;
+                    goto sensor_af_downfirmware_end;
                        }
                }
         }
-               SENSOR_DG("%s sensor_af_wq_function set focus mode(0x%x) ret:0x%x\n",SENSOR_NAME_STRING(), sensor->info_priv.auto_focus,ret);
+               SENSOR_DG("%s sensor_af_downfirmware set focus mode(0x%x) ret:0x%x\n",SENSOR_NAME_STRING(), sensor->info_priv.auto_focus,ret);
        }
 
-sensor_af_wq_function_end:
-       sensor->sensor_wk.state = sensor_work_ready;
-       mutex_unlock(&sensor->wq_lock);
+sensor_af_downfirmware_end:
+       
        return ret;
 }
 static void sensor_af_workqueue(struct work_struct *work)
 {
        struct sensor_work *sensor_work = container_of(work, struct sensor_work, dwork.work);
        struct i2c_client *client = sensor_work->client;
+    struct sensor *sensor = to_sensor(client);
+    struct af_cmdinfo cmdinfo;
+    
+    SENSOR_DG("%s %s Enter, cmd:0x%x \n",SENSOR_NAME_STRING(), __FUNCTION__,sensor_work->cmd);
+    
+    mutex_lock(&sensor->wq_lock);
+    switch (sensor_work->cmd) 
+    {
+        case WqCmd_af_init:
+        {
+               if (sensor_af_downfirmware(client) < 0) {
+                       SENSOR_TR("%s Sensor_af_init is failed in sensor_af_workqueue!\n",SENSOR_NAME_STRING());
+               }            
+            break;
+        }
+        case WqCmd_af_single:
+        {
+            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;
+               } else {
+                sensor_work->result = WqRet_success;
+               }
+            break;
+        }
+        case WqCmd_af_special_pos:
+        {
+            sensor_af_idlechk(client);
 
-       if (sensor_af_wq_function(client) < 0) {
-               SENSOR_TR("%s af workqueue return false\n",SENSOR_NAME_STRING());
-       }
+                       cmdinfo.cmd_tag = StepFocus_Spec_Tag;
+                       cmdinfo.cmd_para[0] = sensor_work->var;
+                       cmdinfo.validate_bit = 0x81;
+                       if (sensor_af_cmdset(client, StepMode_Cmd, &cmdinfo) < 0)
+               sensor_work->result = WqRet_fail;
+            else 
+               sensor_work->result = WqRet_success;
+            break;
+        }
+        case WqCmd_af_near_pos:
+        {            
+            sensor_af_idlechk(client);
+            cmdinfo.cmd_tag = StepFocus_Near_Tag;
+            cmdinfo.validate_bit = 0x80;
+                       if (sensor_af_cmdset(client, StepMode_Cmd, &cmdinfo) < 0)
+               sensor_work->result = WqRet_fail;
+            else 
+               sensor_work->result = WqRet_success;
+            break;
+        }
+        case WqCmd_af_far_pos:
+        {
+            sensor_af_idlechk(client);
+                       cmdinfo.cmd_tag = StepFocus_Far_Tag;
+                       cmdinfo.validate_bit = 0x80;
+                       if (sensor_af_cmdset(client, StepMode_Cmd, &cmdinfo) < 0)
+               sensor_work->result = WqRet_fail;
+            else 
+               sensor_work->result = WqRet_success;
+            break;
+        }
+        case WqCmd_af_continues:
+        {
+            if (sensor_af_const(client) < 0)
+               sensor_work->result = WqRet_fail;
+            else 
+               sensor_work->result = WqRet_success;
+            break;
+        }
+        case WqCmd_af_update_zone:
+        {
+            if (sensor_af_zoneupdate(client) < 0)
+               sensor_work->result = WqRet_fail;
+            else 
+               sensor_work->result = WqRet_success;
+            break;
+        }
+        default:
+            SENSOR_TR("Unknow command(%d) in %s af workqueue!",sensor_work->cmd,SENSOR_NAME_STRING());
+            break;
+    } 
+
+    if (sensor_work->wait == false) {
+        kfree((void*)sensor_work);
+    } else {
+        wake_up(&sensor_work->done); 
+    }
+    mutex_unlock(&sensor->wq_lock); 
+    return;
+}
+
+static int sensor_af_workqueue_set(struct soc_camera_device *icd, enum sensor_wq_cmd cmd, int var, bool wait)
+{
+    struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+       struct sensor *sensor = to_sensor(client); 
+    struct sensor_work *wk;
+    int ret=0;
+
+    if (sensor->sensor_wq == NULL) { 
+        ret = -EINVAL;
+        goto sensor_af_workqueue_set_end;
+    }
+    
+    wk = kzalloc(sizeof(struct sensor_work), GFP_KERNEL);
+    if (wk) {
+           wk->client = client;
+           INIT_WORK(&(wk->dwork.work), sensor_af_workqueue);
+        wk->cmd = cmd;
+        wk->result = WqRet_inval;
+        wk->wait = wait;
+        wk->var = var;
+        init_waitqueue_head(&wk->done);
+        
+           queue_delayed_work(sensor->sensor_wq,&(wk->dwork),0);
+        
+        /* ddl@rock-chips.com: 
+        * video_lock is been locked in v4l2_ioctl function, but auto focus may slow,
+        * As a result any other ioctl calls will proceed very, very slowly since each call
+        * will have to wait for the AF to finish. Camera preview is pause,because VIDIOC_QBUF 
+        * and VIDIOC_DQBUF is sched. so unlock video_lock here.
+        */
+        if (wait == true) {
+            mutex_unlock(&icd->video_lock);                     
+            if (wait_event_timeout(wk->done, (wk->result != WqRet_inval), msecs_to_jiffies(2500)) == 0) {
+                SENSOR_TR("%s %s cmd(%d) is timeout!",SENSOR_NAME_STRING(),__FUNCTION__,cmd);                        
+            }
+            ret = wk->result;
+            kfree((void*)wk);
+            mutex_lock(&icd->video_lock);  
+        }
+        
+    } else {
+        SENSOR_TR("%s %s cmd(%d) ingore,because struct sensor_work malloc failed!",SENSOR_NAME_STRING(),__FUNCTION__,cmd);
+        ret = -1;
+    }
+sensor_af_workqueue_set_end:
+    return ret;
 }
 #endif
 static int sensor_parameter_record(struct i2c_client *client)
@@ -4217,7 +4359,7 @@ static int sensor_init(struct v4l2_subdev *sd, u32 val)
     #endif
     SENSOR_DG("\n%s..%s.. icd->width = %d.. icd->height %d\n",SENSOR_NAME_STRING(),((val == 0)?__FUNCTION__:"sensor_reinit"),icd->user_width,icd->user_height);
 
-    sensor->info_priv.funmodule_state |= SENSOR_INIT_IS_OK;
+    sensor->info_priv.funmodule_state = SENSOR_INIT_IS_OK;
         
     return 0;
 sensor_INIT_ERR:
@@ -4238,7 +4380,7 @@ static int sensor_deactivate(struct i2c_client *client)
        sensor_task_lock(client, 1);
         sensor_write(client, 0x3017, 0x00);  // FREX,VSYNC,HREF,PCLK,D9-D6
        sensor_write(client, 0x3018, 0x03);  // D5-D0
-       sensor_write(client,0x3019,0X00);    // STROBE,SDA
+       sensor_write(client,0x3019,0x00);    // STROBE,SDA
        sensor_task_lock(client, 0);
     } 
     sensor_ioctrl(icd, Sensor_PowerDown, 1);
@@ -4535,12 +4677,12 @@ static int sensor_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
                                sensor_set_whiteBalance(icd, qctrl,sensor->info_priv.whiteBalance);
                        }
                        #if CONFIG_SENSOR_Focus
-            if (sensor->info_priv.auto_focus != SENSOR_AF_MODE_INFINITY) {
-                       if (sensor_af_zoneupdate(client) == 0) {
-                       if ((sensor->info_priv.auto_focus == SENSOR_AF_MODE_AUTO) || 
+            if (sensor->info_priv.auto_focus != SENSOR_AF_MODE_INFINITY) {                     
+                if (sensor_af_workqueue_set(icd, WqCmd_af_update_zone,0,true) == 0) {
+                    if ((sensor->info_priv.auto_focus == SENSOR_AF_MODE_AUTO) || 
                            (sensor->info_priv.auto_focus == SENSOR_AF_MODE_CONTINUOUS)) {
                            msleep(80);
-                        sensor_af_single(client);
+                        sensor_af_workqueue_set(icd, WqCmd_af_single,0,false);
                        }
                        }
             }
@@ -4561,15 +4703,17 @@ static int sensor_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
                                sensor_set_whiteBalance(icd, qctrl,sensor->info_priv.whiteBalance);
                        }
             #if CONFIG_SENSOR_Focus   
-            if (sensor->info_priv.auto_focus != SENSOR_AF_MODE_INFINITY) {
-                       if (sensor_af_zoneupdate(client) == 0) {
-                       if (sensor->info_priv.auto_focus == SENSOR_AF_MODE_CONTINUOUS) {
-                        sensor_af_const(client);
+            if (sensor->info_priv.auto_focus != SENSOR_AF_MODE_INFINITY) { 
+                /* ddl@rock-chips.com: The af operation is not necessary, if user don't care whether in focus after preview*/
+                if (sensor_af_workqueue_set(icd, WqCmd_af_update_zone,0,true) == 0) {
+                    if (sensor->info_priv.auto_focus == SENSOR_AF_MODE_CONTINUOUS) {
+                        sensor_af_workqueue_set(icd, WqCmd_af_continues,0,false);
                        } else if (sensor->info_priv.auto_focus == SENSOR_AF_MODE_AUTO) {
-                           msleep(80);
-                        sensor_af_single(client);
+                           msleep(100);
+                        sensor_af_workqueue_set(icd, WqCmd_af_single,0,false);
                        }
-                       }
+                }
+                
             } else {
                 msleep(600);    /* ddl@rock-chips.com : whitebalance auto must delay */
             }
@@ -4894,24 +5038,15 @@ static int sensor_set_focus_absolute(struct soc_camera_device *icd, const struct
        struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
     struct sensor *sensor = to_sensor(client);
        const struct v4l2_queryctrl *qctrl_info;
-       struct af_cmdinfo cmdinfo;
        int ret = 0;
 
        qctrl_info = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_FOCUS_ABSOLUTE);
        if (!qctrl_info)
                return -EINVAL;
-
+    
        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 (sensor_af_idlechk(client))
-                               goto sensor_set_focus_absolute_end;
-
-                       cmdinfo.cmd_tag = StepFocus_Spec_Tag;
-                       cmdinfo.cmd_para[0] = value;
-                       cmdinfo.validate_bit = 0x81;
-                       ret = sensor_af_cmdset(client, StepMode_Cmd, &cmdinfo);
-                       //ret |= sensor_af_cmdset(client, ReturnIdle_Cmd, NULL);
+            ret = sensor_af_workqueue_set(icd, WqCmd_af_special_pos, value, true);
                        SENSOR_DG("%s..%s : %d  ret:0x%x\n",SENSOR_NAME_STRING(),__FUNCTION__, value,ret);
                } else {
                        ret = -EINVAL;
@@ -4923,7 +5058,6 @@ static int sensor_set_focus_absolute(struct soc_camera_device *icd, const struct
                        sensor->info_priv.funmodule_state,sensor->info_priv.affm_reinit);
        }
 
-sensor_set_focus_absolute_end:
        return ret;
 }
 static int sensor_set_focus_relative(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value)
@@ -4931,27 +5065,19 @@ static int sensor_set_focus_relative(struct soc_camera_device *icd, const struct
        struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
        struct sensor *sensor = to_sensor(client);
        const struct v4l2_queryctrl *qctrl_info;
-       struct af_cmdinfo cmdinfo;
        int ret = 0;
 
        qctrl_info = soc_camera_find_qctrl(&sensor_ops, V4L2_CID_FOCUS_RELATIVE);
        if (!qctrl_info)
-               return -EINVAL;
+               return -EINVAL;    
 
        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 (sensor_af_idlechk(client))
-                               goto sensor_set_focus_relative_end;
-
-                       if (value > 0) {
-                               cmdinfo.cmd_tag = StepFocus_Near_Tag;
-                       } else if (value < 0) {
-                               cmdinfo.cmd_tag = StepFocus_Far_Tag;
-                       }
-                       cmdinfo.validate_bit = 0x80;
-                       ret = sensor_af_cmdset(client, StepMode_Cmd, &cmdinfo);
-
+               if ((value >= qctrl_info->minimum) && (value <= qctrl_info->maximum)) {            
+            if (value > 0) {
+                ret = sensor_af_workqueue_set(icd, WqCmd_af_near_pos, 0, true);
+            } else {
+                ret = sensor_af_workqueue_set(icd, WqCmd_af_far_pos, 0, true);
+            }
                        SENSOR_DG("%s..%s : %d  ret:0x%x\n",SENSOR_NAME_STRING(),__FUNCTION__, value,ret);
                } else {
                        ret = -EINVAL;
@@ -4962,14 +5088,13 @@ static int sensor_set_focus_relative(struct soc_camera_device *icd, const struct
                SENSOR_TR("\n %s..%s AF module state(0x%x, 0x%x) is error!\n",SENSOR_NAME_STRING(),__FUNCTION__,
                        sensor->info_priv.funmodule_state,sensor->info_priv.affm_reinit);
        }
-sensor_set_focus_relative_end:
        return ret;
 }
 
 static int sensor_set_focus_mode(struct soc_camera_device *icd, const struct v4l2_queryctrl *qctrl, int value)
 {
        struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
-       struct sensor *sensor = to_sensor(client);
+       struct sensor *sensor = to_sensor(client); 
        int ret = 0;
 
        if ((sensor->info_priv.funmodule_state & SENSOR_AF_IS_OK)  && (sensor->info_priv.affm_reinit == 0)) {
@@ -4977,7 +5102,7 @@ static int sensor_set_focus_mode(struct soc_camera_device *icd, const struct v4l
                {
                        case SENSOR_AF_MODE_AUTO:
                        {
-                               ret = sensor_af_single(client);
+                               ret = sensor_af_workqueue_set(icd, WqCmd_af_single, 0, true);
                                break;
                        }
 
@@ -4995,7 +5120,7 @@ static int sensor_set_focus_mode(struct soc_camera_device *icd, const struct v4l
 
                        case SENSOR_AF_MODE_CONTINUOUS:
                        {
-                               ret = sensor_af_const(client);
+                               ret = sensor_af_workqueue_set(icd, WqCmd_af_continues, 0, true);
                                break;
                        }
                        default:
@@ -5485,35 +5610,18 @@ static int sensor_s_stream(struct v4l2_subdev *sd, int enable)
        mf.field        = V4L2_FIELD_NONE;
                /* 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)) {
-                               if (sensor->sensor_wq != NULL) {
-                                       mutex_lock(&sensor->wq_lock);
-                                       if (sensor->sensor_wk.state == sensor_working) {
-                                               SENSOR_DG("%s sensor af firmware thread is runing, Ingore current work",SENSOR_NAME_STRING());
-                                               mutex_unlock(&sensor->wq_lock);
-                                               goto sensor_s_stream_end;
-                                       }
-                                       sensor->sensor_wk.state = sensor_working;
-                                       mutex_unlock(&sensor->wq_lock);
-                                       sensor->sensor_wk.client = client;
-                                       INIT_WORK(&(sensor->sensor_wk.dwork.work), sensor_af_workqueue);
-                                       queue_delayed_work(sensor->sensor_wq,&(sensor->sensor_wk.dwork), 0);
-                               }
+                       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->info_priv.affm_reinit = 0;
                        }
                }
                #endif
        } else if (enable == 0) {
                sensor->info_priv.enable = 0;
-               #if CONFIG_SENSOR_Focus
-               flush_work(&(sensor->sensor_wk.dwork.work));
-               mutex_lock(&sensor->wq_lock);
-               sensor->sensor_wk.state = sensor_work_ready;
-               mutex_unlock(&sensor->wq_lock);
+               #if CONFIG_SENSOR_Focus 
+        flush_workqueue(sensor->sensor_wq);
                #endif
        }
-
-sensor_s_stream_end:
        return 0;
 }
 
@@ -5719,11 +5827,10 @@ static int sensor_probe(struct i2c_client *client,
                sensor = NULL;
     } else {
                #if CONFIG_SENSOR_Focus
-               sensor->sensor_wq = create_workqueue(SENSOR_NAME_STRING( wq));
+               sensor->sensor_wq = create_workqueue(SENSOR_NAME_STRING(_af_workqueue));
                if (sensor->sensor_wq == NULL)
-                       SENSOR_TR("%s workqueue create fail!", SENSOR_NAME_STRING( wq));
+                       SENSOR_TR("%s create fail!", SENSOR_NAME_STRING(_af_workqueue));
                mutex_init(&sensor->wq_lock);
-               sensor->sensor_wk.state = sensor_work_ready;
                #endif
     }
 
index 8da0b077f98949bf3be79ceb47ef4cb3ef876fd4..f0b8b2b39b7b00fd2f645c38a445a5cb2fea1351 100755 (executable)
@@ -475,7 +475,6 @@ static void rk29_videobuf_queue(struct videobuf_queue *vq,
                else
                        BUG();    /* ddl@rock-chips.com : The same videobuffer queue again */
        }
-
     if (!pcdev->active) {
         pcdev->active = vb;
         rk29_videobuf_capture(vb);
@@ -643,7 +642,7 @@ static irqreturn_t rk29_camera_irq(int irq, void *data)
                        wk->vb = vb;
                        wk->pcdev = pcdev;
                        queue_work(pcdev->camera_wq, &(wk->work));
-               } else {
+               } else {                    
                        wake_up(&vb->done);
                }
     }
@@ -1994,7 +1993,7 @@ static int rk29_camera_probe(struct platform_device *pdev)
         goto exit_reqirq;
     }
 
-       pcdev->camera_wq = create_workqueue("camera wq");
+       pcdev->camera_wq = create_workqueue("rk_camera_workqueue");
        if (pcdev->camera_wq == NULL)
                goto exit_free_irq;
        INIT_WORK(&pcdev->camera_reinit_work, rk29_camera_reinit_work);