atomisp: flash-light appears on the screen.
authoryoshio wada <yoshio.wada@intel.com>
Wed, 25 Apr 2012 23:53:49 +0000 (01:53 +0200)
committerbuildbot <buildbot@intel.com>
Fri, 8 Jun 2012 14:25:23 +0000 (07:25 -0700)
BZ: 36446

keep the timing to write the itg and gain value into mt9e013 register.
- use SOF irq
- implement the gain delay filter in the sensor driver

Solution :
- atomisp
- libcamera
- libmfldadvci
- bionic

Change-Id: Iaba0da1906af9895af2b6f9054d3601d3455c044
Signed-off-by: Yoshio Wada <yoshio.wada@intel.com>
Reviewed-on: http://android.intel.com:8080/51348
Reviewed-by: Kantola, Lasse <lasse.kantola@intel.com>
Reviewed-by: Kruger, Jozef <jozef.kruger@intel.com>
Reviewed-by: Koski, Anttu <anttu.koski@intel.com>
Tested-by: Koski, Anttu <anttu.koski@intel.com>
Reviewed-by: Koskinen, Ilkka <ilkka.koskinen@intel.com>
Reviewed-by: buildbot <buildbot@intel.com>
Tested-by: buildbot <buildbot@intel.com>
15 files changed:
arch/x86/platform/intel-mid/device_libs/platform_camera.c
arch/x86/platform/intel-mid/device_libs/platform_camera.h
arch/x86/platform/intel-mid/device_libs/platform_mt9e013.c
arch/x86/platform/intel-mid/device_libs/platform_mt9m114.c
arch/x86/platform/intel-mid/device_libs/platform_ov8830.c
drivers/media/video/atomisp/atomisp_cmd.c
drivers/media/video/atomisp/atomisp_cmd.h
drivers/media/video/atomisp/atomisp_fops.c
drivers/media/video/atomisp/atomisp_ioctl.c
drivers/media/video/atomisp/css/sh_css.c
drivers/media/video/atomisp/css/sh_css_hrt.c
drivers/media/video/mt9e013/mt9e013.c
drivers/media/video/mt9e013/mt9e013.h
include/linux/atomisp.h
include/linux/atomisp_platform.h

index d9e6656..fa4f061 100644 (file)
@@ -71,7 +71,8 @@ int camera_sensor_gpio(int gpio, char *name, int dir, int value)
  * @bayer_order: MIPI CSI bayer order, see include/linux/atomisp_platform.h
  */
 int camera_sensor_csi(struct v4l2_subdev *sd, u32 port,
-                       u32 lanes, u32 format, u32 bayer_order, int flag)
+                       u32 lanes, u32 format, u32 bayer_order,
+                       bool need_sof_signal, int flag)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct camera_mipi_info *csi = NULL;
@@ -86,6 +87,7 @@ int camera_sensor_csi(struct v4l2_subdev *sd, u32 port,
                csi->num_lanes = lanes;
                csi->input_format = format;
                csi->raw_bayer_order = bayer_order;
+               csi->need_sof_signal = need_sof_signal;
                v4l2_set_subdev_hostdata(sd, (void *)csi);
        } else {
                csi = v4l2_get_subdev_hostdata(sd);
index fbcac13..00b6359 100644 (file)
@@ -25,7 +25,8 @@ extern const struct intel_v4l2_subdev_id v4l2_ids[] __attribute__((weak));
 
 extern int camera_sensor_gpio(int gpio, char *name, int dir, int value);
 extern int camera_sensor_csi(struct v4l2_subdev *sd, u32 port,
-                       u32 lanes, u32 format, u32 bayer_order, int flag);
+                       u32 lanes, u32 format, u32 bayer_order,
+                       bool need_sof_signal, int flag);
 extern void intel_ignore_i2c_device_register(
                                struct sfi_device_table_entry *pentry,
                                struct devs_id *dev
index 2b8c794..c430814 100644 (file)
@@ -92,7 +92,9 @@ static int mt9e013_power_ctrl(struct v4l2_subdev *sd, int flag)
 static int mt9e013_csi_configure(struct v4l2_subdev *sd, int flag)
 {
        return camera_sensor_csi(sd, ATOMISP_CAMERA_PORT_PRIMARY, 2,
-               ATOMISP_INPUT_FORMAT_RAW_10, atomisp_bayer_order_grbg, flag);
+               ATOMISP_INPUT_FORMAT_RAW_10, atomisp_bayer_order_grbg,
+               true, /*SOF */
+               flag);
 }
 
 static bool mt9e013_low_fps(void)
