• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6.36/drivers/media/video/gspca/m5602/
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 <m5602@x3ng.com.br>
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
21static int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
22static int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
23static int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
24static int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val);
25static int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
26static int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
27static int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
28static int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
29static int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
30static int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
31static int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
32static int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
33static int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev,
34					 __s32 *val);
35static int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev,
36					 __s32 val);
37static int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val);
38static int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val);
39static int ov9650_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val);
40static 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 */
44static
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
114static 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
248static 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
292static void ov9650_dump_registers(struct sd *sd);
293
294int 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
338sensor_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
355int 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
415int 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
543int 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
549void ov9650_disconnect(struct sd *sd)
550{
551	ov9650_stop(sd);
552
553	sd->sensor = NULL;
554	kfree(sd->sensor_priv);
555}
556
557static 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
567static 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
597static 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
607static 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
638static 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
648static 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
664static 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
675static 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
691static 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
701static 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
724static 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
735static 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
760static 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
770static 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
790static 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
800static 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
821static 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
831static 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
850static 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