Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/media/video/gspca/m5602/m5602_ov7660.c
17956 views
1
/*
2
* Driver for the ov7660 sensor
3
*
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 <[email protected]>
7
*
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
12
*
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.
16
*
17
*/
18
19
#include "m5602_ov7660.h"
20
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,
24
__s32 *val);
25
static int ov7660_set_auto_white_balance(struct gspca_dev *gspca_dev,
26
__s32 val);
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);
35
36
static const struct ctrl ov7660_ctrls[] = {
37
#define GAIN_IDX 1
38
{
39
{
40
.id = V4L2_CID_GAIN,
41
.type = V4L2_CTRL_TYPE_INTEGER,
42
.name = "gain",
43
.minimum = 0x00,
44
.maximum = 0xff,
45
.step = 0x1,
46
.default_value = OV7660_DEFAULT_GAIN,
47
.flags = V4L2_CTRL_FLAG_SLIDER
48
},
49
.set = ov7660_set_gain,
50
.get = ov7660_get_gain
51
},
52
#define BLUE_BALANCE_IDX 2
53
#define RED_BALANCE_IDX 3
54
#define AUTO_WHITE_BALANCE_IDX 4
55
{
56
{
57
.id = V4L2_CID_AUTO_WHITE_BALANCE,
58
.type = V4L2_CTRL_TYPE_BOOLEAN,
59
.name = "auto white balance",
60
.minimum = 0,
61
.maximum = 1,
62
.step = 1,
63
.default_value = 1
64
},
65
.set = ov7660_set_auto_white_balance,
66
.get = ov7660_get_auto_white_balance
67
},
68
#define AUTO_GAIN_CTRL_IDX 5
69
{
70
{
71
.id = V4L2_CID_AUTOGAIN,
72
.type = V4L2_CTRL_TYPE_BOOLEAN,
73
.name = "auto gain control",
74
.minimum = 0,
75
.maximum = 1,
76
.step = 1,
77
.default_value = 1
78
},
79
.set = ov7660_set_auto_gain,
80
.get = ov7660_get_auto_gain
81
},
82
#define AUTO_EXPOSURE_IDX 6
83
{
84
{
85
.id = V4L2_CID_EXPOSURE_AUTO,
86
.type = V4L2_CTRL_TYPE_BOOLEAN,
87
.name = "auto exposure",
88
.minimum = 0,
89
.maximum = 1,
90
.step = 1,
91
.default_value = 1
92
},
93
.set = ov7660_set_auto_exposure,
94
.get = ov7660_get_auto_exposure
95
},
96
#define HFLIP_IDX 7
97
{
98
{
99
.id = V4L2_CID_HFLIP,
100
.type = V4L2_CTRL_TYPE_BOOLEAN,
101
.name = "horizontal flip",
102
.minimum = 0,
103
.maximum = 1,
104
.step = 1,
105
.default_value = 0
106
},
107
.set = ov7660_set_hflip,
108
.get = ov7660_get_hflip
109
},
110
#define VFLIP_IDX 8
111
{
112
{
113
.id = V4L2_CID_VFLIP,
114
.type = V4L2_CTRL_TYPE_BOOLEAN,
115
.name = "vertical flip",
116
.minimum = 0,
117
.maximum = 1,
118
.step = 1,
119
.default_value = 0
120
},
121
.set = ov7660_set_vflip,
122
.get = ov7660_get_vflip
123
},
124
125
};
126
127
static struct v4l2_pix_format ov7660_modes[] = {
128
{
129
640,
130
480,
131
V4L2_PIX_FMT_SBGGR8,
132
V4L2_FIELD_NONE,
133
.sizeimage =
134
640 * 480,
135
.bytesperline = 640,
136
.colorspace = V4L2_COLORSPACE_SRGB,
137
.priv = 0
138
}
139
};
140
141
static void ov7660_dump_registers(struct sd *sd);
142
143
int ov7660_probe(struct sd *sd)
144
{
145
int err = 0, i;
146
u8 prod_id = 0, ver_id = 0;
147
148
s32 *sensor_settings;
149
150
if (force_sensor) {
151
if (force_sensor == OV7660_SENSOR) {
152
info("Forcing an %s sensor", ov7660.name);
153
goto sensor_found;
154
}
155
/* If we want to force another sensor,
156
don't try to probe this one */
157
return -ENODEV;
158
}
159
160
/* Do the preinit */
161
for (i = 0; i < ARRAY_SIZE(preinit_ov7660) && !err; i++) {
162
u8 data[2];
163
164
if (preinit_ov7660[i][0] == BRIDGE) {
165
err = m5602_write_bridge(sd,
166
preinit_ov7660[i][1],
167
preinit_ov7660[i][2]);
168
} else {
169
data[0] = preinit_ov7660[i][2];
170
err = m5602_write_sensor(sd,
171
preinit_ov7660[i][1], data, 1);
172
}
173
}
174
if (err < 0)
175
return err;
176
177
if (m5602_read_sensor(sd, OV7660_PID, &prod_id, 1))
178
return -ENODEV;
179
180
if (m5602_read_sensor(sd, OV7660_VER, &ver_id, 1))
181
return -ENODEV;
182
183
info("Sensor reported 0x%x%x", prod_id, ver_id);
184
185
if ((prod_id == 0x76) && (ver_id == 0x60)) {
186
info("Detected a ov7660 sensor");
187
goto sensor_found;
188
}
189
return -ENODEV;
190
191
sensor_found:
192
sensor_settings = kmalloc(
193
ARRAY_SIZE(ov7660_ctrls) * sizeof(s32), GFP_KERNEL);
194
if (!sensor_settings)
195
return -ENOMEM;
196
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);
201
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;
205
206
return 0;
207
}
208
209
int ov7660_init(struct sd *sd)
210
{
211
int i, err = 0;
212
s32 *sensor_settings = sd->sensor_priv;
213
214
/* Init the sensor */
215
for (i = 0; i < ARRAY_SIZE(init_ov7660); i++) {
216
u8 data[2];
217
218
if (init_ov7660[i][0] == BRIDGE) {
219
err = m5602_write_bridge(sd,
220
init_ov7660[i][1],
221
init_ov7660[i][2]);
222
} else {
223
data[0] = init_ov7660[i][2];
224
err = m5602_write_sensor(sd,
225
init_ov7660[i][1], data, 1);
226
}
227
}
228
229
if (dump_sensor)
230
ov7660_dump_registers(sd);
231
232
err = ov7660_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
233
if (err < 0)
234
return err;
235
236
err = ov7660_set_auto_white_balance(&sd->gspca_dev,
237
sensor_settings[AUTO_WHITE_BALANCE_IDX]);
238
if (err < 0)
239
return err;
240
241
err = ov7660_set_auto_gain(&sd->gspca_dev,
242
sensor_settings[AUTO_GAIN_CTRL_IDX]);
243
if (err < 0)
244
return err;
245
246
err = ov7660_set_auto_exposure(&sd->gspca_dev,
247
sensor_settings[AUTO_EXPOSURE_IDX]);
248
if (err < 0)
249
return err;
250
err = ov7660_set_hflip(&sd->gspca_dev,
251
sensor_settings[HFLIP_IDX]);
252
if (err < 0)
253
return err;
254
255
err = ov7660_set_vflip(&sd->gspca_dev,
256
sensor_settings[VFLIP_IDX]);
257
258
return err;
259
}
260
261
int ov7660_start(struct sd *sd)
262
{
263
return 0;
264
}
265
266
int ov7660_stop(struct sd *sd)
267
{
268
return 0;
269
}
270
271
void ov7660_disconnect(struct sd *sd)
272
{
273
ov7660_stop(sd);
274
275
sd->sensor = NULL;
276
kfree(sd->sensor_priv);
277
}
278
279
static int ov7660_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
280
{
281
struct sd *sd = (struct sd *) gspca_dev;
282
s32 *sensor_settings = sd->sensor_priv;
283
284
*val = sensor_settings[GAIN_IDX];
285
PDEBUG(D_V4L2, "Read gain %d", *val);
286
return 0;
287
}
288
289
static int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val)
290
{
291
int err;
292
u8 i2c_data;
293
struct sd *sd = (struct sd *) gspca_dev;
294
s32 *sensor_settings = sd->sensor_priv;
295
296
PDEBUG(D_V4L2, "Setting gain to %d", val);
297
298
sensor_settings[GAIN_IDX] = val;
299
300
err = m5602_write_sensor(sd, OV7660_GAIN, &i2c_data, 1);
301
return err;
302
}
303
304
305
static int ov7660_get_auto_white_balance(struct gspca_dev *gspca_dev,
306
__s32 *val)
307
{
308
struct sd *sd = (struct sd *) gspca_dev;
309
s32 *sensor_settings = sd->sensor_priv;
310
311
*val = sensor_settings[AUTO_WHITE_BALANCE_IDX];
312
return 0;
313
}
314
315
static int ov7660_set_auto_white_balance(struct gspca_dev *gspca_dev,
316
__s32 val)
317
{
318
int err;
319
u8 i2c_data;
320
struct sd *sd = (struct sd *) gspca_dev;
321
s32 *sensor_settings = sd->sensor_priv;
322
323
PDEBUG(D_V4L2, "Set auto white balance to %d", val);
324
325
sensor_settings[AUTO_WHITE_BALANCE_IDX] = val;
326
err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1);
327
if (err < 0)
328
return err;
329
330
i2c_data = ((i2c_data & 0xfd) | ((val & 0x01) << 1));
331
err = m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1);
332
333
return err;
334
}
335
336
static int ov7660_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val)
337
{
338
struct sd *sd = (struct sd *) gspca_dev;
339
s32 *sensor_settings = sd->sensor_priv;
340
341
*val = sensor_settings[AUTO_GAIN_CTRL_IDX];
342
PDEBUG(D_V4L2, "Read auto gain control %d", *val);
343
return 0;
344
}
345
346
static int ov7660_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
347
{
348
int err;
349
u8 i2c_data;
350
struct sd *sd = (struct sd *) gspca_dev;
351
s32 *sensor_settings = sd->sensor_priv;
352
353
PDEBUG(D_V4L2, "Set auto gain control to %d", val);
354
355
sensor_settings[AUTO_GAIN_CTRL_IDX] = val;
356
err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1);
357
if (err < 0)
358
return err;
359
360
i2c_data = ((i2c_data & 0xfb) | ((val & 0x01) << 2));
361
362
return m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1);
363
}
364
365
static int ov7660_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val)
366
{
367
struct sd *sd = (struct sd *) gspca_dev;
368
s32 *sensor_settings = sd->sensor_priv;
369
370
*val = sensor_settings[AUTO_EXPOSURE_IDX];
371
PDEBUG(D_V4L2, "Read auto exposure control %d", *val);
372
return 0;
373
}
374
375
static int ov7660_set_auto_exposure(struct gspca_dev *gspca_dev,
376
__s32 val)
377
{
378
int err;
379
u8 i2c_data;
380
struct sd *sd = (struct sd *) gspca_dev;
381
s32 *sensor_settings = sd->sensor_priv;
382
383
PDEBUG(D_V4L2, "Set auto exposure control to %d", val);
384
385
sensor_settings[AUTO_EXPOSURE_IDX] = val;
386
err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1);
387
if (err < 0)
388
return err;
389
390
i2c_data = ((i2c_data & 0xfe) | ((val & 0x01) << 0));
391
392
return m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1);
393
}
394
395
static int ov7660_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
396
{
397
struct sd *sd = (struct sd *) gspca_dev;
398
s32 *sensor_settings = sd->sensor_priv;
399
400
*val = sensor_settings[HFLIP_IDX];
401
PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
402
return 0;
403
}
404
405
static int ov7660_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
406
{
407
int err;
408
u8 i2c_data;
409
struct sd *sd = (struct sd *) gspca_dev;
410
s32 *sensor_settings = sd->sensor_priv;
411
412
PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
413
414
sensor_settings[HFLIP_IDX] = val;
415
416
i2c_data = ((val & 0x01) << 5) |
417
(sensor_settings[VFLIP_IDX] << 4);
418
419
err = m5602_write_sensor(sd, OV7660_MVFP, &i2c_data, 1);
420
421
return err;
422
}
423
424
static int ov7660_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
425
{
426
struct sd *sd = (struct sd *) gspca_dev;
427
s32 *sensor_settings = sd->sensor_priv;
428
429
*val = sensor_settings[VFLIP_IDX];
430
PDEBUG(D_V4L2, "Read vertical flip %d", *val);
431
432
return 0;
433
}
434
435
static int ov7660_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
436
{
437
int err;
438
u8 i2c_data;
439
struct sd *sd = (struct sd *) gspca_dev;
440
s32 *sensor_settings = sd->sensor_priv;
441
442
PDEBUG(D_V4L2, "Set vertical flip to %d", val);
443
sensor_settings[VFLIP_IDX] = val;
444
445
i2c_data = ((val & 0x01) << 4) | (sensor_settings[VFLIP_IDX] << 5);
446
err = m5602_write_sensor(sd, OV7660_MVFP, &i2c_data, 1);
447
if (err < 0)
448
return err;
449
450
/* When vflip is toggled we need to readjust the bridge hsync/vsync */
451
if (gspca_dev->streaming)
452
err = ov7660_start(sd);
453
454
return err;
455
}
456
457
static void ov7660_dump_registers(struct sd *sd)
458
{
459
int address;
460
info("Dumping the ov7660 register state");
461
for (address = 0; address < 0xa9; address++) {
462
u8 value;
463
m5602_read_sensor(sd, address, &value, 1);
464
info("register 0x%x contains 0x%x",
465
address, value);
466
}
467
468
info("ov7660 register state dump complete");
469
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};
474
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);
478
479
if (ctrl_value == test_value[0])
480
info("register 0x%x is writeable", address);
481
else
482
info("register 0x%x is read only", address);
483
484
/* Restore original value */
485
m5602_write_sensor(sd, address, &old_value, 1);
486
}
487
}
488
489