index e9c188c..12db4ca 100644 (file)
@@ -133,7 +133,9 @@ static int mt9m114_csi_configure(struct v4l2_subdev *sd, int flag)
 {
        /* soc sensor, there is no raw bayer order (set to -1) */
        return camera_sensor_csi(sd, ATOMISP_CAMERA_PORT_SECONDARY, 1,
-               ATOMISP_INPUT_FORMAT_YUV422_8, -1, flag);
+               ATOMISP_INPUT_FORMAT_YUV422_8, -1,
+               false, /*SOF */
+               flag);
 }
 
 static struct camera_sensor_platform_data mt9m114_sensor_platform_data = {
index 4149845..5d68af3 100644 (file)
@@ -78,7 +78,9 @@ static int ov8830_csi_configure(struct v4l2_subdev *sd, int flag)
 {
        static const int LANES = 4;
        return camera_sensor_csi(sd, ATOMISP_CAMERA_PORT_PRIMARY, LANES,
-               ATOMISP_INPUT_FORMAT_RAW_10, atomisp_bayer_order_bggr, flag);
+               ATOMISP_INPUT_FORMAT_RAW_10, atomisp_bayer_order_bggr,
+               false, /*SOF */
+               flag);
 }
 
 static struct camera_sensor_platform_data ov8830_sensor_platform_data = {
index 9f8a510..400e0b9 100644 (file)
@@ -34,6 +34,9 @@
 #include <linux/kernel.h>
 #include <asm/intel-mid.h>
 
+#define        ATOMISP_SOF     (SH_CSS_IRQ_INFO_CSS_RECEIVER_SOF)
+#define        ATOMISP_EOF     (SH_CSS_IRQ_INFO_STATISTICS_READY)
+
 /* We should never need to run the flash for more than 2 frames.
  * At 15fps this means 133ms. We set the timeout a bit longer.
  * Each flash driver is supposed to set its own timeout, but
@@ -97,6 +100,21 @@ static void atomisp_buf_done(struct atomisp_device *isp, int error);
 static int atomisp_start_binary(struct atomisp_device *isp);
 static int atomisp_buffer_dequeue(struct atomisp_device *isp, int wait);
 
+void
+atomisp_setup_mipi_interrupt_enable(struct atomisp_device *isp, int enable)
+{
+       struct camera_mipi_info *mipi_info;
+
+       mipi_info = atomisp_to_sensor_mipi_info(
+                       isp->inputs[isp->input_curr].camera);
+       if (mipi_info == NULL)
+               return;
+
+       if (mipi_info->need_sof_signal)
+               sh_css_enable_interrupt(SH_CSS_IRQ_INFO_CSS_RECEIVER_SOF,
+                                       enable);
+}
+
 /*
  * get sensor:dis71430/ov2720 related info from v4l2_subdev->priv data field.
  * subdev->priv is set in mrst.c
@@ -287,8 +305,29 @@ irqreturn_t atomisp_isr(int irq, void *dev)
        if (err != sh_css_success) {
                v4l2_warn(&atomisp_dev, "%s:failed to translate irq (err = %d,"
                          " infos = %d)\n", __func__, err, irq_infos);
-               spin_unlock_irqrestore(&isp->irq_lock, irqflags);
-               return IRQ_NONE;
+               /* if returns IRQ_NONE, the kernel can block interrupts from
+                * this device. By default, the driver IRQ routine should
+                * return IRQ_HANDLED as it is a bug to return IRQ_NONE
+                * when the driver has actually handled that interrupt.
+                */
+               goto out;
+       }
+
+       /*
+               if (both SOF and EOF) send SOF
+               else {
+                       if (SOF) send SOF
+                       if (EOF) send EOF
+               }
+       */
+       if (irq_infos & ATOMISP_SOF) {
+               int my_signal = ATOMISP_IOC_SIGNAL_SOF;
+               v4l2_subdev_call(isp->inputs[isp->input_curr].camera,
+                       core, ioctl, ATOMISP_IOC_S_SIGNAL, &my_signal);
+       } else if (irq_infos & ATOMISP_EOF) {
+               int my_signal = ATOMISP_IOC_SIGNAL_EOF;
+               v4l2_subdev_call(isp->inputs[isp->input_curr].camera,
+                       core, ioctl, ATOMISP_IOC_S_SIGNAL, &my_signal);
        }
 
        if (irq_infos & SH_CSS_IRQ_INFO_FRAME_DONE ||
@@ -417,6 +456,7 @@ no_frame_done:
                /*make work queue run*/
                complete(&isp->dis_state_complete);
 
+out:
        /* Clear irq reg at PENWELL B0 */
        if (IS_MRFLD) {
                msg_ret = atomisp_msg_read32(isp, IUNIT_PORT_MRFLD, INTR_CTL);
@@ -428,7 +468,6 @@ no_frame_done:
                atomisp_msg_write32(isp, IUNIT_PORT_MDFLD, INTR_CTL, msg_ret);
        }
 
-out:
        spin_unlock_irqrestore(&isp->irq_lock, irqflags);
        return IRQ_HANDLED;
 }
