• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/drivers/media/video/gspca/m5602/
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 <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_ov7660.h"
20
21static int ov7660_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
22static int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val);
23static int ov7660_get_auto_white_balance(struct gspca_dev *gspca_dev,
24					 __s32 *val);
25static int ov7660_set_auto_white_balance(struct gspca_dev *gspca_dev,
26					 __s32 val);
27static int ov7660_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val);
28static int ov7660_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val);
29static int ov7660_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val);
30static int ov7660_set_auto_exposure(struct gspca_dev *gspca_dev, __s32 val);
31static int ov7660_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
32static int ov7660_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
33static int ov7660_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
34static int ov7660_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
35
36static 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
127static 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
141static void ov7660_dump_registers(struct sd *sd);
142
143int 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
191sensor_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
209int 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
261int ov7660_start(struct sd *sd)
262{
263	return 0;
264}
265
266int ov7660_stop(struct sd *sd)
267{
268	return 0;
269}
270
271void ov7660_disconnect(struct sd *sd)
272{
273	ov7660_stop(sd);
274
275	sd->sensor = NULL;
276	kfree(sd->sensor_priv);
277}
278
279static 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
289static 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
305static 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
315static 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
336static 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
346static 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
365static 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
375static 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
395static 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
405static 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
424static 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
435static 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
457static 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