Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/media/video/gspca/m5602/m5602_ov9650.c
17980 views
1
/*
2
* Driver for the ov9650 sensor
3
*
4
* Copyright (C) 2008 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_ov9650.h"
20
21
static int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
22
static int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
23
static int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
24
static int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val);
25
static int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
26
static int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
27
static int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
28
static int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
29
static int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
30
static int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
31
static int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
32
static int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
33
static int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev,
34
__s32 *val);
35
static int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev,
36
__s32 val);
37
static int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val);
38
static int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val);
39
static int ov9650_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val);
40
static int ov9650_set_auto_exposure(struct gspca_dev *gspca_dev, __s32 val);
41
42
/* Vertically and horizontally flips the image if matched, needed for machines
43
where the sensor is mounted upside down */
44
static
45
const
46
struct dmi_system_id ov9650_flip_dmi_table[] = {
47
{
48
.ident = "ASUS A6Ja",
49
.matches = {
50
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
51
DMI_MATCH(DMI_PRODUCT_NAME, "A6J")
52
}
53
},
54
{
55
.ident = "ASUS A6JC",
56
.matches = {
57
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
58
DMI_MATCH(DMI_PRODUCT_NAME, "A6JC")
59
}
60
},
61
{
62
.ident = "ASUS A6K",
63
.matches = {
64
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
65
DMI_MATCH(DMI_PRODUCT_NAME, "A6K")
66
}
67
},
68
{
69
.ident = "ASUS A6Kt",
70
.matches = {
71
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
72
DMI_MATCH(DMI_PRODUCT_NAME, "A6Kt")
73
}
74
},
75
{
76
.ident = "ASUS A6VA",
77
.matches = {
78
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
79
DMI_MATCH(DMI_PRODUCT_NAME, "A6VA")
80
}
81
},
82
{
83
84
.ident = "ASUS A6VC",
85
.matches = {
86
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
87
DMI_MATCH(DMI_PRODUCT_NAME, "A6VC")
88
}
89
},
90
{
91
.ident = "ASUS A6VM",
92
.matches = {
93
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
94
DMI_MATCH(DMI_PRODUCT_NAME, "A6VM")
95
}
96
},
97
{
98
.ident = "ASUS A7V",
99
.matches = {
100
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
101
DMI_MATCH(DMI_PRODUCT_NAME, "A7V")
102
}
103
},
104
{
105
.ident = "Alienware Aurora m9700",
106
.matches = {
107
DMI_MATCH(DMI_SYS_VENDOR, "alienware"),
108
DMI_MATCH(DMI_PRODUCT_NAME, "Aurora m9700")
109
}
110
},
111
{}
112
};
113
114
static const struct ctrl ov9650_ctrls[] = {
115
#define EXPOSURE_IDX 0
116
{
117
{
118
.id = V4L2_CID_EXPOSURE,
119
.type = V4L2_CTRL_TYPE_INTEGER,
120
.name = "exposure",
121
.minimum = 0x00,
122
.maximum = 0x1ff,
123
.step = 0x4,
124
.default_value = EXPOSURE_DEFAULT,
125
.flags = V4L2_CTRL_FLAG_SLIDER
126
},
127
.set = ov9650_set_exposure,
128
.get = ov9650_get_exposure
129
},
130
#define GAIN_IDX 1
131
{
132
{
133
.id = V4L2_CID_GAIN,
134
.type = V4L2_CTRL_TYPE_INTEGER,
135
.name = "gain",
136
.minimum = 0x00,
137
.maximum = 0x3ff,
138
.step = 0x1,
139
.default_value = GAIN_DEFAULT,
140
.flags = V4L2_CTRL_FLAG_SLIDER
141
},
142
.set = ov9650_set_gain,
143
.get = ov9650_get_gain
144
},
145
#define RED_BALANCE_IDX 2
146
{
147
{
148
.id = V4L2_CID_RED_BALANCE,
149
.type = V4L2_CTRL_TYPE_INTEGER,
150
.name = "red balance",
151
.minimum = 0x00,
152
.maximum = 0xff,
153
.step = 0x1,
154
.default_value = RED_GAIN_DEFAULT,
155
.flags = V4L2_CTRL_FLAG_SLIDER
156
},
157
.set = ov9650_set_red_balance,
158
.get = ov9650_get_red_balance
159
},
160
#define BLUE_BALANCE_IDX 3
161
{
162
{
163
.id = V4L2_CID_BLUE_BALANCE,
164
.type = V4L2_CTRL_TYPE_INTEGER,
165
.name = "blue balance",
166
.minimum = 0x00,
167
.maximum = 0xff,
168
.step = 0x1,
169
.default_value = BLUE_GAIN_DEFAULT,
170
.flags = V4L2_CTRL_FLAG_SLIDER
171
},
172
.set = ov9650_set_blue_balance,
173
.get = ov9650_get_blue_balance
174
},
175
#define HFLIP_IDX 4
176
{
177
{
178
.id = V4L2_CID_HFLIP,
179
.type = V4L2_CTRL_TYPE_BOOLEAN,
180
.name = "horizontal flip",
181
.minimum = 0,
182
.maximum = 1,
183
.step = 1,
184
.default_value = 0
185
},
186
.set = ov9650_set_hflip,
187
.get = ov9650_get_hflip
188
},
189
#define VFLIP_IDX 5
190
{
191
{
192
.id = V4L2_CID_VFLIP,
193
.type = V4L2_CTRL_TYPE_BOOLEAN,
194
.name = "vertical flip",
195
.minimum = 0,
196
.maximum = 1,
197
.step = 1,
198
.default_value = 0
199
},
200
.set = ov9650_set_vflip,
201
.get = ov9650_get_vflip
202
},
203
#define AUTO_WHITE_BALANCE_IDX 6
204
{
205
{
206
.id = V4L2_CID_AUTO_WHITE_BALANCE,
207
.type = V4L2_CTRL_TYPE_BOOLEAN,
208
.name = "auto white balance",
209
.minimum = 0,
210
.maximum = 1,
211
.step = 1,
212
.default_value = 1
213
},
214
.set = ov9650_set_auto_white_balance,
215
.get = ov9650_get_auto_white_balance
216
},
217
#define AUTO_GAIN_CTRL_IDX 7
218
{
219
{
220
.id = V4L2_CID_AUTOGAIN,
221
.type = V4L2_CTRL_TYPE_BOOLEAN,
222
.name = "auto gain control",
223
.minimum = 0,
224
.maximum = 1,
225
.step = 1,
226
.default_value = 1
227
},
228
.set = ov9650_set_auto_gain,
229
.get = ov9650_get_auto_gain
230
},
231
#define AUTO_EXPOSURE_IDX 8
232
{
233
{
234
.id = V4L2_CID_EXPOSURE_AUTO,
235
.type = V4L2_CTRL_TYPE_BOOLEAN,
236
.name = "auto exposure",
237
.minimum = 0,
238
.maximum = 1,
239
.step = 1,
240
.default_value = 1
241
},
242
.set = ov9650_set_auto_exposure,
243
.get = ov9650_get_auto_exposure
244
}
245
246
};
247
248
static struct v4l2_pix_format ov9650_modes[] = {
249
{
250
176,
251
144,
252
V4L2_PIX_FMT_SBGGR8,
253
V4L2_FIELD_NONE,
254
.sizeimage =
255
176 * 144,
256
.bytesperline = 176,
257
.colorspace = V4L2_COLORSPACE_SRGB,
258
.priv = 9
259
}, {
260
320,
261
240,
262
V4L2_PIX_FMT_SBGGR8,
263
V4L2_FIELD_NONE,
264
.sizeimage =
265
320 * 240,
266
.bytesperline = 320,
267
.colorspace = V4L2_COLORSPACE_SRGB,
268
.priv = 8
269
}, {
270
352,
271
288,
272
V4L2_PIX_FMT_SBGGR8,
273
V4L2_FIELD_NONE,
274
.sizeimage =
275
352 * 288,
276
.bytesperline = 352,
277
.colorspace = V4L2_COLORSPACE_SRGB,
278
.priv = 9
279
}, {
280
640,
281
480,
282
V4L2_PIX_FMT_SBGGR8,
283
V4L2_FIELD_NONE,
284
.sizeimage =
285
640 * 480,
286
.bytesperline = 640,
287
.colorspace = V4L2_COLORSPACE_SRGB,
288
.priv = 9
289
}
290
};
291
292
static void ov9650_dump_registers(struct sd *sd);
293
294
int ov9650_probe(struct sd *sd)
295
{
296
int err = 0;
297
u8 prod_id = 0, ver_id = 0, i;
298
s32 *sensor_settings;
299
300
if (force_sensor) {
301
if (force_sensor == OV9650_SENSOR) {
302
info("Forcing an %s sensor", ov9650.name);
303
goto sensor_found;
304
}
305
/* If we want to force another sensor,
306
don't try to probe this one */
307
return -ENODEV;
308
}
309
310
PDEBUG(D_PROBE, "Probing for an ov9650 sensor");
311
312
/* Run the pre-init before probing the sensor */
313
for (i = 0; i < ARRAY_SIZE(preinit_ov9650) && !err; i++) {
314
u8 data = preinit_ov9650[i][2];
315
if (preinit_ov9650[i][0] == SENSOR)
316
err = m5602_write_sensor(sd,
317
preinit_ov9650[i][1], &data, 1);
318
else
319
err = m5602_write_bridge(sd,
320
preinit_ov9650[i][1], data);
321
}
322
323
if (err < 0)
324
return err;
325
326
if (m5602_read_sensor(sd, OV9650_PID, &prod_id, 1))
327
return -ENODEV;
328
329
if (m5602_read_sensor(sd, OV9650_VER, &ver_id, 1))
330
return -ENODEV;
331
332
if ((prod_id == 0x96) && (ver_id == 0x52)) {
333
info("Detected an ov9650 sensor");
334
goto sensor_found;
335
}
336
return -ENODEV;
337
338
sensor_found:
339
sensor_settings = kmalloc(
340
ARRAY_SIZE(ov9650_ctrls) * sizeof(s32), GFP_KERNEL);
341
if (!sensor_settings)
342
return -ENOMEM;
343
344
sd->gspca_dev.cam.cam_mode = ov9650_modes;
345
sd->gspca_dev.cam.nmodes = ARRAY_SIZE(ov9650_modes);
346
sd->desc->ctrls = ov9650_ctrls;
347
sd->desc->nctrls = ARRAY_SIZE(ov9650_ctrls);
348
349
for (i = 0; i < ARRAY_SIZE(ov9650_ctrls); i++)
350
sensor_settings[i] = ov9650_ctrls[i].qctrl.default_value;
351
sd->sensor_priv = sensor_settings;
352
return 0;
353
}
354
355
int ov9650_init(struct sd *sd)
356
{
357
int i, err = 0;
358
u8 data;
359
s32 *sensor_settings = sd->sensor_priv;
360
361
if (dump_sensor)
362
ov9650_dump_registers(sd);
363
364
for (i = 0; i < ARRAY_SIZE(init_ov9650) && !err; i++) {
365
data = init_ov9650[i][2];
366
if (init_ov9650[i][0] == SENSOR)
367
err = m5602_write_sensor(sd, init_ov9650[i][1],
368
&data, 1);
369
else
370
err = m5602_write_bridge(sd, init_ov9650[i][1], data);
371
}
372
373
err = ov9650_set_exposure(&sd->gspca_dev,
374
sensor_settings[EXPOSURE_IDX]);
375
if (err < 0)
376
return err;
377
378
err = ov9650_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
379
if (err < 0)
380
return err;
381
382
err = ov9650_set_red_balance(&sd->gspca_dev,
383
sensor_settings[RED_BALANCE_IDX]);
384
if (err < 0)
385
return err;
386
387
err = ov9650_set_blue_balance(&sd->gspca_dev,
388
sensor_settings[BLUE_BALANCE_IDX]);
389
if (err < 0)
390
return err;
391
392
err = ov9650_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
393
if (err < 0)
394
return err;
395
396
err = ov9650_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
397
if (err < 0)
398
return err;
399
400
err = ov9650_set_auto_exposure(&sd->gspca_dev,
401
sensor_settings[AUTO_EXPOSURE_IDX]);
402
if (err < 0)
403
return err;
404
405
err = ov9650_set_auto_white_balance(&sd->gspca_dev,
406
sensor_settings[AUTO_WHITE_BALANCE_IDX]);
407
if (err < 0)
408
return err;
409
410
err = ov9650_set_auto_gain(&sd->gspca_dev,
411
sensor_settings[AUTO_GAIN_CTRL_IDX]);
412
return err;
413
}
414
415
int ov9650_start(struct sd *sd)
416
{
417
u8 data;
418
int i, err = 0;
419
struct cam *cam = &sd->gspca_dev.cam;
420
s32 *sensor_settings = sd->sensor_priv;
421
422
int width = cam->cam_mode[sd->gspca_dev.curr_mode].width;
423
int height = cam->cam_mode[sd->gspca_dev.curr_mode].height;
424
int ver_offs = cam->cam_mode[sd->gspca_dev.curr_mode].priv;
425
int hor_offs = OV9650_LEFT_OFFSET;
426
427
if ((!dmi_check_system(ov9650_flip_dmi_table) &&
428
sensor_settings[VFLIP_IDX]) ||
429
(dmi_check_system(ov9650_flip_dmi_table) &&
430
!sensor_settings[VFLIP_IDX]))
431
ver_offs--;
432
433
if (width <= 320)
434
hor_offs /= 2;
435
436
/* Synthesize the vsync/hsync setup */
437
for (i = 0; i < ARRAY_SIZE(res_init_ov9650) && !err; i++) {
438
if (res_init_ov9650[i][0] == BRIDGE)
439
err = m5602_write_bridge(sd, res_init_ov9650[i][1],
440
res_init_ov9650[i][2]);
441
else if (res_init_ov9650[i][0] == SENSOR) {
442
data = res_init_ov9650[i][2];
443
err = m5602_write_sensor(sd,
444
res_init_ov9650[i][1], &data, 1);
445
}
446
}
447
if (err < 0)
448
return err;
449
450
err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA,
451
((ver_offs >> 8) & 0xff));
452
if (err < 0)
453
return err;
454
455
err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (ver_offs & 0xff));
456
if (err < 0)
457
return err;
458
459
err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0);
460
if (err < 0)
461
return err;
462
463
err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height >> 8) & 0xff);
464
if (err < 0)
465
return err;
466
467
err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height & 0xff));
468
if (err < 0)
469
return err;
470
471
for (i = 0; i < 2 && !err; i++)
472
err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0);
473
if (err < 0)
474
return err;
475
476
err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0);
477
if (err < 0)
478
return err;
479
480
err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 2);
481
if (err < 0)
482
return err;
483
484
err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA,
485
(hor_offs >> 8) & 0xff);
486
if (err < 0)
487
return err;
488
489
err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, hor_offs & 0xff);
490
if (err < 0)
491
return err;
492
493
err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA,
494
((width + hor_offs) >> 8) & 0xff);
495
if (err < 0)
496
return err;
497
498
err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA,
499
((width + hor_offs) & 0xff));
500
if (err < 0)
501
return err;
502
503
err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0);
504
if (err < 0)
505
return err;
506
507
switch (width) {
508
case 640:
509
PDEBUG(D_V4L2, "Configuring camera for VGA mode");
510
511
data = OV9650_VGA_SELECT | OV9650_RGB_SELECT |
512
OV9650_RAW_RGB_SELECT;
513
err = m5602_write_sensor(sd, OV9650_COM7, &data, 1);
514
break;
515
516
case 352:
517
PDEBUG(D_V4L2, "Configuring camera for CIF mode");
518
519
data = OV9650_CIF_SELECT | OV9650_RGB_SELECT |
520
OV9650_RAW_RGB_SELECT;
521
err = m5602_write_sensor(sd, OV9650_COM7, &data, 1);
522
break;
523
524
case 320:
525
PDEBUG(D_V4L2, "Configuring camera for QVGA mode");
526
527
data = OV9650_QVGA_SELECT | OV9650_RGB_SELECT |
528
OV9650_RAW_RGB_SELECT;
529
err = m5602_write_sensor(sd, OV9650_COM7, &data, 1);
530
break;
531
532
case 176:
533
PDEBUG(D_V4L2, "Configuring camera for QCIF mode");
534
535
data = OV9650_QCIF_SELECT | OV9650_RGB_SELECT |
536
OV9650_RAW_RGB_SELECT;
537
err = m5602_write_sensor(sd, OV9650_COM7, &data, 1);
538
break;
539
}
540
return err;
541
}
542
543
int ov9650_stop(struct sd *sd)
544
{
545
u8 data = OV9650_SOFT_SLEEP | OV9650_OUTPUT_DRIVE_2X;
546
return m5602_write_sensor(sd, OV9650_COM2, &data, 1);
547
}
548
549
void ov9650_disconnect(struct sd *sd)
550
{
551
ov9650_stop(sd);
552
553
sd->sensor = NULL;
554
kfree(sd->sensor_priv);
555
}
556
557
static int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
558
{
559
struct sd *sd = (struct sd *) gspca_dev;
560
s32 *sensor_settings = sd->sensor_priv;
561
562
*val = sensor_settings[EXPOSURE_IDX];
563
PDEBUG(D_V4L2, "Read exposure %d", *val);
564
return 0;
565
}
566
567
static int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
568
{
569
struct sd *sd = (struct sd *) gspca_dev;
570
s32 *sensor_settings = sd->sensor_priv;
571
u8 i2c_data;
572
int err;
573
574
PDEBUG(D_V4L2, "Set exposure to %d", val);
575
576
sensor_settings[EXPOSURE_IDX] = val;
577
/* The 6 MSBs */
578
i2c_data = (val >> 10) & 0x3f;
579
err = m5602_write_sensor(sd, OV9650_AECHM,
580
&i2c_data, 1);
581
if (err < 0)
582
return err;
583
584
/* The 8 middle bits */
585
i2c_data = (val >> 2) & 0xff;
586
err = m5602_write_sensor(sd, OV9650_AECH,
587
&i2c_data, 1);
588
if (err < 0)
589
return err;
590
591
/* The 2 LSBs */
592
i2c_data = val & 0x03;
593
err = m5602_write_sensor(sd, OV9650_COM1, &i2c_data, 1);
594
return err;
595
}
596
597
static int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
598
{
599
struct sd *sd = (struct sd *) gspca_dev;
600
s32 *sensor_settings = sd->sensor_priv;
601
602
*val = sensor_settings[GAIN_IDX];
603
PDEBUG(D_V4L2, "Read gain %d", *val);
604
return 0;
605
}
606
607
static int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val)
608
{
609
int err;
610
u8 i2c_data;
611
struct sd *sd = (struct sd *) gspca_dev;
612
s32 *sensor_settings = sd->sensor_priv;
613
614
PDEBUG(D_V4L2, "Setting gain to %d", val);
615
616
sensor_settings[GAIN_IDX] = val;
617
618
/* The 2 MSB */
619
/* Read the OV9650_VREF register first to avoid
620
corrupting the VREF high and low bits */
621
err = m5602_read_sensor(sd, OV9650_VREF, &i2c_data, 1);
622
if (err < 0)
623
return err;
624
625
/* Mask away all uninteresting bits */
626
i2c_data = ((val & 0x0300) >> 2) |
627
(i2c_data & 0x3f);
628
err = m5602_write_sensor(sd, OV9650_VREF, &i2c_data, 1);
629
if (err < 0)
630
return err;
631
632
/* The 8 LSBs */
633
i2c_data = val & 0xff;
634
err = m5602_write_sensor(sd, OV9650_GAIN, &i2c_data, 1);
635
return err;
636
}
637
638
static int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
639
{
640
struct sd *sd = (struct sd *) gspca_dev;
641
s32 *sensor_settings = sd->sensor_priv;
642
643
*val = sensor_settings[RED_BALANCE_IDX];
644
PDEBUG(D_V4L2, "Read red gain %d", *val);
645
return 0;
646
}
647
648
static int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
649
{
650
int err;
651
u8 i2c_data;
652
struct sd *sd = (struct sd *) gspca_dev;
653
s32 *sensor_settings = sd->sensor_priv;
654
655
PDEBUG(D_V4L2, "Set red gain to %d", val);
656
657
sensor_settings[RED_BALANCE_IDX] = val;
658
659
i2c_data = val & 0xff;
660
err = m5602_write_sensor(sd, OV9650_RED, &i2c_data, 1);
661
return err;
662
}
663
664
static int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
665
{
666
struct sd *sd = (struct sd *) gspca_dev;
667
s32 *sensor_settings = sd->sensor_priv;
668
669
*val = sensor_settings[BLUE_BALANCE_IDX];
670
PDEBUG(D_V4L2, "Read blue gain %d", *val);
671
672
return 0;
673
}
674
675
static int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
676
{
677
int err;
678
u8 i2c_data;
679
struct sd *sd = (struct sd *) gspca_dev;
680
s32 *sensor_settings = sd->sensor_priv;
681
682
PDEBUG(D_V4L2, "Set blue gain to %d", val);
683
684
sensor_settings[BLUE_BALANCE_IDX] = val;
685
686
i2c_data = val & 0xff;
687
err = m5602_write_sensor(sd, OV9650_BLUE, &i2c_data, 1);
688
return err;
689
}
690
691
static int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
692
{
693
struct sd *sd = (struct sd *) gspca_dev;
694
s32 *sensor_settings = sd->sensor_priv;
695
696
*val = sensor_settings[HFLIP_IDX];
697
PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
698
return 0;
699
}
700
701
static int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
702
{
703
int err;
704
u8 i2c_data;
705
struct sd *sd = (struct sd *) gspca_dev;
706
s32 *sensor_settings = sd->sensor_priv;
707
708
PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
709
710
sensor_settings[HFLIP_IDX] = val;
711
712
if (!dmi_check_system(ov9650_flip_dmi_table))
713
i2c_data = ((val & 0x01) << 5) |
714
(sensor_settings[VFLIP_IDX] << 4);
715
else
716
i2c_data = ((val & 0x01) << 5) |
717
(!sensor_settings[VFLIP_IDX] << 4);
718
719
err = m5602_write_sensor(sd, OV9650_MVFP, &i2c_data, 1);
720
721
return err;
722
}
723
724
static int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
725
{
726
struct sd *sd = (struct sd *) gspca_dev;
727
s32 *sensor_settings = sd->sensor_priv;
728
729
*val = sensor_settings[VFLIP_IDX];
730
PDEBUG(D_V4L2, "Read vertical flip %d", *val);
731
732
return 0;
733
}
734
735
static int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
736
{
737
int err;
738
u8 i2c_data;
739
struct sd *sd = (struct sd *) gspca_dev;
740
s32 *sensor_settings = sd->sensor_priv;
741
742
PDEBUG(D_V4L2, "Set vertical flip to %d", val);
743
sensor_settings[VFLIP_IDX] = val;
744
745
if (dmi_check_system(ov9650_flip_dmi_table))
746
val = !val;
747
748
i2c_data = ((val & 0x01) << 4) | (sensor_settings[VFLIP_IDX] << 5);
749
err = m5602_write_sensor(sd, OV9650_MVFP, &i2c_data, 1);
750
if (err < 0)
751
return err;
752
753
/* When vflip is toggled we need to readjust the bridge hsync/vsync */
754
if (gspca_dev->streaming)
755
err = ov9650_start(sd);
756
757
return err;
758
}
759
760
static int ov9650_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val)
761
{
762
struct sd *sd = (struct sd *) gspca_dev;
763
s32 *sensor_settings = sd->sensor_priv;
764
765
*val = sensor_settings[AUTO_EXPOSURE_IDX];
766
PDEBUG(D_V4L2, "Read auto exposure control %d", *val);
767
return 0;
768
}
769
770
static int ov9650_set_auto_exposure(struct gspca_dev *gspca_dev,
771
__s32 val)
772
{
773
int err;
774
u8 i2c_data;
775
struct sd *sd = (struct sd *) gspca_dev;
776
s32 *sensor_settings = sd->sensor_priv;
777
778
PDEBUG(D_V4L2, "Set auto exposure control to %d", val);
779
780
sensor_settings[AUTO_EXPOSURE_IDX] = val;
781
err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
782
if (err < 0)
783
return err;
784
785
i2c_data = ((i2c_data & 0xfe) | ((val & 0x01) << 0));
786
787
return m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1);
788
}
789
790
static int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev,
791
__s32 *val)
792
{
793
struct sd *sd = (struct sd *) gspca_dev;
794
s32 *sensor_settings = sd->sensor_priv;
795
796
*val = sensor_settings[AUTO_WHITE_BALANCE_IDX];
797
return 0;
798
}
799
800
static int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev,
801
__s32 val)
802
{
803
int err;
804
u8 i2c_data;
805
struct sd *sd = (struct sd *) gspca_dev;
806
s32 *sensor_settings = sd->sensor_priv;
807
808
PDEBUG(D_V4L2, "Set auto white balance to %d", val);
809
810
sensor_settings[AUTO_WHITE_BALANCE_IDX] = val;
811
err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
812
if (err < 0)
813
return err;
814
815
i2c_data = ((i2c_data & 0xfd) | ((val & 0x01) << 1));
816
err = m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1);
817
818
return err;
819
}
820
821
static int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val)
822
{
823
struct sd *sd = (struct sd *) gspca_dev;
824
s32 *sensor_settings = sd->sensor_priv;
825
826
*val = sensor_settings[AUTO_GAIN_CTRL_IDX];
827
PDEBUG(D_V4L2, "Read auto gain control %d", *val);
828
return 0;
829
}
830
831
static int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
832
{
833
int err;
834
u8 i2c_data;
835
struct sd *sd = (struct sd *) gspca_dev;
836
s32 *sensor_settings = sd->sensor_priv;
837
838
PDEBUG(D_V4L2, "Set auto gain control to %d", val);
839
840
sensor_settings[AUTO_GAIN_CTRL_IDX] = val;
841
err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
842
if (err < 0)
843
return err;
844
845
i2c_data = ((i2c_data & 0xfb) | ((val & 0x01) << 2));
846
847
return m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1);
848
}
849
850
static void ov9650_dump_registers(struct sd *sd)
851
{
852
int address;
853
info("Dumping the ov9650 register state");
854
for (address = 0; address < 0xa9; address++) {
855
u8 value;
856
m5602_read_sensor(sd, address, &value, 1);
857
info("register 0x%x contains 0x%x",
858
address, value);
859
}
860
861
info("ov9650 register state dump complete");
862
863
info("Probing for which registers that are read/write");
864
for (address = 0; address < 0xff; address++) {
865
u8 old_value, ctrl_value;
866
u8 test_value[2] = {0xff, 0xff};
867
868
m5602_read_sensor(sd, address, &old_value, 1);
869
m5602_write_sensor(sd, address, test_value, 1);
870
m5602_read_sensor(sd, address, &ctrl_value, 1);
871
872
if (ctrl_value == test_value[0])
873
info("register 0x%x is writeable", address);
874
else
875
info("register 0x%x is read only", address);
876
877
/* Restore original value */
878
m5602_write_sensor(sd, address, &old_value, 1);
879
}
880
}
881
882