[PATCH 1/1] V4L/DVB: mt9v011: Fixed incorrect value for the first valid column

2011-06-02 Thread Johannes Obermaier
According to the datasheet (page 8), the first optical clear pixel-column is 
not at position 14. The correct/recommended value is 20. Without this patch 
there is a dark line on the left side of the image.

Signed-off-by: Johannes Obermaier johannes.oberma...@gmail.com
---
 drivers/media/video/mt9v011.c |2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/media/video/mt9v011.c b/drivers/media/video/mt9v011.c
index 4904d25..a6cf05a 100644
--- a/drivers/media/video/mt9v011.c
+++ b/drivers/media/video/mt9v011.c
@@ -286,7 +286,7 @@ static void set_res(struct v4l2_subdev *sd)
 * be missing.
 */
 
-   hstart = 14 + (640 - core-width) / 2;
+   hstart = 20 + (640 - core-width) / 2;
mt9v011_write(sd, R02_MT9V011_COLSTART, hstart);
mt9v011_write(sd, R04_MT9V011_WIDTH, core-width);
mt9v011_write(sd, R05_MT9V011_HBLANK, 771 - core-width);
-- 
1.6.4.2

--
To unsubscribe from this list: send the line unsubscribe linux-media in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 1/1] V4L/DVB: mt9v011: Fixed incorrect value for the first valid column

2011-06-02 Thread Johannes Obermaier
According to the datasheet (page 8), the first optical clear pixel-column is 
not at position 14. The correct/recommended value is 20. Without this patch 
there is a dark line on the left side of the image.

Signed-off-by: Johannes Obermaier johannes.oberma...@gmail.com
---
 drivers/media/video/mt9v011.c |2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/media/video/mt9v011.c b/drivers/media/video/mt9v011.c
index 4904d25..a6cf05a 100644
--- a/drivers/media/video/mt9v011.c
+++ b/drivers/media/video/mt9v011.c
@@ -286,7 +286,7 @@ static void set_res(struct v4l2_subdev *sd)
 * be missing.
 */
 
-   hstart = 14 + (640 - core-width) / 2;
+   hstart = 20 + (640 - core-width) / 2;
mt9v011_write(sd, R02_MT9V011_COLSTART, hstart);
mt9v011_write(sd, R04_MT9V011_WIDTH, core-width);
mt9v011_write(sd, R05_MT9V011_HBLANK, 771 - core-width);
-- 
1.6.4.2

--
To unsubscribe from this list: send the line unsubscribe linux-media in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 2/2] V4L/DVB: mt9v011: Added exposure for mt9v011

2011-06-02 Thread Johannes Obermaier
There are problems when you use this camera/sensor in a very bright room or 
outside. The image is completely white, because it is overexposed. The driver 
uses a default value which is not suitable for all environments.
This patch makes it possible to adjust the exposure time by youself. I found 
out by logging the i2c-data, that the windows driver for this sensor is doing 
this, too.
I tested the camera on a sunny day and after adjusting the exposure time, I was 
able to see a very good image.

Signed-off-by: Johannes Obermaier johannes.oberma...@gmail.com
---
 drivers/media/video/mt9v011.c |   22 +-
 1 files changed, 21 insertions(+), 1 deletions(-)

