• 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/stv06xx/
1/*
2 * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher
3 *		      Mark Cave-Ayland, Carlo E Prelz, Dick Streefland
4 * Copyright (c) 2002, 2003 Tuukka Toivonen
5 * Copyright (c) 2008 Erik Andr��n
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20 *
21 * P/N 861037:      Sensor HDCS1000        ASIC STV0600
22 * P/N 861050-0010: Sensor HDCS1000        ASIC STV0600
23 * P/N 861050-0020: Sensor Photobit PB100  ASIC STV0600-1 - QuickCam Express
24 * P/N 861055:      Sensor ST VV6410       ASIC STV0610   - LEGO cam
25 * P/N 861075-0040: Sensor HDCS1000        ASIC
26 * P/N 961179-0700: Sensor ST VV6410       ASIC STV0602   - Dexxa WebCam USB
27 * P/N 861040-0000: Sensor ST VV6410       ASIC STV0610   - QuickCam Web
28 */
29
30/*
31 * The spec file for the PB-0100 suggests the following for best quality
32 * images after the sensor has been reset :
33 *
34 * PB_ADCGAINL      = R60 = 0x03 (3 dec)      : sets low reference of ADC
35						to produce good black level
36 * PB_PREADCTRL     = R32 = 0x1400 (5120 dec) : Enables global gain changes
37						through R53
38 * PB_ADCMINGAIN    = R52 = 0x10 (16 dec)     : Sets the minimum gain for
39						auto-exposure
40 * PB_ADCGLOBALGAIN = R53 = 0x10 (16 dec)     : Sets the global gain
41 * PB_EXPGAIN       = R14 = 0x11 (17 dec)     : Sets the auto-exposure value
42 * PB_UPDATEINT     = R23 = 0x02 (2 dec)      : Sets the speed on
43						auto-exposure routine
44 * PB_CFILLIN       = R5  = 0x0E (14 dec)     : Sets the frame rate
45 */
46
47#include "stv06xx_pb0100.h"
48
49static const struct ctrl pb0100_ctrl[] = {
50#define GAIN_IDX 0
51	{
52		{
53			.id		= V4L2_CID_GAIN,
54			.type		= V4L2_CTRL_TYPE_INTEGER,
55			.name		= "Gain",
56			.minimum	= 0,
57			.maximum	= 255,
58			.step		= 1,
59			.default_value  = 128
60		},
61		.set = pb0100_set_gain,
62		.get = pb0100_get_gain
63	},
64#define RED_BALANCE_IDX 1
65	{
66		{
67			.id		= V4L2_CID_RED_BALANCE,
68			.type		= V4L2_CTRL_TYPE_INTEGER,
69			.name		= "Red Balance",
70			.minimum	= -255,
71			.maximum	= 255,
72			.step		= 1,
73			.default_value  = 0
74		},
75		.set = pb0100_set_red_balance,
76		.get = pb0100_get_red_balance
77	},
78#define BLUE_BALANCE_IDX 2
79	{
80		{
81			.id		= V4L2_CID_BLUE_BALANCE,
82			.type		= V4L2_CTRL_TYPE_INTEGER,
83			.name		= "Blue Balance",
84			.minimum	= -255,
85			.maximum	= 255,
86			.step		= 1,
87			.default_value  = 0
88		},
89		.set = pb0100_set_blue_balance,
90		.get = pb0100_get_blue_balance
91	},
92#define EXPOSURE_IDX 3
93	{
94		{
95			.id		= V4L2_CID_EXPOSURE,
96			.type		= V4L2_CTRL_TYPE_INTEGER,
97			.name		= "Exposure",
98			.minimum	= 0,
99			.maximum	= 511,
100			.step		= 1,
101			.default_value  = 12
102		},
103		.set = pb0100_set_exposure,
104		.get = pb0100_get_exposure
105	},
106#define AUTOGAIN_IDX 4
107	{
108		{
109			.id		= V4L2_CID_AUTOGAIN,
110			.type		= V4L2_CTRL_TYPE_BOOLEAN,
111			.name		= "Automatic Gain and Exposure",
112			.minimum	= 0,
113			.maximum	= 1,
114			.step		= 1,
115			.default_value  = 1
116		},
117		.set = pb0100_set_autogain,
118		.get = pb0100_get_autogain
119	},
120#define AUTOGAIN_TARGET_IDX 5
121	{
122		{
123			.id		= V4L2_CTRL_CLASS_USER + 0x1000,
124			.type		= V4L2_CTRL_TYPE_INTEGER,
125			.name		= "Automatic Gain Target",
126			.minimum	= 0,
127			.maximum	= 255,
128			.step		= 1,
129			.default_value  = 128
130		},
131		.set = pb0100_set_autogain_target,
132		.get = pb0100_get_autogain_target
133	},
134#define NATURAL_IDX 6
135	{
136		{
137			.id		= V4L2_CTRL_CLASS_USER + 0x1001,
138			.type		= V4L2_CTRL_TYPE_BOOLEAN,
139			.name		= "Natural Light Source",
140			.minimum	= 0,
141			.maximum	= 1,
142			.step		= 1,
143			.default_value  = 1
144		},
145		.set = pb0100_set_natural,
146		.get = pb0100_get_natural
147	}
148};
149
150static struct v4l2_pix_format pb0100_mode[] = {
151/* low res / subsample modes disabled as they are only half res horizontal,
152   halving the vertical resolution does not seem to work */
153	{
154		320,
155		240,
156		V4L2_PIX_FMT_SGRBG8,
157		V4L2_FIELD_NONE,
158		.sizeimage = 320 * 240,
159		.bytesperline = 320,
160		.colorspace = V4L2_COLORSPACE_SRGB,
161		.priv = PB0100_CROP_TO_VGA
162	},
163	{
164		352,
165		288,
166		V4L2_PIX_FMT_SGRBG8,
167		V4L2_FIELD_NONE,
168		.sizeimage = 352 * 288,
169		.bytesperline = 352,
170		.colorspace = V4L2_COLORSPACE_SRGB,
171		.priv = 0
172	}
173};
174
175static int pb0100_probe(struct sd *sd)
176{
177	u16 sensor;
178	int i, err;
179	s32 *sensor_settings;
180
181	err = stv06xx_read_sensor(sd, PB_IDENT, &sensor);
182
183	if (err < 0)
184		return -ENODEV;
185
186	if ((sensor >> 8) == 0x64) {
187		sensor_settings = kmalloc(
188				ARRAY_SIZE(pb0100_ctrl) * sizeof(s32),
189				GFP_KERNEL);
190		if (!sensor_settings)
191			return -ENOMEM;
192
193		info("Photobit pb0100 sensor detected");
194
195		sd->gspca_dev.cam.cam_mode = pb0100_mode;
196		sd->gspca_dev.cam.nmodes = ARRAY_SIZE(pb0100_mode);
197		sd->desc.ctrls = pb0100_ctrl;
198		sd->desc.nctrls = ARRAY_SIZE(pb0100_ctrl);
199		for (i = 0; i < sd->desc.nctrls; i++)
200			sensor_settings[i] = pb0100_ctrl[i].qctrl.default_value;
201		sd->sensor_priv = sensor_settings;
202
203		return 0;
204	}
205
206	return -ENODEV;
207}
208
209static int pb0100_start(struct sd *sd)
210{
211	int err;
212	struct cam *cam = &sd->gspca_dev.cam;
213	s32 *sensor_settings = sd->sensor_priv;
214	u32 mode = cam->cam_mode[sd->gspca_dev.curr_mode].priv;
215
216	/* Setup sensor window */
217	if (mode & PB0100_CROP_TO_VGA) {
218		stv06xx_write_sensor(sd, PB_RSTART, 30);
219		stv06xx_write_sensor(sd, PB_CSTART, 20);
220		stv06xx_write_sensor(sd, PB_RWSIZE, 240 - 1);
221		stv06xx_write_sensor(sd, PB_CWSIZE, 320 - 1);
222	} else {
223		stv06xx_write_sensor(sd, PB_RSTART, 8);
224		stv06xx_write_sensor(sd, PB_CSTART, 4);
225		stv06xx_write_sensor(sd, PB_RWSIZE, 288 - 1);
226		stv06xx_write_sensor(sd, PB_CWSIZE, 352 - 1);
227	}
228
229	if (mode & PB0100_SUBSAMPLE) {
230		stv06xx_write_bridge(sd, STV_Y_CTRL, 0x02);
231		stv06xx_write_bridge(sd, STV_X_CTRL, 0x06);
232
233		stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x10);
234	} else {
235		stv06xx_write_bridge(sd, STV_Y_CTRL, 0x01);
236		stv06xx_write_bridge(sd, STV_X_CTRL, 0x0a);
237		/* larger -> slower */
238		stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x20);
239	}
240
241	/* set_gain also sets red and blue balance */
242	pb0100_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
243	pb0100_set_exposure(&sd->gspca_dev, sensor_settings[EXPOSURE_IDX]);
244	pb0100_set_autogain_target(&sd->gspca_dev,
245				   sensor_settings[AUTOGAIN_TARGET_IDX]);
246	pb0100_set_autogain(&sd->gspca_dev, sensor_settings[AUTOGAIN_IDX]);
247
248	err = stv06xx_write_sensor(sd, PB_CONTROL, BIT(5)|BIT(3)|BIT(1));
249	PDEBUG(D_STREAM, "Started stream, status: %d", err);
250
251	return (err < 0) ? err : 0;
252}
253
254static int pb0100_stop(struct sd *sd)
255{
256	int err;
257
258	err = stv06xx_write_sensor(sd, PB_ABORTFRAME, 1);
259
260	if (err < 0)
261		goto out;
262
263	/* Set bit 1 to zero */
264	err = stv06xx_write_sensor(sd, PB_CONTROL, BIT(5)|BIT(3));
265
266	PDEBUG(D_STREAM, "Halting stream");
267out:
268	return (err < 0) ? err : 0;
269}
270
271static void pb0100_disconnect(struct sd *sd)
272{
273	sd->sensor = NULL;
274	kfree(sd->sensor_priv);
275}
276
277static int pb0100_init(struct sd *sd)
278{
279	stv06xx_write_bridge(sd, STV_REG00, 1);
280	stv06xx_write_bridge(sd, STV_SCAN_RATE, 0);
281
282	/* Reset sensor */
283	stv06xx_write_sensor(sd, PB_RESET, 1);
284	stv06xx_write_sensor(sd, PB_RESET, 0);
285
286	/* Disable chip */
287	stv06xx_write_sensor(sd, PB_CONTROL, BIT(5)|BIT(3));
288
289	/* Gain stuff...*/
290	stv06xx_write_sensor(sd, PB_PREADCTRL, BIT(12)|BIT(10)|BIT(6));
291	stv06xx_write_sensor(sd, PB_ADCGLOBALGAIN, 12);
292
293	/* Set up auto-exposure */
294	/* ADC VREF_HI new setting for a transition
295	  from the Expose1 to the Expose2 setting */
296	stv06xx_write_sensor(sd, PB_R28, 12);
297	/* gain max for autoexposure */
298	stv06xx_write_sensor(sd, PB_ADCMAXGAIN, 180);
299	/* gain min for autoexposure  */
300	stv06xx_write_sensor(sd, PB_ADCMINGAIN, 12);
301	/* Maximum frame integration time (programmed into R8)
302	   allowed for auto-exposure routine */
303	stv06xx_write_sensor(sd, PB_R54, 3);
304	/* Minimum frame integration time (programmed into R8)
305	   allowed for auto-exposure routine */
306	stv06xx_write_sensor(sd, PB_R55, 0);
307	stv06xx_write_sensor(sd, PB_UPDATEINT, 1);
308	/* R15  Expose0 (maximum that auto-exposure may use) */
309	stv06xx_write_sensor(sd, PB_R15, 800);
310	/* R17  Expose2 (minimum that auto-exposure may use) */
311	stv06xx_write_sensor(sd, PB_R17, 10);
312
313	stv06xx_write_sensor(sd, PB_EXPGAIN, 0);
314
315	/* 0x14 */
316	stv06xx_write_sensor(sd, PB_VOFFSET, 0);
317	/* 0x0D */
318	stv06xx_write_sensor(sd, PB_ADCGAINH, 11);
319	/* Set black level (important!) */
320	stv06xx_write_sensor(sd, PB_ADCGAINL, 0);
321
322	/* ??? */
323	stv06xx_write_bridge(sd, STV_REG00, 0x11);
324	stv06xx_write_bridge(sd, STV_REG03, 0x45);
325	stv06xx_write_bridge(sd, STV_REG04, 0x07);
326
327	/* ISO-Size (0x27b: 635... why? - HDCS uses 847) */
328	stv06xx_write_bridge(sd, STV_ISO_SIZE_L, 847);
329
330	/* Scan/timing for the sensor */
331	stv06xx_write_sensor(sd, PB_ROWSPEED, BIT(4)|BIT(3)|BIT(1));
332	stv06xx_write_sensor(sd, PB_CFILLIN, 14);
333	stv06xx_write_sensor(sd, PB_VBL, 0);
334	stv06xx_write_sensor(sd, PB_FINTTIME, 0);
335	stv06xx_write_sensor(sd, PB_RINTTIME, 123);
336
337	stv06xx_write_bridge(sd, STV_REG01, 0xc2);
338	stv06xx_write_bridge(sd, STV_REG02, 0xb0);
339	return 0;
340}
341
342static int pb0100_dump(struct sd *sd)
343{
344	return 0;
345}
346
347static int pb0100_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
348{
349	struct sd *sd = (struct sd *) gspca_dev;
350	s32 *sensor_settings = sd->sensor_priv;
351
352	*val = sensor_settings[GAIN_IDX];
353
354	return 0;
355}
356
357static int pb0100_set_gain(struct gspca_dev *gspca_dev, __s32 val)
358{
359	int err;
360	struct sd *sd = (struct sd *) gspca_dev;
361	s32 *sensor_settings = sd->sensor_priv;
362
363	if (sensor_settings[AUTOGAIN_IDX])
364		return -EBUSY;
365
366	sensor_settings[GAIN_IDX] = val;
367	err = stv06xx_write_sensor(sd, PB_G1GAIN, val);
368	if (!err)
369		err = stv06xx_write_sensor(sd, PB_G2GAIN, val);
370	PDEBUG(D_V4L2, "Set green gain to %d, status: %d", val, err);
371
372	if (!err)
373		err = pb0100_set_red_balance(gspca_dev,
374					     sensor_settings[RED_BALANCE_IDX]);
375	if (!err)
376		err = pb0100_set_blue_balance(gspca_dev,
377					    sensor_settings[BLUE_BALANCE_IDX]);
378
379	return err;
380}
381
382static int pb0100_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
383{
384	struct sd *sd = (struct sd *) gspca_dev;
385	s32 *sensor_settings = sd->sensor_priv;
386
387	*val = sensor_settings[RED_BALANCE_IDX];
388
389	return 0;
390}
391
392static int pb0100_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
393{
394	int err;
395	struct sd *sd = (struct sd *) gspca_dev;
396	s32 *sensor_settings = sd->sensor_priv;
397
398	if (sensor_settings[AUTOGAIN_IDX])
399		return -EBUSY;
400
401	sensor_settings[RED_BALANCE_IDX] = val;
402	val += sensor_settings[GAIN_IDX];
403	if (val < 0)
404		val = 0;
405	else if (val > 255)
406		val = 255;
407
408	err = stv06xx_write_sensor(sd, PB_RGAIN, val);
409	PDEBUG(D_V4L2, "Set red gain to %d, status: %d", val, err);
410
411	return err;
412}
413
414static int pb0100_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
415{
416	struct sd *sd = (struct sd *) gspca_dev;
417	s32 *sensor_settings = sd->sensor_priv;
418
419	*val = sensor_settings[BLUE_BALANCE_IDX];
420
421	return 0;
422}
423
424static int pb0100_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
425{
426	int err;
427	struct sd *sd = (struct sd *) gspca_dev;
428	s32 *sensor_settings = sd->sensor_priv;
429
430	if (sensor_settings[AUTOGAIN_IDX])
431		return -EBUSY;
432
433	sensor_settings[BLUE_BALANCE_IDX] = val;
434	val += sensor_settings[GAIN_IDX];
435	if (val < 0)
436		val = 0;
437	else if (val > 255)
438		val = 255;
439
440	err = stv06xx_write_sensor(sd, PB_BGAIN, val);
441	PDEBUG(D_V4L2, "Set blue gain to %d, status: %d", val, err);
442
443	return err;
444}
445
446static int pb0100_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
447{
448	struct sd *sd = (struct sd *) gspca_dev;
449	s32 *sensor_settings = sd->sensor_priv;
450
451	*val = sensor_settings[EXPOSURE_IDX];
452
453	return 0;
454}
455
456static int pb0100_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
457{
458	int err;
459	struct sd *sd = (struct sd *) gspca_dev;
460	s32 *sensor_settings = sd->sensor_priv;
461
462	if (sensor_settings[AUTOGAIN_IDX])
463		return -EBUSY;
464
465	sensor_settings[EXPOSURE_IDX] = val;
466	err = stv06xx_write_sensor(sd, PB_RINTTIME, val);
467	PDEBUG(D_V4L2, "Set exposure to %d, status: %d", val, err);
468
469	return err;
470}
471
472static int pb0100_get_autogain(struct gspca_dev *gspca_dev, __s32 *val)
473{
474	struct sd *sd = (struct sd *) gspca_dev;
475	s32 *sensor_settings = sd->sensor_priv;
476
477	*val = sensor_settings[AUTOGAIN_IDX];
478
479	return 0;
480}
481
482static int pb0100_set_autogain(struct gspca_dev *gspca_dev, __s32 val)
483{
484	int err;
485	struct sd *sd = (struct sd *) gspca_dev;
486	s32 *sensor_settings = sd->sensor_priv;
487
488	sensor_settings[AUTOGAIN_IDX] = val;
489	if (sensor_settings[AUTOGAIN_IDX]) {
490		if (sensor_settings[NATURAL_IDX])
491			val = BIT(6)|BIT(4)|BIT(0);
492		else
493			val = BIT(4)|BIT(0);
494	} else
495		val = 0;
496
497	err = stv06xx_write_sensor(sd, PB_EXPGAIN, val);
498	PDEBUG(D_V4L2, "Set autogain to %d (natural: %d), status: %d",
499	       sensor_settings[AUTOGAIN_IDX], sensor_settings[NATURAL_IDX],
500	       err);
501
502	return err;
503}
504
505static int pb0100_get_autogain_target(struct gspca_dev *gspca_dev, __s32 *val)
506{
507	struct sd *sd = (struct sd *) gspca_dev;
508	s32 *sensor_settings = sd->sensor_priv;
509
510	*val = sensor_settings[AUTOGAIN_TARGET_IDX];
511
512	return 0;
513}
514
515static int pb0100_set_autogain_target(struct gspca_dev *gspca_dev, __s32 val)
516{
517	int err, totalpixels, brightpixels, darkpixels;
518	struct sd *sd = (struct sd *) gspca_dev;
519	s32 *sensor_settings = sd->sensor_priv;
520
521	sensor_settings[AUTOGAIN_TARGET_IDX] = val;
522
523	/* Number of pixels counted by the sensor when subsampling the pixels.
524	 * Slightly larger than the real value to avoid oscillation */
525	totalpixels = gspca_dev->width * gspca_dev->height;
526	totalpixels = totalpixels/(8*8) + totalpixels/(64*64);
527
528	brightpixels = (totalpixels * val) >> 8;
529	darkpixels   = totalpixels - brightpixels;
530	err = stv06xx_write_sensor(sd, PB_R21, brightpixels);
531	if (!err)
532		err = stv06xx_write_sensor(sd, PB_R22, darkpixels);
533
534	PDEBUG(D_V4L2, "Set autogain target to %d, status: %d", val, err);
535
536	return err;
537}
538
539static int pb0100_get_natural(struct gspca_dev *gspca_dev, __s32 *val)
540{
541	struct sd *sd = (struct sd *) gspca_dev;
542	s32 *sensor_settings = sd->sensor_priv;
543
544	*val = sensor_settings[NATURAL_IDX];
545
546	return 0;
547}
548
549static int pb0100_set_natural(struct gspca_dev *gspca_dev, __s32 val)
550{
551	struct sd *sd = (struct sd *) gspca_dev;
552	s32 *sensor_settings = sd->sensor_priv;
553
554	sensor_settings[NATURAL_IDX] = val;
555
556	return pb0100_set_autogain(gspca_dev, sensor_settings[AUTOGAIN_IDX]);
557}
558