aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Obermaier <johannes.obermaier@gmail.com>2011-06-02 12:03:41 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2011-07-27 16:52:25 -0400
commit32127363eebdf63be2f375ed94838a4cdb1d6fe0 (patch)
treee75be3ac94e53092657ba68d4bbd6ed101edf218
parent590929f32adc3aaa702c287b624a0d0382730088 (diff)
[media] mt9v011: Fixed gain calculation
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 1111 (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 0000 (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. Tested-by: Mauro Carvalho Chehab <mchehab@redhat.com> Signed-off-by: Johannes Obermaier <johannes.obermaier@gmail.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/media/video/mt9v011.c63
1 files changed, 52 insertions, 11 deletions
diff --git a/drivers/media/video/mt9v011.c b/drivers/media/video/mt9v011.c
index fbbd018c94ab..893a8b8f5141 100644
--- a/drivers/media/video/mt9v011.c
+++ b/drivers/media/video/mt9v011.c
@@ -54,7 +54,7 @@ static struct v4l2_queryctrl mt9v011_qctrl[] = {
54 .type = V4L2_CTRL_TYPE_INTEGER, 54 .type = V4L2_CTRL_TYPE_INTEGER,
55 .name = "Gain", 55 .name = "Gain",
56 .minimum = 0, 56 .minimum = 0,
57 .maximum = (1 << 10) - 1, 57 .maximum = (1 << 12) - 1 - 0x0020,
58 .step = 1, 58 .step = 1,
59 .default_value = 0x0020, 59 .default_value = 0x0020,
60 .flags = 0, 60 .flags = 0,
@@ -114,7 +114,8 @@ struct mt9v011 {
114 unsigned hflip:1; 114 unsigned hflip:1;
115 unsigned vflip:1; 115 unsigned vflip:1;
116 116
117 u16 global_gain, exposure, red_bal, blue_bal; 117 u16 global_gain, exposure;
118 s16 red_bal, blue_bal;
118}; 119};
119 120
120static inline struct mt9v011 *to_mt9v011(struct v4l2_subdev *sd) 121static inline struct mt9v011 *to_mt9v011(struct v4l2_subdev *sd)
@@ -189,25 +190,65 @@ static const struct i2c_reg_value mt9v011_init_default[] = {
189 { R07_MT9V011_OUT_CTRL, 0x0002 }, /* chip enable */ 190 { R07_MT9V011_OUT_CTRL, 0x0002 }, /* chip enable */
190}; 191};
191 192
193
194static u16 calc_mt9v011_gain(s16 lineargain)
195{
196
197 u16 digitalgain = 0;
198 u16 analogmult = 0;
199 u16 analoginit = 0;
200
201 if (lineargain < 0)
202 lineargain = 0;
203
204 /* recommended minimum */
205 lineargain += 0x0020;
206
207 if (lineargain > 2047)
208 lineargain = 2047;
209
210 if (lineargain > 1023) {
211 digitalgain = 3;
212 analogmult = 3;
213 analoginit = lineargain / 16;
214 } else if (lineargain > 511) {
215 digitalgain = 1;
216 analogmult = 3;
217 analoginit = lineargain / 8;
218 } else if (lineargain > 255) {
219 analogmult = 3;
220 analoginit = lineargain / 4;
221 } else if (lineargain > 127) {
222 analogmult = 1;
223 analoginit = lineargain / 2;
224 } else
225 analoginit = lineargain;
226
227 return analoginit + (analogmult << 7) + (digitalgain << 9);
228
229}
230
192static void set_balance(struct v4l2_subdev *sd) 231static void set_balance(struct v4l2_subdev *sd)
193{ 232{
194 struct mt9v011 *core = to_mt9v011(sd); 233 struct mt9v011 *core = to_mt9v011(sd);
195 u16 green1_gain, green2_gain, blue_gain, red_gain; 234 u16 green_gain, blue_gain, red_gain;
196 u16 exposure; 235 u16 exposure;
236 s16 bal;
197 237
198 exposure = core->exposure; 238 exposure = core->exposure;
199 239
200 green1_gain = core->global_gain; 240 green_gain = calc_mt9v011_gain(core->global_gain);
201 green2_gain = core->global_gain;
202 241
203 blue_gain = core->global_gain + 242 bal = core->global_gain;
204 core->global_gain * core->blue_bal / (1 << 9); 243 bal += (core->blue_bal * core->global_gain / (1 << 7));
244 blue_gain = calc_mt9v011_gain(bal);
205 245
206 red_gain = core->global_gain + 246 bal = core->global_gain;
207 core->global_gain * core->blue_bal / (1 << 9); 247 bal += (core->red_bal * core->global_gain / (1 << 7));
248 red_gain = calc_mt9v011_gain(bal);
208 249
209 mt9v011_write(sd, R2B_MT9V011_GREEN_1_GAIN, green1_gain); 250 mt9v011_write(sd, R2B_MT9V011_GREEN_1_GAIN, green_gain);
210 mt9v011_write(sd, R2E_MT9V011_GREEN_2_GAIN, green1_gain); 251 mt9v011_write(sd, R2E_MT9V011_GREEN_2_GAIN, green_gain);
211 mt9v011_write(sd, R2C_MT9V011_BLUE_GAIN, blue_gain); 252 mt9v011_write(sd, R2C_MT9V011_BLUE_GAIN, blue_gain);
212 mt9v011_write(sd, R2D_MT9V011_RED_GAIN, red_gain); 253 mt9v011_write(sd, R2D_MT9V011_RED_GAIN, red_gain);
213 mt9v011_write(sd, R09_MT9V011_SHUTTER_WIDTH, exposure); 254 mt9v011_write(sd, R09_MT9V011_SHUTTER_WIDTH, exposure);