aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/mt9m001.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/mt9m001.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/mt9m001.c')
-rw-r--r--drivers/media/video/mt9m001.c77
1 files changed, 48 insertions, 29 deletions
diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c
index 4ad834326fa8..acb5454b57eb 100644
--- a/drivers/media/video/mt9m001.c
+++ b/drivers/media/video/mt9m001.c
@@ -210,40 +210,64 @@ static int bus_switch_act(struct mt9m001 *mt9m001, int go8bit)
210#endif 210#endif
211} 211}
212 212
213static int mt9m001_set_capture_format(struct soc_camera_device *icd, 213static int bus_switch_possible(struct mt9m001 *mt9m001)
214 __u32 pixfmt, struct v4l2_rect *rect, unsigned int flags) 214{
215#ifdef CONFIG_MT9M001_PCA9536_SWITCH
216 return gpio_is_valid(mt9m001->switch_gpio);
217#else
218 return 0;
219#endif
220}
221
222static int mt9m001_set_bus_param(struct soc_camera_device *icd,
223 unsigned long flags)
215{ 224{
216 struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd); 225 struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
217 unsigned int width_flag = flags & (IS_DATAWIDTH_10 | IS_DATAWIDTH_9 | 226 unsigned int width_flag = flags & SOCAM_DATAWIDTH_MASK;
218 IS_DATAWIDTH_8);
219 int ret; 227 int ret;
220 const u16 hblank = 9, vblank = 25;
221 228
222 /* MT9M001 has all capture_format parameters fixed */ 229 /* Flags validity verified in test_bus_param */
223 if (!(flags & IS_MASTER) ||
224 !(flags & IS_PCLK_SAMPLE_RISING) ||
225 !(flags & IS_HSYNC_ACTIVE_HIGH) ||
226 !(flags & IS_VSYNC_ACTIVE_HIGH))
227 return -EINVAL;
228
229 /* Only one width bit may be set */
230 if (!is_power_of_2(width_flag))
231 return -EINVAL;
232 230
233 if ((mt9m001->datawidth != 10 && (width_flag == IS_DATAWIDTH_10)) || 231 if ((mt9m001->datawidth != 10 && (width_flag == SOCAM_DATAWIDTH_10)) ||
234 (mt9m001->datawidth != 9 && (width_flag == IS_DATAWIDTH_9)) || 232 (mt9m001->datawidth != 9 && (width_flag == SOCAM_DATAWIDTH_9)) ||
235 (mt9m001->datawidth != 8 && (width_flag == IS_DATAWIDTH_8))) { 233 (mt9m001->datawidth != 8 && (width_flag == SOCAM_DATAWIDTH_8))) {
236 /* Well, we actually only can do 10 or 8 bits... */ 234 /* Well, we actually only can do 10 or 8 bits... */
237 if (width_flag == IS_DATAWIDTH_9) 235 if (width_flag == SOCAM_DATAWIDTH_9)
238 return -EINVAL; 236 return -EINVAL;
239 ret = bus_switch_act(mt9m001, 237 ret = bus_switch_act(mt9m001,
240 width_flag == IS_DATAWIDTH_8); 238 width_flag == SOCAM_DATAWIDTH_8);
241 if (ret < 0) 239 if (ret < 0)
242 return ret; 240 return ret;
243 241
244 mt9m001->datawidth = width_flag == IS_DATAWIDTH_8 ? 8 : 10; 242 mt9m001->datawidth = width_flag == SOCAM_DATAWIDTH_8 ? 8 : 10;
245 } 243 }
246 244
245 return 0;
246}
247
248static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd)
249{
250 struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
251 unsigned int width_flag = SOCAM_DATAWIDTH_10;
252
253 if (bus_switch_possible(mt9m001))
254 width_flag |= SOCAM_DATAWIDTH_8;
255
256 /* MT9M001 has all capture_format parameters fixed */
257 return SOCAM_PCLK_SAMPLE_RISING |
258 SOCAM_HSYNC_ACTIVE_HIGH |
259 SOCAM_VSYNC_ACTIVE_HIGH |
260 SOCAM_MASTER |
261 width_flag;
262}
263
264static int mt9m001_set_fmt_cap(struct soc_camera_device *icd,
265 __u32 pixfmt, struct v4l2_rect *rect)
266{
267 struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
268 int ret;
269 const u16 hblank = 9, vblank = 25;
270
247 /* Blanking and start values - default... */ 271 /* Blanking and start values - default... */
248 ret = reg_write(icd, MT9M001_HORIZONTAL_BLANKING, hblank); 272 ret = reg_write(icd, MT9M001_HORIZONTAL_BLANKING, hblank);
249 if (ret >= 0) 273 if (ret >= 0)
@@ -348,12 +372,6 @@ static int mt9m001_set_register(struct soc_camera_device *icd,
348} 372}
349#endif 373#endif
350 374
351static unsigned int mt9m001_get_datawidth(struct soc_camera_device *icd)
352{
353 struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
354 return mt9m001->datawidth;
355}
356
357const struct v4l2_queryctrl mt9m001_controls[] = { 375const struct v4l2_queryctrl mt9m001_controls[] = {
358 { 376 {
359 .id = V4L2_CID_VFLIP, 377 .id = V4L2_CID_VFLIP,
@@ -401,11 +419,12 @@ static struct soc_camera_ops mt9m001_ops = {
401 .release = mt9m001_release, 419 .release = mt9m001_release,
402 .start_capture = mt9m001_start_capture, 420 .start_capture = mt9m001_start_capture,
403 .stop_capture = mt9m001_stop_capture, 421 .stop_capture = mt9m001_stop_capture,
404 .set_capture_format = mt9m001_set_capture_format, 422 .set_fmt_cap = mt9m001_set_fmt_cap,
405 .try_fmt_cap = mt9m001_try_fmt_cap, 423 .try_fmt_cap = mt9m001_try_fmt_cap,
424 .set_bus_param = mt9m001_set_bus_param,
425 .query_bus_param = mt9m001_query_bus_param,
406 .formats = NULL, /* Filled in later depending on the */ 426 .formats = NULL, /* Filled in later depending on the */
407 .num_formats = 0, /* camera type and data widths */ 427 .num_formats = 0, /* camera type and data widths */
408 .get_datawidth = mt9m001_get_datawidth,
409 .controls = mt9m001_controls, 428 .controls = mt9m001_controls,
410 .num_controls = ARRAY_SIZE(mt9m001_controls), 429 .num_controls = ARRAY_SIZE(mt9m001_controls),
411 .get_control = mt9m001_get_control, 430 .get_control = mt9m001_get_control,