diff --git a/drivers/media/video/mt9v011.c b/drivers/media/video/mt9v011.c
index a6cf05a..fbbd018 100644
--- a/drivers/media/video/mt9v011.c
+++ b/drivers/media/video/mt9v011.c
@@ -59,6 +59,15 @@ static struct v4l2_queryctrl mt9v011_qctrl[] = {
.default_value = 0x0020,
.flags = 0,
}, {
+   .id = V4L2_CID_EXPOSURE,
+   .type = V4L2_CTRL_TYPE_INTEGER,
+   .name = Exposure,
+   .minimum = 0,
+   .maximum = 2047,
+   .step = 1,
+   .default_value = 0x01fc,
+   .flags = 0,
+   }, {
.id = V4L2_CID_RED_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = Red Balance,
@@ -105,7 +114,7 @@ struct mt9v011 {
unsigned hflip:1;
unsigned vflip:1;
 
-   u16 global_gain, red_bal, blue_bal;
+   u16 global_gain, exposure, red_bal, blue_bal;
 };
 
 static inline struct mt9v011 *to_mt9v011(struct v4l2_subdev *sd)
@@ -184,6 +193,9 @@ static void set_balance(struct v4l2_subdev *sd)
 {
struct mt9v011 *core = to_mt9v011(sd);
u16 green1_gain, green2_gain, blue_gain, red_gain;
+   u16 exposure;
+
+   exposure = core-exposure;
 
green1_gain = core-global_gain;
green2_gain = core-global_gain;
@@ -198,6 +210,7 @@ static void set_balance(struct v4l2_subdev *sd)
mt9v011_write(sd, R2E_MT9V011_GREEN_2_GAIN,  green1_gain);
mt9v011_write(sd, R2C_MT9V011_BLUE_GAIN, blue_gain);
mt9v011_write(sd, R2D_MT9V011_RED_GAIN, red_gain);
+   mt9v011_write(sd, R09_MT9V011_SHUTTER_WIDTH, exposure);
 }
 
 static void calc_fps(struct v4l2_subdev *sd, u32 *numerator, u32 *denominator)
@@ -338,6 +351,9 @@ static int mt9v011_g_ctrl(struct v4l2_subdev *sd, struct 
v4l2_control *ctrl)
case V4L2_CID_GAIN:
ctrl-value = core-global_gain;
return 0;
+   case V4L2_CID_EXPOSURE:
+   ctrl-value = core-exposure;
+   return 0;
case V4L2_CID_RED_BALANCE:
ctrl-value = core-red_bal;
return 0;
@@ -392,6 +408,9 @@ static int mt9v011_s_ctrl(struct v4l2_subdev *sd, struct 
v4l2_control *ctrl)
case V4L2_CID_GAIN:
core-global_gain = ctrl-value;
break;
+   case V4L2_CID_EXPOSURE:
+   core-exposure = ctrl-value;
+   break;
case V4L2_CID_RED_BALANCE:
core-red_bal = ctrl-value;
break;
@@ -598,6 +617,7 @@ static int mt9v011_probe(struct i2c_client *c,
}
 
core-global_gain = 0x0024;
+   core-exposure = 0x01fc;
core-width  = 640;
core-height = 480;
core-xtal = 2700;  /* Hz */
-- 
1.6.4.2

--
To unsubscribe from this list: send the line unsubscribe linux-media in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 3/3] V4L/DVB: mt9v011: Fixed gain calculation

2011-06-02 Thread Johannes Obermaier
(This patch must be used AFTER the patch V4L/DVB: mt9v011: Added exposure for 
mt9v011)
The implementation of the gain calculation for this sensor is incorrect. It is 
only working for the first 127 values.
The reason is, that the gain cannot be set directly by writing a value into the 
gain registers of the sensor. The gain register work this way (see datasheet 
page 24): bits 0 to 6 are called initial gain. These are linear. But bits 7 
and 8 (analog multiplicative factors) and bits 9 and 10 (digital 
multiplicative factors) work completely different: Each of these bits increase 
the gain by the factor 2. So if the bits 7-10 are 0011, 0110, 1100 or 0101 for 
example, the gain from bits 0-6 is multiplied by 4. The order of the bits 7-10 
is not important for the resulting gain. (But there are some recommended values 
for low noise)
The current driver doesn't do this correctly: If the current gain is 000 0111 
 (127) and the gain is increased by 1, you would expect the image to become 
brighter. But the image is completly dark, because the new gain is 000 1000 
 (128). This means: Initial gain of 0, multiplied by 2. The result is 0.
This patch adds a new function which does the gain calculation and also fixes 
the same bug for red_balance and blue_balance. Additionally, the driver follows 
the recommendation from the datasheet, which says, that the gain should always 
be above 0x0020.

Signed-off-by: Johannes Obermaier johannes.oberma...@gmail.com
---
 drivers/media/video/mt9v011.c |   63 +---
 1 files changed, 52 insertions(+), 11 deletions(-)

