[Meego-kernel] [PATCH] MRST Tablet camera driver ver-0.953, fix 9411 and 9541

He, Yong M yong.m.he at intel.com
Fri Jun 10 01:38:55 PDT 2011


From: Yong He <yong.m.he at intel.com>
Subject: [PATCH] MRST Tablet camera driver ver-0.953, fix 9411 and 9541

=====This patch is going to fix these bugs ===

Bug 9541<https://bugzilla.otcshare.org/show_bug.cgi?id=9541> - Flip settings of driver is not correct
Bug 9411<https://bugzilla.otcshare.org/show_bug.cgi?id=9411> - power regression test failed for camera driver version 0.941

=====solution ===

Bug 9541<https://bugzilla.otcshare.org/show_bug.cgi?id=9541> - the solution is to keep flip status in the sensor's global status structure. When waked up, restore the previous saved settings.
Bug 9411<https://bugzilla.otcshare.org/show_bug.cgi?id=9411> - is caused by the back sensor HW power down GPIO-49, when perform a HW power down using this GPIO, somewhere else is leaking,
So I change back to software power down instead for now. I'll investigate this later.


Signed-off-by: He, Yong <yong.m.he at intel.com<mailto:yong.m.he at intel.com>>
---
Index: a/drivers/staging/mrstci/mrstov5640/mrstov5640.c
===================================================================
--- a/drivers/staging/mrstci/mrstov5640/mrstov5640.c         (revision 87)
+++ a/drivers/staging/mrstci/mrstov5640/mrstov5640.c      (revision 88)
@@ -49,7 +49,7 @@
#include "ci_sensor_common.h"
#include "ov5640.h"
-#define DRIVER_VERSION "0.952"
+#define DRIVER_VERSION "0.953"
 static int mrstov5640_debug=5;
module_param(mrstov5640_debug, int, 0644);
@@ -229,11 +229,8 @@
     int exp_comp_val;
       int af_x, af_y, af_mode;
     int ae_x, ae_y, ae_w, ae_h,ae_mode;
+    int hflip,vflip;
-        // hw status
-        u8 REG20;
-        u8 REG21;
-
       ov5640_exp_info_1_t snapshot;
       ov5640_exp_info_1_t preview;
       ov5640_exp_info_2_t expo;
@@ -242,10 +239,10 @@
                .power = OV5640_POWER_OFF,
                .reg_inited = OV5640_REG_BEFORE_PROBE,
                .fw_inited = OV5640_FW_RESET,
-        .REG20 = 0,
-        .REG21 = 0,
         .anti_banding = 0,
         .iso_mode = 0,
+        .hflip = 0,
+        .vflip = 1,
         .iso_val = 100,
};
@@ -597,6 +594,7 @@
 static int ov5640_save_hw_status(struct i2c_client *c);
static int ov5640_restore_hw_status(struct i2c_client *c);
+static int ov5640_s_stream(struct v4l2_subdev *sd, int enable);
 /*
  * Sensor specific helper function
@@ -612,7 +610,8 @@
     }
     ov5640_status.fw_inited = OV5640_FW_RESET;
-        gpio_set_value(GPIO_STDBY_PIN, 1);
+    ov5640_s_stream(sd , 0);
+       //gpio_set_value(GPIO_STDBY_PIN, 1);
       ov5640_status.power = OV5640_POWER_OFF;
        dprintk(1, "PM: ov5640 standby called\n");
@@ -689,7 +688,6 @@
       memcpy(info->name, "ov5640", 7);
        ov5640_status.reg_inited = OV5640_REG_RESET; // need do init reg here
-        ret = ov5640_write(c, 0x3008, 0x82);
       ret = ov5640_write(c, 0x3013, 0x11);
       ret = ov5640_write(c, 0x3008, 0x82);
       ret = ov5640_hw_init(c);
@@ -1220,6 +1218,7 @@
                //info->bpat = SENSOR_BPAT_BGBGGRGR;
       }
       err += ov5640_write(client, 0x3821, v);
+       ov5640_status.hflip = value;
       msleep(10);  /* FIXME */
        return err;
@@ -1250,6 +1249,7 @@
       else
                v &= ~0x06;
       err += ov5640_write(client, 0x3820, v);
+    ov5640_status.vflip = value;
       msleep(10);  /* FIXME */
        return err;
@@ -2693,6 +2693,7 @@
       } else {
                ov5640_set_aec_agc(client,0);
                ov5640_save_expo_val(sd);
+        ov5640_save_hw_status(client);
                ov5640_write(client, 0x3008, 0x42);
                //ov5640_set_data_pin_in(client);
       }
