aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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);