2 * Driver for the ov7660 sensor
4 * Copyright (C) 2009 Erik Andrén
5 * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
6 * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
8 * Portions of code to USB interface and ALi driver software,
9 * Copyright (c) 2006 Willem Duinker
10 * v4l2 interface modeled after the V4L2 driver
11 * for SN9C10x PC Camera Controllers
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License as
15 * published by the Free Software Foundation, version 2.
19 #include "m5602_ov7660.h"
21 static int ov7660_get_gain(struct gspca_dev
*gspca_dev
, __s32
*val
);
22 static int ov7660_set_gain(struct gspca_dev
*gspca_dev
, __s32 val
);
23 static int ov7660_get_auto_white_balance(struct gspca_dev
*gspca_dev
,
25 static int ov7660_set_auto_white_balance(struct gspca_dev
*gspca_dev
,
27 static int ov7660_get_auto_gain(struct gspca_dev
*gspca_dev
, __s32
*val
);
28 static int ov7660_set_auto_gain(struct gspca_dev
*gspca_dev
, __s32 val
);
29 static int ov7660_get_auto_exposure(struct gspca_dev
*gspca_dev
, __s32
*val
);
30 static int ov7660_set_auto_exposure(struct gspca_dev
*gspca_dev
, __s32 val
);
31 static int ov7660_get_hflip(struct gspca_dev
*gspca_dev
, __s32
*val
);
32 static int ov7660_set_hflip(struct gspca_dev
*gspca_dev
, __s32 val
);
33 static int ov7660_get_vflip(struct gspca_dev
*gspca_dev
, __s32
*val
);
34 static int ov7660_set_vflip(struct gspca_dev
*gspca_dev
, __s32 val
);
36 const static struct ctrl ov7660_ctrls
[] = {
41 .type
= V4L2_CTRL_TYPE_INTEGER
,
46 .default_value
= OV7660_DEFAULT_GAIN
,
47 .flags
= V4L2_CTRL_FLAG_SLIDER
49 .set
= ov7660_set_gain
,
50 .get
= ov7660_get_gain
52 #define BLUE_BALANCE_IDX 2
53 #define RED_BALANCE_IDX 3
54 #define AUTO_WHITE_BALANCE_IDX 4
57 .id
= V4L2_CID_AUTO_WHITE_BALANCE
,
58 .type
= V4L2_CTRL_TYPE_BOOLEAN
,
59 .name
= "auto white balance",
65 .set
= ov7660_set_auto_white_balance
,
66 .get
= ov7660_get_auto_white_balance
68 #define AUTO_GAIN_CTRL_IDX 5
71 .id
= V4L2_CID_AUTOGAIN
,
72 .type
= V4L2_CTRL_TYPE_BOOLEAN
,
73 .name
= "auto gain control",
79 .set
= ov7660_set_auto_gain
,
80 .get
= ov7660_get_auto_gain
82 #define AUTO_EXPOSURE_IDX 6
85 .id
= V4L2_CID_EXPOSURE_AUTO
,
86 .type
= V4L2_CTRL_TYPE_BOOLEAN
,
87 .name
= "auto exposure",
93 .set
= ov7660_set_auto_exposure
,
94 .get
= ov7660_get_auto_exposure
100 .type
= V4L2_CTRL_TYPE_BOOLEAN
,
101 .name
= "horizontal flip",
107 .set
= ov7660_set_hflip
,
108 .get
= ov7660_get_hflip
113 .id
= V4L2_CID_VFLIP
,
114 .type
= V4L2_CTRL_TYPE_BOOLEAN
,
115 .name
= "vertical flip",
121 .set
= ov7660_set_vflip
,
122 .get
= ov7660_get_vflip
127 static struct v4l2_pix_format ov7660_modes
[] = {
136 .colorspace
= V4L2_COLORSPACE_SRGB
,
141 static void ov7660_dump_registers(struct sd
*sd
);
143 int ov7660_probe(struct sd
*sd
)
146 u8 prod_id
= 0, ver_id
= 0;
148 s32
*sensor_settings
;
151 if (force_sensor
== OV7660_SENSOR
) {
152 info("Forcing an %s sensor", ov7660
.name
);
155 /* If we want to force another sensor,
156 don't try to probe this one */
161 for (i
= 0; i
< ARRAY_SIZE(preinit_ov7660
) && !err
; i
++) {
164 if (preinit_ov7660
[i
][0] == BRIDGE
) {
165 err
= m5602_write_bridge(sd
,
166 preinit_ov7660
[i
][1],
167 preinit_ov7660
[i
][2]);
169 data
[0] = preinit_ov7660
[i
][2];
170 err
= m5602_write_sensor(sd
,
171 preinit_ov7660
[i
][1], data
, 1);
177 if (m5602_read_sensor(sd
, OV7660_PID
, &prod_id
, 1))
180 if (m5602_read_sensor(sd
, OV7660_VER
, &ver_id
, 1))
183 info("Sensor reported 0x%x%x", prod_id
, ver_id
);
185 if ((prod_id
== 0x76) && (ver_id
== 0x60)) {
186 info("Detected a ov7660 sensor");
192 sensor_settings
= kmalloc(
193 ARRAY_SIZE(ov7660_ctrls
) * sizeof(s32
), GFP_KERNEL
);
194 if (!sensor_settings
)
197 sd
->gspca_dev
.cam
.cam_mode
= ov7660_modes
;
198 sd
->gspca_dev
.cam
.nmodes
= ARRAY_SIZE(ov7660_modes
);
199 sd
->desc
->ctrls
= ov7660_ctrls
;
200 sd
->desc
->nctrls
= ARRAY_SIZE(ov7660_ctrls
);
202 for (i
= 0; i
< ARRAY_SIZE(ov7660_ctrls
); i
++)
203 sensor_settings
[i
] = ov7660_ctrls
[i
].qctrl
.default_value
;
204 sd
->sensor_priv
= sensor_settings
;
209 int ov7660_init(struct sd
*sd
)
212 s32
*sensor_settings
= sd
->sensor_priv
;
214 /* Init the sensor */
215 for (i
= 0; i
< ARRAY_SIZE(init_ov7660
); i
++) {
218 if (init_ov7660
[i
][0] == BRIDGE
) {
219 err
= m5602_write_bridge(sd
,
223 data
[0] = init_ov7660
[i
][2];
224 err
= m5602_write_sensor(sd
,
225 init_ov7660
[i
][1], data
, 1);
230 ov7660_dump_registers(sd
);
232 err
= ov7660_set_gain(&sd
->gspca_dev
, sensor_settings
[GAIN_IDX
]);
236 err
= ov7660_set_auto_white_balance(&sd
->gspca_dev
,
237 sensor_settings
[AUTO_WHITE_BALANCE_IDX
]);
241 err
= ov7660_set_auto_gain(&sd
->gspca_dev
,
242 sensor_settings
[AUTO_GAIN_CTRL_IDX
]);
246 err
= ov7660_set_auto_exposure(&sd
->gspca_dev
,
247 sensor_settings
[AUTO_EXPOSURE_IDX
]);
250 err
= ov7660_set_hflip(&sd
->gspca_dev
,
251 sensor_settings
[HFLIP_IDX
]);
255 err
= ov7660_set_vflip(&sd
->gspca_dev
,
256 sensor_settings
[VFLIP_IDX
]);
261 int ov7660_start(struct sd
*sd
)
266 int ov7660_stop(struct sd
*sd
)
271 void ov7660_disconnect(struct sd
*sd
)
276 kfree(sd
->sensor_priv
);
279 static int ov7660_get_gain(struct gspca_dev
*gspca_dev
, __s32
*val
)
281 struct sd
*sd
= (struct sd
*) gspca_dev
;
282 s32
*sensor_settings
= sd
->sensor_priv
;
284 *val
= sensor_settings
[GAIN_IDX
];
285 PDEBUG(D_V4L2
, "Read gain %d", *val
);
289 static int ov7660_set_gain(struct gspca_dev
*gspca_dev
, __s32 val
)
293 struct sd
*sd
= (struct sd
*) gspca_dev
;
294 s32
*sensor_settings
= sd
->sensor_priv
;
296 PDEBUG(D_V4L2
, "Setting gain to %d", val
);
298 sensor_settings
[GAIN_IDX
] = val
;
300 err
= m5602_write_sensor(sd
, OV7660_GAIN
, &i2c_data
, 1);
305 static int ov7660_get_auto_white_balance(struct gspca_dev
*gspca_dev
,
308 struct sd
*sd
= (struct sd
*) gspca_dev
;
309 s32
*sensor_settings
= sd
->sensor_priv
;
311 *val
= sensor_settings
[AUTO_WHITE_BALANCE_IDX
];
315 static int ov7660_set_auto_white_balance(struct gspca_dev
*gspca_dev
,
320 struct sd
*sd
= (struct sd
*) gspca_dev
;
321 s32
*sensor_settings
= sd
->sensor_priv
;
323 PDEBUG(D_V4L2
, "Set auto white balance to %d", val
);
325 sensor_settings
[AUTO_WHITE_BALANCE_IDX
] = val
;
326 err
= m5602_read_sensor(sd
, OV7660_COM8
, &i2c_data
, 1);
330 i2c_data
= ((i2c_data
& 0xfd) | ((val
& 0x01) << 1));
331 err
= m5602_write_sensor(sd
, OV7660_COM8
, &i2c_data
, 1);
336 static int ov7660_get_auto_gain(struct gspca_dev
*gspca_dev
, __s32
*val
)
338 struct sd
*sd
= (struct sd
*) gspca_dev
;
339 s32
*sensor_settings
= sd
->sensor_priv
;
341 *val
= sensor_settings
[AUTO_GAIN_CTRL_IDX
];
342 PDEBUG(D_V4L2
, "Read auto gain control %d", *val
);
346 static int ov7660_set_auto_gain(struct gspca_dev
*gspca_dev
, __s32 val
)
350 struct sd
*sd
= (struct sd
*) gspca_dev
;
351 s32
*sensor_settings
= sd
->sensor_priv
;
353 PDEBUG(D_V4L2
, "Set auto gain control to %d", val
);
355 sensor_settings
[AUTO_GAIN_CTRL_IDX
] = val
;
356 err
= m5602_read_sensor(sd
, OV7660_COM8
, &i2c_data
, 1);
360 i2c_data
= ((i2c_data
& 0xfb) | ((val
& 0x01) << 2));
362 return m5602_write_sensor(sd
, OV7660_COM8
, &i2c_data
, 1);
365 static int ov7660_get_auto_exposure(struct gspca_dev
*gspca_dev
, __s32
*val
)
367 struct sd
*sd
= (struct sd
*) gspca_dev
;
368 s32
*sensor_settings
= sd
->sensor_priv
;
370 *val
= sensor_settings
[AUTO_EXPOSURE_IDX
];
371 PDEBUG(D_V4L2
, "Read auto exposure control %d", *val
);
375 static int ov7660_set_auto_exposure(struct gspca_dev
*gspca_dev
,
380 struct sd
*sd
= (struct sd
*) gspca_dev
;
381 s32
*sensor_settings
= sd
->sensor_priv
;
383 PDEBUG(D_V4L2
, "Set auto exposure control to %d", val
);
385 sensor_settings
[AUTO_EXPOSURE_IDX
] = val
;
386 err
= m5602_read_sensor(sd
, OV7660_COM8
, &i2c_data
, 1);
390 i2c_data
= ((i2c_data
& 0xfe) | ((val
& 0x01) << 0));
392 return m5602_write_sensor(sd
, OV7660_COM8
, &i2c_data
, 1);
395 static int ov7660_get_hflip(struct gspca_dev
*gspca_dev
, __s32
*val
)
397 struct sd
*sd
= (struct sd
*) gspca_dev
;
398 s32
*sensor_settings
= sd
->sensor_priv
;
400 *val
= sensor_settings
[HFLIP_IDX
];
401 PDEBUG(D_V4L2
, "Read horizontal flip %d", *val
);
405 static int ov7660_set_hflip(struct gspca_dev
*gspca_dev
, __s32 val
)
409 struct sd
*sd
= (struct sd
*) gspca_dev
;
410 s32
*sensor_settings
= sd
->sensor_priv
;
412 PDEBUG(D_V4L2
, "Set horizontal flip to %d", val
);
414 sensor_settings
[HFLIP_IDX
] = val
;
416 i2c_data
= ((val
& 0x01) << 5) |
417 (sensor_settings
[VFLIP_IDX
] << 4);
419 err
= m5602_write_sensor(sd
, OV7660_MVFP
, &i2c_data
, 1);
424 static int ov7660_get_vflip(struct gspca_dev
*gspca_dev
, __s32
*val
)
426 struct sd
*sd
= (struct sd
*) gspca_dev
;
427 s32
*sensor_settings
= sd
->sensor_priv
;
429 *val
= sensor_settings
[VFLIP_IDX
];
430 PDEBUG(D_V4L2
, "Read vertical flip %d", *val
);
435 static int ov7660_set_vflip(struct gspca_dev
*gspca_dev
, __s32 val
)
439 struct sd
*sd
= (struct sd
*) gspca_dev
;
440 s32
*sensor_settings
= sd
->sensor_priv
;
442 PDEBUG(D_V4L2
, "Set vertical flip to %d", val
);
443 sensor_settings
[VFLIP_IDX
] = val
;
445 i2c_data
= ((val
& 0x01) << 4) | (sensor_settings
[VFLIP_IDX
] << 5);
446 err
= m5602_write_sensor(sd
, OV7660_MVFP
, &i2c_data
, 1);
450 /* When vflip is toggled we need to readjust the bridge hsync/vsync */
451 if (gspca_dev
->streaming
)
452 err
= ov7660_start(sd
);
457 static void ov7660_dump_registers(struct sd
*sd
)
460 info("Dumping the ov7660 register state");
461 for (address
= 0; address
< 0xa9; address
++) {
463 m5602_read_sensor(sd
, address
, &value
, 1);
464 info("register 0x%x contains 0x%x",
468 info("ov7660 register state dump complete");
470 info("Probing for which registers that are read/write");
471 for (address
= 0; address
< 0xff; address
++) {
472 u8 old_value
, ctrl_value
;
473 u8 test_value
[2] = {0xff, 0xff};
475 m5602_read_sensor(sd
, address
, &old_value
, 1);
476 m5602_write_sensor(sd
, address
, test_value
, 1);
477 m5602_read_sensor(sd
, address
, &ctrl_value
, 1);
479 if (ctrl_value
== test_value
[0])
480 info("register 0x%x is writeable", address
);
482 info("register 0x%x is read only", address
);
484 /* Restore original value */
485 m5602_write_sensor(sd
, address
, &old_value
, 1);