index ba302d8..f8b9aef 100644 (file)
@@ -64,6 +64,9 @@ irqreturn_t atomisp_isr(int irq, void *dev);
 void atomisp_work(struct work_struct *work);
 int atomisp_get_frame_pgnr(const struct sh_css_frame *frame, u32 * p_pgnr);
 
+void
+atomisp_setup_mipi_interrupt_enable(struct atomisp_device *isp, int enable);
+
 /*
  * Get internal fmt according to V4L2 fmt
  */
index 1a2df98..2d2fbd3 100644 (file)
@@ -457,6 +457,7 @@ static int atomisp_release(struct file *file)
                isp->vf_frame = NULL;
        }
 
+       atomisp_setup_mipi_interrupt_enable(isp, false);
 
        atomisp_free_3a_buffers(isp);
        atomisp_free_dis_buffers(isp);
index e6c85e1..f0f1e84 100644 (file)
@@ -1643,6 +1643,19 @@ static int atomisp_s_parm_file(struct file *file, void *fh,
        return 0;
 }
 
+static int atomisp_setup_mipi_interrput(struct atomisp_device *isp, void *arg)
+{
+       mutex_lock(&isp->input_lock);
+       mutex_lock(&isp->isp_lock);
+
+       atomisp_setup_mipi_interrupt_enable(isp, *((int *)arg));
+
+       mutex_unlock(&isp->isp_lock);
+       mutex_unlock(&isp->input_lock);
+
+       return 0;
+}
+
 /* set default atomisp ioctl value */
 static long atomisp_vidioc_default(struct file *file, void *fh,
        bool valid_prio, int cmd, void *arg)
@@ -1836,6 +1849,9 @@ static long atomisp_vidioc_default(struct file *file, void *fh,
        case ATOMISP_IOC_S_ISP_GAMMA_CORRECTION:
                return atomisp_gamma_correction(isp, 1, arg);
 
+       case ATOMISP_IOC_S_MIPI_IRQ:
+               return atomisp_setup_mipi_interrput(isp, arg);
+
        default:
                return -EINVAL;
        }