diff --git a/drivers/media/video/mt9v011.c b/drivers/media/video/mt9v011.c
index fbbd018..893a8b8 100644
--- a/drivers/media/video/mt9v011.c
+++ b/drivers/media/video/mt9v011.c
@@ -54,7 +54,7 @@ static struct v4l2_queryctrl mt9v011_qctrl[] = {
.type = V4L2_CTRL_TYPE_INTEGER,
.name = Gain,
.minimum = 0,
-   .maximum = (1  10) - 1,
+   .maximum = (1  12) - 1 - 0x0020,
.step = 1,
.default_value = 0x0020,
.flags = 0,
@@ -114,7 +114,8 @@ struct mt9v011 {
unsigned hflip:1;
unsigned vflip:1;
 
-   u16 global_gain, exposure, red_bal, blue_bal;
+   u16 global_gain, exposure;
+   s16 red_bal, blue_bal;
 };
 
 static inline struct mt9v011 *to_mt9v011(struct v4l2_subdev *sd)
@@ -189,25 +190,65 @@ static const struct i2c_reg_value mt9v011_init_default[] 
= {
{ R07_MT9V011_OUT_CTRL, 0x0002 },   /* chip enable */
 };
 
+
+static u16 calc_mt9v011_gain(s16 lineargain)
+{
+
+   u16 digitalgain = 0;
+   u16 analogmult = 0;
+   u16 analoginit = 0;
+
+   if (lineargain  0)
+   lineargain = 0;
+
+   /* recommended minimum */
+   lineargain += 0x0020;
+
+   if (lineargain  2047)
+   lineargain = 2047;
+
+   if (lineargain  1023) {
+   digitalgain = 3;
+   analogmult = 3;
+   analoginit = lineargain / 16;
+   } else if (lineargain  511) {
+   digitalgain = 1;
+   analogmult = 3;
+   analoginit = lineargain / 8;
+   } else if (lineargain  255) {
+   analogmult = 3;
+   analoginit = lineargain / 4;
+   } else if (lineargain  127) {
+   analogmult = 1;
+   analoginit = lineargain / 2;
+   } else
+   analoginit = lineargain;
+
+   return analoginit + (analogmult  7) + (digitalgain  9);
+
+}
+
 static void set_balance(struct v4l2_subdev *sd)
 {
struct mt9v011 *core = to_mt9v011(sd);
-   u16 green1_gain, green2_gain, blue_gain, red_gain;
+   u16 green_gain, blue_gain, red_gain;
u16 exposure;
+   s16 bal;
 
exposure = core-exposure;
 
-   green1_gain = core-global_gain;
-   green2_gain = core-global_gain;
+   green_gain = calc_mt9v011_gain(core-global_gain);
 
-   blue_gain = core-global_gain +
-   core-global_gain * core-blue_bal / (1  9);
+   bal = core-global_gain;
+   bal += (core-blue_bal * core-global_gain / (1  7));
+   blue_gain = calc_mt9v011_gain(bal);
 
-   red_gain = core-global_gain +
-  core-global_gain * core-blue_bal / (1  9);
+   bal = core-global_gain;
+   bal += (core-red_bal * core-global_gain / (1  7));
+   red_gain = calc_mt9v011_gain(bal);
 
-   mt9v011_write(sd, R2B_MT9V011_GREEN_1_GAIN, green1_gain);
-   mt9v011_write(sd, R2E_MT9V011_GREEN_2_GAIN,  green1_gain);
+   mt9v011_write(sd, R2B_MT9V011_GREEN_1_GAIN, green_gain);
+   mt9v011_write(sd, R2E_MT9V011_GREEN_2_GAIN, green_gain);
mt9v011_write(sd, R2C_MT9V011_BLUE_GAIN, blue_gain);
mt9v011_write(sd, R2D_MT9V011_RED_GAIN, red_gain);
mt9v011_write(sd, R09_MT9V011_SHUTTER_WIDTH, exposure);
-- 
1.6.4.2

--
To unsubscribe from this list: send the line