aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/mt9v022.c
diff options
context:
space:
mode:
authorGuennadi Liakhovetski <g.liakhovetski@pengutronix.de>2008-03-07 19:57:18 -0500
committerMauro Carvalho Chehab <mchehab@infradead.org>2008-04-24 13:07:49 -0400
commitad5f2e859d76dccb7eb1aa942171b1a32211efc2 (patch)
tree1716d5c82322d55886de36dddd9535b90dd57630 /drivers/media/video/mt9v022.c
parent1c659689fe9959c017bfaaa8301243f7d99f1a46 (diff)
V4L/DVB (7336): soc-camera: streamline hardware parameter negotiation
Improve hardware parameter negotiation between the camera host driver and camera drivers. Parameters like horizontal and vertical synchronisation, pixel clock polarity shall be set depending on capabilities of the parties. Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@pengutronix.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/video/mt9v022.c')
-rw-r--r--drivers/media/video/mt9v022.c129
1 files changed, 78 insertions, 51 deletions
diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c
index d677344d233d..a2f161dcc72d 100644
--- a/drivers/media/video/mt9v022.c
+++ b/drivers/media/video/mt9v022.c
@@ -241,19 +241,89 @@ static int bus_switch_act(struct mt9v022 *mt9v022, int go8bit)
241#endif 241#endif
242} 242}
243 243
244static int mt9v022_set_capture_format(struct soc_camera_device *icd, 244static int bus_switch_possible(struct mt9v022 *mt9v022)
245 __u32 pixfmt, struct v4l2_rect *rect, unsigned int flags) 245{
246#ifdef CONFIG_MT9V022_PCA9536_SWITCH
247 return gpio_is_valid(mt9v022->switch_gpio);
248#else
249 return 0;
250#endif
251}
252
253static int mt9v022_set_bus_param(struct soc_camera_device *icd,
254 unsigned long flags)
246{ 255{
247 struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); 256 struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
248 unsigned int width_flag = flags & (IS_DATAWIDTH_10 | IS_DATAWIDTH_9 | 257 unsigned int width_flag = flags & SOCAM_DATAWIDTH_MASK;
249 IS_DATAWIDTH_8);
250 u16 pixclk = 0;
251 int ret; 258 int ret;
259 u16 pixclk = 0;
252 260
253 /* Only one width bit may be set */ 261 /* Only one width bit may be set */
254 if (!is_power_of_2(width_flag)) 262 if (!is_power_of_2(width_flag))
255 return -EINVAL; 263 return -EINVAL;
256 264
265 if ((mt9v022->datawidth != 10 && (width_flag == SOCAM_DATAWIDTH_10)) ||
266 (mt9v022->datawidth != 9 && (width_flag == SOCAM_DATAWIDTH_9)) ||
267 (mt9v022->datawidth != 8 && (width_flag == SOCAM_DATAWIDTH_8))) {
268 /* Well, we actually only can do 10 or 8 bits... */
269 if (width_flag == SOCAM_DATAWIDTH_9)
270 return -EINVAL;
271
272 ret = bus_switch_act(mt9v022,
273 width_flag == SOCAM_DATAWIDTH_8);
274 if (ret < 0)
275 return ret;
276
277 mt9v022->datawidth = width_flag == SOCAM_DATAWIDTH_8 ? 8 : 10;
278 }
279
280 if (flags & SOCAM_PCLK_SAMPLE_RISING)
281 pixclk |= 0x10;
282
283 if (!(flags & SOCAM_HSYNC_ACTIVE_HIGH))
284 pixclk |= 0x1;
285
286 if (!(flags & SOCAM_VSYNC_ACTIVE_HIGH))
287 pixclk |= 0x2;
288
289 ret = reg_write(icd, MT9V022_PIXCLK_FV_LV, pixclk);
290 if (ret < 0)
291 return ret;
292
293 if (!(flags & SOCAM_MASTER))
294 mt9v022->chip_control &= ~0x8;
295
296 ret = reg_write(icd, MT9V022_CHIP_CONTROL, mt9v022->chip_control);
297 if (ret < 0)
298 return ret;
299
300 dev_dbg(&icd->dev, "Calculated pixclk 0x%x, chip control 0x%x\n",
301 pixclk, mt9v022->chip_control);
302
303 return 0;
304}
305
306static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd)
307{
308 struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
309 unsigned int width_flag = SOCAM_DATAWIDTH_10;
310
311 if (bus_switch_possible(mt9v022))
312 width_flag |= SOCAM_DATAWIDTH_8;
313
314 return SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING |
315 SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW |
316 SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW |
317 SOCAM_MASTER | SOCAM_SLAVE |
318 width_flag;
319}
320
321static int mt9v022_set_fmt_cap(struct soc_camera_device *icd,
322 __u32 pixfmt, struct v4l2_rect *rect)
323{
324 struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
325 int ret;
326
257 /* The caller provides a supported format, as verified per call to 327 /* The caller provides a supported format, as verified per call to
258 * icd->try_fmt_cap(), datawidth is from our supported format list */ 328 * icd->try_fmt_cap(), datawidth is from our supported format list */
259 switch (pixfmt) { 329 switch (pixfmt) {
@@ -308,44 +378,6 @@ static int mt9v022_set_capture_format(struct soc_camera_device *icd,
308 378
309 dev_dbg(&icd->dev, "Frame %ux%u pixel\n", rect->width, rect->height); 379 dev_dbg(&icd->dev, "Frame %ux%u pixel\n", rect->width, rect->height);
310 380
311 if ((mt9v022->datawidth != 10 && (width_flag == IS_DATAWIDTH_10)) ||
312 (mt9v022->datawidth != 9 && (width_flag == IS_DATAWIDTH_9)) ||
313 (mt9v022->datawidth != 8 && (width_flag == IS_DATAWIDTH_8))) {
314 /* Well, we actually only can do 10 or 8 bits... */
315 if (width_flag == IS_DATAWIDTH_9)
316 return -EINVAL;
317
318 ret = bus_switch_act(mt9v022,
319 width_flag == IS_DATAWIDTH_8);
320 if (ret < 0)
321 return ret;
322
323 mt9v022->datawidth = width_flag == IS_DATAWIDTH_8 ? 8 : 10;
324 }
325
326 if (flags & IS_PCLK_SAMPLE_RISING)
327 pixclk |= 0x10;
328
329 if (!(flags & IS_HSYNC_ACTIVE_HIGH))
330 pixclk |= 0x1;
331
332 if (!(flags & IS_VSYNC_ACTIVE_HIGH))
333 pixclk |= 0x2;
334
335 ret = reg_write(icd, MT9V022_PIXCLK_FV_LV, pixclk);
336 if (ret < 0)
337 return ret;
338
339 if (!(flags & IS_MASTER))
340 mt9v022->chip_control &= ~0x8;
341
342 ret = reg_write(icd, MT9V022_CHIP_CONTROL, mt9v022->chip_control);
343 if (ret < 0)
344 return ret;
345
346 dev_dbg(&icd->dev, "Calculated pixclk 0x%x, chip control 0x%x\n",
347 pixclk, mt9v022->chip_control);
348
349 return 0; 381 return 0;
350} 382}
351 383
@@ -420,12 +452,6 @@ static int mt9v022_set_register(struct soc_camera_device *icd,
420} 452}
421#endif 453#endif
422 454
423static unsigned int mt9v022_get_datawidth(struct soc_camera_device *icd)
424{
425 struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
426 return mt9v022->datawidth;
427}
428
429const struct v4l2_queryctrl mt9v022_controls[] = { 455const struct v4l2_queryctrl mt9v022_controls[] = {
430 { 456 {
431 .id = V4L2_CID_VFLIP, 457 .id = V4L2_CID_VFLIP,
@@ -491,11 +517,12 @@ static struct soc_camera_ops mt9v022_ops = {
491 .release = mt9v022_release, 517 .release = mt9v022_release,
492 .start_capture = mt9v022_start_capture, 518 .start_capture = mt9v022_start_capture,
493 .stop_capture = mt9v022_stop_capture, 519 .stop_capture = mt9v022_stop_capture,
494 .set_capture_format = mt9v022_set_capture_format, 520 .set_fmt_cap = mt9v022_set_fmt_cap,
495 .try_fmt_cap = mt9v022_try_fmt_cap, 521 .try_fmt_cap = mt9v022_try_fmt_cap,
522 .set_bus_param = mt9v022_set_bus_param,
523 .query_bus_param = mt9v022_query_bus_param,
496 .formats = NULL, /* Filled in later depending on the */ 524 .formats = NULL, /* Filled in later depending on the */
497 .num_formats = 0, /* sensor type and data widths */ 525 .num_formats = 0, /* sensor type and data widths */
498 .get_datawidth = mt9v022_get_datawidth,
499 .controls = mt9v022_controls, 526 .controls = mt9v022_controls,
500 .num_controls = ARRAY_SIZE(mt9v022_controls), 527 .num_controls = ARRAY_SIZE(mt9v022_controls),
501 .get_control = mt9v022_get_control, 528 .get_control = mt9v022_get_control,