diff options
-rw-r--r-- | 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 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 | ||
120 | static inline struct mt9v011 *to_mt9v011(struct v4l2_subdev *sd) | 121 | static 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 | |||
194 | static 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 | |||
192 | static void set_balance(struct v4l2_subdev *sd) | 231 | static 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); |