• 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/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#include "stv06xx_vv6410.h"
31
32static struct v4l2_pix_format vv6410_mode[] = {
33	{
34		356,
35		292,
36		V4L2_PIX_FMT_SGRBG8,
37		V4L2_FIELD_NONE,
38		.sizeimage = 356 * 292,
39		.bytesperline = 356,
40		.colorspace = V4L2_COLORSPACE_SRGB,
41		.priv = 0
42	}
43};
44
45static const struct ctrl vv6410_ctrl[] = {
46#define HFLIP_IDX 0
47	{
48		{
49			.id		= V4L2_CID_HFLIP,
50			.type		= V4L2_CTRL_TYPE_BOOLEAN,
51			.name		= "horizontal flip",
52			.minimum	= 0,
53			.maximum	= 1,
54			.step		= 1,
55			.default_value	= 0
56		},
57		.set = vv6410_set_hflip,
58		.get = vv6410_get_hflip
59	},
60#define VFLIP_IDX 1
61	{
62		{
63			.id		= V4L2_CID_VFLIP,
64			.type		= V4L2_CTRL_TYPE_BOOLEAN,
65			.name		= "vertical flip",
66			.minimum	= 0,
67			.maximum	= 1,
68			.step		= 1,
69			.default_value 	= 0
70		},
71		.set = vv6410_set_vflip,
72		.get = vv6410_get_vflip
73	},
74#define GAIN_IDX 2
75	{
76		{
77			.id		= V4L2_CID_GAIN,
78			.type		= V4L2_CTRL_TYPE_INTEGER,
79			.name		= "analog gain",
80			.minimum	= 0,
81			.maximum	= 15,
82			.step		= 1,
83			.default_value  = 10
84		},
85		.set = vv6410_set_analog_gain,
86		.get = vv6410_get_analog_gain
87	},
88#define EXPOSURE_IDX 3
89	{
90		{
91			.id		= V4L2_CID_EXPOSURE,
92			.type		= V4L2_CTRL_TYPE_INTEGER,
93			.name		= "exposure",
94			.minimum	= 0,
95			.maximum	= 32768,
96			.step		= 1,
97			.default_value  = 20000
98		},
99		.set = vv6410_set_exposure,
100		.get = vv6410_get_exposure
101	}
102	};
103
104static int vv6410_probe(struct sd *sd)
105{
106	u16 data;
107	int err, i;
108	s32 *sensor_settings;
109
110	err = stv06xx_read_sensor(sd, VV6410_DEVICEH, &data);
111	if (err < 0)
112		return -ENODEV;
113
114	if (data == 0x19) {
115		info("vv6410 sensor detected");
116
117		sensor_settings = kmalloc(ARRAY_SIZE(vv6410_ctrl) * sizeof(s32),
118					  GFP_KERNEL);
119		if (!sensor_settings)
120			return -ENOMEM;
121
122		sd->gspca_dev.cam.cam_mode = vv6410_mode;
123		sd->gspca_dev.cam.nmodes = ARRAY_SIZE(vv6410_mode);
124		sd->desc.ctrls = vv6410_ctrl;
125		sd->desc.nctrls = ARRAY_SIZE(vv6410_ctrl);
126
127		for (i = 0; i < sd->desc.nctrls; i++)
128			sensor_settings[i] = vv6410_ctrl[i].qctrl.default_value;
129		sd->sensor_priv = sensor_settings;
130		return 0;
131	}
132	return -ENODEV;
133}
134
135static int vv6410_init(struct sd *sd)
136{
137	int err = 0, i;
138	s32 *sensor_settings = sd->sensor_priv;
139
140	for (i = 0; i < ARRAY_SIZE(stv_bridge_init); i++) {
141		/* if NULL then len contains single value */
142		if (stv_bridge_init[i].data == NULL) {
143			err = stv06xx_write_bridge(sd,
144				stv_bridge_init[i].start,
145				stv_bridge_init[i].len);
146		} else {
147			int j;
148			for (j = 0; j < stv_bridge_init[i].len; j++)
149				err = stv06xx_write_bridge(sd,
150					stv_bridge_init[i].start + j,
151					stv_bridge_init[i].data[j]);
152		}
153	}
154
155	if (err < 0)
156		return err;
157
158	err = stv06xx_write_sensor_bytes(sd, (u8 *) vv6410_sensor_init,
159					 ARRAY_SIZE(vv6410_sensor_init));
160	if (err < 0)
161		return err;
162
163	err = vv6410_set_exposure(&sd->gspca_dev,
164				   sensor_settings[EXPOSURE_IDX]);
165	if (err < 0)
166		return err;
167
168	err = vv6410_set_analog_gain(&sd->gspca_dev,
169				      sensor_settings[GAIN_IDX]);
170
171	return (err < 0) ? err : 0;
172}
173
174static void vv6410_disconnect(struct sd *sd)
175{
176	sd->sensor = NULL;
177	kfree(sd->sensor_priv);
178}
179
180static int vv6410_start(struct sd *sd)
181{
182	int err;
183	struct cam *cam = &sd->gspca_dev.cam;
184	u32 priv = cam->cam_mode[sd->gspca_dev.curr_mode].priv;
185
186	if (priv & VV6410_CROP_TO_QVGA) {
187		PDEBUG(D_CONF, "Cropping to QVGA");
188		stv06xx_write_sensor(sd, VV6410_XENDH, 320 - 1);
189		stv06xx_write_sensor(sd, VV6410_YENDH, 240 - 1);
190	} else {
191		stv06xx_write_sensor(sd, VV6410_XENDH, 360 - 1);
192		stv06xx_write_sensor(sd, VV6410_YENDH, 294 - 1);
193	}
194
195	if (priv & VV6410_SUBSAMPLE) {
196		PDEBUG(D_CONF, "Enabling subsampling");
197		stv06xx_write_bridge(sd, STV_Y_CTRL, 0x02);
198		stv06xx_write_bridge(sd, STV_X_CTRL, 0x06);
199
200		stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x10);
201	} else {
202		stv06xx_write_bridge(sd, STV_Y_CTRL, 0x01);
203		stv06xx_write_bridge(sd, STV_X_CTRL, 0x0a);
204
205		stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x20);
206	}
207
208	/* Turn on LED */
209	err = stv06xx_write_bridge(sd, STV_LED_CTRL, LED_ON);
210	if (err < 0)
211		return err;
212
213	err = stv06xx_write_sensor(sd, VV6410_SETUP0, 0);
214	if (err < 0)
215		return err;
216
217	PDEBUG(D_STREAM, "Starting stream");
218
219	return 0;
220}
221
222static int vv6410_stop(struct sd *sd)
223{
224	int err;
225
226	/* Turn off LED */
227	err = stv06xx_write_bridge(sd, STV_LED_CTRL, LED_OFF);
228	if (err < 0)
229		return err;
230
231	err = stv06xx_write_sensor(sd, VV6410_SETUP0, VV6410_LOW_POWER_MODE);
232	if (err < 0)
233		return err;
234
235	PDEBUG(D_STREAM, "Halting stream");
236
237	return (err < 0) ? err : 0;
238}
239
240static int vv6410_dump(struct sd *sd)
241{
242	u8 i;
243	int err = 0;
244
245	info("Dumping all vv6410 sensor registers");
246	for (i = 0; i < 0xff && !err; i++) {
247		u16 data;
248		err = stv06xx_read_sensor(sd, i, &data);
249		info("Register 0x%x contained 0x%x", i, data);
250	}
251	return (err < 0) ? err : 0;
252}
253
254static int vv6410_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
255{
256	struct sd *sd = (struct sd *) gspca_dev;
257	s32 *sensor_settings = sd->sensor_priv;
258
259	*val = sensor_settings[HFLIP_IDX];
260	PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
261
262	return 0;
263}
264
265static int vv6410_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
266{
267	int err;
268	u16 i2c_data;
269	struct sd *sd = (struct sd *) gspca_dev;
270	s32 *sensor_settings = sd->sensor_priv;
271
272	sensor_settings[HFLIP_IDX] = val;
273	err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data);
274	if (err < 0)
275		return err;
276
277	if (val)
278		i2c_data |= VV6410_HFLIP;
279	else
280		i2c_data &= ~VV6410_HFLIP;
281
282	PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
283	err = stv06xx_write_sensor(sd, VV6410_DATAFORMAT, i2c_data);
284
285	return (err < 0) ? err : 0;
286}
287
288static int vv6410_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
289{
290	struct sd *sd = (struct sd *) gspca_dev;
291	s32 *sensor_settings = sd->sensor_priv;
292
293	*val = sensor_settings[VFLIP_IDX];
294	PDEBUG(D_V4L2, "Read vertical flip %d", *val);
295
296	return 0;
297}
298
299static int vv6410_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
300{
301	int err;
302	u16 i2c_data;
303	struct sd *sd = (struct sd *) gspca_dev;
304	s32 *sensor_settings = sd->sensor_priv;
305
306	sensor_settings[VFLIP_IDX] = val;
307	err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data);
308	if (err < 0)
309		return err;
310
311	if (val)
312		i2c_data |= VV6410_VFLIP;
313	else
314		i2c_data &= ~VV6410_VFLIP;
315
316	PDEBUG(D_V4L2, "Set vertical flip to %d", val);
317	err = stv06xx_write_sensor(sd, VV6410_DATAFORMAT, i2c_data);
318
319	return (err < 0) ? err : 0;
320}
321
322static int vv6410_get_analog_gain(struct gspca_dev *gspca_dev, __s32 *val)
323{
324	struct sd *sd = (struct sd *) gspca_dev;
325	s32 *sensor_settings = sd->sensor_priv;
326
327	*val = sensor_settings[GAIN_IDX];
328
329	PDEBUG(D_V4L2, "Read analog gain %d", *val);
330
331	return 0;
332}
333
334static int vv6410_set_analog_gain(struct gspca_dev *gspca_dev, __s32 val)
335{
336	int err;
337	struct sd *sd = (struct sd *) gspca_dev;
338	s32 *sensor_settings = sd->sensor_priv;
339
340	sensor_settings[GAIN_IDX] = val;
341	PDEBUG(D_V4L2, "Set analog gain to %d", val);
342	err = stv06xx_write_sensor(sd, VV6410_ANALOGGAIN, 0xf0 | (val & 0xf));
343
344	return (err < 0) ? err : 0;
345}
346
347static int vv6410_get_exposure(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[EXPOSURE_IDX];
353
354	PDEBUG(D_V4L2, "Read exposure %d", *val);
355
356	return 0;
357}
358
359static int vv6410_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
360{
361	int err;
362	struct sd *sd = (struct sd *) gspca_dev;
363	s32 *sensor_settings = sd->sensor_priv;
364	unsigned int fine, coarse;
365
366	sensor_settings[EXPOSURE_IDX] = val;
367
368	val = (val * val >> 14) + val / 4;
369
370	fine = val % VV6410_CIF_LINELENGTH;
371	coarse = min(512, val / VV6410_CIF_LINELENGTH);
372
373	PDEBUG(D_V4L2, "Set coarse exposure to %d, fine expsure to %d",
374	       coarse, fine);
375
376	err = stv06xx_write_sensor(sd, VV6410_FINEH, fine >> 8);
377	if (err < 0)
378		goto out;
379
380	err = stv06xx_write_sensor(sd, VV6410_FINEL, fine & 0xff);
381	if (err < 0)
382		goto out;
383
384	err = stv06xx_write_sensor(sd, VV6410_COARSEH, coarse >> 8);
385	if (err < 0)
386		goto out;
387
388	err = stv06xx_write_sensor(sd, VV6410_COARSEL, coarse & 0xff);
389
390out:
391	return err;
392}
393