diff options
Diffstat (limited to 'drivers/media/video/mt9v011.c')
-rw-r--r-- | drivers/media/video/mt9v011.c | 69 |
1 files changed, 67 insertions, 2 deletions
diff --git a/drivers/media/video/mt9v011.c b/drivers/media/video/mt9v011.c index 1fe8fc9183a7..b2260de645f0 100644 --- a/drivers/media/video/mt9v011.c +++ b/drivers/media/video/mt9v011.c | |||
@@ -8,6 +8,7 @@ | |||
8 | #include <linux/i2c.h> | 8 | #include <linux/i2c.h> |
9 | #include <linux/videodev2.h> | 9 | #include <linux/videodev2.h> |
10 | #include <linux/delay.h> | 10 | #include <linux/delay.h> |
11 | #include <asm/div64.h> | ||
11 | #include <media/v4l2-device.h> | 12 | #include <media/v4l2-device.h> |
12 | #include "mt9v011.h" | 13 | #include "mt9v011.h" |
13 | #include <media/v4l2-i2c-drv.h> | 14 | #include <media/v4l2-i2c-drv.h> |
@@ -57,6 +58,7 @@ static struct v4l2_queryctrl mt9v011_qctrl[] = { | |||
57 | struct mt9v011 { | 58 | struct mt9v011 { |
58 | struct v4l2_subdev sd; | 59 | struct v4l2_subdev sd; |
59 | unsigned width, height; | 60 | unsigned width, height; |
61 | unsigned xtal; | ||
60 | 62 | ||
61 | u16 global_gain, red_bal, blue_bal; | 63 | u16 global_gain, red_bal, blue_bal; |
62 | }; | 64 | }; |
@@ -131,7 +133,7 @@ static const struct i2c_reg_value mt9v011_init_default[] = { | |||
131 | { R1E_MT9V011_DIGITAL_ZOOM, 0x0000 }, | 133 | { R1E_MT9V011_DIGITAL_ZOOM, 0x0000 }, |
132 | { R20_MT9V011_READ_MODE, 0x1000 }, | 134 | { R20_MT9V011_READ_MODE, 0x1000 }, |
133 | 135 | ||
134 | { R07_MT9V011_OUT_CTRL, 0x000a }, /* chip enable */ | 136 | { R07_MT9V011_OUT_CTRL, 0x0002 }, /* chip enable */ |
135 | }; | 137 | }; |
136 | 138 | ||
137 | static void set_balance(struct v4l2_subdev *sd) | 139 | static void set_balance(struct v4l2_subdev *sd) |
@@ -154,6 +156,31 @@ static void set_balance(struct v4l2_subdev *sd) | |||
154 | mt9v011_write(sd, R2D_MT9V011_RED_GAIN, red_gain); | 156 | mt9v011_write(sd, R2D_MT9V011_RED_GAIN, red_gain); |
155 | } | 157 | } |
156 | 158 | ||
159 | static void calc_fps(struct v4l2_subdev *sd) | ||
160 | { | ||
161 | struct mt9v011 *core = to_mt9v011(sd); | ||
162 | unsigned height, width, hblank, vblank, speed; | ||
163 | unsigned row_time, t_time; | ||
164 | u64 frames_per_ms; | ||
165 | unsigned tmp; | ||
166 | |||
167 | height = mt9v011_read(sd, R03_MT9V011_HEIGHT); | ||
168 | width = mt9v011_read(sd, R04_MT9V011_WIDTH); | ||
169 | hblank = mt9v011_read(sd, R05_MT9V011_HBLANK); | ||
170 | vblank = mt9v011_read(sd, R06_MT9V011_VBLANK); | ||
171 | speed = mt9v011_read(sd, R0A_MT9V011_CLK_SPEED); | ||
172 | |||
173 | row_time = (width + 113 + hblank) * (speed + 2); | ||
174 | t_time = row_time * (height + vblank + 1); | ||
175 | |||
176 | frames_per_ms = core->xtal * 1000l; | ||
177 | do_div(frames_per_ms, t_time); | ||
178 | tmp = frames_per_ms; | ||
179 | |||
180 | v4l2_dbg(1, debug, sd, "Programmed to %u.%03u fps (%d pixel clcks)\n", | ||
181 | tmp / 1000, tmp % 1000, t_time); | ||
182 | } | ||
183 | |||
157 | static void set_res(struct v4l2_subdev *sd) | 184 | static void set_res(struct v4l2_subdev *sd) |
158 | { | 185 | { |
159 | struct mt9v011 *core = to_mt9v011(sd); | 186 | struct mt9v011 *core = to_mt9v011(sd); |
@@ -175,10 +202,12 @@ static void set_res(struct v4l2_subdev *sd) | |||
175 | mt9v011_write(sd, R04_MT9V011_WIDTH, core->width); | 202 | mt9v011_write(sd, R04_MT9V011_WIDTH, core->width); |
176 | mt9v011_write(sd, R05_MT9V011_HBLANK, 771 - core->width); | 203 | mt9v011_write(sd, R05_MT9V011_HBLANK, 771 - core->width); |
177 | 204 | ||
178 | vstart = 8 + (640 - core->height) / 2; | 205 | vstart = 8 + (480 - core->height) / 2; |
179 | mt9v011_write(sd, R01_MT9V011_ROWSTART, vstart); | 206 | mt9v011_write(sd, R01_MT9V011_ROWSTART, vstart); |
180 | mt9v011_write(sd, R03_MT9V011_HEIGHT, core->height); | 207 | mt9v011_write(sd, R03_MT9V011_HEIGHT, core->height); |
181 | mt9v011_write(sd, R06_MT9V011_VBLANK, 508 - core->height); | 208 | mt9v011_write(sd, R06_MT9V011_VBLANK, 508 - core->height); |
209 | |||
210 | calc_fps(sd); | ||
182 | }; | 211 | }; |
183 | 212 | ||
184 | static int mt9v011_reset(struct v4l2_subdev *sd, u32 val) | 213 | static int mt9v011_reset(struct v4l2_subdev *sd, u32 val) |
@@ -215,6 +244,23 @@ static int mt9v011_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | |||
215 | return -EINVAL; | 244 | return -EINVAL; |
216 | } | 245 | } |
217 | 246 | ||
247 | static int mt9v011_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) | ||
248 | { | ||
249 | int i; | ||
250 | |||
251 | v4l2_dbg(1, debug, sd, "queryctrl called\n"); | ||
252 | |||
253 | for (i = 0; i < ARRAY_SIZE(mt9v011_qctrl); i++) | ||
254 | if (qc->id && qc->id == mt9v011_qctrl[i].id) { | ||
255 | memcpy(qc, &(mt9v011_qctrl[i]), | ||
256 | sizeof(*qc)); | ||
257 | return 0; | ||
258 | } | ||
259 | |||
260 | return -EINVAL; | ||
261 | } | ||
262 | |||
263 | |||
218 | static int mt9v011_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | 264 | static int mt9v011_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) |
219 | { | 265 | { |
220 | struct mt9v011 *core = to_mt9v011(sd); | 266 | struct mt9v011 *core = to_mt9v011(sd); |
@@ -294,6 +340,22 @@ static int mt9v011_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) | |||
294 | return 0; | 340 | return 0; |
295 | } | 341 | } |
296 | 342 | ||
343 | static int mt9v011_s_config(struct v4l2_subdev *sd, int dumb, void *data) | ||
344 | { | ||
345 | struct mt9v011 *core = to_mt9v011(sd); | ||
346 | unsigned *xtal = data; | ||
347 | |||
348 | v4l2_dbg(1, debug, sd, "s_config called\n"); | ||
349 | |||
350 | if (xtal) { | ||
351 | core->xtal = *xtal; | ||
352 | v4l2_dbg(1, debug, sd, "xtal set to %d.%03d MHz\n", | ||
353 | *xtal / 1000000, (*xtal / 1000) % 1000); | ||
354 | } | ||
355 | |||
356 | return 0; | ||
357 | } | ||
358 | |||
297 | 359 | ||
298 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 360 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
299 | static int mt9v011_g_register(struct v4l2_subdev *sd, | 361 | static int mt9v011_g_register(struct v4l2_subdev *sd, |
@@ -338,9 +400,11 @@ static int mt9v011_g_chip_ident(struct v4l2_subdev *sd, | |||
338 | } | 400 | } |
339 | 401 | ||
340 | static const struct v4l2_subdev_core_ops mt9v011_core_ops = { | 402 | static const struct v4l2_subdev_core_ops mt9v011_core_ops = { |
403 | .queryctrl = mt9v011_queryctrl, | ||
341 | .g_ctrl = mt9v011_g_ctrl, | 404 | .g_ctrl = mt9v011_g_ctrl, |
342 | .s_ctrl = mt9v011_s_ctrl, | 405 | .s_ctrl = mt9v011_s_ctrl, |
343 | .reset = mt9v011_reset, | 406 | .reset = mt9v011_reset, |
407 | .s_config = mt9v011_s_config, | ||
344 | .g_chip_ident = mt9v011_g_chip_ident, | 408 | .g_chip_ident = mt9v011_g_chip_ident, |
345 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 409 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
346 | .g_register = mt9v011_g_register, | 410 | .g_register = mt9v011_g_register, |
@@ -395,6 +459,7 @@ static int mt9v011_probe(struct i2c_client *c, | |||
395 | core->global_gain = 0x0024; | 459 | core->global_gain = 0x0024; |
396 | core->width = 640; | 460 | core->width = 640; |
397 | core->height = 480; | 461 | core->height = 480; |
462 | core->xtal = 27000000; /* Hz */ | ||
398 | 463 | ||
399 | v4l_info(c, "chip found @ 0x%02x (%s)\n", | 464 | v4l_info(c, "chip found @ 0x%02x (%s)\n", |
400 | c->addr << 1, c->adapter->name); | 465 | c->addr << 1, c->adapter->name); |