@@ -2815,9 +2816,7 @@
{
     struct v4l2_subdev *sd = i2c_get_clientdata(c);
-    // save original flip status
-    ov5640_read(c,0x3820,&ov5640_status.REG20);
-    ov5640_read(c,0x3821,&ov5640_status.REG21);
+    // save original flip status, (already saved in ioctl)
     // save anti-banding status
     ov5640_q_anti_banding(sd, &ov5640_status.anti_banding);
@@ -2827,13 +2826,10 @@
static int ov5640_restore_hw_status(struct i2c_client *c)
{
     struct v4l2_subdev *sd = i2c_get_clientdata(c);
-    u8 REG20_new,REG21_new;
     // restore original flip status
-    ov5640_read(c,0x3820,&REG20_new);
-    ov5640_read(c,0x3821,&REG21_new);
-    ov5640_write(c,0x3820,((REG20_new & 0xf9) | (ov5640_status.REG20& 0x6)));
-    ov5640_write(c,0x3821,((REG21_new & 0xf9) | (ov5640_status.REG21& 0x6)));
+    ov5640_t_hflip(sd, ov5640_status.hflip);
+    ov5640_t_vflip(sd, ov5640_status.vflip);
     // restore anti-banding status
     ov5640_t_anti_banding(sd, ov5640_status.anti_banding);
Index: a/drivers/staging/mrstci/mrstov9740/mrstov9740.c
===================================================================
--- a/drivers/staging/mrstci/mrstov9740/mrstov9740.c         (revision 87)
+++ a/drivers/staging/mrstci/mrstov9740/mrstov9740.c      (revision 88)
@@ -48,7 +48,7 @@
#include "ci_sensor_common.h"
#include "ov9740.h"
-#define DRIVER_VERSION "0.941"
+#define DRIVER_VERSION "0.953"
//#define pr_fmt(fmt) "ov9740: " fmt
 static int mrstov9740_debug=5;
@@ -131,6 +131,31 @@
 #define N_RES (ARRAY_SIZE(ov9740_res))
+#define OV9740_POWER_OFF 0
+#define OV9740_POWER_ON 1
+
+#define OV9740_REG_RESET 2
+#define OV9740_REG_INITED 1
+#define OV9740_REG_BEFORE_PROBE 0
+
+static struct __ov9740_status_ {
+    // sw status
+    int current_res_i;
+    int power;
+    int reg_inited;
+
+    // hw status
+    int anti_banding;
+    int hflip,vflip;
+} ov9740_status = {
+        .current_res_i = 2,//SENSOR_RES_VGA;
+        .power = OV9740_POWER_OFF,
+        .reg_inited = OV9740_REG_BEFORE_PROBE,
+        .anti_banding = 0,
+        .hflip = 0,
+        .vflip = 0,
+};
+
/*
  * I2C Read & Write stuff
  */
@@ -230,29 +255,82 @@
*/
       return ret;
}
+
+static int ov9740_save_hw_status(struct i2c_client *c);
+static int ov9740_restore_hw_status(struct i2c_client *c);
+
+static int ov9740_hw_init(struct i2c_client *c)
+{
+    int ret;
+    DBG_entering;
+
+    if (ov9740_status.reg_inited !=  OV9740_REG_RESET) {
+        return 0;
+    }
+
+    /* Set registers into default config value */
+    ret = ov9740_write_array(c, ov9740_def);
+    ret += ov9740_write_array(c, ov9740_reg_vga);
+    //ov9740_write(c, 0x0100, 0x00);
+
+    dprintk( 1, "[ov9740-wr-reg] <----------- load ov9740 default settings\n");
+
+    ov9740_set_data_pin_in(c);
+    ov9740_status.reg_inited = OV9740_REG_INITED;
+    ov9740_status.current_res_i = 2 ;
+
+    DBG_leaving;
+    return ret;
+}
+
/*
  * Sensor specific helper function
  */
-static int ov9740_standby(void)
+static int ov9740_standby(struct v4l2_subdev *sd)
{
-        gpio_set_value(GPIO_STDBY_PIN, 1);
+    if (ov9740_status.reg_inited == OV9740_REG_INITED)
+    {
+        struct i2c_client *c = v4l2_get_subdevdata(sd);
+        ov9740_save_hw_status(c);
+        ov9740_status.reg_inited = OV9740_REG_RESET;
+    }
+
+    //ov9740_s_stream(sd , 0);
+    gpio_set_value(GPIO_STDBY_PIN, 1);
+    ov9740_status.power = OV9740_POWER_OFF;
+
       dprintk(1, "PM: ov9740 standby called\n");
       return 0;
}
-static int ov9740_wakeup(void)
+static int ov9740_wakeup(struct v4l2_subdev *sd, int hw_reinit)
{
-        gpio_set_value(GPIO_STDBY_PIN, 0);
-        dprintk(1, "PM: ov9740 wakeup called\n");
+    dprintk(1, "PM: ov9740 wakeup called (%d)\n",hw_reinit);
+
+    if (ov9740_status.power == OV9740_POWER_OFF)
+    {
+        dprintk(1, "PM: ov9740 switch OFF to ON.\n");
+        gpio_set_value(GPIO_STDBY_PIN, 0);
+        ov9740_status.power = OV9740_POWER_ON;
+    }
+
+    if (hw_reinit)
+    {
+        struct i2c_client *c = v4l2_get_subdevdata(sd);
+        //ov9740_hw_init(c);
+        ov9740_status.reg_inited = OV9740_REG_INITED;
+        ov9740_restore_hw_status(c);
+    }
+
       return 0;
}
 static int ov9740_s_power(struct v4l2_subdev *sd, u32 val)
{
       if (val == 1)
-                 ov9740_standby();
+                ov9740_standby(sd);
       if (val == 0)
-                 ov9740_wakeup();
+                ov9740_wakeup(sd,0);
       return 0;
}
@@ -291,19 +369,10 @@
       info->cie_profile = 0;
       memcpy(info->name, "ov9740", 7);
-        //
-        // added
-        // ret = ov9740_write(c, OV9740_SYS, 0x80);
       /* Set registers into default config value */
-        ret = ov9740_write_array(c, ov9740_def);
-        ret += ov9740_write_array(c, ov9740_reg_vga);
-
-        /* added by wen to stop sensor from streaming */
-        // ov9740_write(c, 0x3086, 0x0f);
-        // commented out in workshop
-        //
-///        ov9740_set_data_pin_in(c);
-        ssleep(1);
+    ov9740_status.reg_inited = OV9740_REG_RESET; // need do init reg here
+    ov9740_hw_init(c);
+       msleep(300);

         DBG_leaving;
@@ -453,8 +522,6 @@
       return index;
}
-static int previous_res = 2;//SENSOR_RES_VGA;
-
static int ov9740_set_fmt(struct v4l2_subdev *sd,
                           struct v4l2_mbus_framefmt *fmt)
{
@@ -473,7 +540,7 @@
       ret = ov9740_try_res(&width, &height);
       res_index = ov9740_to_res(width, height);
-        ov9740_wakeup();
+       ov9740_wakeup(sd,1);
        /* if ((info->res != res_index->res) && (res_index->regs)) { */
       if (res_index->regs) {
@@ -481,11 +548,13 @@
                 target_res_index = find_OV9740_TIMING_index(res_index->res);
-                 if (previous_res != target_res_index) {
-                           dprintk( 3, "[ov9740-wr-reg] <----------- changing res from index-%d to index-%d (%dx%d)", previous_res, target_res_index,width, height);
+                if (ov9740_status.current_res_i != target_res_index) {
+                          dprintk( 3, "[ov9740-wr-reg] <----------- changing res from index-%d to index-%d (%dx%d)",ov9740_status.current_res_i , target_res_index,width, height);
                          dprintk( 3, "[ov9740-wr-reg] <----------- Set resolutiojn Configs");
+                          ret += ov9740_save_hw_status(client);
                          ret += ov9740_write_array(client, res_index->regs);
-                           previous_res = target_res_index;
+                          ret += ov9740_restore_hw_status(client);
+                          ov9740_status.current_res_i = target_res_index;
                }
                else {
                          dprintk(3, "[ov9740-wr-reg] <----------- same res index-%d (%dx%d)", target_res_index,width, height);
@@ -522,7 +591,7 @@
       unsigned char v;
        err = ov9740_read(client, 0x0101, &v);
-        *value = (v & 0x01) == 0x01;
+       *value = ((v & 0x01) == 0x01);
       return err;
}
@@ -543,6 +612,7 @@
                //info->bpat = SENSOR_BPAT_BGBGGRGR;
       }
       err += ov9740_write(client, 0x0101, v);
+       ov9740_status.hflip = value;
       msleep(10);  /* FIXME */
        return err;
@@ -555,7 +625,7 @@
       unsigned char v;
        err = ov9740_read(client, 0x0101, &v);
-        *value = (v & 0x02) == 0x02;
+       *value = ((v & 0x02) == 0x02);
       return err;
}
@@ -577,6 +647,7 @@
                //info->bpat = SENSOR_BPAT_BGBGGRGR;
       }
       err += ov9740_write(client, 0x0101, v);
