aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media
diff options
context:
space:
mode:
authorErik Andren <erik.andren@gmail.com>2008-12-29 05:35:23 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2008-12-30 06:40:06 -0500
commit4c98834addfee3fdd42c505c37569261bf669d94 (patch)
tree71ca38fcaef06e5a854bfdf1ff13168d500ca4aa /drivers/media
parent15f64864e392612b230bc71d84e4537b80c607b1 (diff)
V4L/DVB (10048): gspca - stv06xx: New subdriver.
Signed-off-by: Erik Andren <erik.andren@gmail.com> Signed-off-by: Jean-Francois Moine <moinejf@free.fr> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media')
-rw-r--r--drivers/media/video/gspca/Kconfig1
-rw-r--r--drivers/media/video/gspca/Makefile2
-rw-r--r--drivers/media/video/gspca/stv06xx/Kconfig9
-rw-r--r--drivers/media/video/gspca/stv06xx/Makefile6
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx.c522
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx.h107
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c533
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h263
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c430
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h275
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx_sensor.h92
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c251
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h315
13 files changed, 2805 insertions, 1 deletions
diff --git a/drivers/media/video/gspca/Kconfig b/drivers/media/video/gspca/Kconfig
index 770fb699d048..ee6a691dff22 100644
--- a/drivers/media/video/gspca/Kconfig
+++ b/drivers/media/video/gspca/Kconfig
@@ -18,6 +18,7 @@ menuconfig USB_GSPCA
18if USB_GSPCA && VIDEO_V4L2 18if USB_GSPCA && VIDEO_V4L2
19 19
20source "drivers/media/video/gspca/m5602/Kconfig" 20source "drivers/media/video/gspca/m5602/Kconfig"
21source "drivers/media/video/gspca/stv06xx/Kconfig"
21 22
22config USB_GSPCA_CONEX 23config USB_GSPCA_CONEX
23 tristate "Conexant Camera Driver" 24 tristate "Conexant Camera Driver"
diff --git a/drivers/media/video/gspca/Makefile b/drivers/media/video/gspca/Makefile
index 6c8046e232c7..bd8d9ee40504 100644
--- a/drivers/media/video/gspca/Makefile
+++ b/drivers/media/video/gspca/Makefile
@@ -47,4 +47,4 @@ gspca_vc032x-objs := vc032x.o
47gspca_zc3xx-objs := zc3xx.o 47gspca_zc3xx-objs := zc3xx.o
48 48
49obj-$(CONFIG_USB_M5602) += m5602/ 49obj-$(CONFIG_USB_M5602) += m5602/
50 50obj-$(CONFIG_USB_STV06XX) += stv06xx/
diff --git a/drivers/media/video/gspca/stv06xx/Kconfig b/drivers/media/video/gspca/stv06xx/Kconfig
new file mode 100644
index 000000000000..634ad38d9fb8
--- /dev/null
+++ b/drivers/media/video/gspca/stv06xx/Kconfig
@@ -0,0 +1,9 @@
1config USB_STV06XX
2 tristate "STV06XX USB Camera Driver"
3 depends on USB_GSPCA
4 help
5 Say Y here if you want support for cameras based on
6 the ST STV06XX chip.
7
8 To compile this driver as a module, choose M here: the
9 module will be called gspca_stv06xx.
diff --git a/drivers/media/video/gspca/stv06xx/Makefile b/drivers/media/video/gspca/stv06xx/Makefile
new file mode 100644
index 000000000000..8f002b6233b2
--- /dev/null
+++ b/drivers/media/video/gspca/stv06xx/Makefile
@@ -0,0 +1,6 @@
1obj-$(CONFIG_USB_STV06XX) += gspca_stv06xx.o
2
3gspca_stv06xx-objs := stv06xx.o \
4 stv06xx_vv6410.o \
5 stv06xx_hdcs.o \
6 stv06xx_pb0100.o
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx.c b/drivers/media/video/gspca/stv06xx/stv06xx.c
new file mode 100644
index 000000000000..29e43718bfdf
--- /dev/null
+++ b/drivers/media/video/gspca/stv06xx/stv06xx.c
@@ -0,0 +1,522 @@
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_sensor.h"
31
32MODULE_AUTHOR("Erik Andrén");
33MODULE_DESCRIPTION("STV06XX USB Camera Driver");
34MODULE_LICENSE("GPL");
35
36int dump_bridge;
37int dump_sensor;
38
39int stv06xx_write_bridge(struct sd *sd, u16 address, u16 i2c_data)
40{
41 int err;
42 struct usb_device *udev = sd->gspca_dev.dev;
43 __u8 *buf = sd->gspca_dev.usb_buf;
44 u8 len = (i2c_data > 0xff) ? 2 : 1;
45
46 buf[0] = i2c_data & 0xff;
47 buf[1] = (i2c_data >> 8) & 0xff;
48
49 err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
50 0x04, 0x40, address, 0, buf, len,
51 STV06XX_URB_MSG_TIMEOUT);
52
53
54 PDEBUG(D_CONF, "Written 0x%x to address 0x%x, status: %d",
55 i2c_data, address, err);
56
57 return (err < 0) ? err : 0;
58}
59
60int stv06xx_read_bridge(struct sd *sd, u16 address, u8 *i2c_data)
61{
62 int err;
63 struct usb_device *udev = sd->gspca_dev.dev;
64 __u8 *buf = sd->gspca_dev.usb_buf;
65
66 err = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
67 0x04, 0xc0, address, 0, buf, 1,
68 STV06XX_URB_MSG_TIMEOUT);
69
70 *i2c_data = buf[0];
71
72 PDEBUG(D_CONF, "Read 0x%x from address 0x%x, status %d",
73 *i2c_data, address, err);
74
75 return (err < 0) ? err : 0;
76}
77
78/* Wraps the normal write sensor bytes / words functions for writing a
79 single value */
80int stv06xx_write_sensor(struct sd *sd, u8 address, u16 value)
81{
82 if (sd->sensor->i2c_len == 2) {
83 u16 data[2] = { address, value };
84 return stv06xx_write_sensor_words(sd, data, 1);
85 } else {
86 u8 data[2] = { address, value };
87 return stv06xx_write_sensor_bytes(sd, data, 1);
88 }
89}
90
91static int stv06xx_write_sensor_finish(struct sd *sd)
92{
93 int err = 0;
94
95 if (IS_850(sd)) {
96 struct usb_device *udev = sd->gspca_dev.dev;
97 __u8 *buf = sd->gspca_dev.usb_buf;
98
99 /* Quickam Web needs an extra packet */
100 buf[0] = 0;
101 err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
102 0x04, 0x40, 0x1704, 0, buf, 1,
103 STV06XX_URB_MSG_TIMEOUT);
104 }
105
106 return (err < 0) ? err : 0;
107}
108
109int stv06xx_write_sensor_bytes(struct sd *sd, const u8 *data, u8 len)
110{
111 int err, i, j;
112 struct usb_device *udev = sd->gspca_dev.dev;
113 __u8 *buf = sd->gspca_dev.usb_buf;
114
115 PDEBUG(D_USBO, "I2C: Command buffer contains %d entries", len);
116 for (i = 0; i < len;) {
117 /* Build the command buffer */
118 memset(buf, 0, I2C_BUFFER_LENGTH);
119 for (j = 0; j < I2C_MAX_BYTES && i < len; j++, i++) {
120 buf[j] = data[2*i];
121 buf[0x10 + j] = data[2*i+1];
122 PDEBUG(D_USBO, "I2C: Writing 0x%02x to reg 0x%02x",
123 data[2*i+1], data[2*i]);
124 }
125 buf[0x20] = sd->sensor->i2c_addr;
126 buf[0x21] = j - 1; /* Number of commands to send - 1 */
127 buf[0x22] = I2C_WRITE_CMD;
128 err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
129 0x04, 0x40, 0x0400, 0, buf,
130 I2C_BUFFER_LENGTH,
131 STV06XX_URB_MSG_TIMEOUT);
132 if (err < 0)
133 return err;
134 }
135 return stv06xx_write_sensor_finish(sd);
136}
137
138int stv06xx_write_sensor_words(struct sd *sd, const u16 *data, u8 len)
139{
140 int err, i, j;
141 struct usb_device *udev = sd->gspca_dev.dev;
142 __u8 *buf = sd->gspca_dev.usb_buf;
143
144 PDEBUG(D_USBO, "I2C: Command buffer contains %d entries", len);
145
146 for (i = 0; i < len;) {
147 /* Build the command buffer */
148 memset(buf, 0, I2C_BUFFER_LENGTH);
149 for (j = 0; j < I2C_MAX_WORDS && i < len; j++, i++) {
150 buf[j] = data[2*i];
151 buf[0x10 + j * 2] = data[2*i+1];
152 buf[0x10 + j * 2 + 1] = data[2*i+1] >> 8;
153 PDEBUG(D_USBO, "I2C: Writing 0x%04x to reg 0x%02x",
154 data[2*i+1], data[2*i]);
155 }
156 buf[0x20] = sd->sensor->i2c_addr;
157 buf[0x21] = j - 1; /* Number of commands to send - 1 */
158 buf[0x22] = I2C_WRITE_CMD;
159 err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
160 0x04, 0x40, 0x0400, 0, buf,
161 I2C_BUFFER_LENGTH,
162 STV06XX_URB_MSG_TIMEOUT);
163 if (err < 0)
164 return err;
165 }
166 return stv06xx_write_sensor_finish(sd);
167}
168
169int stv06xx_read_sensor(struct sd *sd, const u8 address, u16 *value)
170{
171 int err;
172 struct usb_device *udev = sd->gspca_dev.dev;
173 __u8 *buf = sd->gspca_dev.usb_buf;
174
175 err = stv06xx_write_bridge(sd, STV_I2C_FLUSH, sd->sensor->i2c_flush);
176 if (err < 0)
177 return err;
178
179 /* Clear mem */
180 memset(buf, 0, I2C_BUFFER_LENGTH);
181
182 buf[0] = address;
183 buf[0x20] = sd->sensor->i2c_addr;
184 buf[0x21] = 0;
185
186 /* Read I2C register */
187 buf[0x22] = I2C_READ_CMD;
188
189 err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
190 0x04, 0x40, 0x1400, 0, buf, I2C_BUFFER_LENGTH,
191 STV06XX_URB_MSG_TIMEOUT);
192 if (err < 0) {
193 PDEBUG(D_ERR, "I2C Read: error writing address: %d", err);
194 return err;
195 }
196
197 err = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
198 0x04, 0xc0, 0x1410, 0, buf, sd->sensor->i2c_len,
199 STV06XX_URB_MSG_TIMEOUT);
200 if (sd->sensor->i2c_len == 2)
201 *value = buf[0] | (buf[1] << 8);
202 else
203 *value = buf[0];
204
205 PDEBUG(D_USBO, "I2C: Read 0x%x from address 0x%x, status: %d",
206 *value, address, err);
207
208 return (err < 0) ? err : 0;
209}
210
211/* Dumps all bridge registers */
212static void stv06xx_dump_bridge(struct sd *sd)
213{
214 int i;
215 u8 data, buf;
216
217 info("Dumping all stv06xx bridge registers");
218 for (i = 0x1400; i < 0x160f; i++) {
219 stv06xx_read_bridge(sd, i, &data);
220
221 info("Read 0x%x from address 0x%x", data, i);
222 }
223
224 for (i = 0x1400; i < 0x160f; i++) {
225 stv06xx_read_bridge(sd, i, &data);
226 buf = data;
227
228 stv06xx_write_bridge(sd, i, 0xff);
229 stv06xx_read_bridge(sd, i, &data);
230 if (data == 0xff)
231 info("Register 0x%x is read/write", i);
232 else if (data != buf)
233 info("Register 0x%x is read/write,"
234 "but only partially", i);
235 else
236 info("Register 0x%x is read-only", i);
237
238 stv06xx_write_bridge(sd, i, buf);
239 }
240}
241
242/* this function is called at probe and resume time */
243static int stv06xx_init(struct gspca_dev *gspca_dev)
244{
245 struct sd *sd = (struct sd *) gspca_dev;
246 int err;
247
248 PDEBUG(D_PROBE, "Initializing camera");
249
250 /* Let the usb init settle for a bit
251 before performing the initialization */
252 msleep(250);
253
254 err = sd->sensor->init(sd);
255
256 if (dump_sensor)
257 sd->sensor->dump(sd);
258
259 return (err < 0) ? err : 0;
260}
261
262/* Start the camera */
263static int stv06xx_start(struct gspca_dev *gspca_dev)
264{
265 struct sd *sd = (struct sd *) gspca_dev;
266 int err;
267
268 /* Prepare the sensor for start */
269 err = sd->sensor->start(sd);
270 if (err < 0)
271 goto out;
272
273 /* Start isochronous streaming */
274 err = stv06xx_write_bridge(sd, STV_ISO_ENABLE, 1);
275
276out:
277 if (err < 0)
278 PDEBUG(D_STREAM, "Starting stream failed");
279 else
280 PDEBUG(D_STREAM, "Started streaming");
281
282 return (err < 0) ? err : 0;
283}
284
285static void stv06xx_stopN(struct gspca_dev *gspca_dev)
286{
287 int err;
288 struct sd *sd = (struct sd *) gspca_dev;
289
290 /* stop ISO-streaming */
291 err = stv06xx_write_bridge(sd, STV_ISO_ENABLE, 0);
292 if (err < 0)
293 goto out;
294
295 err = sd->sensor->stop(sd);
296 if (err < 0)
297 goto out;
298
299out:
300 if (err < 0)
301 PDEBUG(D_STREAM, "Failed to stop stream");
302 else
303 PDEBUG(D_STREAM, "Stopped streaming");
304}
305
306/*
307 * Analyse an USB packet of the data stream and store it appropriately.
308 * Each packet contains an integral number of chunks. Each chunk has
309 * 2-bytes identification, followed by 2-bytes that describe the chunk
310 * length. Known/guessed chunk identifications are:
311 * 8001/8005/C001/C005 - Begin new frame
312 * 8002/8006/C002/C006 - End frame
313 * 0200/4200 - Contains actual image data, bayer or compressed
314 * 0005 - 11 bytes of unknown data
315 * 0100 - 2 bytes of unknown data
316 * The 0005 and 0100 chunks seem to appear only in compressed stream.
317 */
318static void stv06xx_pkt_scan(struct gspca_dev *gspca_dev,
319 struct gspca_frame *frame, /* target */
320 __u8 *data, /* isoc packet */
321 int len) /* iso packet length */
322{
323 PDEBUG(D_PACK, "Packet of length %d arrived", len);
324
325 /* A packet may contain several frames
326 loop until the whole packet is reached */
327 while (len) {
328 int id, chunk_len;
329
330 if (len < 4) {
331 PDEBUG(D_PACK, "Packet is smaller than 4 bytes");
332 return;
333 }
334
335 /* Capture the id */
336 id = (data[0] << 8) | data[1];
337
338 /* Capture the chunk length */
339 chunk_len = (data[2] << 8) | data[3];
340 PDEBUG(D_PACK, "Chunk id: %x, length: %d", id, chunk_len);
341
342 data += 4;
343 len -= 4;
344
345 if (len < chunk_len) {
346 PDEBUG(D_ERR, "URB packet length is smaller"
347 " than the specified chunk length");
348 return;
349 }
350
351 switch (id) {
352 case 0x0200:
353 case 0x4200:
354 PDEBUG(D_PACK, "Frame data packet detected");
355
356 gspca_frame_add(gspca_dev, INTER_PACKET, frame,
357 data, chunk_len);
358 break;
359
360 case 0x8001:
361 case 0x8005:
362 case 0xc001:
363 case 0xc005:
364 PDEBUG(D_PACK, "Starting new frame");
365
366 /* Create a new frame, chunk length should be zero */
367 gspca_frame_add(gspca_dev, FIRST_PACKET,
368 frame, data, 0);
369
370 if (chunk_len)
371 PDEBUG(D_ERR, "Chunk length is "
372 "non-zero on a SOF");
373 break;
374
375 case 0x8002:
376 case 0x8006:
377 case 0xc002:
378 PDEBUG(D_PACK, "End of frame detected");
379
380 /* Complete the last frame (if any) */
381 gspca_frame_add(gspca_dev, LAST_PACKET, frame, data, 0);
382
383 if (chunk_len)
384 PDEBUG(D_ERR, "Chunk length is "
385 "non-zero on a EOF");
386 break;
387
388 case 0x0005:
389 PDEBUG(D_PACK, "Chunk 0x005 detected");
390 /* Unknown chunk with 11 bytes of data,
391 occurs just before end of each frame
392 in compressed mode */
393 break;
394
395 case 0x0100:
396 PDEBUG(D_PACK, "Chunk 0x0100 detected");
397 /* Unknown chunk with 2 bytes of data,
398 occurs 2-3 times per USB interrupt */
399 break;
400 default:
401 PDEBUG(D_PACK, "Unknown chunk %d detected", id);
402 /* Unknown chunk */
403 }
404 data += chunk_len;
405 len -= chunk_len;
406 }
407}
408
409static int stv06xx_config(struct gspca_dev *gspca_dev,
410 const struct usb_device_id *id);
411
412/* sub-driver description */
413static const struct sd_desc sd_desc = {
414 .name = MODULE_NAME,
415 .config = stv06xx_config,
416 .init = stv06xx_init,
417 .start = stv06xx_start,
418 .stopN = stv06xx_stopN,
419 .pkt_scan = stv06xx_pkt_scan
420};
421
422/* This function is called at probe time */
423static int stv06xx_config(struct gspca_dev *gspca_dev,
424 const struct usb_device_id *id)
425{
426 struct sd *sd = (struct sd *) gspca_dev;
427 struct cam *cam;
428
429 PDEBUG(D_PROBE, "Configuring camera");
430
431 cam = &gspca_dev->cam;
432 cam->epaddr = STV_ISOC_ENDPOINT_ADDR;
433 sd->desc = sd_desc;
434 gspca_dev->sd_desc = &sd->desc;
435
436 if (dump_bridge)
437 stv06xx_dump_bridge(sd);
438
439 sd->sensor = &stv06xx_sensor_vv6410;
440 if (!sd->sensor->probe(sd))
441 return 0;
442
443 sd->sensor = &stv06xx_sensor_hdcs1x00;
444 if (!sd->sensor->probe(sd))
445 return 0;
446
447 sd->sensor = &stv06xx_sensor_hdcs1020;
448 if (!sd->sensor->probe(sd))
449 return 0;
450
451 sd->sensor = &stv06xx_sensor_pb0100;
452 if (!sd->sensor->probe(sd))
453 return 0;
454
455 sd->sensor = NULL;
456 return -ENODEV;
457}
458
459
460
461/* -- module initialisation -- */
462static const __devinitdata struct usb_device_id device_table[] = {
463 {USB_DEVICE(0x046d, 0x0840)}, /* QuickCam Express */
464 {USB_DEVICE(0x046d, 0x0850)}, /* LEGO cam / QuickCam Web */
465 {USB_DEVICE(0x046d, 0x0870)}, /* Dexxa WebCam USB */
466 {}
467};
468MODULE_DEVICE_TABLE(usb, device_table);
469
470/* -- device connect -- */
471static int sd_probe(struct usb_interface *intf,
472 const struct usb_device_id *id)
473{
474 PDEBUG(D_PROBE, "Probing for a stv06xx device");
475 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
476 THIS_MODULE);
477}
478
479void sd_disconnect(struct usb_interface *intf)
480{
481 struct gspca_dev *gspca_dev = usb_get_intfdata(intf);
482 struct sd *sd = (struct sd *) gspca_dev;
483 PDEBUG(D_PROBE, "Disconnecting the stv06xx device");
484
485 if (sd->sensor->disconnect)
486 sd->sensor->disconnect(sd);
487 gspca_disconnect(intf);
488}
489
490static struct usb_driver sd_driver = {
491 .name = MODULE_NAME,
492 .id_table = device_table,
493 .probe = sd_probe,
494 .disconnect = sd_disconnect,
495#ifdef CONFIG_PM
496 .suspend = gspca_suspend,
497 .resume = gspca_resume,
498#endif
499};
500
501/* -- module insert / remove -- */
502static int __init sd_mod_init(void)
503{
504 if (usb_register(&sd_driver) < 0)
505 return -1;
506 PDEBUG(D_PROBE, "registered");
507 return 0;
508}
509static void __exit sd_mod_exit(void)
510{
511 usb_deregister(&sd_driver);
512 PDEBUG(D_PROBE, "deregistered");
513}
514
515module_init(sd_mod_init);
516module_exit(sd_mod_exit);
517
518module_param(dump_bridge, bool, S_IRUGO | S_IWUSR);
519MODULE_PARM_DESC(dump_bridge, "Dumps all usb bridge registers at startup");
520
521module_param(dump_sensor, bool, S_IRUGO | S_IWUSR);
522MODULE_PARM_DESC(dump_sensor, "Dumps all sensor registers at startup");
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx.h b/drivers/media/video/gspca/stv06xx/stv06xx.h
new file mode 100644
index 000000000000..1207e7d17f14
--- /dev/null
+++ b/drivers/media/video/gspca/stv06xx/stv06xx.h
@@ -0,0 +1,107 @@
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#ifndef STV06XX_H_
31#define STV06XX_H_
32
33#include "gspca.h"
34
35#define MODULE_NAME "STV06xx"
36
37#define STV_ISOC_ENDPOINT_ADDR 0x81
38
39#ifndef V4L2_PIX_FMT_SGRBG8
40#define V4L2_PIX_FMT_SGRBG8 v4l2_fourcc('G', 'R', 'B', 'G')
41#endif
42
43#define STV_REG23 0x0423
44
45/* Control registers of the STV0600 ASIC */
46#define STV_I2C_PARTNER 0x1420
47#define STV_I2C_VAL_REG_VAL_PAIRS_MIN1 0x1421
48#define STV_I2C_READ_WRITE_TOGGLE 0x1422
49#define STV_I2C_FLUSH 0x1423
50#define STV_I2C_SUCC_READ_REG_VALS 0x1424
51
52#define STV_ISO_ENABLE 0x1440
53#define STV_SCAN_RATE 0x1443
54#define STV_LED_CTRL 0x1445
55#define STV_STV0600_EMULATION 0x1446
56#define STV_REG00 0x1500
57#define STV_REG01 0x1501
58#define STV_REG02 0x1502
59#define STV_REG03 0x1503
60#define STV_REG04 0x1504
61
62#define STV_ISO_SIZE_L 0x15c1
63#define STV_ISO_SIZE_H 0x15c2
64
65/* Refers to the CIF 352x288 and QCIF 176x144 */
66/* 1: 288 lines, 2: 144 lines */
67#define STV_Y_CTRL 0x15c3
68
69/* 0xa: 352 columns, 0x6: 176 columns */
70#define STV_X_CTRL 0x1680
71
72#define STV06XX_URB_MSG_TIMEOUT 5000
73
74#define I2C_MAX_BYTES 16
75#define I2C_MAX_WORDS 8
76
77#define I2C_BUFFER_LENGTH 0x23
78#define I2C_READ_CMD 3
79#define I2C_WRITE_CMD 1
80
81#define LED_ON 1
82#define LED_OFF 0
83
84/* STV06xx device descriptor */
85struct sd {
86 struct gspca_dev gspca_dev;
87
88 /* A pointer to the currently connected sensor */
89 const struct stv06xx_sensor *sensor;
90
91 /* A pointer to the sd_desc struct */
92 struct sd_desc desc;
93
94 /* Sensor private data */
95 void *sensor_priv;
96};
97
98int stv06xx_write_bridge(struct sd *sd, u16 address, u16 i2c_data);
99int stv06xx_read_bridge(struct sd *sd, u16 address, u8 *i2c_data);
100
101int stv06xx_write_sensor_bytes(struct sd *sd, const u8 *data, u8 len);
102int stv06xx_write_sensor_words(struct sd *sd, const u16 *data, u8 len);
103
104int stv06xx_read_sensor(struct sd *sd, const u8 address, u16 *value);
105int stv06xx_write_sensor(struct sd *sd, u8 address, u16 value);
106
107#endif
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c
new file mode 100644
index 000000000000..1cfe58504553
--- /dev/null
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c
@@ -0,0 +1,533 @@
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 * Copyright (c) 2008 Chia-I Wu
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 * P/N 861037: Sensor HDCS1000 ASIC STV0600
23 * P/N 861050-0010: Sensor HDCS1000 ASIC STV0600
24 * P/N 861050-0020: Sensor Photobit PB100 ASIC STV0600-1 - QuickCam Express
25 * P/N 861055: Sensor ST VV6410 ASIC STV0610 - LEGO cam
26 * P/N 861075-0040: Sensor HDCS1000 ASIC
27 * P/N 961179-0700: Sensor ST VV6410 ASIC STV0602 - Dexxa WebCam USB
28 * P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web
29 */
30
31#include "stv06xx_hdcs.h"
32
33enum hdcs_power_state {
34 HDCS_STATE_SLEEP,
35 HDCS_STATE_IDLE,
36 HDCS_STATE_RUN
37};
38
39/* no lock? */
40struct hdcs {
41 enum hdcs_power_state state;
42 int w, h;
43
44 /* visible area of the sensor array */
45 struct {
46 int left, top;
47 int width, height;
48 int border;
49 } array;
50
51 struct {
52 /* Column timing overhead */
53 u8 cto;
54 /* Column processing overhead */
55 u8 cpo;
56 /* Row sample period constant */
57 u16 rs;
58 /* Exposure reset duration */
59 u16 er;
60 } exp;
61
62 int psmp;
63};
64
65static int hdcs_reg_write_seq(struct sd *sd, u8 reg, u8 *vals, u8 len)
66{
67 u8 regs[I2C_MAX_BYTES * 2];
68 int i;
69
70 if (unlikely((len <= 0) || (len >= I2C_MAX_BYTES) ||
71 (reg + len > 0xff)))
72 return -EINVAL;
73
74 for (i = 0; i < len; i++, reg++) {
75 regs[2*i] = reg;
76 regs[2*i+1] = vals[i];
77 }
78
79 return stv06xx_write_sensor_bytes(sd, regs, len);
80}
81
82static int hdcs_set_state(struct sd *sd, enum hdcs_power_state state)
83{
84 struct hdcs *hdcs = sd->sensor_priv;
85 u8 val;
86 int ret;
87
88 if (hdcs->state == state)
89 return 0;
90
91 /* we need to go idle before running or sleeping */
92 if (hdcs->state != HDCS_STATE_IDLE) {
93 ret = stv06xx_write_sensor(sd, HDCS_REG_CONTROL(sd), 0);
94 if (ret)
95 return ret;
96 }
97
98 hdcs->state = HDCS_STATE_IDLE;
99
100 if (state == HDCS_STATE_IDLE)
101 return 0;
102
103 switch (state) {
104 case HDCS_STATE_SLEEP:
105 val = HDCS_SLEEP_MODE;
106 break;
107
108 case HDCS_STATE_RUN:
109 val = HDCS_RUN_ENABLE;
110 break;
111
112 default:
113 return -EINVAL;
114 }
115
116 ret = stv06xx_write_sensor(sd, HDCS_REG_CONTROL(sd), val);
117 if (ret < 0)
118 hdcs->state = state;
119
120 return ret;
121}
122
123static int hdcs_reset(struct sd *sd)
124{
125 struct hdcs *hdcs = sd->sensor_priv;
126 int err;
127
128 err = stv06xx_write_sensor(sd, HDCS_REG_CONTROL(sd), 1);
129 if (err < 0)
130 return err;
131
132 err = stv06xx_write_sensor(sd, HDCS_REG_CONTROL(sd), 0);
133 if (err < 0)
134 hdcs->state = HDCS_STATE_IDLE;
135
136 return err;
137}
138
139static int hdcs_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
140{
141 struct sd *sd = (struct sd *) gspca_dev;
142 struct hdcs *hdcs = sd->sensor_priv;
143
144 /* Column time period */
145 int ct;
146 /* Column processing period */
147 int cp;
148 /* Row processing period */
149 int rp;
150 int cycles;
151 int err;
152 int rowexp;
153 u16 data[2];
154
155 err = stv06xx_read_sensor(sd, HDCS_ROWEXPL, &data[0]);
156 if (err < 0)
157 return err;
158
159 err = stv06xx_read_sensor(sd, HDCS_ROWEXPH, &data[1]);
160 if (err < 0)
161 return err;
162
163 rowexp = (data[1] << 8) | data[0];
164
165 ct = hdcs->exp.cto + hdcs->psmp + (HDCS_ADC_START_SIG_DUR + 2);
166 cp = hdcs->exp.cto + (hdcs->w * ct / 2);
167 rp = hdcs->exp.rs + cp;
168
169 cycles = rp * rowexp;
170 *val = cycles / HDCS_CLK_FREQ_MHZ;
171 PDEBUG(D_V4L2, "Read exposure %d", *val);
172 return 0;
173}
174
175static int hdcs_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
176{
177 struct sd *sd = (struct sd *) gspca_dev;
178 struct hdcs *hdcs = sd->sensor_priv;
179 int rowexp, srowexp;
180 int max_srowexp;
181 /* Column time period */
182 int ct;
183 /* Column processing period */
184 int cp;
185 /* Row processing period */
186 int rp;
187 /* Minimum number of column timing periods
188 within the column processing period */
189 int mnct;
190 int cycles, err;
191 u8 exp[4];
192
193 cycles = val * HDCS_CLK_FREQ_MHZ;
194
195 ct = hdcs->exp.cto + hdcs->psmp + (HDCS_ADC_START_SIG_DUR + 2);
196 cp = hdcs->exp.cto + (hdcs->w * ct / 2);
197
198 /* the cycles one row takes */
199 rp = hdcs->exp.rs + cp;
200
201 rowexp = cycles / rp;
202
203 /* the remaining cycles */
204 cycles -= rowexp * rp;
205
206 /* calculate sub-row exposure */
207 if (IS_1020(sd)) {
208 /* see HDCS-1020 datasheet 3.5.6.4, p. 63 */
209 srowexp = hdcs->w - (cycles + hdcs->exp.er + 13) / ct;
210
211 mnct = (hdcs->exp.er + 12 + ct - 1) / ct;
212 max_srowexp = hdcs->w - mnct;
213 } else {
214 /* see HDCS-1000 datasheet 3.4.5.5, p. 61 */
215 srowexp = cp - hdcs->exp.er - 6 - cycles;
216
217 mnct = (hdcs->exp.er + 5 + ct - 1) / ct;
218 max_srowexp = cp - mnct * ct - 1;
219 }
220
221 if (srowexp < 0)
222 srowexp = 0;
223 else if (srowexp > max_srowexp)
224 srowexp = max_srowexp;
225
226 if (IS_1020(sd)) {
227 exp[0] = rowexp & 0xff;
228 exp[1] = rowexp >> 8;
229 exp[2] = (srowexp >> 2) & 0xff;
230 /* this clears exposure error flag */
231 exp[3] = 0x1;
232 err = hdcs_reg_write_seq(sd, HDCS_ROWEXPL, exp, 4);
233 } else {
234 exp[0] = rowexp & 0xff;
235 exp[1] = rowexp >> 8;
236 exp[2] = srowexp & 0xff;
237 exp[3] = srowexp >> 8;
238 err = hdcs_reg_write_seq(sd, HDCS_ROWEXPL, exp, 4);
239 if (err < 0)
240 return err;
241
242 /* clear exposure error flag */
243 err = stv06xx_write_sensor(sd,
244 HDCS_STATUS, BIT(4));
245 }
246 PDEBUG(D_V4L2, "Writing exposure %d, rowexp %d, srowexp %d",
247 val, rowexp, srowexp);
248 return err;
249}
250
251static int hdcs_set_gains(struct sd *sd, u8 r, u8 g, u8 b)
252{
253 u8 gains[4];
254
255 /* the voltage gain Av = (1 + 19 * val / 127) * (1 + bit7) */
256 if (r > 127)
257 r = 0x80 | (r / 2);
258 if (g > 127)
259 g = 0x80 | (g / 2);
260 if (b > 127)
261 b = 0x80 | (b / 2);
262
263 gains[0] = g;
264 gains[1] = r;
265 gains[2] = b;
266 gains[3] = g;
267
268 return hdcs_reg_write_seq(sd, HDCS_ERECPGA, gains, 4);
269}
270
271static int hdcs_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
272{
273 struct sd *sd = (struct sd *) gspca_dev;
274 int err;
275 u16 data;
276
277 err = stv06xx_read_sensor(sd, HDCS_ERECPGA, &data);
278
279 /* Bit 7 doubles the gain */
280 if (data & 0x80)
281 *val = (data & 0x7f) * 2;
282 else
283 *val = data;
284
285 PDEBUG(D_V4L2, "Read gain %d", *val);
286 return err;
287}
288
289static int hdcs_set_gain(struct gspca_dev *gspca_dev, __s32 val)
290{
291 PDEBUG(D_V4L2, "Writing gain %d", val);
292 return hdcs_set_gains((struct sd *) gspca_dev,
293 val & 0xff, val & 0xff, val & 0xff);
294}
295
296static int hdcs_set_size(struct sd *sd,
297 unsigned int width, unsigned int height)
298{
299 struct hdcs *hdcs = sd->sensor_priv;
300 u8 win[4];
301 unsigned int x, y;
302 int err;
303
304 /* must be multiple of 4 */
305 width = (width + 3) & ~0x3;
306 height = (height + 3) & ~0x3;
307
308 if (width > hdcs->array.width)
309 width = hdcs->array.width;
310
311 if (IS_1020(sd)) {
312 /* the borders are also invalid */
313 if (height + 2 * hdcs->array.border + HDCS_1020_BOTTOM_Y_SKIP
314 > hdcs->array.height)
315 height = hdcs->array.height - 2 * hdcs->array.border -
316 HDCS_1020_BOTTOM_Y_SKIP;
317
318 y = (hdcs->array.height - HDCS_1020_BOTTOM_Y_SKIP - height) / 2
319 + hdcs->array.top;
320 } else if (height > hdcs->array.height) {
321 height = hdcs->array.height;
322 y = hdcs->array.top + (hdcs->array.height - height) / 2;
323 }
324
325 x = hdcs->array.left + (hdcs->array.width - width) / 2;
326
327 win[0] = y / 4;
328 win[1] = x / 4;
329 win[2] = (y + height) / 4 - 1;
330 win[3] = (x + width) / 4 - 1;
331
332 err = hdcs_reg_write_seq(sd, HDCS_FWROW, win, 4);
333 if (err < 0)
334 return err;
335
336 /* Update the current width and height */
337 hdcs->w = width;
338 hdcs->h = height;
339 return err;
340}
341
342static int hdcs_probe_1x00(struct sd *sd)
343{
344 struct hdcs *hdcs;
345 u16 sensor;
346 int ret;
347
348 ret = stv06xx_read_sensor(sd, HDCS_IDENT, &sensor);
349 if (ret < 0 || sensor != 0x08)
350 return -ENODEV;
351
352 info("HDCS-1000/1100 sensor detected");
353
354 sd->gspca_dev.cam.cam_mode = stv06xx_sensor_hdcs1x00.modes;
355 sd->gspca_dev.cam.nmodes = stv06xx_sensor_hdcs1x00.nmodes;
356 sd->desc.ctrls = stv06xx_sensor_hdcs1x00.ctrls;
357 sd->desc.nctrls = stv06xx_sensor_hdcs1x00.nctrls;
358
359 hdcs = kmalloc(sizeof(struct hdcs), GFP_KERNEL);
360 if (!hdcs)
361 return -ENOMEM;
362
363 hdcs->array.left = 8;
364 hdcs->array.top = 8;
365 hdcs->array.width = HDCS_1X00_DEF_WIDTH;
366 hdcs->array.height = HDCS_1X00_DEF_HEIGHT;
367 hdcs->array.border = 4;
368
369 hdcs->exp.cto = 4;
370 hdcs->exp.cpo = 2;
371 hdcs->exp.rs = 186;
372 hdcs->exp.er = 100;
373
374 /*
375 * Frame rate on HDCS-1000 0x46D:0x840 depends on PSMP:
376 * 4 = doesn't work at all
377 * 5 = 7.8 fps,
378 * 6 = 6.9 fps,
379 * 8 = 6.3 fps,
380 * 10 = 5.5 fps,
381 * 15 = 4.4 fps,
382 * 31 = 2.8 fps
383 *
384 * Frame rate on HDCS-1000 0x46D:0x870 depends on PSMP:
385 * 15 = doesn't work at all
386 * 18 = doesn't work at all
387 * 19 = 7.3 fps
388 * 20 = 7.4 fps
389 * 21 = 7.4 fps
390 * 22 = 7.4 fps
391 * 24 = 6.3 fps
392 * 30 = 5.4 fps
393 */
394 hdcs->psmp = IS_870(sd) ? 20 : 5;
395
396 sd->sensor_priv = hdcs;
397
398 return 0;
399}
400
401static int hdcs_probe_1020(struct sd *sd)
402{
403 struct hdcs *hdcs;
404 u16 sensor;
405 int ret;
406
407 ret = stv06xx_read_sensor(sd, HDCS_IDENT, &sensor);
408 if (ret < 0 || sensor != 0x10)
409 return -ENODEV;
410
411 info("HDCS-1020 sensor detected");
412
413 sd->gspca_dev.cam.cam_mode = stv06xx_sensor_hdcs1020.modes;
414 sd->gspca_dev.cam.nmodes = stv06xx_sensor_hdcs1020.nmodes;
415 sd->desc.ctrls = stv06xx_sensor_hdcs1020.ctrls;
416 sd->desc.nctrls = stv06xx_sensor_hdcs1020.nctrls;
417
418 hdcs = kmalloc(sizeof(struct hdcs), GFP_KERNEL);
419 if (!hdcs)
420 return -ENOMEM;
421
422 /*
423 * From Andrey's test image: looks like HDCS-1020 upper-left
424 * visible pixel is at 24,8 (y maybe even smaller?) and lower-right
425 * visible pixel at 375,299 (x maybe even larger?)
426 */
427 hdcs->array.left = 24;
428 hdcs->array.top = 4;
429 hdcs->array.width = HDCS_1020_DEF_WIDTH;
430 hdcs->array.height = 304;
431 hdcs->array.border = 4;
432
433 hdcs->psmp = 6;
434
435 hdcs->exp.cto = 3;
436 hdcs->exp.cpo = 3;
437 hdcs->exp.rs = 155;
438 hdcs->exp.er = 96;
439
440 sd->sensor_priv = hdcs;
441
442 return 0;
443}
444
445static int hdcs_start(struct sd *sd)
446{
447 PDEBUG(D_STREAM, "Starting stream");
448
449 return hdcs_set_state(sd, HDCS_STATE_RUN);
450}
451
452static int hdcs_stop(struct sd *sd)
453{
454 PDEBUG(D_STREAM, "Halting stream");
455
456 return hdcs_set_state(sd, HDCS_STATE_SLEEP);
457}
458
459static void hdcs_disconnect(struct sd *sd)
460{
461 PDEBUG(D_PROBE, "Disconnecting the sensor");
462 kfree(sd->sensor_priv);
463}
464
465static int hdcs_init(struct sd *sd)
466{
467 struct hdcs *hdcs = sd->sensor_priv;
468 int i, err = 0;
469
470 /* Set the STV0602AA in STV0600 emulation mode */
471 if (IS_870(sd))
472 stv06xx_write_bridge(sd, STV_STV0600_EMULATION, 1);
473
474 /* Execute the bridge init */
475 for (i = 0; i < ARRAY_SIZE(stv_bridge_init) && !err; i++) {
476 err = stv06xx_write_bridge(sd, stv_bridge_init[i][0],
477 stv_bridge_init[i][1]);
478 }
479 if (err < 0)
480 return err;
481
482 /* sensor soft reset */
483 hdcs_reset(sd);
484
485 /* Execute the sensor init */
486 for (i = 0; i < ARRAY_SIZE(stv_sensor_init) && !err; i++) {
487 err = stv06xx_write_sensor(sd, stv_sensor_init[i][0],
488 stv_sensor_init[i][1]);
489 }
490 if (err < 0)
491 return err;
492
493 /* Enable continous frame capture, bit 2: stop when frame complete */
494 err = stv06xx_write_sensor(sd, HDCS_REG_CONFIG(sd), BIT(3));
495 if (err < 0)
496 return err;
497
498 /* Set PGA sample duration
499 (was 0x7E for IS_870, but caused slow framerate with HDCS-1020) */
500 if (IS_1020(sd))
501 err = stv06xx_write_sensor(sd, HDCS_TCTRL,
502 (HDCS_ADC_START_SIG_DUR << 6) | hdcs->psmp);
503 else
504 err = stv06xx_write_sensor(sd, HDCS_TCTRL,
505 (HDCS_ADC_START_SIG_DUR << 5) | hdcs->psmp);
506 if (err < 0)
507 return err;
508
509 err = hdcs_set_gains(sd, HDCS_DEFAULT_GAIN, HDCS_DEFAULT_GAIN,
510 HDCS_DEFAULT_GAIN);
511 if (err < 0)
512 return err;
513
514 err = hdcs_set_exposure(&sd->gspca_dev, HDCS_DEFAULT_EXPOSURE);
515 if (err < 0)
516 return err;
517
518 err = hdcs_set_size(sd, hdcs->array.width, hdcs->array.height);
519 return err;
520}
521
522static int hdcs_dump(struct sd *sd)
523{
524 u16 reg, val;
525
526 info("Dumping sensor registers:");
527
528 for (reg = HDCS_IDENT; reg <= HDCS_ROWEXPH; reg++) {
529 stv06xx_read_sensor(sd, reg, &val);
530 info("reg 0x%02x = 0x%02x", reg, val);
531 }
532 return 0;
533}
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h
new file mode 100644
index 000000000000..9c7279a4cd88
--- /dev/null
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h
@@ -0,0 +1,263 @@
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 * Copyright (c) 2008 Chia-I Wu
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 * P/N 861037: Sensor HDCS1000 ASIC STV0600
23 * P/N 861050-0010: Sensor HDCS1000 ASIC STV0600
24 * P/N 861050-0020: Sensor Photobit PB100 ASIC STV0600-1 - QuickCam Express
25 * P/N 861055: Sensor ST VV6410 ASIC STV0610 - LEGO cam
26 * P/N 861075-0040: Sensor HDCS1000 ASIC
27 * P/N 961179-0700: Sensor ST VV6410 ASIC STV0602 - Dexxa WebCam USB
28 * P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web
29 */
30
31#ifndef STV06XX_HDCS_H_
32#define STV06XX_HDCS_H_
33
34#include "stv06xx_sensor.h"
35
36#define HDCS_REG_CONFIG(sd) (IS_1020(sd) ? HDCS20_CONFIG : HDCS00_CONFIG)
37#define HDCS_REG_CONTROL(sd) (IS_1020(sd) ? HDCS20_CONTROL : HDCS00_CONTROL)
38
39#define HDCS_1X00_DEF_WIDTH 360
40#define HDCS_1X00_DEF_HEIGHT 296
41
42#define HDCS_1020_DEF_WIDTH 352
43#define HDCS_1020_DEF_HEIGHT 292
44
45#define HDCS_1020_BOTTOM_Y_SKIP 4
46
47#define HDCS_CLK_FREQ_MHZ 25
48
49#define HDCS_ADC_START_SIG_DUR 3
50
51/* LSB bit of I2C or register address signifies write (0) or read (1) */
52/* I2C Registers common for both HDCS-1000/1100 and HDCS-1020 */
53/* Identifications Register */
54#define HDCS_IDENT (0x00 << 1)
55/* Status Register */
56#define HDCS_STATUS (0x01 << 1)
57/* Interrupt Mask Register */
58#define HDCS_IMASK (0x02 << 1)
59/* Pad Control Register */
60#define HDCS_PCTRL (0x03 << 1)
61/* Pad Drive Control Register */
62#define HDCS_PDRV (0x04 << 1)
63/* Interface Control Register */
64#define HDCS_ICTRL (0x05 << 1)
65/* Interface Timing Register */
66#define HDCS_ITMG (0x06 << 1)
67/* Baud Fraction Register */
68#define HDCS_BFRAC (0x07 << 1)
69/* Baud Rate Register */
70#define HDCS_BRATE (0x08 << 1)
71/* ADC Control Register */
72#define HDCS_ADCCTRL (0x09 << 1)
73/* First Window Row Register */
74#define HDCS_FWROW (0x0a << 1)
75/* First Window Column Register */
76#define HDCS_FWCOL (0x0b << 1)
77/* Last Window Row Register */
78#define HDCS_LWROW (0x0c << 1)
79/* Last Window Column Register */
80#define HDCS_LWCOL (0x0d << 1)
81/* Timing Control Register */
82#define HDCS_TCTRL (0x0e << 1)
83/* PGA Gain Register: Even Row, Even Column */
84#define HDCS_ERECPGA (0x0f << 1)
85/* PGA Gain Register: Even Row, Odd Column */
86#define HDCS_EROCPGA (0x10 << 1)
87/* PGA Gain Register: Odd Row, Even Column */
88#define HDCS_ORECPGA (0x11 << 1)
89/* PGA Gain Register: Odd Row, Odd Column */
90#define HDCS_OROCPGA (0x12 << 1)
91/* Row Exposure Low Register */
92#define HDCS_ROWEXPL (0x13 << 1)
93/* Row Exposure High Register */
94#define HDCS_ROWEXPH (0x14 << 1)
95
96/* I2C Registers only for HDCS-1000/1100 */
97/* Sub-Row Exposure Low Register */
98#define HDCS00_SROWEXPL (0x15 << 1)
99/* Sub-Row Exposure High Register */
100#define HDCS00_SROWEXPH (0x16 << 1)
101/* Configuration Register */
102#define HDCS00_CONFIG (0x17 << 1)
103/* Control Register */
104#define HDCS00_CONTROL (0x18 << 1)
105
106/* I2C Registers only for HDCS-1020 */
107/* Sub-Row Exposure Register */
108#define HDCS20_SROWEXP (0x15 << 1)
109/* Error Control Register */
110#define HDCS20_ERROR (0x16 << 1)
111/* Interface Timing 2 Register */
112#define HDCS20_ITMG2 (0x17 << 1)
113/* Interface Control 2 Register */
114#define HDCS20_ICTRL2 (0x18 << 1)
115/* Horizontal Blank Register */
116#define HDCS20_HBLANK (0x19 << 1)
117/* Vertical Blank Register */
118#define HDCS20_VBLANK (0x1a << 1)
119/* Configuration Register */
120#define HDCS20_CONFIG (0x1b << 1)
121/* Control Register */
122#define HDCS20_CONTROL (0x1c << 1)
123
124#define HDCS_RUN_ENABLE (1 << 2)
125#define HDCS_SLEEP_MODE (1 << 1)
126
127#define HDCS_DEFAULT_EXPOSURE 5000
128#define HDCS_DEFAULT_GAIN 128
129
130static int hdcs_probe_1x00(struct sd *sd);
131static int hdcs_probe_1020(struct sd *sd);
132static int hdcs_start(struct sd *sd);
133static int hdcs_init(struct sd *sd);
134static int hdcs_stop(struct sd *sd);
135static int hdcs_dump(struct sd *sd);
136static void hdcs_disconnect(struct sd *sd);
137
138static int hdcs_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
139static int hdcs_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
140static int hdcs_set_gain(struct gspca_dev *gspca_dev, __s32 val);
141static int hdcs_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
142
143const struct stv06xx_sensor stv06xx_sensor_hdcs1x00 = {
144 .name = "HP HDCS-1000/1100",
145 .i2c_flush = 0,
146 .i2c_addr = (0x55 << 1),
147 .i2c_len = 1,
148
149 .init = hdcs_init,
150 .probe = hdcs_probe_1x00,
151 .start = hdcs_start,
152 .stop = hdcs_stop,
153 .disconnect = hdcs_disconnect,
154 .dump = hdcs_dump,
155
156 .nctrls = 2,
157 .ctrls = {
158 {
159 {
160 .id = V4L2_CID_EXPOSURE,
161 .type = V4L2_CTRL_TYPE_INTEGER,
162 .name = "exposure",
163 .minimum = 0x00,
164 .maximum = 0xffff,
165 .step = 0x1,
166 .default_value = HDCS_DEFAULT_EXPOSURE,
167 .flags = V4L2_CTRL_FLAG_SLIDER
168 },
169 .set = hdcs_set_exposure,
170 .get = hdcs_get_exposure
171 },
172 {
173 {
174 .id = V4L2_CID_GAIN,
175 .type = V4L2_CTRL_TYPE_INTEGER,
176 .name = "gain",
177 .minimum = 0x00,
178 .maximum = 0xff,
179 .step = 0x1,
180 .default_value = HDCS_DEFAULT_GAIN,
181 .flags = V4L2_CTRL_FLAG_SLIDER
182 },
183 .set = hdcs_set_gain,
184 .get = hdcs_get_gain
185 }
186 },
187
188 .nmodes = 1,
189 .modes = {
190 {
191 HDCS_1X00_DEF_WIDTH,
192 HDCS_1X00_DEF_HEIGHT,
193 V4L2_PIX_FMT_SBGGR8,
194 V4L2_FIELD_NONE,
195 .sizeimage =
196 HDCS_1X00_DEF_WIDTH * HDCS_1X00_DEF_HEIGHT,
197 .bytesperline = HDCS_1X00_DEF_WIDTH,
198 .colorspace = V4L2_COLORSPACE_SRGB,
199 .priv = 1
200 }
201 }
202};
203
204const struct stv06xx_sensor stv06xx_sensor_hdcs1020 = {
205 .name = "HDCS-1020",
206 .i2c_flush = 0,
207 .i2c_addr = (0x55 << 1),
208 .i2c_len = 1,
209
210 .nctrls = 0,
211 .ctrls = {},
212
213 .init = hdcs_init,
214 .probe = hdcs_probe_1020,
215 .start = hdcs_start,
216 .stop = hdcs_stop,
217 .dump = hdcs_dump,
218
219 .nmodes = 1,
220 .modes = {
221 {
222 HDCS_1020_DEF_WIDTH,
223 HDCS_1020_DEF_HEIGHT,
224 V4L2_PIX_FMT_SBGGR8,
225 V4L2_FIELD_NONE,
226 .sizeimage =
227 HDCS_1020_DEF_WIDTH * HDCS_1020_DEF_HEIGHT,
228 .bytesperline = HDCS_1020_DEF_WIDTH,
229 .colorspace = V4L2_COLORSPACE_SRGB,
230 .priv = 1
231 }
232 }
233};
234
235static const u16 stv_bridge_init[][2] = {
236 {STV_ISO_ENABLE, 0},
237 {STV_REG23, 0},
238 {STV_REG00, 0x1d},
239 {STV_REG01, 0xb5},
240 {STV_REG02, 0xa8},
241 {STV_REG03, 0x95},
242 {STV_REG04, 0x07},
243
244 {STV_SCAN_RATE, 0x20},
245 {STV_ISO_SIZE_L, 847},
246 {STV_Y_CTRL, 0x01},
247 {STV_X_CTRL, 0x0a}
248};
249
250static const u8 stv_sensor_init[][2] = {
251 /* Clear status (writing 1 will clear the corresponding status bit) */
252 {HDCS_STATUS, BIT(6) | BIT(5) | BIT(4) | BIT(3) | BIT(2) | BIT(1)},
253 /* Disable all interrupts */
254 {HDCS_IMASK, 0x00},
255 {HDCS_PCTRL, BIT(6) | BIT(5) | BIT(1) | BIT(0)},
256 {HDCS_PDRV, 0x00},
257 {HDCS_ICTRL, BIT(5)},
258 {HDCS_ITMG, BIT(4) | BIT(1)},
259 /* ADC output resolution to 10 bits */
260 {HDCS_ADCCTRL, 10}
261};
262
263#endif
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c b/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c
new file mode 100644
index 000000000000..d0a0f8596454
--- /dev/null
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c
@@ -0,0 +1,430 @@
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 int pb0100_probe(struct sd *sd)
50{
51 u16 sensor;
52 int i, err;
53 s32 *sensor_settings;
54
55 err = stv06xx_read_sensor(sd, PB_IDENT, &sensor);
56
57 if (err < 0)
58 return -ENODEV;
59
60 if ((sensor >> 8) == 0x64) {
61 sensor_settings = kmalloc(
62 stv06xx_sensor_pb0100.nctrls * sizeof(s32),
63 GFP_KERNEL);
64 if (!sensor_settings)
65 return -ENOMEM;
66
67 info("Photobit pb0100 sensor detected");
68
69 sd->gspca_dev.cam.cam_mode = stv06xx_sensor_pb0100.modes;
70 sd->gspca_dev.cam.nmodes = stv06xx_sensor_pb0100.nmodes;
71 sd->desc.ctrls = stv06xx_sensor_pb0100.ctrls;
72 sd->desc.nctrls = stv06xx_sensor_pb0100.nctrls;
73 for (i = 0; i < stv06xx_sensor_pb0100.nctrls; i++)
74 sensor_settings[i] = stv06xx_sensor_pb0100.
75 ctrls[i].qctrl.default_value;
76 sd->sensor_priv = sensor_settings;
77
78 return 0;
79 }
80
81 return -ENODEV;
82}
83
84static int pb0100_start(struct sd *sd)
85{
86 int err;
87 struct cam *cam = &sd->gspca_dev.cam;
88 s32 *sensor_settings = sd->sensor_priv;
89 u32 mode = cam->cam_mode[sd->gspca_dev.curr_mode].priv;
90
91 /* Setup sensor window */
92 if (mode & PB0100_CROP_TO_VGA) {
93 stv06xx_write_sensor(sd, PB_RSTART, 30);
94 stv06xx_write_sensor(sd, PB_CSTART, 20);
95 stv06xx_write_sensor(sd, PB_RWSIZE, 240 - 1);
96 stv06xx_write_sensor(sd, PB_CWSIZE, 320 - 1);
97 } else {
98 stv06xx_write_sensor(sd, PB_RSTART, 8);
99 stv06xx_write_sensor(sd, PB_CSTART, 4);
100 stv06xx_write_sensor(sd, PB_RWSIZE, 288 - 1);
101 stv06xx_write_sensor(sd, PB_CWSIZE, 352 - 1);
102 }
103
104 if (mode & PB0100_SUBSAMPLE) {
105 stv06xx_write_bridge(sd, STV_Y_CTRL, 0x02); /* Wrong, FIXME */
106 stv06xx_write_bridge(sd, STV_X_CTRL, 0x06);
107
108 stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x10);
109 } else {
110 stv06xx_write_bridge(sd, STV_Y_CTRL, 0x01);
111 stv06xx_write_bridge(sd, STV_X_CTRL, 0x0a);
112 /* larger -> slower */
113 stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x20);
114 }
115
116 /* set_gain also sets red and blue balance */
117 pb0100_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
118 pb0100_set_exposure(&sd->gspca_dev, sensor_settings[EXPOSURE_IDX]);
119 pb0100_set_autogain_target(&sd->gspca_dev,
120 sensor_settings[AUTOGAIN_TARGET_IDX]);
121 pb0100_set_autogain(&sd->gspca_dev, sensor_settings[AUTOGAIN_IDX]);
122
123 err = stv06xx_write_sensor(sd, PB_CONTROL, BIT(5)|BIT(3)|BIT(1));
124 PDEBUG(D_STREAM, "Started stream, status: %d", err);
125
126 return (err < 0) ? err : 0;
127}
128
129static int pb0100_stop(struct sd *sd)
130{
131 int err;
132
133 err = stv06xx_write_sensor(sd, PB_ABORTFRAME, 1);
134
135 if (err < 0)
136 goto out;
137
138 /* Set bit 1 to zero */
139 err = stv06xx_write_sensor(sd, PB_CONTROL, BIT(5)|BIT(3));
140
141 PDEBUG(D_STREAM, "Halting stream");
142out:
143 return (err < 0) ? err : 0;
144}
145
146/* FIXME: Sort the init commands out and put them into tables,
147 this is only for getting the camera to work */
148/* FIXME: No error handling for now,
149 add this once the init has been converted to proper tables */
150static int pb0100_init(struct sd *sd)
151{
152 stv06xx_write_bridge(sd, STV_REG00, 1);
153 stv06xx_write_bridge(sd, STV_SCAN_RATE, 0);
154
155 /* Reset sensor */
156 stv06xx_write_sensor(sd, PB_RESET, 1);
157 stv06xx_write_sensor(sd, PB_RESET, 0);
158
159 /* Disable chip */
160 stv06xx_write_sensor(sd, PB_CONTROL, BIT(5)|BIT(3));
161
162 /* Gain stuff...*/
163 stv06xx_write_sensor(sd, PB_PREADCTRL, BIT(12)|BIT(10)|BIT(6));
164 stv06xx_write_sensor(sd, PB_ADCGLOBALGAIN, 12);
165
166 /* Set up auto-exposure */
167 /* ADC VREF_HI new setting for a transition
168 from the Expose1 to the Expose2 setting */
169 stv06xx_write_sensor(sd, PB_R28, 12);
170 /* gain max for autoexposure */
171 stv06xx_write_sensor(sd, PB_ADCMAXGAIN, 180);
172 /* gain min for autoexposure */
173 stv06xx_write_sensor(sd, PB_ADCMINGAIN, 12);
174 /* Maximum frame integration time (programmed into R8)
175 allowed for auto-exposure routine */
176 stv06xx_write_sensor(sd, PB_R54, 3);
177 /* Minimum frame integration time (programmed into R8)
178 allowed for auto-exposure routine */
179 stv06xx_write_sensor(sd, PB_R55, 0);
180 stv06xx_write_sensor(sd, PB_UPDATEINT, 1);
181 /* R15 Expose0 (maximum that auto-exposure may use) */
182 stv06xx_write_sensor(sd, PB_R15, 800);
183 /* R17 Expose2 (minimum that auto-exposure may use) */
184 stv06xx_write_sensor(sd, PB_R17, 10);
185
186 stv06xx_write_sensor(sd, PB_EXPGAIN, 0);
187
188 /* 0x14 */
189 stv06xx_write_sensor(sd, PB_VOFFSET, 0);
190 /* 0x0D */
191 stv06xx_write_sensor(sd, PB_ADCGAINH, 11);
192 /* Set black level (important!) */
193 stv06xx_write_sensor(sd, PB_ADCGAINL, 0);
194
195 /* ??? */
196 stv06xx_write_bridge(sd, STV_REG00, 0x11);
197 stv06xx_write_bridge(sd, STV_REG03, 0x45);
198 stv06xx_write_bridge(sd, STV_REG04, 0x07);
199
200 /* ISO-Size (0x27b: 635... why? - HDCS uses 847) */
201 stv06xx_write_bridge(sd, STV_ISO_SIZE_L, 847);
202
203 /* Scan/timing for the sensor */
204 stv06xx_write_sensor(sd, PB_ROWSPEED, BIT(4)|BIT(3)|BIT(1));
205 stv06xx_write_sensor(sd, PB_CFILLIN, 14);
206 stv06xx_write_sensor(sd, PB_VBL, 0);
207 stv06xx_write_sensor(sd, PB_FINTTIME, 0);
208 stv06xx_write_sensor(sd, PB_RINTTIME, 123);
209
210 stv06xx_write_bridge(sd, STV_REG01, 0xc2);
211 stv06xx_write_bridge(sd, STV_REG02, 0xb0);
212 return 0;
213}
214
215static int pb0100_dump(struct sd *sd)
216{
217 return 0;
218}
219
220static int pb0100_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
221{
222 struct sd *sd = (struct sd *) gspca_dev;
223 s32 *sensor_settings = sd->sensor_priv;
224
225 *val = sensor_settings[GAIN_IDX];
226
227 return 0;
228}
229
230static int pb0100_set_gain(struct gspca_dev *gspca_dev, __s32 val)
231{
232 int err;
233 struct sd *sd = (struct sd *) gspca_dev;
234 s32 *sensor_settings = sd->sensor_priv;
235
236 if (sensor_settings[AUTOGAIN_IDX])
237 return -EBUSY;
238
239 sensor_settings[GAIN_IDX] = val;
240 err = stv06xx_write_sensor(sd, PB_G1GAIN, val);
241 if (!err)
242 err = stv06xx_write_sensor(sd, PB_G2GAIN, val);
243 PDEBUG(D_V4L2, "Set green gain to %d, status: %d", val, err);
244
245 if (!err)
246 err = pb0100_set_red_balance(gspca_dev,
247 sensor_settings[RED_BALANCE_IDX]);
248 if (!err)
249 err = pb0100_set_blue_balance(gspca_dev,
250 sensor_settings[BLUE_BALANCE_IDX]);
251
252 return err;
253}
254
255static int pb0100_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
256{
257 struct sd *sd = (struct sd *) gspca_dev;
258 s32 *sensor_settings = sd->sensor_priv;
259
260 *val = sensor_settings[RED_BALANCE_IDX];
261
262 return 0;
263}
264
265static int pb0100_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
266{
267 int err;
268 struct sd *sd = (struct sd *) gspca_dev;
269 s32 *sensor_settings = sd->sensor_priv;
270
271 if (sensor_settings[AUTOGAIN_IDX])
272 return -EBUSY;
273
274 sensor_settings[RED_BALANCE_IDX] = val;
275 val += sensor_settings[GAIN_IDX];
276 if (val < 0)
277 val = 0;
278 else if (val > 255)
279 val = 255;
280
281 err = stv06xx_write_sensor(sd, PB_RGAIN, val);
282 PDEBUG(D_V4L2, "Set red gain to %d, status: %d", val, err);
283
284 return err;
285}
286
287static int pb0100_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
288{
289 struct sd *sd = (struct sd *) gspca_dev;
290 s32 *sensor_settings = sd->sensor_priv;
291
292 *val = sensor_settings[BLUE_BALANCE_IDX];
293
294 return 0;
295}
296
297static int pb0100_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
298{
299 int err;
300 struct sd *sd = (struct sd *) gspca_dev;
301 s32 *sensor_settings = sd->sensor_priv;
302
303 if (sensor_settings[AUTOGAIN_IDX])
304 return -EBUSY;
305
306 sensor_settings[BLUE_BALANCE_IDX] = val;
307 val += sensor_settings[GAIN_IDX];
308 if (val < 0)
309 val = 0;
310 else if (val > 255)
311 val = 255;
312
313 err = stv06xx_write_sensor(sd, PB_BGAIN, val);
314 PDEBUG(D_V4L2, "Set blue gain to %d, status: %d", val, err);
315
316 return err;
317}
318
319static int pb0100_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
320{
321 struct sd *sd = (struct sd *) gspca_dev;
322 s32 *sensor_settings = sd->sensor_priv;
323
324 *val = sensor_settings[EXPOSURE_IDX];
325
326 return 0;
327}
328
329static int pb0100_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
330{
331 int err;
332 struct sd *sd = (struct sd *) gspca_dev;
333 s32 *sensor_settings = sd->sensor_priv;
334
335 if (sensor_settings[AUTOGAIN_IDX])
336 return -EBUSY;
337
338 sensor_settings[EXPOSURE_IDX] = val;
339 err = stv06xx_write_sensor(sd, PB_RINTTIME, val);
340 PDEBUG(D_V4L2, "Set exposure to %d, status: %d", val, err);
341
342 return err;
343}
344
345static int pb0100_get_autogain(struct gspca_dev *gspca_dev, __s32 *val)
346{
347 struct sd *sd = (struct sd *) gspca_dev;
348 s32 *sensor_settings = sd->sensor_priv;
349
350 *val = sensor_settings[AUTOGAIN_IDX];
351
352 return 0;
353}
354
355static int pb0100_set_autogain(struct gspca_dev *gspca_dev, __s32 val)
356{
357 int err;
358 struct sd *sd = (struct sd *) gspca_dev;
359 s32 *sensor_settings = sd->sensor_priv;
360
361 sensor_settings[AUTOGAIN_IDX] = val;
362 if (sensor_settings[AUTOGAIN_IDX]) {
363 if (sensor_settings[NATURAL_IDX])
364 val = BIT(6)|BIT(4)|BIT(0);
365 else
366 val = BIT(4)|BIT(0);
367 } else
368 val = 0;
369
370 err = stv06xx_write_sensor(sd, PB_EXPGAIN, val);
371 PDEBUG(D_V4L2, "Set autogain to %d (natural: %d), status: %d",
372 sensor_settings[AUTOGAIN_IDX], sensor_settings[NATURAL_IDX],
373 err);
374
375 return err;
376}
377
378static int pb0100_get_autogain_target(struct gspca_dev *gspca_dev, __s32 *val)
379{
380 struct sd *sd = (struct sd *) gspca_dev;
381 s32 *sensor_settings = sd->sensor_priv;
382
383 *val = sensor_settings[AUTOGAIN_TARGET_IDX];
384
385 return 0;
386}
387
388static int pb0100_set_autogain_target(struct gspca_dev *gspca_dev, __s32 val)
389{
390 int err, totalpixels, brightpixels, darkpixels;
391 struct sd *sd = (struct sd *) gspca_dev;
392 s32 *sensor_settings = sd->sensor_priv;
393
394 sensor_settings[AUTOGAIN_TARGET_IDX] = val;
395
396 /* Number of pixels counted by the sensor when subsampling the pixels.
397 * Slightly larger than the real value to avoid oscillation */
398 totalpixels = gspca_dev->width * gspca_dev->height;
399 totalpixels = totalpixels/(8*8) + totalpixels/(64*64);
400
401 brightpixels = (totalpixels * val) >> 8;
402 darkpixels = totalpixels - brightpixels;
403 err = stv06xx_write_sensor(sd, PB_R21, brightpixels);
404 if (!err)
405 err = stv06xx_write_sensor(sd, PB_R22, darkpixels);
406
407 PDEBUG(D_V4L2, "Set autogain target to %d, status: %d", val, err);
408
409 return err;
410}
411
412static int pb0100_get_natural(struct gspca_dev *gspca_dev, __s32 *val)
413{
414 struct sd *sd = (struct sd *) gspca_dev;
415 s32 *sensor_settings = sd->sensor_priv;
416
417 *val = sensor_settings[NATURAL_IDX];
418
419 return 0;
420}
421
422static int pb0100_set_natural(struct gspca_dev *gspca_dev, __s32 val)
423{
424 struct sd *sd = (struct sd *) gspca_dev;
425 s32 *sensor_settings = sd->sensor_priv;
426
427 sensor_settings[NATURAL_IDX] = val;
428
429 return pb0100_set_autogain(gspca_dev, sensor_settings[AUTOGAIN_IDX]);
430}
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h b/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h
new file mode 100644
index 000000000000..5ea21a1154c4
--- /dev/null
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h
@@ -0,0 +1,275 @@
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#ifndef STV06XX_PB0100_H_
31#define STV06XX_PB0100_H_
32
33#include "stv06xx_sensor.h"
34
35/* mode priv field flags */
36#define PB0100_CROP_TO_VGA 0x01
37#define PB0100_SUBSAMPLE 0x02
38
39/* I2C Registers */
40#define PB_IDENT 0x00 /* Chip Version */
41#define PB_RSTART 0x01 /* Row Window Start */
42#define PB_CSTART 0x02 /* Column Window Start */
43#define PB_RWSIZE 0x03 /* Row Window Size */
44#define PB_CWSIZE 0x04 /* Column Window Size */
45#define PB_CFILLIN 0x05 /* Column Fill-In */
46#define PB_VBL 0x06 /* Vertical Blank Count */
47#define PB_CONTROL 0x07 /* Control Mode */
48#define PB_FINTTIME 0x08 /* Integration Time/Frame Unit Count */
49#define PB_RINTTIME 0x09 /* Integration Time/Row Unit Count */
50#define PB_ROWSPEED 0x0a /* Row Speed Control */
51#define PB_ABORTFRAME 0x0b /* Abort Frame */
52#define PB_R12 0x0c /* Reserved */
53#define PB_RESET 0x0d /* Reset */
54#define PB_EXPGAIN 0x0e /* Exposure Gain Command */
55#define PB_R15 0x0f /* Expose0 */
56#define PB_R16 0x10 /* Expose1 */
57#define PB_R17 0x11 /* Expose2 */
58#define PB_R18 0x12 /* Low0_DAC */
59#define PB_R19 0x13 /* Low1_DAC */
60#define PB_R20 0x14 /* Low2_DAC */
61#define PB_R21 0x15 /* Threshold11 */
62#define PB_R22 0x16 /* Threshold0x */
63#define PB_UPDATEINT 0x17 /* Update Interval */
64#define PB_R24 0x18 /* High_DAC */
65#define PB_R25 0x19 /* Trans0H */
66#define PB_R26 0x1a /* Trans1L */
67#define PB_R27 0x1b /* Trans1H */
68#define PB_R28 0x1c /* Trans2L */
69#define PB_R29 0x1d /* Reserved */
70#define PB_R30 0x1e /* Reserved */
71#define PB_R31 0x1f /* Wait to Read */
72#define PB_PREADCTRL 0x20 /* Pixel Read Control Mode */
73#define PB_R33 0x21 /* IREF_VLN */
74#define PB_R34 0x22 /* IREF_VLP */
75#define PB_R35 0x23 /* IREF_VLN_INTEG */
76#define PB_R36 0x24 /* IREF_MASTER */
77#define PB_R37 0x25 /* IDACP */
78#define PB_R38 0x26 /* IDACN */
79#define PB_R39 0x27 /* DAC_Control_Reg */
80#define PB_R40 0x28 /* VCL */
81#define PB_R41 0x29 /* IREF_VLN_ADCIN */
82#define PB_R42 0x2a /* Reserved */
83#define PB_G1GAIN 0x2b /* Green 1 Gain */
84#define PB_BGAIN 0x2c /* Blue Gain */
85#define PB_RGAIN 0x2d /* Red Gain */
86#define PB_G2GAIN 0x2e /* Green 2 Gain */
87#define PB_R47 0x2f /* Dark Row Address */
88#define PB_R48 0x30 /* Dark Row Options */
89#define PB_R49 0x31 /* Reserved */
90#define PB_R50 0x32 /* Image Test Data */
91#define PB_ADCMAXGAIN 0x33 /* Maximum Gain */
92#define PB_ADCMINGAIN 0x34 /* Minimum Gain */
93#define PB_ADCGLOBALGAIN 0x35 /* Global Gain */
94#define PB_R54 0x36 /* Maximum Frame */
95#define PB_R55 0x37 /* Minimum Frame */
96#define PB_R56 0x38 /* Reserved */
97#define PB_VOFFSET 0x39 /* VOFFSET */
98#define PB_R58 0x3a /* Snap-Shot Sequence Trigger */
99#define PB_ADCGAINH 0x3b /* VREF_HI */
100#define PB_ADCGAINL 0x3c /* VREF_LO */
101#define PB_R61 0x3d /* Reserved */
102#define PB_R62 0x3e /* Reserved */
103#define PB_R63 0x3f /* Reserved */
104#define PB_R64 0x40 /* Red/Blue Gain */
105#define PB_R65 0x41 /* Green 2/Green 1 Gain */
106#define PB_R66 0x42 /* VREF_HI/LO */
107#define PB_R67 0x43 /* Integration Time/Row Unit Count */
108#define PB_R240 0xf0 /* ADC Test */
109#define PB_R241 0xf1 /* Chip Enable */
110#define PB_R242 0xf2 /* Reserved */
111
112static int pb0100_probe(struct sd *sd);
113static int pb0100_start(struct sd *sd);
114static int pb0100_init(struct sd *sd);
115static int pb0100_stop(struct sd *sd);
116static int pb0100_dump(struct sd *sd);
117
118/* V4L2 controls supported by the driver */
119static int pb0100_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
120static int pb0100_set_gain(struct gspca_dev *gspca_dev, __s32 val);
121static int pb0100_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
122static int pb0100_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
123static int pb0100_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
124static int pb0100_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
125static int pb0100_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
126static int pb0100_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
127static int pb0100_get_autogain(struct gspca_dev *gspca_dev, __s32 *val);
128static int pb0100_set_autogain(struct gspca_dev *gspca_dev, __s32 val);
129static int pb0100_get_autogain_target(struct gspca_dev *gspca_dev, __s32 *val);
130static int pb0100_set_autogain_target(struct gspca_dev *gspca_dev, __s32 val);
131static int pb0100_get_natural(struct gspca_dev *gspca_dev, __s32 *val);
132static int pb0100_set_natural(struct gspca_dev *gspca_dev, __s32 val);
133
134const struct stv06xx_sensor stv06xx_sensor_pb0100 = {
135 .name = "PB-0100",
136 .i2c_flush = 1,
137 .i2c_addr = 0xba,
138 .i2c_len = 2,
139
140 .nctrls = 7,
141 .ctrls = {
142#define GAIN_IDX 0
143 {
144 {
145 .id = V4L2_CID_GAIN,
146 .type = V4L2_CTRL_TYPE_INTEGER,
147 .name = "Gain",
148 .minimum = 0,
149 .maximum = 255,
150 .step = 1,
151 .default_value = 128
152 },
153 .set = pb0100_set_gain,
154 .get = pb0100_get_gain
155 },
156#define RED_BALANCE_IDX 1
157 {
158 {
159 .id = V4L2_CID_RED_BALANCE,
160 .type = V4L2_CTRL_TYPE_INTEGER,
161 .name = "Red Balance",
162 .minimum = -255,
163 .maximum = 255,
164 .step = 1,
165 .default_value = 0
166 },
167 .set = pb0100_set_red_balance,
168 .get = pb0100_get_red_balance
169 },
170#define BLUE_BALANCE_IDX 2
171 {
172 {
173 .id = V4L2_CID_BLUE_BALANCE,
174 .type = V4L2_CTRL_TYPE_INTEGER,
175 .name = "Blue Balance",
176 .minimum = -255,
177 .maximum = 255,
178 .step = 1,
179 .default_value = 0
180 },
181 .set = pb0100_set_blue_balance,
182 .get = pb0100_get_blue_balance
183 },
184#define EXPOSURE_IDX 3
185 {
186 {
187 .id = V4L2_CID_EXPOSURE,
188 .type = V4L2_CTRL_TYPE_INTEGER,
189 .name = "Exposure",
190 .minimum = 0,
191 .maximum = 511,
192 .step = 1,
193 .default_value = 12
194 },
195 .set = pb0100_set_exposure,
196 .get = pb0100_get_exposure
197 },
198#define AUTOGAIN_IDX 4
199 {
200 {
201 .id = V4L2_CID_AUTOGAIN,
202 .type = V4L2_CTRL_TYPE_BOOLEAN,
203 .name = "Automatic Gain and Exposure",
204 .minimum = 0,
205 .maximum = 1,
206 .step = 1,
207 .default_value = 1
208 },
209 .set = pb0100_set_autogain,
210 .get = pb0100_get_autogain
211 },
212#define AUTOGAIN_TARGET_IDX 5
213 {
214 {
215 .id = V4L2_CTRL_CLASS_USER + 0x1000,
216 .type = V4L2_CTRL_TYPE_INTEGER,
217 .name = "Automatic Gain Target",
218 .minimum = 0,
219 .maximum = 255,
220 .step = 1,
221 .default_value = 128
222 },
223 .set = pb0100_set_autogain_target,
224 .get = pb0100_get_autogain_target
225 },
226#define NATURAL_IDX 6
227 {
228 {
229 .id = V4L2_CTRL_CLASS_USER + 0x1001,
230 .type = V4L2_CTRL_TYPE_BOOLEAN,
231 .name = "Natural Light Source",
232 .minimum = 0,
233 .maximum = 1,
234 .step = 1,
235 .default_value = 1
236 },
237 .set = pb0100_set_natural,
238 .get = pb0100_get_natural
239 },
240 },
241
242 .init = pb0100_init,
243 .probe = pb0100_probe,
244 .start = pb0100_start,
245 .stop = pb0100_stop,
246 .dump = pb0100_dump,
247
248 .nmodes = 2,
249 .modes = {
250/* low res / subsample modes disabled as they are only half res horizontal,
251 halving the vertical resolution does not seem to work */
252 {
253 320,
254 240,
255 V4L2_PIX_FMT_SGRBG8,
256 V4L2_FIELD_NONE,
257 .sizeimage = 320 * 240,
258 .bytesperline = 320,
259 .colorspace = V4L2_COLORSPACE_SRGB,
260 .priv = PB0100_CROP_TO_VGA
261 },
262 {
263 352,
264 288,
265 V4L2_PIX_FMT_SGRBG8,
266 V4L2_FIELD_NONE,
267 .sizeimage = 352 * 288,
268 .bytesperline = 352,
269 .colorspace = V4L2_COLORSPACE_SRGB,
270 .priv = 0
271 },
272 }
273};
274
275#endif
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h b/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h
new file mode 100644
index 000000000000..c726dacefa1f
--- /dev/null
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h
@@ -0,0 +1,92 @@
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#ifndef STV06XX_SENSOR_H_
31#define STV06XX_SENSOR_H_
32
33#include "stv06xx.h"
34
35#define IS_850(sd) ((sd)->gspca_dev.dev->descriptor.idProduct == 0x850)
36#define IS_870(sd) ((sd)->gspca_dev.dev->descriptor.idProduct == 0x870)
37#define IS_1020(sd) ((sd)->sensor == &stv06xx_sensor_hdcs1020)
38
39extern const struct stv06xx_sensor stv06xx_sensor_vv6410;
40extern const struct stv06xx_sensor stv06xx_sensor_hdcs1x00;
41extern const struct stv06xx_sensor stv06xx_sensor_hdcs1020;
42extern const struct stv06xx_sensor stv06xx_sensor_pb0100;
43
44#define STV06XX_MAX_CTRLS (V4L2_CID_LASTP1 - V4L2_CID_BASE + 10)
45
46struct stv06xx_sensor {
47 /* Defines the name of a sensor */
48 char name[32];
49
50 /* Sensor i2c address */
51 u8 i2c_addr;
52
53 /* Flush value*/
54 u8 i2c_flush;
55
56 /* length of an i2c word */
57 u8 i2c_len;
58
59 /* Probes if the sensor is connected */
60 int (*probe)(struct sd *sd);
61
62 /* Performs a initialization sequence */
63 int (*init)(struct sd *sd);
64
65 /* Executed at device disconnect */
66 void (*disconnect)(struct sd *sd);
67
68 /* Reads a sensor register */
69 int (*read_sensor)(struct sd *sd, const u8 address,
70 u8 *i2c_data, const u8 len);
71
72 /* Writes to a sensor register */
73 int (*write_sensor)(struct sd *sd, const u8 address,
74 u8 *i2c_data, const u8 len);
75
76 /* Instructs the sensor to start streaming */
77 int (*start)(struct sd *sd);
78
79 /* Instructs the sensor to stop streaming */
80 int (*stop)(struct sd *sd);
81
82 /* Instructs the sensor to dump all its contents */
83 int (*dump)(struct sd *sd);
84
85 int nctrls;
86 struct ctrl ctrls[STV06XX_MAX_CTRLS];
87
88 char nmodes;
89 struct v4l2_pix_format modes[];
90};
91
92#endif
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c
new file mode 100644
index 000000000000..1ca91f2a6dee
--- /dev/null
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c
@@ -0,0 +1,251 @@
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 int vv6410_probe(struct sd *sd)
33{
34 u16 data;
35 int err;
36
37 err = stv06xx_read_sensor(sd, VV6410_DEVICEH, &data);
38
39 if (err < 0)
40 return -ENODEV;
41
42 if (data == 0x19) {
43 info("vv6410 sensor detected");
44
45 sd->gspca_dev.cam.cam_mode = stv06xx_sensor_vv6410.modes;
46 sd->gspca_dev.cam.nmodes = stv06xx_sensor_vv6410.nmodes;
47 sd->desc.ctrls = stv06xx_sensor_vv6410.ctrls;
48 sd->desc.nctrls = stv06xx_sensor_vv6410.nctrls;
49 return 0;
50 }
51
52 return -ENODEV;
53}
54
55static int vv6410_init(struct sd *sd)
56{
57 int err = 0, i;
58
59 for (i = 0; i < ARRAY_SIZE(stv_bridge_init); i++) {
60 /* if NULL then len contains single value */
61 if (stv_bridge_init[i].data == NULL) {
62 err = stv06xx_write_bridge(sd,
63 stv_bridge_init[i].start,
64 stv_bridge_init[i].len);
65 } else {
66 int j;
67 for (j = 0; j < stv_bridge_init[i].len; j++)
68 err = stv06xx_write_bridge(sd,
69 stv_bridge_init[i].start + j,
70 stv_bridge_init[i].data[j]);
71 }
72 }
73
74 if (err < 0)
75 return err;
76
77 err = stv06xx_write_sensor_bytes(sd, (u8 *) vv6410_sensor_init,
78 ARRAY_SIZE(vv6410_sensor_init));
79
80 return (err < 0) ? err : 0;
81}
82
83static int vv6410_start(struct sd *sd)
84{
85 int err;
86 struct cam *cam = &sd->gspca_dev.cam;
87 u32 priv = cam->cam_mode[sd->gspca_dev.curr_mode].priv;
88
89 if (priv & VV6410_CROP_TO_QVGA) {
90 PDEBUG(D_CONF, "Cropping to QVGA");
91 stv06xx_write_sensor(sd, VV6410_XENDH, 320 - 1);
92 stv06xx_write_sensor(sd, VV6410_YENDH, 240 - 1);
93 } else {
94 stv06xx_write_sensor(sd, VV6410_XENDH, 360 - 1);
95 stv06xx_write_sensor(sd, VV6410_YENDH, 294 - 1);
96 }
97
98 if (priv & VV6410_SUBSAMPLE) {
99 PDEBUG(D_CONF, "Enabling subsampling");
100 stv06xx_write_bridge(sd, STV_Y_CTRL, 0x02);
101 stv06xx_write_bridge(sd, STV_X_CTRL, 0x06);
102
103 stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x10);
104 } else {
105 stv06xx_write_bridge(sd, STV_Y_CTRL, 0x01);
106 stv06xx_write_bridge(sd, STV_X_CTRL, 0x0a);
107
108 stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x20);
109 }
110
111 /* Turn on LED */
112 err = stv06xx_write_bridge(sd, STV_LED_CTRL, LED_ON);
113 if (err < 0)
114 return err;
115
116 err = stv06xx_write_sensor(sd, VV6410_SETUP0, 0);
117 if (err < 0)
118 return err;
119
120 PDEBUG(D_STREAM, "Starting stream");
121
122 return 0;
123}
124
125static int vv6410_stop(struct sd *sd)
126{
127 int err;
128
129 /* Turn off LED */
130 err = stv06xx_write_bridge(sd, STV_LED_CTRL, LED_OFF);
131 if (err < 0)
132 return err;
133
134 err = stv06xx_write_sensor(sd, VV6410_SETUP0, VV6410_LOW_POWER_MODE);
135 if (err < 0)
136 return err;
137
138 PDEBUG(D_STREAM, "Halting stream");
139
140 return (err < 0) ? err : 0;
141}
142
143static int vv6410_dump(struct sd *sd)
144{
145 u8 i;
146 int err = 0;
147
148 info("Dumping all vv6410 sensor registers");
149 for (i = 0; i < 0xff && !err; i++) {
150 u16 data;
151 err = stv06xx_read_sensor(sd, i, &data);
152 info("Register 0x%x contained 0x%x", i, data);
153 }
154 return (err < 0) ? err : 0;
155}
156
157static int vv6410_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
158{
159 int err;
160 u16 i2c_data;
161 struct sd *sd = (struct sd *) gspca_dev;
162
163 err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data);
164
165 *val = (i2c_data & VV6410_HFLIP) ? 1 : 0;
166
167 PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
168
169 return (err < 0) ? err : 0;
170}
171
172static int vv6410_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
173{
174 int err;
175 u16 i2c_data;
176 struct sd *sd = (struct sd *) gspca_dev;
177 err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data);
178 if (err < 0)
179 return err;
180
181 if (val)
182 i2c_data |= VV6410_HFLIP;
183 else
184 i2c_data &= ~VV6410_HFLIP;
185
186 PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
187 err = stv06xx_write_sensor(sd, VV6410_DATAFORMAT, i2c_data);
188
189 return (err < 0) ? err : 0;
190}
191
192static int vv6410_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
193{
194 int err;
195 u16 i2c_data;
196 struct sd *sd = (struct sd *) gspca_dev;
197
198 err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data);
199
200 *val = (i2c_data & VV6410_VFLIP) ? 1 : 0;
201
202 PDEBUG(D_V4L2, "Read vertical flip %d", *val);
203
204 return (err < 0) ? err : 0;
205}
206
207static int vv6410_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
208{
209 int err;
210 u16 i2c_data;
211 struct sd *sd = (struct sd *) gspca_dev;
212 err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data);
213 if (err < 0)
214 return err;
215
216 if (val)
217 i2c_data |= VV6410_VFLIP;
218 else
219 i2c_data &= ~VV6410_VFLIP;
220
221 PDEBUG(D_V4L2, "Set vertical flip to %d", val);
222 err = stv06xx_write_sensor(sd, VV6410_DATAFORMAT, i2c_data);
223
224 return (err < 0) ? err : 0;
225}
226
227static int vv6410_get_analog_gain(struct gspca_dev *gspca_dev, __s32 *val)
228{
229 int err;
230 u16 i2c_data;
231 struct sd *sd = (struct sd *) gspca_dev;
232
233 err = stv06xx_read_sensor(sd, VV6410_ANALOGGAIN, &i2c_data);
234
235 *val = i2c_data & 0xf;
236
237 PDEBUG(D_V4L2, "Read analog gain %d", *val);
238
239 return (err < 0) ? err : 0;
240}
241
242static int vv6410_set_analog_gain(struct gspca_dev *gspca_dev, __s32 val)
243{
244 int err;
245 struct sd *sd = (struct sd *) gspca_dev;
246
247 PDEBUG(D_V4L2, "Set analog gain to %d", val);
248 err = stv06xx_write_sensor(sd, VV6410_ANALOGGAIN, 0xf0 | (val & 0xf));
249
250 return (err < 0) ? err : 0;
251}
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h
new file mode 100644
index 000000000000..3ff8c4ea3362
--- /dev/null
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h
@@ -0,0 +1,315 @@
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#ifndef STV06XX_VV6410_H_
31#define STV06XX_VV6410_H_
32
33#include "stv06xx_sensor.h"
34
35#define VV6410_COLS 416
36#define VV6410_ROWS 320
37
38/* Status registers */
39/* Chip identification number including revision indicator */
40#define VV6410_DEVICEH 0x00
41#define VV6410_DEVICEL 0x01
42
43/* User can determine whether timed I2C data
44 has been consumed by interrogating flag states */
45#define VV6410_STATUS0 0x02
46
47/* Current line counter value */
48#define VV6410_LINECOUNTH 0x03
49#define VV6410_LINECOUNTL 0x04
50
51/* End x coordinate of image size */
52#define VV6410_XENDH 0x05
53#define VV6410_XENDL 0x06
54
55/* End y coordinate of image size */
56#define VV6410_YENDH 0x07
57#define VV6410_YENDL 0x08
58
59/* This is the average pixel value returned from the
60 dark line offset cancellation algorithm */
61#define VV6410_DARKAVGH 0x09
62#define VV6410_DARKAVGL 0x0a
63
64/* This is the average pixel value returned from the
65 black line offset cancellation algorithm */
66#define VV6410_BLACKAVGH 0x0b
67#define VV6410_BLACKAVGL 0x0c
68
69/* Flags to indicate whether the x or y image coordinates have been clipped */
70#define VV6410_STATUS1 0x0d
71
72/* Setup registers */
73
74/* Low-power/sleep modes & video timing */
75#define VV6410_SETUP0 0x10
76
77/* Various parameters */
78#define VV6410_SETUP1 0x11
79
80/* Contains pixel counter reset value used by external sync */
81#define VV6410_SYNCVALUE 0x12
82
83/* Frame grabbing modes (FST, LST and QCK) */
84#define VV6410_FGMODES 0x14
85
86/* FST and QCK mapping modes. */
87#define VV6410_PINMAPPING 0x15
88
89/* Data resolution */
90#define VV6410_DATAFORMAT 0x16
91
92/* Output coding formats */
93#define VV6410_OPFORMAT 0x17
94
95/* Various mode select bits */
96#define VV6410_MODESELECT 0x18
97
98/* Exposure registers */
99/* Fine exposure. */
100#define VV6410_FINEH 0x20
101#define VV6410_FINEL 0x21
102
103/* Coarse exposure */
104#define VV6410_COARSEH 0x22
105#define VV6410_COARSEL 0x23
106
107/* Analog gain setting */
108#define VV6410_ANALOGGAIN 0x24
109
110/* Clock division */
111#define VV6410_CLKDIV 0x25
112
113/* Dark line offset cancellation value */
114#define VV6410_DARKOFFSETH 0x2c
115#define VV6410_DARKOFFSETL 0x2d
116
117/* Dark line offset cancellation enable */
118#define VV6410_DARKOFFSETSETUP 0x2e
119
120/* Video timing registers */
121/* Line Length (Pixel Clocks) */
122#define VV6410_LINELENGTHH 0x52
123#define VV6410_LINELENGTHL 0x53
124
125/* X-co-ordinate of top left corner of region of interest (x-offset) */
126#define VV6410_XOFFSETH 0x57
127#define VV6410_XOFFSETL 0x58
128
129/* Y-coordinate of top left corner of region of interest (y-offset) */
130#define VV6410_YOFFSETH 0x59
131#define VV6410_YOFFSETL 0x5a
132
133/* Field length (Lines) */
134#define VV6410_FIELDLENGTHH 0x61
135#define VV6410_FIELDLENGTHL 0x62
136
137/* System registers */
138/* Black offset cancellation default value */
139#define VV6410_BLACKOFFSETH 0x70
140#define VV6410_BLACKOFFSETL 0x71
141
142/* Black offset cancellation setup */
143#define VV6410_BLACKOFFSETSETUP 0x72
144
145/* Analog Control Register 0 */
146#define VV6410_CR0 0x75
147
148/* Analog Control Register 1 */
149#define VV6410_CR1 0x76
150
151/* ADC Setup Register */
152#define VV6410_AS0 0x77
153
154/* Analog Test Register */
155#define VV6410_AT0 0x78
156
157/* Audio Amplifier Setup Register */
158#define VV6410_AT1 0x79
159
160#define VV6410_HFLIP (1 << 3)
161#define VV6410_VFLIP (1 << 4)
162
163#define VV6410_LOW_POWER_MODE (1 << 0)
164#define VV6410_SOFT_RESET (1 << 2)
165#define VV6410_PAL_25_FPS (0 << 3)
166
167#define VV6410_CLK_DIV_2 (1 << 1)
168
169#define VV6410_FINE_EXPOSURE 320
170#define VV6410_COARSE_EXPOSURE 192
171#define VV6410_DEFAULT_GAIN 5
172
173#define VV6410_SUBSAMPLE 0x01
174#define VV6410_CROP_TO_QVGA 0x02
175
176static int vv6410_probe(struct sd *sd);
177static int vv6410_start(struct sd *sd);
178static int vv6410_init(struct sd *sd);
179static int vv6410_stop(struct sd *sd);
180static int vv6410_dump(struct sd *sd);
181
182/* V4L2 controls supported by the driver */
183static int vv6410_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
184static int vv6410_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
185static int vv6410_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
186static int vv6410_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
187static int vv6410_get_analog_gain(struct gspca_dev *gspca_dev, __s32 *val);
188static int vv6410_set_analog_gain(struct gspca_dev *gspca_dev, __s32 val);
189
190const struct stv06xx_sensor stv06xx_sensor_vv6410 = {
191 .name = "ST VV6410",
192 .i2c_flush = 5,
193 .i2c_addr = 0x20,
194 .i2c_len = 1,
195 .init = vv6410_init,
196 .probe = vv6410_probe,
197 .start = vv6410_start,
198 .stop = vv6410_stop,
199 .dump = vv6410_dump,
200
201 .nctrls = 3,
202 .ctrls = {
203 {
204 {
205 .id = V4L2_CID_HFLIP,
206 .type = V4L2_CTRL_TYPE_BOOLEAN,
207 .name = "horizontal flip",
208 .minimum = 0,
209 .maximum = 1,
210 .step = 1,
211 .default_value = 0
212 },
213 .set = vv6410_set_hflip,
214 .get = vv6410_get_hflip
215 }, {
216 {
217 .id = V4L2_CID_VFLIP,
218 .type = V4L2_CTRL_TYPE_BOOLEAN,
219 .name = "vertical flip",
220 .minimum = 0,
221 .maximum = 1,
222 .step = 1,
223 .default_value = 0
224 },
225 .set = vv6410_set_vflip,
226 .get = vv6410_get_vflip
227 }, {
228 {
229 .id = V4L2_CID_GAIN,
230 .type = V4L2_CTRL_TYPE_INTEGER,
231 .name = "analog gain",
232 .minimum = 0,
233 .maximum = 15,
234 .step = 1,
235 .default_value = 0
236 },
237 .set = vv6410_set_analog_gain,
238 .get = vv6410_get_analog_gain
239 }
240 },
241
242 .nmodes = 1,
243 .modes = {
244 {
245 356,
246 292,
247 V4L2_PIX_FMT_SGRBG8,
248 V4L2_FIELD_NONE,
249 .sizeimage =
250 356 * 292,
251 .bytesperline = 356,
252 .colorspace = V4L2_COLORSPACE_SRGB,
253 .priv = 0
254 }
255 }
256};
257
258/* If NULL, only single value to write, stored in len */
259struct stv_init {
260 const u8 *data;
261 u16 start;
262 u8 len;
263};
264
265static const u8 x1500[] = { /* 0x1500 - 0x150f */
266 0x0b, 0xa7, 0xb7, 0x00, 0x00
267};
268
269static const u8 x1536[] = { /* 0x1536 - 0x153b */
270 0x02, 0x00, 0x60, 0x01, 0x20, 0x01
271};
272
273static const u8 x15c1[] = { /* 0x15c1 - 0x15c2 */
274 0xff, 0x03 /* Output word 0x03ff = 1023 (ISO size) */
275};
276
277static const struct stv_init stv_bridge_init[] = {
278 /* This reg is written twice. Some kind of reset? */
279 {NULL, 0x1620, 0x80},
280 {NULL, 0x1620, 0x00},
281 {NULL, 0x1423, 0x04},
282 {x1500, 0x1500, ARRAY_SIZE(x1500)},
283 {x1536, 0x1536, ARRAY_SIZE(x1536)},
284 {x15c1, 0x15c1, ARRAY_SIZE(x15c1)}
285};
286
287static const u8 vv6410_sensor_init[][2] = {
288 /* Setup registers */
289 {VV6410_SETUP0, VV6410_SOFT_RESET},
290 {VV6410_SETUP0, VV6410_LOW_POWER_MODE},
291 /* Use shuffled read-out mode */
292 {VV6410_SETUP1, BIT(6)},
293 /* All modes to 1 */
294 {VV6410_FGMODES, BIT(6) | BIT(4) | BIT(2) | BIT(0)},
295 {VV6410_PINMAPPING, 0x00},
296 /* Pre-clock generator divide off */
297 {VV6410_DATAFORMAT, BIT(7) | BIT(0)},
298
299 /* Exposure registers */
300 {VV6410_FINEH, VV6410_FINE_EXPOSURE >> 8},
301 {VV6410_FINEL, VV6410_FINE_EXPOSURE & 0xff},
302 {VV6410_COARSEH, VV6410_COARSE_EXPOSURE >> 8},
303 {VV6410_COARSEL, VV6410_COARSE_EXPOSURE & 0xff},
304 {VV6410_ANALOGGAIN, 0xf0 | VV6410_DEFAULT_GAIN},
305 {VV6410_CLKDIV, VV6410_CLK_DIV_2},
306
307 /* System registers */
308 /* Enable voltage doubler */
309 {VV6410_AS0, BIT(6) | BIT(4) | BIT(3) | BIT(2) | BIT(1)},
310 {VV6410_AT0, 0x00},
311 /* Power up audio, differential */
312 {VV6410_AT1, BIT(4)|BIT(0)},
313};
314
315#endif