aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/mt9v011.c
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@redhat.com>2009-07-04 07:03:48 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-07-05 13:30:04 -0400
commit27fe4a30a211a0561c72b0e519997e91fa91c452 (patch)
tree33d8c55054816a366b99ec2df3c5bcc19917b3ec /drivers/media/video/mt9v011.c
parentfbe2800c932573e90e38a9c703165839e0c00515 (diff)
V4L/DVB (12173): mt9v011: properly calculate image resolution registers
Instead of working with a table of precalculated values, fill them with the proper values. Also, adds format functions that allow changing the resolution, by cropping the image to the center of the sensor. While here, move the sensor version check to the probe routine, to indicate to the caller if the sensor is not supported by this driver. Also, fixes a stupid bug where we're using &buffer[] instead of buffer[]. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/mt9v011.c')
-rw-r--r--drivers/media/video/mt9v011.c114
1 files changed, 94 insertions, 20 deletions
diff --git a/drivers/media/video/mt9v011.c b/drivers/media/video/mt9v011.c
index 58a619436783..3ed9511da8ed 100644
--- a/drivers/media/video/mt9v011.c
+++ b/drivers/media/video/mt9v011.c
@@ -56,6 +56,7 @@ static struct v4l2_queryctrl mt9v011_qctrl[] = {
56 56
57struct mt9v011 { 57struct mt9v011 {
58 struct v4l2_subdev sd; 58 struct v4l2_subdev sd;
59 unsigned width, height;
59 60
60 u16 global_gain, red_bal, blue_bal; 61 u16 global_gain, red_bal, blue_bal;
61}; 62};
@@ -103,7 +104,7 @@ static void mt9v011_write(struct v4l2_subdev *sd, unsigned char addr,
103 104
104 v4l2_dbg(2, debug, sd, 105 v4l2_dbg(2, debug, sd,
105 "mt9v011: writing 0x%02x 0x%04x\n", buffer[0], value); 106 "mt9v011: writing 0x%02x 0x%04x\n", buffer[0], value);
106 rc = i2c_master_send(c, &buffer, 3); 107 rc = i2c_master_send(c, buffer, 3);
107 if (rc != 3) 108 if (rc != 3)
108 v4l2_dbg(0, debug, sd, 109 v4l2_dbg(0, debug, sd,
109 "i2c i/o error: rc == %d (should be 3)\n", rc); 110 "i2c i/o error: rc == %d (should be 3)\n", rc);
@@ -123,12 +124,6 @@ static const struct i2c_reg_value mt9v011_init_default[] = {
123 { R0D_MT9V011_RESET, 0x0001 }, 124 { R0D_MT9V011_RESET, 0x0001 },
124 { R0D_MT9V011_RESET, 0x0000 }, 125 { R0D_MT9V011_RESET, 0x0000 },
125 126
126 { R01_MT9V011_ROWSTART, 0x0008 },
127 { R02_MT9V011_COLSTART, 0x0014 },
128 { R03_MT9V011_HEIGHT, 0x01e0 },
129 { R04_MT9V011_WIDTH, 0x0280 },
130 { R05_MT9V011_HBLANK, 0x007b },
131 { R06_MT9V011_VBLANK, 0x001c },
132 { R09_MT9V011_SHUTTER_WIDTH, 0x0418 }, 127 { R09_MT9V011_SHUTTER_WIDTH, 0x0418 },
133 { R0A_MT9V011_CLK_SPEED, 0x0000 }, 128 { R0A_MT9V011_CLK_SPEED, 0x0000 },
134 { R0C_MT9V011_SHUTTER_DELAY, 0x0000 }, 129 { R0C_MT9V011_SHUTTER_DELAY, 0x0000 },
@@ -171,25 +166,40 @@ static void set_balance(struct v4l2_subdev *sd)
171 mt9v011_write(sd, R2D_MT9V011_RED_GAIN, red_gain); 166 mt9v011_write(sd, R2D_MT9V011_RED_GAIN, red_gain);
172} 167}
173 168
169static void set_res(struct v4l2_subdev *sd)
170{
171 struct mt9v011 *core = to_mt9v011(sd);
172 unsigned vstart, hstart;
173
174 /*
175 * The mt9v011 doesn't have scaling. So, in order to select the desired
176 * resolution, we're cropping at the middle of the sensor.
177 * hblank and vblank should be adjusted, in order to warrant that
178 * we'll preserve the line timings for 30 fps, no matter what resolution
179 * is selected.
180 */
181
182 hstart = 14 + (640 - core->width) / 2;
183 mt9v011_write(sd, R02_MT9V011_COLSTART, hstart);
184 mt9v011_write(sd, R04_MT9V011_WIDTH, core->width);
185 mt9v011_write(sd, R05_MT9V011_HBLANK, 771 - core->width);
186
187 vstart = 8 + (640 - core->height) / 2;
188 mt9v011_write(sd, R01_MT9V011_ROWSTART, vstart);
189 mt9v011_write(sd, R03_MT9V011_HEIGHT, core->height);
190 mt9v011_write(sd, R06_MT9V011_VBLANK, 508 - core->height);
191};
192
174static int mt9v011_reset(struct v4l2_subdev *sd, u32 val) 193static int mt9v011_reset(struct v4l2_subdev *sd, u32 val)
175{ 194{
176 u16 version;
177 int i; 195 int i;
178 196
179 version = mt9v011_read(sd, R00_MT9V011_CHIP_VERSION);
180
181 if (version != MT9V011_VERSION) {
182 v4l2_info(sd, "*** unknown micron chip detected (0x%04x.\n",
183 version);
184 return -EINVAL;
185
186 }
187
188 for (i = 0; i < ARRAY_SIZE(mt9v011_init_default); i++) 197 for (i = 0; i < ARRAY_SIZE(mt9v011_init_default); i++)
189 mt9v011_write(sd, mt9v011_init_default[i].reg, 198 mt9v011_write(sd, mt9v011_init_default[i].reg,
190 mt9v011_init_default[i].value); 199 mt9v011_init_default[i].value);
191 200
192 set_balance(sd); 201 set_balance(sd);
202 set_res(sd);
193 203
194 return 0; 204 return 0;
195}; 205};
@@ -250,6 +260,50 @@ static int mt9v011_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
250 return 0; 260 return 0;
251} 261}
252 262
263static int mt9v011_enum_fmt(struct v4l2_subdev *sd, struct v4l2_fmtdesc *fmt)
264{
265 if (fmt->index > 0)
266 return -EINVAL;
267
268 fmt->flags = 0;
269 strcpy(fmt->description, "8 bpp Bayer GRGR..BGBG");
270 fmt->pixelformat = V4L2_PIX_FMT_SGRBG8;
271
272 return 0;
273}
274
275static int mt9v011_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
276{
277 struct v4l2_pix_format *pix = &fmt->fmt.pix;
278
279 if (pix->pixelformat != V4L2_PIX_FMT_SGRBG8)
280 return -EINVAL;
281
282 v4l_bound_align_image(&pix->width, 48, 639, 1,
283 &pix->height, 32, 480, 1, 0);
284
285 return 0;
286}
287
288static int mt9v011_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
289{
290 struct v4l2_pix_format *pix = &fmt->fmt.pix;
291 struct mt9v011 *core = to_mt9v011(sd);
292 int rc;
293
294 rc = mt9v011_try_fmt(sd, fmt);
295 if (rc < 0)
296 return -EINVAL;
297
298 core->width = pix->width;
299 core->height = pix->height;
300
301 set_res(sd);
302
303 return 0;
304}
305
306
253#ifdef CONFIG_VIDEO_ADV_DEBUG 307#ifdef CONFIG_VIDEO_ADV_DEBUG
254static int mt9v011_g_register(struct v4l2_subdev *sd, 308static int mt9v011_g_register(struct v4l2_subdev *sd,
255 struct v4l2_dbg_register *reg) 309 struct v4l2_dbg_register *reg)
@@ -303,8 +357,15 @@ static const struct v4l2_subdev_core_ops mt9v011_core_ops = {
303#endif 357#endif
304}; 358};
305 359
360static const struct v4l2_subdev_video_ops mt9v011_video_ops = {
361 .enum_fmt = mt9v011_enum_fmt,
362 .try_fmt = mt9v011_try_fmt,
363 .s_fmt = mt9v011_s_fmt,
364};
365
306static const struct v4l2_subdev_ops mt9v011_ops = { 366static const struct v4l2_subdev_ops mt9v011_ops = {
307 .core = &mt9v011_core_ops, 367 .core = &mt9v011_core_ops,
368 .video = &mt9v011_video_ops,
308}; 369};
309 370
310 371
@@ -315,6 +376,7 @@ static const struct v4l2_subdev_ops mt9v011_ops = {
315static int mt9v011_probe(struct i2c_client *c, 376static int mt9v011_probe(struct i2c_client *c,
316 const struct i2c_device_id *id) 377 const struct i2c_device_id *id)
317{ 378{
379 u16 version;
318 struct mt9v011 *core; 380 struct mt9v011 *core;
319 struct v4l2_subdev *sd; 381 struct v4l2_subdev *sd;
320 382
@@ -327,10 +389,22 @@ static int mt9v011_probe(struct i2c_client *c,
327 if (!core) 389 if (!core)
328 return -ENOMEM; 390 return -ENOMEM;
329 391
330 core->global_gain = 0x0024;
331
332 sd = &core->sd; 392 sd = &core->sd;
333 v4l2_i2c_subdev_init(sd, c, &mt9v011_ops); 393 v4l2_i2c_subdev_init(sd, c, &mt9v011_ops);
394
395 /* Check if the sensor is really a MT9V011 */
396 version = mt9v011_read(sd, R00_MT9V011_CHIP_VERSION);
397 if (version != MT9V011_VERSION) {
398 v4l2_info(sd, "*** unknown micron chip detected (0x%04x.\n",
399 version);
400 kfree(core);
401 return -EINVAL;
402 }
403
404 core->global_gain = 0x0024;
405 core->width = 640;
406 core->height = 480;
407
334 v4l_info(c, "chip found @ 0x%02x (%s)\n", 408 v4l_info(c, "chip found @ 0x%02x (%s)\n",
335 c->addr << 1, c->adapter->name); 409 c->addr << 1, c->adapter->name);
336 410