+    ov9740_status.vflip = value;
       msleep(10);  /* FIXME */
        return err;
@@ -820,6 +891,7 @@
                          msleep(300);
                }
       } else {
+        ov9740_save_hw_status(client);
                ov9740_write(client, 0x0100, 0x00);
       }
@@ -895,16 +967,16 @@
        target_fps = param->parm.capture.timeperframe.denominator / param->parm.capture.timeperframe.numerator;
-        if (ov9740_res[previous_res].used) {
+       if (ov9740_res[ov9740_status.current_res_i].used) {
                for (fps_i = 0; fps_i < OV9740_N_FPS;  fps_i++) {
-                           if (target_fps == ov9740_res[previous_res].fps[fps_i]) {
+                          if (target_fps == ov9740_res[ov9740_status.current_res_i].fps[fps_i]) {
                                   // found the target fps
                                   u8 val;
                                   dprintk( 1, "set sensor FPS to %d\n", target_fps);
                                   ov9740_read(client, 0x0100, &val);
                                   if (val == 0x01) ov9740_s_stream(sd, 0);
-                                    target_vts = (ov9740_vts_setting[previous_res] * ov9740_res[previous_res].fps[0]) / target_fps;
+                                   target_vts = (ov9740_vts_setting[ov9740_status.current_res_i] * ov9740_res[ov9740_status.current_res_i].fps[0]) / target_fps;
                                   ov9740_write(client, 0x0340, (target_vts>>8)&0xff);
                                   ov9740_write(client, 0x0341, target_vts&0xff);
@@ -919,7 +991,7 @@
                }
       } else {
                dprintk( 1, "Warning!! current_res (%d) is not used??\n",
-                                    previous_res);
+                                   ov9740_status.current_res_i);
       }
        DBG_leaving;
@@ -937,6 +1009,25 @@
       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_OV9740, 0);
}
+static int ov9740_save_hw_status(struct i2c_client *c)
+{
+    struct v4l2_subdev *sd = i2c_get_clientdata(c);
+
+    // save original flip status (already saved in the ioctl)
+
+    return 0;
+}
+
+static int ov9740_restore_hw_status(struct i2c_client *c)
+{
+    struct v4l2_subdev *sd = i2c_get_clientdata(c);
+
+    // restore flip status
+    ov9740_t_hflip(sd, ov9740_status.hflip);
+    ov9740_t_vflip(sd, ov9740_status.vflip);
+    return 0;
+}
+
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int ov9740_g_register(struct v4l2_subdev *sd,
                               struct v4l2_dbg_register *reg)
