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