index 98f85c8..28358ef 100644 (file)
@@ -2067,7 +2067,6 @@ sh_css_translate_interrupt(unsigned int *irq_infos)
 
                switch (irq) {
                case hrt_isp_css_irq_sp:
-                       sh_css_hrt_irq_clear_sp();
                        if (sh_css_frame_done()) {
                                infos |= SH_CSS_IRQ_INFO_FRAME_DONE;
                                if (my_css.mode == sh_css_mode_video &&
index 743b7d8..c3a8b74 100644 (file)
@@ -1893,6 +1893,8 @@ sh_css_hrt_irq_get_id(enum hrt_isp_css_irq *irq_id)
                return hrt_isp_css_irq_status_error;
 
        irq_status &= ~(1u << id1);
+       if ((enum hrt_isp_css_irq) id1 == hrt_isp_css_irq_sp)
+               sh_css_hrt_irq_clear_sp();
 
        /* now check whether there are more bits set */
        id2 = ffs(irq_status) - 1;
index 15e9e8d..815b7cf 100644 (file)
@@ -57,6 +57,8 @@
 #define PR3_2_FW 0x0400
 #define PR3_3_FW 0x0500
 
+#define MINIMUM_GLOBAL_GAIN    0x1060
+
 /* divides a by b using half up rounding and div/0 prevention
  * (result is 0 if b == 0) */
 #define divsave_rounded(a, b)  (((b) != 0) ? (((a)+((b)>>1))/(b)) : (-1))
@@ -450,21 +452,12 @@ static int mt9e013_q_focus_abs(struct v4l2_subdev *sd, s32 *value)
        return 0;
 }
 
-static long mt9e013_set_exposure(struct v4l2_subdev *sd, u16 coarse_itg,
+static long mt9e013_set_exposure(struct mt9e013_device *dev, u16 coarse_itg,
                                 u16 fine_itg, u16 gain)
 
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(&dev->sd);
        int ret;
-       u16 frame_length;
-       struct mt9e013_device *dev = to_mt9e013_sensor(sd);
-
-       mutex_lock(&dev->input_lock);
-
-       ret = mt9e013_read_reg(client, MT9E013_16BIT,
-                              MT9E013_FRAME_LENGTH_LINES, &frame_length);
-       if (ret)
-               goto out;
 
        /* enable group hold */
        ret = mt9e013_write_reg_array(client, mt9e013_param_hold);
@@ -472,52 +465,175 @@ static long mt9e013_set_exposure(struct v4l2_subdev *sd, u16 coarse_itg,
                goto out;
 
        /* set coarse integration time */
-       ret = mt9e013_write_reg(client, MT9E013_16BIT,
-                       MT9E013_COARSE_INTEGRATION_TIME, coarse_itg);
-       if (ret)
-               goto out_disable;
+       if (dev->coarse_itg != coarse_itg) {
+               ret = mt9e013_write_reg(client, MT9E013_16BIT,
+                               MT9E013_COARSE_INTEGRATION_TIME, coarse_itg);
+               if (ret)
+                       goto out_disable;
+               dev->coarse_itg = coarse_itg;
+       }
 
        /* set fine integration time */
-       ret = mt9e013_write_reg(client, MT9E013_16BIT,
-                       MT9E013_FINE_INTEGRATION_TIME, fine_itg);
-       if (ret)
-               goto out_disable;
+       if (dev->fine_itg != fine_itg) {
+               ret = mt9e013_write_reg(client, MT9E013_16BIT,
+                               MT9E013_FINE_INTEGRATION_TIME, fine_itg);
+               if (ret)
+                       goto out_disable;
+               dev->fine_itg = fine_itg;
+       }
 
        /* set global gain */
-       ret = mt9e013_write_reg(client, MT9E013_16BIT,
-                       MT9E013_GLOBAL_GAIN, gain);
+       if (dev->gain != gain) {
+               ret = mt9e013_write_reg(client, MT9E013_16BIT,
+                               MT9E013_GLOBAL_GAIN, gain);
 
-       if (ret)
-               goto out_disable;
-       dev->gain       = gain;
-       dev->coarse_itg = coarse_itg;
-       dev->fine_itg   = fine_itg;
+               if (ret)
+                       goto out_disable;
+               dev->gain = gain;
+       }
 
 out_disable:
        /* disable group hold */
-       mt9e013_write_reg_array(client, mt9e013_param_update);
+       ret = mt9e013_write_reg_array(client, mt9e013_param_update);
 out:
-       mutex_unlock(&dev->input_lock);
-
        return ret;
 }
 
+/*
+ * this function set the delayed gain automatically.
+ * "automatically" means "without ATOMISP_IOC_S_EXPOSURE
+ * subdev call from 3a for every frame".
+ * This mechanism uses the sof signal for trigger to set gain into register.
+ */
+static bool mt9e013_gain_filter(struct mt9e013_device *dev, u16 *p_gain,
+                              bool only_dequeue)
+{
+       bool need_set_gain = false;
+       u16 gain = *p_gain;
+
+       if (gain < MINIMUM_GLOBAL_GAIN)
+               gain = MINIMUM_GLOBAL_GAIN;
+
+       if (dev->streaming) {
+               if (only_dequeue) {
+                       if (dev->queue_cnt > 0) {
+                               gain = dev->gain_delay;
+                               dev->queue_cnt = 0;
+                               need_set_gain = true;
+                       } else {
+                               need_set_gain = false; /* empty */
+                       }
+               } else {
+                       u16 s_gain = gain;
+                       if (dev->queue_cnt == 0) {
+                               /* empty : already set via SOF trigger */
+                               need_set_gain = false; /* empty */
+                       } else {
+                               gain = dev->gain_delay;
+                               need_set_gain = true;
+                       }
+                       dev->gain_delay = s_gain;
+                       dev->queue_cnt = 1;
+               }
+       } else {
+               /* gain value should be set without delay */
+               need_set_gain = true;
+               dev->queue_cnt = 0; /* flush queue */
+       }
+       if (need_set_gain)
+               *p_gain = gain;
+
+       return need_set_gain;
+}
+
+static long mt9e013_set_exposure_filter(struct mt9e013_device *dev,
+                                       u16 coarse_itg, u16 fine_itg,
+                                       u16 s_gain, bool only_dequeue)
+{
+       u16 gain = s_gain;
+
+       if (fine_itg == 0)
+               return -EINVAL;
+
+       if (!mt9e013_gain_filter(dev, &gain, only_dequeue))
+               gain = dev->gain;
+
+       if (coarse_itg == dev->coarse_itg && fine_itg == dev->fine_itg &&
+           gain == dev->gain)
+               return 0;
+
+       return mt9e013_set_exposure(dev, coarse_itg, fine_itg, gain);
+}
+
 static long mt9e013_s_exposure(struct v4l2_subdev *sd,
                               struct atomisp_exposure *exposure)
 {
-       u16 coarse_itg, fine_itg, gain;
+       struct mt9e013_device *dev = to_mt9e013_sensor(sd);
+       long ret;
 
-       coarse_itg = exposure->integration_time[0];
-       fine_itg = exposure->integration_time[1];
-       gain = exposure->gain[0];
+       mutex_lock(&dev->input_lock);
 
-       /* we should not accept the invalid value below */
-       if (fine_itg == 0 || gain == 0) {
-               struct i2c_client *client = v4l2_get_subdevdata(sd);
-               v4l2_err(client, "%s: invalid value\n", __func__);
-               return -EINVAL;
+       if (dev->frame_valid || !dev->streaming) {
+               ret = mt9e013_set_exposure_filter(dev,
+                       exposure->integration_time[0],
+                       exposure->integration_time[1],
+                       exposure->gain[0], false);
+       } else {
+               ret = 0;
+               dev->suspended_exposure_request = true;
+               dev->suspended_exposure_value = *exposure;
        }
-       return mt9e013_set_exposure(sd, coarse_itg, fine_itg, gain);
+
+       mutex_unlock(&dev->input_lock);
+       return ret;
+}
+
+static long mt9e013_s_signal(struct v4l2_subdev *sd, int *signal)
+{
+       struct mt9e013_device *dev = to_mt9e013_sensor(sd);
+       long ret;
+
+       switch (*signal) {
+       case ATOMISP_IOC_SIGNAL_SOF:
+               dev->frame_valid = true;
+               ret = queue_work(dev->wq, &dev->work);
+               break;
+       case ATOMISP_IOC_SIGNAL_EOF:
+               dev->frame_valid = false;
+               ret = 0;
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+       return ret;
+}
+
+static void work_queue_callback(struct work_struct *work)
+{
+       u16 gain, coarse_itg, fine_itg;
+       bool only_dequeue;
+       struct mt9e013_device *dev = container_of(work, struct mt9e013_device,
+                                                 work);
+
+       mutex_lock(&dev->input_lock);
+
+       if (dev->suspended_exposure_request) {
+               dev->suspended_exposure_request = false;
+               coarse_itg = dev->suspended_exposure_value.integration_time[0];
+               fine_itg = dev->suspended_exposure_value.integration_time[1];
+               gain = dev->suspended_exposure_value.gain[0];
+               only_dequeue = false;
+       } else {
+               coarse_itg = dev->coarse_itg;
+               fine_itg = dev->fine_itg;
+               gain = dev->gain;
+               only_dequeue = true;
+       }
+       mt9e013_set_exposure_filter(dev,
+               coarse_itg, fine_itg, gain, only_dequeue);
+
+       mutex_unlock(&dev->input_lock);
 }
 
 static int mt9e013_read_reg_array(struct i2c_client *client, u16 size, u16 addr,
@@ -756,6 +872,8 @@ static long mt9e013_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
                return mt9e013_s_exposure(sd, (struct atomisp_exposure *)arg);
        case ATOMISP_IOC_G_SENSOR_PRIV_INT_DATA:
                return mt9e013_g_priv_int_data(sd, arg);
+       case ATOMISP_IOC_S_SIGNAL:
+               return mt9e013_s_signal(sd, (int *)arg);
        default:
                return -EINVAL;
        }
@@ -1586,6 +1704,27 @@ static int mt9e013_detect(struct i2c_client *client, u16 *id, u8 *revision)
        return 0;
 }
 
+static int
+mt9e013_setup_sensor_mode(struct v4l2_subdev *sd)
+{
+       struct mt9e013_device *dev = to_mt9e013_sensor(sd);
+
+       switch (dev->run_mode) {
+       case CI_MODE_VIDEO:
+               mt9e013_res = mt9e013_res_video;
+               N_RES = N_RES_VIDEO;
+               break;
+       case CI_MODE_STILL_CAPTURE:
+               mt9e013_res = mt9e013_res_still;
+               N_RES = N_RES_STILL;
+               break;
+       default:
+               mt9e013_res = mt9e013_res_preview;
+               N_RES = N_RES_PREVIEW;
+       }
+       return 0;
+}
+
 /*
  * mt9e013 stream on/off
  */
@@ -1635,8 +1774,7 @@ static int mt9e013_s_stream(struct v4l2_subdev *sd, int enable)
        }
 
        /* restore settings */
-       mt9e013_res = mt9e013_res_preview;
-       N_RES = N_RES_PREVIEW;
+       mt9e013_setup_sensor_mode(sd);
        mutex_unlock(&dev->input_lock);
 
        return 0;
@@ -1856,25 +1994,14 @@ static int
 mt9e013_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *param)
 {
        struct mt9e013_device *dev = to_mt9e013_sensor(sd);
+       int ret;
 
        dev->run_mode = param->parm.capture.capturemode;
 
        mutex_lock(&dev->input_lock);
-       switch (dev->run_mode) {
-       case CI_MODE_VIDEO:
-               mt9e013_res = mt9e013_res_video;
-               N_RES = N_RES_VIDEO;
-               break;
-       case CI_MODE_STILL_CAPTURE:
-               mt9e013_res = mt9e013_res_still;
-               N_RES = N_RES_STILL;
-               break;
-       default:
-               mt9e013_res = mt9e013_res_preview;
-               N_RES = N_RES_PREVIEW;
-       }
+       ret = mt9e013_setup_sensor_mode(sd);
        mutex_unlock(&dev->input_lock);
-       return 0;
+       return ret;
 }
 
 static int
@@ -1985,6 +2112,7 @@ static int mt9e013_remove(struct i2c_client *client)
        v4l2_device_unregister_subdev(sd);
        kfree(dev->otp_data);
        kfree(dev->fuseid);
+       destroy_workqueue(dev->wq);
        kfree(dev);
 
        return 0;
@@ -2003,6 +2131,15 @@ static int mt9e013_probe(struct i2c_client *client,
                return -ENOMEM;
        }
 
+       dev->wq = create_singlethread_workqueue("mt9e013_sof_handler");
+       if (dev->wq == NULL) {
+               dev_err(&client->dev, "%s: cannot create workqueue\n",
+                       __func__);
+               kfree(dev);
+               return -ENOMEM;
+       }
+       INIT_WORK(&dev->work, work_queue_callback);
+
        mutex_init(&dev->input_lock);
 
        dev->fmt_idx = 0;
@@ -2012,8 +2149,7 @@ static int mt9e013_probe(struct i2c_client *client,
                ret = mt9e013_s_config(&dev->sd, client->irq,
                                       client->dev.platform_data);
                if (ret) {
-                       v4l2_device_unregister_subdev(&dev->sd);
-                       kfree(dev);
+                       mt9e013_remove(client);
                        return ret;
                }
        }
@@ -2022,6 +2158,8 @@ static int mt9e013_probe(struct i2c_client *client,
        dev->pad.flags = MEDIA_PAD_FL_SOURCE;
        dev->sd.entity.ops = &mt9e013_entity_ops;
        dev->format.code = V4L2_MBUS_FMT_SGRBG10_1X10;
+       dev->gain_delay = MINIMUM_GLOBAL_GAIN;
+       dev->queue_cnt = 0;
 
        /* REVISIT: Do we need media controller? */
        ret = media_entity_init(&dev->sd.entity, 1, &dev->pad, 0);
index 1edee5e..752a92d 100644 (file)
@@ -304,6 +304,15 @@ struct mt9e013_device {
        void *fuseid;
        /* Older VCMs could not maintain the focus position in standby mode. */
        bool keeps_focus_pos;
+
+       struct workqueue_struct *wq;
+       struct work_struct work;
+       int queue_cnt;
+       u16 gain_delay;
+
+       bool frame_valid;
+       bool suspended_exposure_request;
+       struct atomisp_exposure suspended_exposure_value;
 };
 
 #define MT9E013_MAX_WRITE_BUF_SIZE     32
index 5cfa31e..edb0693 100644 (file)
@@ -431,6 +431,11 @@ enum atomisp_acc_arg_type {
        ATOMISP_ACC_ARG_FRAME        /* Frame argument */
 };
 
+enum {
+       ATOMISP_IOC_SIGNAL_SOF, /* Start Of Frame */
+       ATOMISP_IOC_SIGNAL_EOF, /* End Of Frame */
+};
+
 struct atomisp_sp_arg {
        enum atomisp_acc_arg_type type; /* Type  of SP argument */
        void                    *value; /* Value of SP argument */
@@ -641,6 +646,13 @@ struct v4l2_private_int_data {
 #define ATOMISP_IOC_G_MOTOR_PRIV_INT_DATA \
        _IOWR('v', BASE_VIDIOC_PRIVATE + 57, struct v4l2_private_int_data)
 
+/* signal */
+#define ATOMISP_IOC_S_SIGNAL \
+       _IOW('v', BASE_VIDIOC_PRIVATE + 58, int)
+
+#define ATOMISP_IOC_S_MIPI_IRQ \
+       _IOW('v', BASE_VIDIOC_PRIVATE + 59, int)
+
 /*  ISP Private control IDs */
 #define V4L2_CID_ATOMISP_BAD_PIXEL_DETECTION \
        (V4L2_CID_PRIVATE_BASE + 0)
index 8cce510..57d1a19 100644 (file)
@@ -109,6 +109,7 @@ struct camera_mipi_info {
        unsigned int                    num_lanes;
        enum atomisp_input_format       input_format;
        enum atomisp_bayer_order        raw_bayer_order;
+       bool                            need_sof_signal;
        struct atomisp_sensor_mode_data data;
 };