@@ -1027,6 +1118,7 @@
#endif
static int ov9740_detect(struct i2c_client *client)
{
+    struct v4l2_subdev *sd = i2c_get_clientdata(client);
       struct i2c_adapter *adapter = client->adapter;
       int adap_id = i2c_adapter_id(adapter);
       u8 value;
@@ -1045,7 +1137,7 @@
         }
       /* if (ov9740_wakeup()) */
                /* return -ENODEV; */
-        ov9740_wakeup();
+       ov9740_wakeup(sd, 0);
        ov9740_read(client, 0x300b, &value);
       if (value != 0x40)
@@ -1091,7 +1183,7 @@
        */
       /* ov9740_standby(); */
       ret += ov9740_init(client);
-        ov9740_standby();
+       ov9740_standby(sd);
        printk(KERN_INFO "Init ov9740 (Version-%s) sensor success, ret = %d\n", DRIVER_VERSION, ret);



Best Regards,

Yong He
Software Engineer, PCSD SW Solutions,
Intel Asia-Pacific R&D Ltd.
Phone (+86) 21-61166334
Lab (+86) 21-61167881

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.meego.com/pipermail/meego-kernel/attachments/20110610/9647f682/attachment-0001.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: linux-2.6.37-camera-ov5640-ov9740-version-0.952_to_0.953.patch
Type: application/octet-stream
Size: 12005 bytes
Desc: linux-2.6.37-camera-ov5640-ov9740-version-0.952_to_0.953.patch
URL: <http://lists.meego.com/pipermail/meego-kernel/attachments/20110610/9647f682/attachment-0001.obj>


More information about the MeeGo-kernel mailing list